if_nge.c revision 152315
1139749Simp/*- 276479Swpaul * Copyright (c) 2001 Wind River Systems 376479Swpaul * Copyright (c) 1997, 1998, 1999, 2000, 2001 476479Swpaul * Bill Paul <wpaul@bsdi.com>. All rights reserved. 576479Swpaul * 676479Swpaul * Redistribution and use in source and binary forms, with or without 776479Swpaul * modification, are permitted provided that the following conditions 876479Swpaul * are met: 976479Swpaul * 1. Redistributions of source code must retain the above copyright 1076479Swpaul * notice, this list of conditions and the following disclaimer. 1176479Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1276479Swpaul * notice, this list of conditions and the following disclaimer in the 1376479Swpaul * documentation and/or other materials provided with the distribution. 1476479Swpaul * 3. All advertising materials mentioning features or use of this software 1576479Swpaul * must display the following acknowledgement: 1676479Swpaul * This product includes software developed by Bill Paul. 1776479Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1876479Swpaul * may be used to endorse or promote products derived from this software 1976479Swpaul * without specific prior written permission. 2076479Swpaul * 2176479Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2276479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2376479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2476479Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2576479Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2676479Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2776479Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2876479Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2976479Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3076479Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3176479Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3276479Swpaul */ 3376479Swpaul 34119418Sobrien#include <sys/cdefs.h> 35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/nge/if_nge.c 152315 2005-11-11 16:04:59Z ru $"); 36119418Sobrien 3776479Swpaul/* 3876479Swpaul * National Semiconductor DP83820/DP83821 gigabit ethernet driver 3976479Swpaul * for FreeBSD. Datasheets are available from: 4076479Swpaul * 4176479Swpaul * http://www.national.com/ds/DP/DP83820.pdf 4276479Swpaul * http://www.national.com/ds/DP/DP83821.pdf 4376479Swpaul * 4476479Swpaul * These chips are used on several low cost gigabit ethernet NICs 4576479Swpaul * sold by D-Link, Addtron, SMC and Asante. Both parts are 4676479Swpaul * virtually the same, except the 83820 is a 64-bit/32-bit part, 4776479Swpaul * while the 83821 is 32-bit only. 4876479Swpaul * 4976479Swpaul * Many cards also use National gigE transceivers, such as the 5076479Swpaul * DP83891, DP83861 and DP83862 gigPHYTER parts. The DP83861 datasheet 5176479Swpaul * contains a full register description that applies to all of these 5276479Swpaul * components: 5376479Swpaul * 5476479Swpaul * http://www.national.com/ds/DP/DP83861.pdf 5576479Swpaul * 5676479Swpaul * Written by Bill Paul <wpaul@bsdi.com> 5776479Swpaul * BSDi Open Source Solutions 5876479Swpaul */ 5976479Swpaul 6076479Swpaul/* 6176479Swpaul * The NatSemi DP83820 and 83821 controllers are enhanced versions 6276479Swpaul * of the NatSemi MacPHYTER 10/100 devices. They support 10, 100 6376479Swpaul * and 1000Mbps speeds with 1000baseX (ten bit interface), MII and GMII 6476479Swpaul * ports. Other features include 8K TX FIFO and 32K RX FIFO, TCP/IP 6576479Swpaul * hardware checksum offload (IPv4 only), VLAN tagging and filtering, 6676479Swpaul * priority TX and RX queues, a 2048 bit multicast hash filter, 4 RX pattern 6776479Swpaul * matching buffers, one perfect address filter buffer and interrupt 6876479Swpaul * moderation. The 83820 supports both 64-bit and 32-bit addressing 6976479Swpaul * and data transfers: the 64-bit support can be toggled on or off 7076479Swpaul * via software. This affects the size of certain fields in the DMA 7176479Swpaul * descriptors. 7276479Swpaul * 7378323Swpaul * There are two bugs/misfeatures in the 83820/83821 that I have 7478323Swpaul * discovered so far: 7578323Swpaul * 7678323Swpaul * - Receive buffers must be aligned on 64-bit boundaries, which means 7778323Swpaul * you must resort to copying data in order to fix up the payload 7878323Swpaul * alignment. 7978323Swpaul * 8078323Swpaul * - In order to transmit jumbo frames larger than 8170 bytes, you have 8178323Swpaul * to turn off transmit checksum offloading, because the chip can't 8278323Swpaul * compute the checksum on an outgoing frame unless it fits entirely 8378323Swpaul * within the TX FIFO, which is only 8192 bytes in size. If you have 8478323Swpaul * TX checksum offload enabled and you transmit attempt to transmit a 8578323Swpaul * frame larger than 8170 bytes, the transmitter will wedge. 8678323Swpaul * 8778323Swpaul * To work around the latter problem, TX checksum offload is disabled 8878323Swpaul * if the user selects an MTU larger than 8152 (8170 - 18). 8976479Swpaul */ 9076479Swpaul 91150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 92150968Sglebius#include "opt_device_polling.h" 93150968Sglebius#endif 94150968Sglebius 9576479Swpaul#include <sys/param.h> 9676479Swpaul#include <sys/systm.h> 9776479Swpaul#include <sys/sockio.h> 9876479Swpaul#include <sys/mbuf.h> 9976479Swpaul#include <sys/malloc.h> 100129879Sphk#include <sys/module.h> 10176479Swpaul#include <sys/kernel.h> 10276479Swpaul#include <sys/socket.h> 10376479Swpaul 10476479Swpaul#include <net/if.h> 10576479Swpaul#include <net/if_arp.h> 10676479Swpaul#include <net/ethernet.h> 10776479Swpaul#include <net/if_dl.h> 10876479Swpaul#include <net/if_media.h> 10976479Swpaul#include <net/if_types.h> 11076479Swpaul#include <net/if_vlan_var.h> 11176479Swpaul 11276479Swpaul#include <net/bpf.h> 11376479Swpaul 11476479Swpaul#include <vm/vm.h> /* for vtophys */ 11576479Swpaul#include <vm/pmap.h> /* for vtophys */ 11676479Swpaul#include <machine/clock.h> /* for DELAY */ 11776479Swpaul#include <machine/bus.h> 11876479Swpaul#include <machine/resource.h> 11976479Swpaul#include <sys/bus.h> 12076479Swpaul#include <sys/rman.h> 12176479Swpaul 12276479Swpaul#include <dev/mii/mii.h> 12376479Swpaul#include <dev/mii/miivar.h> 12476479Swpaul 125119285Simp#include <dev/pci/pcireg.h> 126119285Simp#include <dev/pci/pcivar.h> 12776479Swpaul 12876479Swpaul#define NGE_USEIOSPACE 12976479Swpaul 13076522Swpaul#include <dev/nge/if_ngereg.h> 13176479Swpaul 132113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1); 133113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1); 13476479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1); 13576479Swpaul 136151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 13776479Swpaul#include "miibus_if.h" 13876479Swpaul 13976479Swpaul#define NGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 14076479Swpaul 14176479Swpaul/* 14276479Swpaul * Various supported device vendors/types and their names. 14376479Swpaul */ 14476479Swpaulstatic struct nge_type nge_devs[] = { 14576479Swpaul { NGE_VENDORID, NGE_DEVICEID, 14676479Swpaul "National Semiconductor Gigabit Ethernet" }, 14776479Swpaul { 0, 0, NULL } 14876479Swpaul}; 14976479Swpaul 15099497Salfredstatic int nge_probe(device_t); 15199497Salfredstatic int nge_attach(device_t); 15299497Salfredstatic int nge_detach(device_t); 15376479Swpaul 15499497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *); 15599497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *); 156135254Salc#ifdef NGE_FIXUP_RX 157135250Swpaulstatic __inline void nge_fixup_rx (struct mbuf *); 158135250Swpaul#endif 15999497Salfredstatic void nge_rxeof(struct nge_softc *); 16099497Salfredstatic void nge_txeof(struct nge_softc *); 16199497Salfredstatic void nge_intr(void *); 16299497Salfredstatic void nge_tick(void *); 16399497Salfredstatic void nge_start(struct ifnet *); 164135250Swpaulstatic void nge_start_locked(struct ifnet *); 16599497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t); 16699497Salfredstatic void nge_init(void *); 167135250Swpaulstatic void nge_init_locked(struct nge_softc *); 16899497Salfredstatic void nge_stop(struct nge_softc *); 16999497Salfredstatic void nge_watchdog(struct ifnet *); 17099497Salfredstatic void nge_shutdown(device_t); 17199497Salfredstatic int nge_ifmedia_upd(struct ifnet *); 172151296Sjhbstatic void nge_ifmedia_upd_locked(struct ifnet *); 17399497Salfredstatic void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 17476479Swpaul 17599497Salfredstatic void nge_delay(struct nge_softc *); 17699497Salfredstatic void nge_eeprom_idle(struct nge_softc *); 17799497Salfredstatic void nge_eeprom_putbyte(struct nge_softc *, int); 17899497Salfredstatic void nge_eeprom_getword(struct nge_softc *, int, u_int16_t *); 17999497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int); 18076479Swpaul 18199497Salfredstatic void nge_mii_sync(struct nge_softc *); 18299497Salfredstatic void nge_mii_send(struct nge_softc *, u_int32_t, int); 18399497Salfredstatic int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *); 18499497Salfredstatic int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *); 18576479Swpaul 18699497Salfredstatic int nge_miibus_readreg(device_t, int, int); 18799497Salfredstatic int nge_miibus_writereg(device_t, int, int, int); 18899497Salfredstatic void nge_miibus_statchg(device_t); 18976479Swpaul 19099497Salfredstatic void nge_setmulti(struct nge_softc *); 19199497Salfredstatic void nge_reset(struct nge_softc *); 19299497Salfredstatic int nge_list_rx_init(struct nge_softc *); 19399497Salfredstatic int nge_list_tx_init(struct nge_softc *); 19476479Swpaul 19576479Swpaul#ifdef NGE_USEIOSPACE 19676479Swpaul#define NGE_RES SYS_RES_IOPORT 19776479Swpaul#define NGE_RID NGE_PCI_LOIO 19876479Swpaul#else 19976479Swpaul#define NGE_RES SYS_RES_MEMORY 20076479Swpaul#define NGE_RID NGE_PCI_LOMEM 20176479Swpaul#endif 20276479Swpaul 20376479Swpaulstatic device_method_t nge_methods[] = { 20476479Swpaul /* Device interface */ 20576479Swpaul DEVMETHOD(device_probe, nge_probe), 20676479Swpaul DEVMETHOD(device_attach, nge_attach), 20776479Swpaul DEVMETHOD(device_detach, nge_detach), 20876479Swpaul DEVMETHOD(device_shutdown, nge_shutdown), 20976479Swpaul 21076479Swpaul /* bus interface */ 21176479Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21276479Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21376479Swpaul 21476479Swpaul /* MII interface */ 21576479Swpaul DEVMETHOD(miibus_readreg, nge_miibus_readreg), 21676479Swpaul DEVMETHOD(miibus_writereg, nge_miibus_writereg), 21776479Swpaul DEVMETHOD(miibus_statchg, nge_miibus_statchg), 21876479Swpaul 21976479Swpaul { 0, 0 } 22076479Swpaul}; 22176479Swpaul 22276479Swpaulstatic driver_t nge_driver = { 22376479Swpaul "nge", 22476479Swpaul nge_methods, 22576479Swpaul sizeof(struct nge_softc) 22676479Swpaul}; 22776479Swpaul 22876479Swpaulstatic devclass_t nge_devclass; 22976479Swpaul 230113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0); 23176479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0); 23276479Swpaul 23376479Swpaul#define NGE_SETBIT(sc, reg, x) \ 23476479Swpaul CSR_WRITE_4(sc, reg, \ 23576479Swpaul CSR_READ_4(sc, reg) | (x)) 23676479Swpaul 23776479Swpaul#define NGE_CLRBIT(sc, reg, x) \ 23876479Swpaul CSR_WRITE_4(sc, reg, \ 23976479Swpaul CSR_READ_4(sc, reg) & ~(x)) 24076479Swpaul 24176479Swpaul#define SIO_SET(x) \ 242106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x)) 24376479Swpaul 24476479Swpaul#define SIO_CLR(x) \ 245106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x)) 24676479Swpaul 24799497Salfredstatic void 24899497Salfrednge_delay(sc) 24976479Swpaul struct nge_softc *sc; 25076479Swpaul{ 25176479Swpaul int idx; 25276479Swpaul 25376479Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 25476479Swpaul CSR_READ_4(sc, NGE_CSR); 25576479Swpaul 25676479Swpaul return; 25776479Swpaul} 25876479Swpaul 25999497Salfredstatic void 26099497Salfrednge_eeprom_idle(sc) 26176479Swpaul struct nge_softc *sc; 26276479Swpaul{ 26376479Swpaul register int i; 26476479Swpaul 26576479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26676479Swpaul nge_delay(sc); 26776479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26876479Swpaul nge_delay(sc); 26976479Swpaul 27076479Swpaul for (i = 0; i < 25; i++) { 27176479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27276479Swpaul nge_delay(sc); 27376479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 27476479Swpaul nge_delay(sc); 27576479Swpaul } 27676479Swpaul 27776479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27876479Swpaul nge_delay(sc); 27976479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 28076479Swpaul nge_delay(sc); 28176479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 28276479Swpaul 28376479Swpaul return; 28476479Swpaul} 28576479Swpaul 28676479Swpaul/* 28776479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28876479Swpaul */ 28999497Salfredstatic void 29099497Salfrednge_eeprom_putbyte(sc, addr) 29176479Swpaul struct nge_softc *sc; 29276479Swpaul int addr; 29376479Swpaul{ 29476479Swpaul register int d, i; 29576479Swpaul 29676479Swpaul d = addr | NGE_EECMD_READ; 29776479Swpaul 29876479Swpaul /* 29976479Swpaul * Feed in each bit and stobe the clock. 30076479Swpaul */ 30176479Swpaul for (i = 0x400; i; i >>= 1) { 30276479Swpaul if (d & i) { 30376479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 30476479Swpaul } else { 30576479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 30676479Swpaul } 30776479Swpaul nge_delay(sc); 30876479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30976479Swpaul nge_delay(sc); 31076479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 31176479Swpaul nge_delay(sc); 31276479Swpaul } 31376479Swpaul 31476479Swpaul return; 31576479Swpaul} 31676479Swpaul 31776479Swpaul/* 31876479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 31976479Swpaul */ 32099497Salfredstatic void 32199497Salfrednge_eeprom_getword(sc, addr, dest) 32276479Swpaul struct nge_softc *sc; 32376479Swpaul int addr; 32476479Swpaul u_int16_t *dest; 32576479Swpaul{ 32676479Swpaul register int i; 32776479Swpaul u_int16_t word = 0; 32876479Swpaul 32976479Swpaul /* Force EEPROM to idle state. */ 33076479Swpaul nge_eeprom_idle(sc); 33176479Swpaul 33276479Swpaul /* Enter EEPROM access mode. */ 33376479Swpaul nge_delay(sc); 33476479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 33576479Swpaul nge_delay(sc); 33676479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 33776479Swpaul nge_delay(sc); 33876479Swpaul 33976479Swpaul /* 34076479Swpaul * Send address of word we want to read. 34176479Swpaul */ 34276479Swpaul nge_eeprom_putbyte(sc, addr); 34376479Swpaul 34476479Swpaul /* 34576479Swpaul * Start reading bits from EEPROM. 34676479Swpaul */ 34776479Swpaul for (i = 0x8000; i; i >>= 1) { 34876479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 34976479Swpaul nge_delay(sc); 35076479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT) 35176479Swpaul word |= i; 35276479Swpaul nge_delay(sc); 35376479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 35476479Swpaul nge_delay(sc); 35576479Swpaul } 35676479Swpaul 35776479Swpaul /* Turn off EEPROM access mode. */ 35876479Swpaul nge_eeprom_idle(sc); 35976479Swpaul 36076479Swpaul *dest = word; 36176479Swpaul 36276479Swpaul return; 36376479Swpaul} 36476479Swpaul 36576479Swpaul/* 36676479Swpaul * Read a sequence of words from the EEPROM. 36776479Swpaul */ 36899497Salfredstatic void 36999497Salfrednge_read_eeprom(sc, dest, off, cnt, swap) 37076479Swpaul struct nge_softc *sc; 37176479Swpaul caddr_t dest; 37276479Swpaul int off; 37376479Swpaul int cnt; 37476479Swpaul int swap; 37576479Swpaul{ 37676479Swpaul int i; 37776479Swpaul u_int16_t word = 0, *ptr; 37876479Swpaul 37976479Swpaul for (i = 0; i < cnt; i++) { 38076479Swpaul nge_eeprom_getword(sc, off + i, &word); 38176479Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 38276479Swpaul if (swap) 38376479Swpaul *ptr = ntohs(word); 38476479Swpaul else 38576479Swpaul *ptr = word; 38676479Swpaul } 38776479Swpaul 38876479Swpaul return; 38976479Swpaul} 39076479Swpaul 39176479Swpaul/* 39276479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 39376479Swpaul */ 39499497Salfredstatic void 39599497Salfrednge_mii_sync(sc) 39676479Swpaul struct nge_softc *sc; 39776479Swpaul{ 39876479Swpaul register int i; 39976479Swpaul 40076479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 40176479Swpaul 40276479Swpaul for (i = 0; i < 32; i++) { 40376479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 40476479Swpaul DELAY(1); 40576479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40676479Swpaul DELAY(1); 40776479Swpaul } 40876479Swpaul 40976479Swpaul return; 41076479Swpaul} 41176479Swpaul 41276479Swpaul/* 41376479Swpaul * Clock a series of bits through the MII. 41476479Swpaul */ 41599497Salfredstatic void 41699497Salfrednge_mii_send(sc, bits, cnt) 41776479Swpaul struct nge_softc *sc; 41876479Swpaul u_int32_t bits; 41976479Swpaul int cnt; 42076479Swpaul{ 42176479Swpaul int i; 42276479Swpaul 42376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 42476479Swpaul 42576479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 42676479Swpaul if (bits & i) { 42776479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 42876479Swpaul } else { 42976479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 43076479Swpaul } 43176479Swpaul DELAY(1); 43276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 43376479Swpaul DELAY(1); 43476479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 43576479Swpaul } 43676479Swpaul} 43776479Swpaul 43876479Swpaul/* 43976479Swpaul * Read an PHY register through the MII. 44076479Swpaul */ 44199497Salfredstatic int 44299497Salfrednge_mii_readreg(sc, frame) 44376479Swpaul struct nge_softc *sc; 44476479Swpaul struct nge_mii_frame *frame; 44576479Swpaul 44676479Swpaul{ 447135250Swpaul int i, ack; 44876479Swpaul 44976479Swpaul /* 45076479Swpaul * Set up frame for RX. 45176479Swpaul */ 45276479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 45376479Swpaul frame->mii_opcode = NGE_MII_READOP; 45476479Swpaul frame->mii_turnaround = 0; 45576479Swpaul frame->mii_data = 0; 45676479Swpaul 45776479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 45876479Swpaul 45976479Swpaul /* 46076479Swpaul * Turn on data xmit. 46176479Swpaul */ 46276479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 46376479Swpaul 46476479Swpaul nge_mii_sync(sc); 46576479Swpaul 46676479Swpaul /* 46776479Swpaul * Send command/address info. 46876479Swpaul */ 46976479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 47076479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 47176479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 47276479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 47376479Swpaul 47476479Swpaul /* Idle bit */ 47576479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 47676479Swpaul DELAY(1); 47776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 47876479Swpaul DELAY(1); 47976479Swpaul 48076479Swpaul /* Turn off xmit. */ 48176479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 48276479Swpaul /* Check for ack */ 48376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 48476479Swpaul DELAY(1); 485109058Smbr ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 48676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48776479Swpaul DELAY(1); 48876479Swpaul 48976479Swpaul /* 49076479Swpaul * Now try reading data bits. If the ack failed, we still 49176479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 49276479Swpaul */ 49376479Swpaul if (ack) { 49476479Swpaul for(i = 0; i < 16; i++) { 49576479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 49676479Swpaul DELAY(1); 49776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 49876479Swpaul DELAY(1); 49976479Swpaul } 50076479Swpaul goto fail; 50176479Swpaul } 50276479Swpaul 50376479Swpaul for (i = 0x8000; i; i >>= 1) { 50476479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 50576479Swpaul DELAY(1); 50676479Swpaul if (!ack) { 50776479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 50876479Swpaul frame->mii_data |= i; 50976479Swpaul DELAY(1); 51076479Swpaul } 51176479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 51276479Swpaul DELAY(1); 51376479Swpaul } 51476479Swpaul 51576479Swpaulfail: 51676479Swpaul 51776479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 51876479Swpaul DELAY(1); 51976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 52076479Swpaul DELAY(1); 52176479Swpaul 52276479Swpaul if (ack) 52376479Swpaul return(1); 52476479Swpaul return(0); 52576479Swpaul} 52676479Swpaul 52776479Swpaul/* 52876479Swpaul * Write to a PHY register through the MII. 52976479Swpaul */ 53099497Salfredstatic int 53199497Salfrednge_mii_writereg(sc, frame) 53276479Swpaul struct nge_softc *sc; 53376479Swpaul struct nge_mii_frame *frame; 53476479Swpaul 53576479Swpaul{ 53676479Swpaul 53776479Swpaul /* 53876479Swpaul * Set up frame for TX. 53976479Swpaul */ 54076479Swpaul 54176479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 54276479Swpaul frame->mii_opcode = NGE_MII_WRITEOP; 54376479Swpaul frame->mii_turnaround = NGE_MII_TURNAROUND; 54476479Swpaul 54576479Swpaul /* 54676479Swpaul * Turn on data output. 54776479Swpaul */ 54876479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 54976479Swpaul 55076479Swpaul nge_mii_sync(sc); 55176479Swpaul 55276479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 55376479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 55476479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 55576479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 55676479Swpaul nge_mii_send(sc, frame->mii_turnaround, 2); 55776479Swpaul nge_mii_send(sc, frame->mii_data, 16); 55876479Swpaul 55976479Swpaul /* Idle bit. */ 56076479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 56176479Swpaul DELAY(1); 56276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 56376479Swpaul DELAY(1); 56476479Swpaul 56576479Swpaul /* 56676479Swpaul * Turn off xmit. 56776479Swpaul */ 56876479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 56976479Swpaul 57076479Swpaul return(0); 57176479Swpaul} 57276479Swpaul 57399497Salfredstatic int 57499497Salfrednge_miibus_readreg(dev, phy, reg) 57576479Swpaul device_t dev; 57676479Swpaul int phy, reg; 57776479Swpaul{ 57876479Swpaul struct nge_softc *sc; 57976479Swpaul struct nge_mii_frame frame; 58076479Swpaul 58176479Swpaul sc = device_get_softc(dev); 58276479Swpaul 58376479Swpaul bzero((char *)&frame, sizeof(frame)); 58476479Swpaul 58576479Swpaul frame.mii_phyaddr = phy; 58676479Swpaul frame.mii_regaddr = reg; 58776479Swpaul nge_mii_readreg(sc, &frame); 58876479Swpaul 58976479Swpaul return(frame.mii_data); 59076479Swpaul} 59176479Swpaul 59299497Salfredstatic int 59399497Salfrednge_miibus_writereg(dev, phy, reg, data) 59476479Swpaul device_t dev; 59576479Swpaul int phy, reg, data; 59676479Swpaul{ 59776479Swpaul struct nge_softc *sc; 59876479Swpaul struct nge_mii_frame frame; 59976479Swpaul 60076479Swpaul sc = device_get_softc(dev); 60176479Swpaul 60276479Swpaul bzero((char *)&frame, sizeof(frame)); 60376479Swpaul 60476479Swpaul frame.mii_phyaddr = phy; 60576479Swpaul frame.mii_regaddr = reg; 60676479Swpaul frame.mii_data = data; 60776479Swpaul nge_mii_writereg(sc, &frame); 60876479Swpaul 60976479Swpaul return(0); 61076479Swpaul} 61176479Swpaul 61299497Salfredstatic void 61399497Salfrednge_miibus_statchg(dev) 61476479Swpaul device_t dev; 61576479Swpaul{ 616101540Sambrisko int status; 61776479Swpaul struct nge_softc *sc; 61876479Swpaul struct mii_data *mii; 61976479Swpaul 62076479Swpaul sc = device_get_softc(dev); 621101540Sambrisko if (sc->nge_tbi) { 622101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 623101540Sambrisko == IFM_AUTO) { 624101540Sambrisko status = CSR_READ_4(sc, NGE_TBI_ANLPAR); 625101540Sambrisko if (status == 0 || status & NGE_TBIANAR_FDX) { 626101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 627101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 628101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 629101540Sambrisko } else { 630101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 631101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 632101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 633101540Sambrisko } 63476479Swpaul 635101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 636101540Sambrisko != IFM_FDX) { 637101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 638101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 639101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 640101540Sambrisko } else { 641101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 642101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 643101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 644101540Sambrisko } 64576479Swpaul } else { 646101540Sambrisko mii = device_get_softc(sc->nge_miibus); 64776479Swpaul 648101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 649101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 650101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 651101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 652101540Sambrisko } else { 653101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 654101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 655101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 656101540Sambrisko } 657101540Sambrisko 658101540Sambrisko /* If we have a 1000Mbps link, set the mode_1000 bit. */ 659101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 660101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 661101540Sambrisko NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 662101540Sambrisko } else { 663101540Sambrisko NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 664101540Sambrisko } 66579424Swpaul } 66676479Swpaul return; 66776479Swpaul} 66876479Swpaul 66999497Salfredstatic void 67099497Salfrednge_setmulti(sc) 67176479Swpaul struct nge_softc *sc; 67276479Swpaul{ 67376479Swpaul struct ifnet *ifp; 67476479Swpaul struct ifmultiaddr *ifma; 67576479Swpaul u_int32_t h = 0, i, filtsave; 67676479Swpaul int bit, index; 67776479Swpaul 678135250Swpaul NGE_LOCK_ASSERT(sc); 679147256Sbrooks ifp = sc->nge_ifp; 68076479Swpaul 68176479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 68276479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 68376479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 68476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 68576479Swpaul return; 68676479Swpaul } 68776479Swpaul 68876479Swpaul /* 68976479Swpaul * We have to explicitly enable the multicast hash table 69076479Swpaul * on the NatSemi chip if we want to use it, which we do. 69176479Swpaul * We also have to tell it that we don't want to use the 69276479Swpaul * hash table for matching unicast addresses. 69376479Swpaul */ 69476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 69576479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 69676479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 69776479Swpaul 69876479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 69976479Swpaul 70076479Swpaul /* first, zot all the existing hash bits */ 70176479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 70276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 70376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 70476479Swpaul } 70576479Swpaul 70676479Swpaul /* 70776479Swpaul * From the 11 bits returned by the crc routine, the top 7 70876479Swpaul * bits represent the 16-bit word in the mcast hash table 70976479Swpaul * that needs to be updated, and the lower 4 bits represent 71076479Swpaul * which bit within that byte needs to be set. 71176479Swpaul */ 712148654Srwatson IF_ADDR_LOCK(ifp); 71376479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 71476479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71576479Swpaul continue; 716130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 717130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 21; 71876479Swpaul index = (h >> 4) & 0x7F; 71976479Swpaul bit = h & 0xF; 72076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 72176479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 72276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 72376479Swpaul } 724148654Srwatson IF_ADDR_UNLOCK(ifp); 72576479Swpaul 72676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 72776479Swpaul 72876479Swpaul return; 72976479Swpaul} 73076479Swpaul 73199497Salfredstatic void 73299497Salfrednge_reset(sc) 73376479Swpaul struct nge_softc *sc; 73476479Swpaul{ 73576479Swpaul register int i; 73676479Swpaul 73776479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 73876479Swpaul 73976479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 74076479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 74176479Swpaul break; 74276479Swpaul } 74376479Swpaul 74476479Swpaul if (i == NGE_TIMEOUT) 745151296Sjhb if_printf(sc->nge_ifp, "reset never completed\n"); 74676479Swpaul 74776479Swpaul /* Wait a little while for the chip to get its brains in order. */ 74876479Swpaul DELAY(1000); 74976479Swpaul 75076479Swpaul /* 75176479Swpaul * If this is a NetSemi chip, make sure to clear 75276479Swpaul * PME mode. 75376479Swpaul */ 75476479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 75576479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 75676479Swpaul 75776479Swpaul return; 75876479Swpaul} 75976479Swpaul 76076479Swpaul/* 761108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 76276479Swpaul * IDs against our list and return a device name if we find a match. 76376479Swpaul */ 76499497Salfredstatic int 76599497Salfrednge_probe(dev) 76676479Swpaul device_t dev; 76776479Swpaul{ 76876479Swpaul struct nge_type *t; 76976479Swpaul 77076479Swpaul t = nge_devs; 77176479Swpaul 77276479Swpaul while(t->nge_name != NULL) { 77376479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 77476479Swpaul (pci_get_device(dev) == t->nge_did)) { 77576479Swpaul device_set_desc(dev, t->nge_name); 776143158Simp return(BUS_PROBE_DEFAULT); 77776479Swpaul } 77876479Swpaul t++; 77976479Swpaul } 78076479Swpaul 78176479Swpaul return(ENXIO); 78276479Swpaul} 78376479Swpaul 78476479Swpaul/* 78576479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 78676479Swpaul * setup and ethernet/BPF attach. 78776479Swpaul */ 78899497Salfredstatic int 78999497Salfrednge_attach(dev) 79076479Swpaul device_t dev; 79176479Swpaul{ 79276479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 79376479Swpaul struct nge_softc *sc; 794151296Sjhb struct ifnet *ifp = NULL; 795151296Sjhb int error = 0, rid; 79676479Swpaul 79776479Swpaul sc = device_get_softc(dev); 79876479Swpaul 799135250Swpaul NGE_LOCK_INIT(sc, device_get_nameunit(dev)); 800151296Sjhb callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0); 801151296Sjhb 80276479Swpaul /* 80376479Swpaul * Map control/status registers. 80476479Swpaul */ 80576479Swpaul pci_enable_busmaster(dev); 80676479Swpaul 80776479Swpaul rid = NGE_RID; 808127135Snjl sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE); 80976479Swpaul 81076479Swpaul if (sc->nge_res == NULL) { 811151296Sjhb device_printf(dev, "couldn't map ports/memory\n"); 81276479Swpaul error = ENXIO; 81376479Swpaul goto fail; 81476479Swpaul } 81576479Swpaul 81676479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 81776479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 81876479Swpaul 81976479Swpaul /* Allocate interrupt */ 82076479Swpaul rid = 0; 821127135Snjl sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 82276479Swpaul RF_SHAREABLE | RF_ACTIVE); 82376479Swpaul 82476479Swpaul if (sc->nge_irq == NULL) { 825151296Sjhb device_printf(dev, "couldn't map interrupt\n"); 82676479Swpaul error = ENXIO; 82776479Swpaul goto fail; 82876479Swpaul } 82976479Swpaul 83076479Swpaul /* Reset the adapter. */ 83176479Swpaul nge_reset(sc); 83276479Swpaul 83376479Swpaul /* 83476479Swpaul * Get station address from the EEPROM. 83576479Swpaul */ 83676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 83776479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 83876479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 83976479Swpaul 84076479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 841151296Sjhb M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 84276479Swpaul 84376479Swpaul if (sc->nge_ldata == NULL) { 844151296Sjhb device_printf(dev, "no memory for list buffers!\n"); 84576479Swpaul error = ENXIO; 84676479Swpaul goto fail; 84776479Swpaul } 84876479Swpaul 849147256Sbrooks ifp = sc->nge_ifp = if_alloc(IFT_ETHER); 850147256Sbrooks if (ifp == NULL) { 851151296Sjhb device_printf(dev, "can not if_alloc()\n"); 852147256Sbrooks error = ENOSPC; 853147256Sbrooks goto fail; 854147256Sbrooks } 85576479Swpaul ifp->if_softc = sc; 856121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 85776479Swpaul ifp->if_mtu = ETHERMTU; 858135250Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 85976479Swpaul ifp->if_ioctl = nge_ioctl; 86076479Swpaul ifp->if_start = nge_start; 86176479Swpaul ifp->if_watchdog = nge_watchdog; 86276479Swpaul ifp->if_init = nge_init; 86376479Swpaul ifp->if_baudrate = 1000000000; 86476479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 86576479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 866106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 867150789Sglebius ifp->if_capenable = ifp->if_capabilities; 868128132Sru#ifdef DEVICE_POLLING 869128132Sru ifp->if_capabilities |= IFCAP_POLLING; 870128132Sru#endif 87176479Swpaul 87276479Swpaul /* 87376479Swpaul * Do MII setup. 87476479Swpaul */ 875150185Sru /* XXX: leaked on error */ 87676479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 877101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 878101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 879101540Sambrisko sc->nge_tbi = 1; 880101540Sambrisko device_printf(dev, "Using TBI\n"); 881101540Sambrisko 882101540Sambrisko sc->nge_miibus = dev; 883101540Sambrisko 884101540Sambrisko ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 885101540Sambrisko nge_ifmedia_sts); 886101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 887101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 888101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 889101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 890101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 891101540Sambrisko#undef ADD 892151296Sjhb device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n"); 893151296Sjhb 894101540Sambrisko ifmedia_set(&sc->nge_ifmedia, 895101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 896101540Sambrisko 897101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 898101540Sambrisko | NGE_GPIO_GP4_OUT 899101540Sambrisko | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 900101540Sambrisko | NGE_GPIO_GP3_OUTENB 901101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 902101540Sambrisko 903101540Sambrisko } else { 904151296Sjhb device_printf(dev, "MII without any PHY!\n"); 905101540Sambrisko error = ENXIO; 906101540Sambrisko goto fail; 907101540Sambrisko } 90876479Swpaul } 90976479Swpaul 91076479Swpaul /* 91176479Swpaul * Call MI attach routine. 91276479Swpaul */ 913106937Ssam ether_ifattach(ifp, eaddr); 91476479Swpaul 915135250Swpaul /* 916135250Swpaul * Hookup IRQ last. 917135250Swpaul */ 918135250Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE, 919135250Swpaul nge_intr, sc, &sc->nge_intrhand); 920135250Swpaul if (error) { 921151296Sjhb device_printf(dev, "couldn't set up irq\n"); 922151296Sjhb goto fail; 923151296Sjhb } 924151296Sjhb 925151296Sjhb return (0); 926151296Sjhb 927151296Sjhbfail: 928151296Sjhb if (sc->nge_ldata) 929151296Sjhb contigfree(sc->nge_ldata, 930151296Sjhb sizeof(struct nge_list_data), M_DEVBUF); 931151296Sjhb if (ifp) 932150185Sru if_free(ifp); 933151296Sjhb if (sc->nge_irq) 934135250Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 935151296Sjhb if (sc->nge_res) 936135250Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 937151296Sjhb NGE_LOCK_DESTROY(sc); 93876479Swpaul return(error); 93976479Swpaul} 94076479Swpaul 94199497Salfredstatic int 94299497Salfrednge_detach(dev) 94376479Swpaul device_t dev; 94476479Swpaul{ 94576479Swpaul struct nge_softc *sc; 94676479Swpaul struct ifnet *ifp; 94776479Swpaul 94876479Swpaul sc = device_get_softc(dev); 949147256Sbrooks ifp = sc->nge_ifp; 95076479Swpaul 951150789Sglebius#ifdef DEVICE_POLLING 952150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 953150789Sglebius ether_poll_deregister(ifp); 954150789Sglebius#endif 955135250Swpaul NGE_LOCK(sc); 95676479Swpaul nge_reset(sc); 95776479Swpaul nge_stop(sc); 958135250Swpaul NGE_UNLOCK(sc); 959151296Sjhb callout_drain(&sc->nge_stat_ch); 960106937Ssam ether_ifdetach(ifp); 96176479Swpaul 96276479Swpaul bus_generic_detach(dev); 963101540Sambrisko if (!sc->nge_tbi) { 964101540Sambrisko device_delete_child(dev, sc->nge_miibus); 965101540Sambrisko } 96676479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 96776479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 96876479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 96976479Swpaul 97076479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 971150306Simp if_free(ifp); 97276479Swpaul 973135251Swpaul NGE_LOCK_DESTROY(sc); 974135251Swpaul 97576479Swpaul return(0); 97676479Swpaul} 97776479Swpaul 97876479Swpaul/* 97976479Swpaul * Initialize the transmit descriptors. 98076479Swpaul */ 98199497Salfredstatic int 98299497Salfrednge_list_tx_init(sc) 98376479Swpaul struct nge_softc *sc; 98476479Swpaul{ 98576479Swpaul struct nge_list_data *ld; 98676479Swpaul struct nge_ring_data *cd; 98776479Swpaul int i; 98876479Swpaul 98976479Swpaul cd = &sc->nge_cdata; 99076479Swpaul ld = sc->nge_ldata; 99176479Swpaul 99276479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 99376479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 99476479Swpaul ld->nge_tx_list[i].nge_nextdesc = 99576479Swpaul &ld->nge_tx_list[0]; 99676479Swpaul ld->nge_tx_list[i].nge_next = 99776479Swpaul vtophys(&ld->nge_tx_list[0]); 99876479Swpaul } else { 99976479Swpaul ld->nge_tx_list[i].nge_nextdesc = 100076479Swpaul &ld->nge_tx_list[i + 1]; 100176479Swpaul ld->nge_tx_list[i].nge_next = 100276479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 100376479Swpaul } 100476479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 100576479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 100676479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 100776479Swpaul } 100876479Swpaul 100976479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 101076479Swpaul 101176479Swpaul return(0); 101276479Swpaul} 101376479Swpaul 101476479Swpaul 101576479Swpaul/* 101676479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 101776479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 101876479Swpaul * points back to the first. 101976479Swpaul */ 102099497Salfredstatic int 102199497Salfrednge_list_rx_init(sc) 102276479Swpaul struct nge_softc *sc; 102376479Swpaul{ 102476479Swpaul struct nge_list_data *ld; 102576479Swpaul struct nge_ring_data *cd; 102676479Swpaul int i; 102776479Swpaul 102876479Swpaul ld = sc->nge_ldata; 102976479Swpaul cd = &sc->nge_cdata; 103076479Swpaul 103176479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 103276479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 103376479Swpaul return(ENOBUFS); 103476479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 103576479Swpaul ld->nge_rx_list[i].nge_nextdesc = 103676479Swpaul &ld->nge_rx_list[0]; 103776479Swpaul ld->nge_rx_list[i].nge_next = 103876479Swpaul vtophys(&ld->nge_rx_list[0]); 103976479Swpaul } else { 104076479Swpaul ld->nge_rx_list[i].nge_nextdesc = 104176479Swpaul &ld->nge_rx_list[i + 1]; 104276479Swpaul ld->nge_rx_list[i].nge_next = 104376479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 104476479Swpaul } 104576479Swpaul } 104676479Swpaul 104776479Swpaul cd->nge_rx_prod = 0; 1048135250Swpaul sc->nge_head = sc->nge_tail = NULL; 104976479Swpaul 105076479Swpaul return(0); 105176479Swpaul} 105276479Swpaul 105376479Swpaul/* 105476479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 105576479Swpaul */ 105699497Salfredstatic int 105799497Salfrednge_newbuf(sc, c, m) 105876479Swpaul struct nge_softc *sc; 105976479Swpaul struct nge_desc *c; 106076479Swpaul struct mbuf *m; 106176479Swpaul{ 106276479Swpaul 106376479Swpaul if (m == NULL) { 1064144241Ssam m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1065144241Ssam if (m == NULL) 1066135250Swpaul return (ENOBUFS); 1067135250Swpaul } else 1068135250Swpaul m->m_data = m->m_ext.ext_buf; 106976479Swpaul 1070135250Swpaul m->m_len = m->m_pkthdr.len = MCLBYTES; 107176479Swpaul 1072144241Ssam m_adj(m, sizeof(u_int64_t)); 107376479Swpaul 1074144241Ssam c->nge_mbuf = m; 1075144241Ssam c->nge_ptr = vtophys(mtod(m, caddr_t)); 1076144241Ssam c->nge_ctl = m->m_len; 107776479Swpaul c->nge_extsts = 0; 107876479Swpaul 107976479Swpaul return(0); 108076479Swpaul} 108176479Swpaul 1082135250Swpaul#ifdef NGE_FIXUP_RX 1083135250Swpaulstatic __inline void 1084135250Swpaulnge_fixup_rx(m) 1085135250Swpaul struct mbuf *m; 1086135250Swpaul{ 1087135250Swpaul int i; 1088135250Swpaul uint16_t *src, *dst; 1089135250Swpaul 1090135250Swpaul src = mtod(m, uint16_t *); 1091135250Swpaul dst = src - 1; 1092135250Swpaul 1093135250Swpaul for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1094135250Swpaul *dst++ = *src++; 1095135250Swpaul 1096135250Swpaul m->m_data -= ETHER_ALIGN; 1097135250Swpaul 109876479Swpaul return; 1099135250Swpaul} 110076479Swpaul#endif 110176479Swpaul 110276479Swpaul/* 110376479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 110476479Swpaul * the higher level protocols. 110576479Swpaul */ 110699497Salfredstatic void 110799497Salfrednge_rxeof(sc) 110876479Swpaul struct nge_softc *sc; 110976479Swpaul{ 111076479Swpaul struct mbuf *m; 111176479Swpaul struct ifnet *ifp; 111276479Swpaul struct nge_desc *cur_rx; 111376479Swpaul int i, total_len = 0; 111476479Swpaul u_int32_t rxstat; 111576479Swpaul 1116135250Swpaul NGE_LOCK_ASSERT(sc); 1117147256Sbrooks ifp = sc->nge_ifp; 111876479Swpaul i = sc->nge_cdata.nge_rx_prod; 111976479Swpaul 112076479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 112176479Swpaul u_int32_t extsts; 112276479Swpaul 1123106507Ssimokawa#ifdef DEVICE_POLLING 1124150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1125106507Ssimokawa if (sc->rxcycles <= 0) 1126106507Ssimokawa break; 1127106507Ssimokawa sc->rxcycles--; 1128106507Ssimokawa } 1129150789Sglebius#endif 1130106507Ssimokawa 113176479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 113276479Swpaul rxstat = cur_rx->nge_rxstat; 113376479Swpaul extsts = cur_rx->nge_extsts; 113476479Swpaul m = cur_rx->nge_mbuf; 113576479Swpaul cur_rx->nge_mbuf = NULL; 113676479Swpaul total_len = NGE_RXBYTES(cur_rx); 113776479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 1138135250Swpaul 1139135250Swpaul if (rxstat & NGE_CMDSTS_MORE) { 1140135250Swpaul m->m_len = total_len; 1141135250Swpaul if (sc->nge_head == NULL) { 1142135250Swpaul m->m_pkthdr.len = total_len; 1143135250Swpaul sc->nge_head = sc->nge_tail = m; 1144135250Swpaul } else { 1145135250Swpaul m->m_flags &= ~M_PKTHDR; 1146135250Swpaul sc->nge_head->m_pkthdr.len += total_len; 1147135250Swpaul sc->nge_tail->m_next = m; 1148135250Swpaul sc->nge_tail = m; 1149135250Swpaul } 1150135250Swpaul nge_newbuf(sc, cur_rx, NULL); 1151135250Swpaul continue; 1152135250Swpaul } 1153135250Swpaul 115476479Swpaul /* 115576479Swpaul * If an error occurs, update stats, clear the 115676479Swpaul * status word and leave the mbuf cluster in place: 115776479Swpaul * it should simply get re-used next time this descriptor 115876479Swpaul * comes up in the ring. 115976479Swpaul */ 116076479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 116176479Swpaul ifp->if_ierrors++; 1162135250Swpaul if (sc->nge_head != NULL) { 1163135250Swpaul m_freem(sc->nge_head); 1164135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1165135250Swpaul } 116676479Swpaul nge_newbuf(sc, cur_rx, m); 116776479Swpaul continue; 116876479Swpaul } 116976479Swpaul 1170135250Swpaul /* Try conjure up a replacement mbuf. */ 1171135250Swpaul 1172135250Swpaul if (nge_newbuf(sc, cur_rx, NULL)) { 1173135250Swpaul ifp->if_ierrors++; 1174135250Swpaul if (sc->nge_head != NULL) { 1175135250Swpaul m_freem(sc->nge_head); 1176135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1177135250Swpaul } 1178135250Swpaul nge_newbuf(sc, cur_rx, m); 1179135250Swpaul continue; 1180135250Swpaul } 1181135250Swpaul 1182135250Swpaul if (sc->nge_head != NULL) { 1183135250Swpaul m->m_len = total_len; 1184135250Swpaul m->m_flags &= ~M_PKTHDR; 1185135250Swpaul sc->nge_tail->m_next = m; 1186135250Swpaul m = sc->nge_head; 1187135250Swpaul m->m_pkthdr.len += total_len; 1188135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1189135250Swpaul } else 1190135250Swpaul m->m_pkthdr.len = m->m_len = total_len; 1191135250Swpaul 119276479Swpaul /* 119376479Swpaul * Ok. NatSemi really screwed up here. This is the 119476479Swpaul * only gigE chip I know of with alignment constraints 119576479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 119676479Swpaul */ 119779562Swpaul /* 119879562Swpaul * By popular demand, ignore the alignment problems 119979562Swpaul * on the Intel x86 platform. The performance hit 120079562Swpaul * incurred due to unaligned accesses is much smaller 120179562Swpaul * than the hit produced by forcing buffer copies all 120279562Swpaul * the time, especially with jumbo frames. We still 120379562Swpaul * need to fix up the alignment everywhere else though. 120479562Swpaul */ 1205135250Swpaul#ifdef NGE_FIXUP_RX 1206135250Swpaul nge_fixup_rx(m); 120779562Swpaul#endif 120876479Swpaul 120976479Swpaul ifp->if_ipackets++; 1210135250Swpaul m->m_pkthdr.rcvif = ifp; 121176479Swpaul 121276479Swpaul /* Do IP checksum checking. */ 121378323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 121478323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 121578323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 121678323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 121778323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 121878323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 121978323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 122078323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 122178323Swpaul m->m_pkthdr.csum_flags |= 122278323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 122378323Swpaul m->m_pkthdr.csum_data = 0xffff; 122478323Swpaul } 122576479Swpaul 122676479Swpaul /* 122776479Swpaul * If we received a packet with a vlan tag, pass it 122876479Swpaul * to vlan_input() instead of ether_input(). 122976479Swpaul */ 123076479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1231106937Ssam VLAN_INPUT_TAG(ifp, m, 1232127615Sru ntohs(extsts & NGE_RXEXTSTS_VTCI), continue); 1233106937Ssam } 1234135250Swpaul NGE_UNLOCK(sc); 1235106937Ssam (*ifp->if_input)(ifp, m); 1236135250Swpaul NGE_LOCK(sc); 123776479Swpaul } 123876479Swpaul 123976479Swpaul sc->nge_cdata.nge_rx_prod = i; 124076479Swpaul 124176479Swpaul return; 124276479Swpaul} 124376479Swpaul 124476479Swpaul/* 124576479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 124676479Swpaul * the list buffers. 124776479Swpaul */ 124876479Swpaul 124999497Salfredstatic void 125099497Salfrednge_txeof(sc) 125176479Swpaul struct nge_softc *sc; 125276479Swpaul{ 1253128130Sru struct nge_desc *cur_tx; 125476479Swpaul struct ifnet *ifp; 125576479Swpaul u_int32_t idx; 125676479Swpaul 1257135250Swpaul NGE_LOCK_ASSERT(sc); 1258147256Sbrooks ifp = sc->nge_ifp; 125976479Swpaul 126076479Swpaul /* 126176479Swpaul * Go through our tx list and free mbufs for those 126276479Swpaul * frames that have been transmitted. 126376479Swpaul */ 126476479Swpaul idx = sc->nge_cdata.nge_tx_cons; 126576479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 126676479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 126776479Swpaul 126876479Swpaul if (NGE_OWNDESC(cur_tx)) 126976479Swpaul break; 127076479Swpaul 127176479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 127276479Swpaul sc->nge_cdata.nge_tx_cnt--; 127376479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 127476479Swpaul continue; 127576479Swpaul } 127676479Swpaul 127776479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 127876479Swpaul ifp->if_oerrors++; 127976479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 128076479Swpaul ifp->if_collisions++; 128176479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 128276479Swpaul ifp->if_collisions++; 128376479Swpaul } 128476479Swpaul 128576479Swpaul ifp->if_collisions += 128676479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 128776479Swpaul 128876479Swpaul ifp->if_opackets++; 128976479Swpaul if (cur_tx->nge_mbuf != NULL) { 129076479Swpaul m_freem(cur_tx->nge_mbuf); 129176479Swpaul cur_tx->nge_mbuf = NULL; 1292148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 129376479Swpaul } 129476479Swpaul 129576479Swpaul sc->nge_cdata.nge_tx_cnt--; 129676479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 129776479Swpaul } 129876479Swpaul 129976479Swpaul sc->nge_cdata.nge_tx_cons = idx; 130076479Swpaul 1301128130Sru if (idx == sc->nge_cdata.nge_tx_prod) 1302128130Sru ifp->if_timer = 0; 130376479Swpaul 130476479Swpaul return; 130576479Swpaul} 130676479Swpaul 130799497Salfredstatic void 130899497Salfrednge_tick(xsc) 130976479Swpaul void *xsc; 131076479Swpaul{ 131176479Swpaul struct nge_softc *sc; 131276479Swpaul struct mii_data *mii; 131376479Swpaul struct ifnet *ifp; 131476479Swpaul 1315151296Sjhb sc = xsc; 1316135250Swpaul NGE_LOCK_ASSERT(sc); 1317147256Sbrooks ifp = sc->nge_ifp; 131876479Swpaul 1319101540Sambrisko if (sc->nge_tbi) { 1320101540Sambrisko if (!sc->nge_link) { 1321101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) 1322101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 1323137402Sphk if (bootverbose) 1324151296Sjhb if_printf(sc->nge_ifp, 1325151296Sjhb "gigabit link up\n"); 1326101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1327101540Sambrisko sc->nge_link++; 1328101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1329135250Swpaul nge_start_locked(ifp); 1330101540Sambrisko } 133196028Sphk } 1332101540Sambrisko } else { 1333101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1334101540Sambrisko mii_tick(mii); 1335101540Sambrisko 1336101540Sambrisko if (!sc->nge_link) { 1337101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1338101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1339101540Sambrisko sc->nge_link++; 1340101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) 1341137402Sphk == IFM_1000_T && bootverbose) 1342151296Sjhb if_printf(sc->nge_ifp, 1343151296Sjhb "gigabit link up\n"); 1344101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1345135250Swpaul nge_start_locked(ifp); 1346101540Sambrisko } 1347101540Sambrisko } 134876479Swpaul } 1349135250Swpaul callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc); 135076479Swpaul 135176479Swpaul return; 135276479Swpaul} 135376479Swpaul 1354106507Ssimokawa#ifdef DEVICE_POLLING 1355106507Ssimokawastatic poll_handler_t nge_poll; 1356106507Ssimokawa 135799497Salfredstatic void 1358106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1359106507Ssimokawa{ 1360106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1361106507Ssimokawa 1362135250Swpaul NGE_LOCK(sc); 1363150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1364135250Swpaul NGE_UNLOCK(sc); 1365106507Ssimokawa return; 1366106507Ssimokawa } 1367106507Ssimokawa 1368106507Ssimokawa /* 1369106507Ssimokawa * On the nge, reading the status register also clears it. 1370106507Ssimokawa * So before returning to intr mode we must make sure that all 1371106507Ssimokawa * possible pending sources of interrupts have been served. 1372106507Ssimokawa * In practice this means run to completion the *eof routines, 1373106507Ssimokawa * and then call the interrupt routine 1374106507Ssimokawa */ 1375106507Ssimokawa sc->rxcycles = count; 1376106507Ssimokawa nge_rxeof(sc); 1377106507Ssimokawa nge_txeof(sc); 1378106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1379135250Swpaul nge_start_locked(ifp); 1380106507Ssimokawa 1381106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1382106507Ssimokawa u_int32_t status; 1383106507Ssimokawa 1384106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1385106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1386106507Ssimokawa 1387106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1388106507Ssimokawa nge_rxeof(sc); 1389106507Ssimokawa 1390106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1391106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1392106507Ssimokawa 1393106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1394106507Ssimokawa nge_reset(sc); 1395135250Swpaul nge_init_locked(sc); 1396106507Ssimokawa } 1397106507Ssimokawa } 1398135250Swpaul NGE_UNLOCK(sc); 1399106507Ssimokawa} 1400106507Ssimokawa#endif /* DEVICE_POLLING */ 1401106507Ssimokawa 1402106507Ssimokawastatic void 140399497Salfrednge_intr(arg) 140476479Swpaul void *arg; 140576479Swpaul{ 140676479Swpaul struct nge_softc *sc; 140776479Swpaul struct ifnet *ifp; 140876479Swpaul u_int32_t status; 140976479Swpaul 141076479Swpaul sc = arg; 1411147256Sbrooks ifp = sc->nge_ifp; 141276479Swpaul 1413135250Swpaul NGE_LOCK(sc); 1414106507Ssimokawa#ifdef DEVICE_POLLING 1415150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1416135250Swpaul NGE_UNLOCK(sc); 1417106507Ssimokawa return; 1418135250Swpaul } 1419150789Sglebius#endif 1420106507Ssimokawa 142176479Swpaul /* Supress unwanted interrupts */ 142276479Swpaul if (!(ifp->if_flags & IFF_UP)) { 142376479Swpaul nge_stop(sc); 1424135250Swpaul NGE_UNLOCK(sc); 142576479Swpaul return; 142676479Swpaul } 142776479Swpaul 142876479Swpaul /* Disable interrupts. */ 142976479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 143076479Swpaul 1431101540Sambrisko /* Data LED on for TBI mode */ 1432101540Sambrisko if(sc->nge_tbi) 1433101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1434101540Sambrisko | NGE_GPIO_GP3_OUT); 1435101540Sambrisko 143676479Swpaul for (;;) { 143776479Swpaul /* Reading the ISR register clears all interrupts. */ 143876479Swpaul status = CSR_READ_4(sc, NGE_ISR); 143976479Swpaul 144076479Swpaul if ((status & NGE_INTRS) == 0) 144176479Swpaul break; 144276479Swpaul 144376479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 144476479Swpaul (status & NGE_ISR_TX_ERR) || 144576479Swpaul (status & NGE_ISR_TX_OK) || 144676479Swpaul (status & NGE_ISR_TX_IDLE)) 144776479Swpaul nge_txeof(sc); 144876479Swpaul 144976479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 145079798Swpaul (status & NGE_ISR_RX_ERR) || 145183678Swpaul (status & NGE_ISR_RX_OFLOW) || 145294612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 145394612Sphk (status & NGE_ISR_RX_IDLE) || 145476479Swpaul (status & NGE_ISR_RX_OK)) 145576479Swpaul nge_rxeof(sc); 145694612Sphk 145794612Sphk if ((status & NGE_ISR_RX_IDLE)) 145894612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 145994612Sphk 146076479Swpaul if (status & NGE_ISR_SYSERR) { 146176479Swpaul nge_reset(sc); 1462148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1463135250Swpaul nge_init_locked(sc); 146476479Swpaul } 146576479Swpaul 146696028Sphk#if 0 146796028Sphk /* 146896028Sphk * XXX: nge_tick() is not ready to be called this way 146996028Sphk * it screws up the aneg timeout because mii_tick() is 147096028Sphk * only to be called once per second. 147196028Sphk */ 147276479Swpaul if (status & NGE_IMR_PHY_INTR) { 147376479Swpaul sc->nge_link = 0; 1474151296Sjhb nge_tick(sc); 147576479Swpaul } 147696028Sphk#endif 147776479Swpaul } 147876479Swpaul 147976479Swpaul /* Re-enable interrupts. */ 148076479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 148176479Swpaul 148276479Swpaul if (ifp->if_snd.ifq_head != NULL) 1483135250Swpaul nge_start_locked(ifp); 148476479Swpaul 1485101540Sambrisko /* Data LED off for TBI mode */ 1486101540Sambrisko 1487101540Sambrisko if(sc->nge_tbi) 1488101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1489101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1490101540Sambrisko 1491135250Swpaul NGE_UNLOCK(sc); 1492135250Swpaul 149376479Swpaul return; 149476479Swpaul} 149576479Swpaul 149676479Swpaul/* 149776479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 149876479Swpaul * pointers to the fragment pointers. 149976479Swpaul */ 150099497Salfredstatic int 150199497Salfrednge_encap(sc, m_head, txidx) 150276479Swpaul struct nge_softc *sc; 150376479Swpaul struct mbuf *m_head; 150476479Swpaul u_int32_t *txidx; 150576479Swpaul{ 150676479Swpaul struct nge_desc *f = NULL; 150776479Swpaul struct mbuf *m; 150876479Swpaul int frag, cur, cnt = 0; 1509106937Ssam struct m_tag *mtag; 151076479Swpaul 151176479Swpaul /* 151276479Swpaul * Start packing the mbufs in this chain into 151376479Swpaul * the fragment pointers. Stop when we run out 151476479Swpaul * of fragments or hit the end of the mbuf chain. 151576479Swpaul */ 151676479Swpaul m = m_head; 151776479Swpaul cur = frag = *txidx; 151876479Swpaul 151976479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 152076479Swpaul if (m->m_len != 0) { 152176479Swpaul if ((NGE_TX_LIST_CNT - 152276479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 152376479Swpaul return(ENOBUFS); 152476479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 152576479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 152676479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 152776479Swpaul if (cnt != 0) 152876479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 152976479Swpaul cur = frag; 153076479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 153176479Swpaul cnt++; 153276479Swpaul } 153376479Swpaul } 153476479Swpaul 153576479Swpaul if (m != NULL) 153676479Swpaul return(ENOBUFS); 153776479Swpaul 153878286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 153976479Swpaul if (m_head->m_pkthdr.csum_flags) { 154076479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 154178286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 154276479Swpaul NGE_TXEXTSTS_IPCSUM; 154376479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 154478286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 154576479Swpaul NGE_TXEXTSTS_TCPCSUM; 154676479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 154778286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 154876479Swpaul NGE_TXEXTSTS_UDPCSUM; 154976479Swpaul } 155076479Swpaul 1551147256Sbrooks mtag = VLAN_OUTPUT_TAG(sc->nge_ifp, m_head); 1552106937Ssam if (mtag != NULL) { 155376479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1554127615Sru (NGE_TXEXTSTS_VLANPKT|htons(VLAN_TAG_VALUE(mtag))); 155576479Swpaul } 155676479Swpaul 155776479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 155876479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 155976479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 156076479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 156176479Swpaul *txidx = frag; 156276479Swpaul 156376479Swpaul return(0); 156476479Swpaul} 156576479Swpaul 156676479Swpaul/* 156776479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 156876479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 156976479Swpaul * copy of the pointers since the transmit list fragment pointers are 157076479Swpaul * physical addresses. 157176479Swpaul */ 157276479Swpaul 157399497Salfredstatic void 157499497Salfrednge_start(ifp) 157576479Swpaul struct ifnet *ifp; 157676479Swpaul{ 157776479Swpaul struct nge_softc *sc; 1578135250Swpaul 1579135250Swpaul sc = ifp->if_softc; 1580135250Swpaul NGE_LOCK(sc); 1581135250Swpaul nge_start_locked(ifp); 1582135250Swpaul NGE_UNLOCK(sc); 1583135250Swpaul} 1584135250Swpaul 1585135250Swpaulstatic void 1586135250Swpaulnge_start_locked(ifp) 1587135250Swpaul struct ifnet *ifp; 1588135250Swpaul{ 1589135250Swpaul struct nge_softc *sc; 159076479Swpaul struct mbuf *m_head = NULL; 159176479Swpaul u_int32_t idx; 159276479Swpaul 159376479Swpaul sc = ifp->if_softc; 159476479Swpaul 159576479Swpaul if (!sc->nge_link) 159676479Swpaul return; 159776479Swpaul 159876479Swpaul idx = sc->nge_cdata.nge_tx_prod; 159976479Swpaul 1600148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 160176479Swpaul return; 160276479Swpaul 160376479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 160476479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 160576479Swpaul if (m_head == NULL) 160676479Swpaul break; 160776479Swpaul 160876479Swpaul if (nge_encap(sc, m_head, &idx)) { 160976479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1610148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 161176479Swpaul break; 161276479Swpaul } 161376479Swpaul 161476479Swpaul /* 161576479Swpaul * If there's a BPF listener, bounce a copy of this frame 161676479Swpaul * to him. 161776479Swpaul */ 1618106937Ssam BPF_MTAP(ifp, m_head); 161976479Swpaul 162076479Swpaul } 162176479Swpaul 162276479Swpaul /* Transmit */ 162376479Swpaul sc->nge_cdata.nge_tx_prod = idx; 162476479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 162576479Swpaul 162676479Swpaul /* 162776479Swpaul * Set a timeout in case the chip goes out to lunch. 162876479Swpaul */ 162976479Swpaul ifp->if_timer = 5; 163076479Swpaul 163176479Swpaul return; 163276479Swpaul} 163376479Swpaul 163499497Salfredstatic void 163599497Salfrednge_init(xsc) 163676479Swpaul void *xsc; 163776479Swpaul{ 163876479Swpaul struct nge_softc *sc = xsc; 1639135250Swpaul 1640135250Swpaul NGE_LOCK(sc); 1641135250Swpaul nge_init_locked(sc); 1642135250Swpaul NGE_UNLOCK(sc); 1643135250Swpaul} 1644135250Swpaul 1645135250Swpaulstatic void 1646135250Swpaulnge_init_locked(sc) 1647135250Swpaul struct nge_softc *sc; 1648135250Swpaul{ 1649147256Sbrooks struct ifnet *ifp = sc->nge_ifp; 165076479Swpaul struct mii_data *mii; 165176479Swpaul 1652135250Swpaul NGE_LOCK_ASSERT(sc); 1653135250Swpaul 1654148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 165576479Swpaul return; 165676479Swpaul 165776479Swpaul /* 165876479Swpaul * Cancel pending I/O and free all RX/TX buffers. 165976479Swpaul */ 166076479Swpaul nge_stop(sc); 166176479Swpaul 1662101540Sambrisko if (sc->nge_tbi) { 1663101540Sambrisko mii = NULL; 1664101540Sambrisko } else { 1665101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1666101540Sambrisko } 166776479Swpaul 166876479Swpaul /* Set MAC address */ 166976479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 167076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1671152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[0]); 167276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 167376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1674152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[1]); 167576479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 167676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1677152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[2]); 167876479Swpaul 167976479Swpaul /* Init circular RX list. */ 168076479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 1681151296Sjhb if_printf(sc->nge_ifp, "initialization failed: no " 1682151296Sjhb "memory for rx buffers\n"); 168376479Swpaul nge_stop(sc); 168476479Swpaul return; 168576479Swpaul } 168676479Swpaul 168776479Swpaul /* 168876479Swpaul * Init tx descriptors. 168976479Swpaul */ 169076479Swpaul nge_list_tx_init(sc); 169176479Swpaul 169276479Swpaul /* 169376479Swpaul * For the NatSemi chip, we have to explicitly enable the 169476479Swpaul * reception of ARP frames, as well as turn on the 'perfect 169576479Swpaul * match' filter where we store the station address, otherwise 169676479Swpaul * we won't receive unicasts meant for this host. 169776479Swpaul */ 169876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 169976479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 170076479Swpaul 170176479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 170276479Swpaul if (ifp->if_flags & IFF_PROMISC) { 170376479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 170476479Swpaul } else { 170576479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 170676479Swpaul } 170776479Swpaul 170876479Swpaul /* 170976479Swpaul * Set the capture broadcast bit to capture broadcast frames. 171076479Swpaul */ 171176479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 171276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 171376479Swpaul } else { 171476479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 171576479Swpaul } 171676479Swpaul 171776479Swpaul /* 171876479Swpaul * Load the multicast filter. 171976479Swpaul */ 172076479Swpaul nge_setmulti(sc); 172176479Swpaul 172276479Swpaul /* Turn the receive filter on */ 172376479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 172476479Swpaul 172576479Swpaul /* 172676479Swpaul * Load the address of the RX and TX lists. 172776479Swpaul */ 172876479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 172976479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 173076479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 173176479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 173276479Swpaul 173376479Swpaul /* Set RX configuration */ 173476479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 173576479Swpaul /* 173676479Swpaul * Enable hardware checksum validation for all IPv4 173776479Swpaul * packets, do not reject packets with bad checksums. 173876479Swpaul */ 173978323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 174076479Swpaul 174176479Swpaul /* 174283115Sbrooks * Tell the chip to detect and strip VLAN tag info from 174383115Sbrooks * received frames. The tag will be provided in the extsts 174483115Sbrooks * field in the RX descriptors. 174576479Swpaul */ 174676479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 174776479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 174876479Swpaul 174976479Swpaul /* Set TX configuration */ 175076479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 175176479Swpaul 175276479Swpaul /* 175376479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 175476479Swpaul */ 175578323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 175676479Swpaul 175776479Swpaul /* 175883115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 175983115Sbrooks * dictated by the code in the frame encapsulation routine. 176076479Swpaul */ 176176479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 176276479Swpaul 176376479Swpaul /* Set full/half duplex mode. */ 1764101540Sambrisko if (sc->nge_tbi) { 1765101540Sambrisko if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1766101540Sambrisko == IFM_FDX) { 1767101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1768101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1769101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1770101540Sambrisko } else { 1771101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1772101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1773101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1774101540Sambrisko } 177576479Swpaul } else { 1776101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1777101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1778101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1779101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1780101540Sambrisko } else { 1781101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1782101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1783101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1784101540Sambrisko } 178576479Swpaul } 178676479Swpaul 1787151296Sjhb nge_tick(sc); 178896028Sphk 178976479Swpaul /* 179076479Swpaul * Enable the delivery of PHY interrupts based on 179177842Swpaul * link/speed/duplex status changes. Also enable the 179277842Swpaul * extsts field in the DMA descriptors (needed for 179377842Swpaul * TCP/IP checksum offload on transmit). 179476479Swpaul */ 179579424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 179677842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 179776479Swpaul 179876479Swpaul /* 179979562Swpaul * Configure interrupt holdoff (moderation). We can 180079562Swpaul * have the chip delay interrupt delivery for a certain 180179562Swpaul * period. Units are in 100us, and the max setting 180279562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 180379562Swpaul */ 180479562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 180579562Swpaul 180679562Swpaul /* 180776479Swpaul * Enable interrupts. 180876479Swpaul */ 180976479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1810106507Ssimokawa#ifdef DEVICE_POLLING 1811106507Ssimokawa /* 1812106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1813106507Ssimokawa * they are off otherwise. 1814106507Ssimokawa */ 1815150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1816106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1817106507Ssimokawa else 1818150789Sglebius#endif 181976479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 182076479Swpaul 182176479Swpaul /* Enable receiver and transmitter. */ 182276479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 182376479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 182476479Swpaul 1825151296Sjhb nge_ifmedia_upd_locked(ifp); 182676479Swpaul 1827148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1828148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 182976479Swpaul 183076479Swpaul return; 183176479Swpaul} 183276479Swpaul 183376479Swpaul/* 183476479Swpaul * Set media options. 183576479Swpaul */ 183699497Salfredstatic int 183799497Salfrednge_ifmedia_upd(ifp) 183876479Swpaul struct ifnet *ifp; 183976479Swpaul{ 184076479Swpaul struct nge_softc *sc; 1841151296Sjhb 1842151296Sjhb sc = ifp->if_softc; 1843151296Sjhb NGE_LOCK(sc); 1844151296Sjhb nge_ifmedia_upd_locked(ifp); 1845151296Sjhb NGE_UNLOCK(sc); 1846151296Sjhb return (0); 1847151296Sjhb} 1848151296Sjhb 1849151296Sjhbstatic void 1850151296Sjhbnge_ifmedia_upd_locked(ifp) 1851151296Sjhb struct ifnet *ifp; 1852151296Sjhb{ 1853151296Sjhb struct nge_softc *sc; 185476479Swpaul struct mii_data *mii; 185576479Swpaul 185676479Swpaul sc = ifp->if_softc; 1857151296Sjhb NGE_LOCK_ASSERT(sc); 185876479Swpaul 1859101540Sambrisko if (sc->nge_tbi) { 1860101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1861101540Sambrisko == IFM_AUTO) { 1862101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 1863101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 1864101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 1865101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 1866101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 1867101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 1868101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 1869101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 1870101540Sambrisko & IFM_GMASK) == IFM_FDX) { 1871101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1872101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1873101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1874101540Sambrisko 1875101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1876101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1877101540Sambrisko } else { 1878101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1879101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1880101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1881101540Sambrisko 1882101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1883101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1884101540Sambrisko } 1885101540Sambrisko 1886101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1887101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1888101540Sambrisko } else { 1889101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1890101540Sambrisko sc->nge_link = 0; 1891101540Sambrisko if (mii->mii_instance) { 1892101540Sambrisko struct mii_softc *miisc; 1893151296Sjhb 1894151296Sjhb LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1895101540Sambrisko mii_phy_reset(miisc); 1896101540Sambrisko } 1897101540Sambrisko mii_mediachg(mii); 189876479Swpaul } 189976479Swpaul} 190076479Swpaul 190176479Swpaul/* 190276479Swpaul * Report current media status. 190376479Swpaul */ 190499497Salfredstatic void 190599497Salfrednge_ifmedia_sts(ifp, ifmr) 190676479Swpaul struct ifnet *ifp; 190776479Swpaul struct ifmediareq *ifmr; 190876479Swpaul{ 190976479Swpaul struct nge_softc *sc; 191076479Swpaul struct mii_data *mii; 191176479Swpaul 191276479Swpaul sc = ifp->if_softc; 191376479Swpaul 1914151296Sjhb NGE_LOCK(sc); 1915101540Sambrisko if (sc->nge_tbi) { 1916101540Sambrisko ifmr->ifm_status = IFM_AVALID; 1917101540Sambrisko ifmr->ifm_active = IFM_ETHER; 191876479Swpaul 1919101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1920101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 1921101540Sambrisko } 1922101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 1923101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 1924101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1925101540Sambrisko ifmr->ifm_active |= IFM_NONE; 1926101540Sambrisko ifmr->ifm_status = 0; 1927151296Sjhb NGE_UNLOCK(sc); 1928101540Sambrisko return; 1929101540Sambrisko } 1930101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 1931101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1932101540Sambrisko == IFM_AUTO) { 1933101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 1934101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1935101540Sambrisko & NGE_TBIANAR_FDX) { 1936101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1937101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1938101540Sambrisko & NGE_TBIANAR_HDX) { 1939101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1940101540Sambrisko } 1941101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1942101540Sambrisko == IFM_FDX) 1943101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1944101540Sambrisko else 1945101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1946101540Sambrisko 1947101540Sambrisko } else { 1948101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1949101540Sambrisko mii_pollstat(mii); 1950101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 1951101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 1952101540Sambrisko } 1953151296Sjhb NGE_UNLOCK(sc); 1954101540Sambrisko 195576479Swpaul return; 195676479Swpaul} 195776479Swpaul 195899497Salfredstatic int 195999497Salfrednge_ioctl(ifp, command, data) 196076479Swpaul struct ifnet *ifp; 196176479Swpaul u_long command; 196276479Swpaul caddr_t data; 196376479Swpaul{ 196476479Swpaul struct nge_softc *sc = ifp->if_softc; 196576479Swpaul struct ifreq *ifr = (struct ifreq *) data; 196676479Swpaul struct mii_data *mii; 1967135250Swpaul int error = 0; 196876479Swpaul 196976479Swpaul switch(command) { 197076479Swpaul case SIOCSIFMTU: 197176479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 197276479Swpaul error = EINVAL; 197378323Swpaul else { 1974151296Sjhb NGE_LOCK(sc); 197576479Swpaul ifp->if_mtu = ifr->ifr_mtu; 197678323Swpaul /* 197778323Swpaul * Workaround: if the MTU is larger than 197878323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 197978323Swpaul * TX checksum offloading. 198078323Swpaul */ 1981129632Syar if (ifr->ifr_mtu >= 8152) { 1982129632Syar ifp->if_capenable &= ~IFCAP_TXCSUM; 198378323Swpaul ifp->if_hwassist = 0; 1984129632Syar } else { 1985129632Syar ifp->if_capenable |= IFCAP_TXCSUM; 198678323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 1987129632Syar } 1988151296Sjhb NGE_UNLOCK(sc); 198978323Swpaul } 199076479Swpaul break; 199176479Swpaul case SIOCSIFFLAGS: 1992135250Swpaul NGE_LOCK(sc); 199376479Swpaul if (ifp->if_flags & IFF_UP) { 1994148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 199576479Swpaul ifp->if_flags & IFF_PROMISC && 199676479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 199776479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 199876479Swpaul NGE_RXFILTCTL_ALLPHYS| 199976479Swpaul NGE_RXFILTCTL_ALLMULTI); 2000148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 200176479Swpaul !(ifp->if_flags & IFF_PROMISC) && 200276479Swpaul sc->nge_if_flags & IFF_PROMISC) { 200376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 200476479Swpaul NGE_RXFILTCTL_ALLPHYS); 200576479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 200676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 200776479Swpaul NGE_RXFILTCTL_ALLMULTI); 200876479Swpaul } else { 2009148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2010135250Swpaul nge_init_locked(sc); 201176479Swpaul } 201276479Swpaul } else { 2013148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 201476479Swpaul nge_stop(sc); 201576479Swpaul } 201676479Swpaul sc->nge_if_flags = ifp->if_flags; 2017135250Swpaul NGE_UNLOCK(sc); 201876479Swpaul error = 0; 201976479Swpaul break; 202076479Swpaul case SIOCADDMULTI: 202176479Swpaul case SIOCDELMULTI: 2022135250Swpaul NGE_LOCK(sc); 202376479Swpaul nge_setmulti(sc); 2024135250Swpaul NGE_UNLOCK(sc); 202576479Swpaul error = 0; 202676479Swpaul break; 202776479Swpaul case SIOCGIFMEDIA: 202876479Swpaul case SIOCSIFMEDIA: 2029101540Sambrisko if (sc->nge_tbi) { 2030101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 2031101540Sambrisko command); 2032101540Sambrisko } else { 2033101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2034101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 2035101540Sambrisko command); 2036101540Sambrisko } 203776479Swpaul break; 2038128132Sru case SIOCSIFCAP: 2039150789Sglebius#ifdef DEVICE_POLLING 2040150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 2041150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 2042150789Sglebius error = ether_poll_register(nge_poll, ifp); 2043150789Sglebius if (error) 2044150789Sglebius return(error); 2045150789Sglebius NGE_LOCK(sc); 2046150789Sglebius /* Disable interrupts */ 2047150789Sglebius CSR_WRITE_4(sc, NGE_IER, 0); 2048150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 2049150789Sglebius NGE_UNLOCK(sc); 2050150789Sglebius return (error); 2051150789Sglebius 2052150789Sglebius } 2053150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 2054150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 2055150789Sglebius error = ether_poll_deregister(ifp); 2056150789Sglebius /* Enable interrupts. */ 2057150789Sglebius NGE_LOCK(sc); 2058150789Sglebius CSR_WRITE_4(sc, NGE_IER, 1); 2059150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 2060150789Sglebius NGE_UNLOCK(sc); 2061150789Sglebius return (error); 2062150789Sglebius } 2063150789Sglebius#endif /* DEVICE_POLLING */ 2064128132Sru break; 206576479Swpaul default: 2066106937Ssam error = ether_ioctl(ifp, command, data); 206776479Swpaul break; 206876479Swpaul } 206976479Swpaul 207076479Swpaul return(error); 207176479Swpaul} 207276479Swpaul 207399497Salfredstatic void 207499497Salfrednge_watchdog(ifp) 207576479Swpaul struct ifnet *ifp; 207676479Swpaul{ 207776479Swpaul struct nge_softc *sc; 207876479Swpaul 207976479Swpaul sc = ifp->if_softc; 208076479Swpaul 208176479Swpaul ifp->if_oerrors++; 2082151296Sjhb if_printf(sc->nge_ifp, "watchdog timeout\n"); 208376479Swpaul 2084135250Swpaul NGE_LOCK(sc); 208576479Swpaul nge_stop(sc); 208676479Swpaul nge_reset(sc); 2087148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2088135250Swpaul nge_init_locked(sc); 208976479Swpaul 209076479Swpaul if (ifp->if_snd.ifq_head != NULL) 2091135250Swpaul nge_start_locked(ifp); 209276479Swpaul 2093135250Swpaul NGE_UNLOCK(sc); 2094135250Swpaul 209576479Swpaul return; 209676479Swpaul} 209776479Swpaul 209876479Swpaul/* 209976479Swpaul * Stop the adapter and free any mbufs allocated to the 210076479Swpaul * RX and TX lists. 210176479Swpaul */ 210299497Salfredstatic void 210399497Salfrednge_stop(sc) 210476479Swpaul struct nge_softc *sc; 210576479Swpaul{ 210676479Swpaul register int i; 210776479Swpaul struct ifnet *ifp; 210876479Swpaul struct mii_data *mii; 210976479Swpaul 2110135250Swpaul NGE_LOCK_ASSERT(sc); 2111147256Sbrooks ifp = sc->nge_ifp; 211276479Swpaul ifp->if_timer = 0; 2113101540Sambrisko if (sc->nge_tbi) { 2114101540Sambrisko mii = NULL; 2115101540Sambrisko } else { 2116101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2117101540Sambrisko } 211876479Swpaul 2119135250Swpaul callout_stop(&sc->nge_stat_ch); 212076479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 212176479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 212276479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 212376479Swpaul DELAY(1000); 212476479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 212576479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 212676479Swpaul 2127101540Sambrisko if (!sc->nge_tbi) 2128101540Sambrisko mii_down(mii); 212976479Swpaul 213076479Swpaul sc->nge_link = 0; 213176479Swpaul 213276479Swpaul /* 213376479Swpaul * Free data in the RX lists. 213476479Swpaul */ 213576479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 213676479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 213776479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 213876479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 213976479Swpaul } 214076479Swpaul } 214176479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 214276479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 214376479Swpaul 214476479Swpaul /* 214576479Swpaul * Free the TX list buffers. 214676479Swpaul */ 214776479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 214876479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 214976479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 215076479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 215176479Swpaul } 215276479Swpaul } 215376479Swpaul 215476479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 215576479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 215676479Swpaul 2157148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 215876479Swpaul 215976479Swpaul return; 216076479Swpaul} 216176479Swpaul 216276479Swpaul/* 216376479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 216476479Swpaul * get confused by errant DMAs when rebooting. 216576479Swpaul */ 216699497Salfredstatic void 216799497Salfrednge_shutdown(dev) 216876479Swpaul device_t dev; 216976479Swpaul{ 217076479Swpaul struct nge_softc *sc; 217176479Swpaul 217276479Swpaul sc = device_get_softc(dev); 217376479Swpaul 2174135250Swpaul NGE_LOCK(sc); 217576479Swpaul nge_reset(sc); 217676479Swpaul nge_stop(sc); 2177135250Swpaul NGE_UNLOCK(sc); 217876479Swpaul 217976479Swpaul return; 218076479Swpaul} 2181