if_nge.c revision 192294
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 192294 2009-05-18 06:32:38Z yongari $"); 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/bus.h> 11776479Swpaul#include <machine/resource.h> 11876479Swpaul#include <sys/bus.h> 11976479Swpaul#include <sys/rman.h> 12076479Swpaul 12176479Swpaul#include <dev/mii/mii.h> 12276479Swpaul#include <dev/mii/miivar.h> 12376479Swpaul 124119285Simp#include <dev/pci/pcireg.h> 125119285Simp#include <dev/pci/pcivar.h> 12676479Swpaul 12776479Swpaul#define NGE_USEIOSPACE 12876479Swpaul 12976522Swpaul#include <dev/nge/if_ngereg.h> 13076479Swpaul 131113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1); 132113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1); 13376479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1); 13476479Swpaul 135151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 13676479Swpaul#include "miibus_if.h" 13776479Swpaul 13876479Swpaul#define NGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 13976479Swpaul 14076479Swpaul/* 14176479Swpaul * Various supported device vendors/types and their names. 14276479Swpaul */ 14376479Swpaulstatic struct nge_type nge_devs[] = { 14476479Swpaul { NGE_VENDORID, NGE_DEVICEID, 14576479Swpaul "National Semiconductor Gigabit Ethernet" }, 14676479Swpaul { 0, 0, NULL } 14776479Swpaul}; 14876479Swpaul 14999497Salfredstatic int nge_probe(device_t); 15099497Salfredstatic int nge_attach(device_t); 15199497Salfredstatic int nge_detach(device_t); 15276479Swpaul 15399497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *); 154192294Syongaristatic int nge_encap(struct nge_softc *, struct mbuf *, uint32_t *); 155135254Salc#ifdef NGE_FIXUP_RX 156135250Swpaulstatic __inline void nge_fixup_rx (struct mbuf *); 157135250Swpaul#endif 15899497Salfredstatic void nge_rxeof(struct nge_softc *); 15999497Salfredstatic void nge_txeof(struct nge_softc *); 16099497Salfredstatic void nge_intr(void *); 16199497Salfredstatic void nge_tick(void *); 16299497Salfredstatic void nge_start(struct ifnet *); 163135250Swpaulstatic void nge_start_locked(struct ifnet *); 16499497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t); 16599497Salfredstatic void nge_init(void *); 166135250Swpaulstatic void nge_init_locked(struct nge_softc *); 16799497Salfredstatic void nge_stop(struct nge_softc *); 16899497Salfredstatic void nge_watchdog(struct ifnet *); 169173839Syongaristatic int nge_shutdown(device_t); 17099497Salfredstatic int nge_ifmedia_upd(struct ifnet *); 171151296Sjhbstatic void nge_ifmedia_upd_locked(struct ifnet *); 17299497Salfredstatic void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 17376479Swpaul 17499497Salfredstatic void nge_delay(struct nge_softc *); 17599497Salfredstatic void nge_eeprom_idle(struct nge_softc *); 17699497Salfredstatic void nge_eeprom_putbyte(struct nge_softc *, int); 177192294Syongaristatic void nge_eeprom_getword(struct nge_softc *, int, uint16_t *); 17899497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int); 17976479Swpaul 18099497Salfredstatic void nge_mii_sync(struct nge_softc *); 181192294Syongaristatic void nge_mii_send(struct nge_softc *, uint32_t, int); 18299497Salfredstatic int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *); 18399497Salfredstatic int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *); 18476479Swpaul 18599497Salfredstatic int nge_miibus_readreg(device_t, int, int); 18699497Salfredstatic int nge_miibus_writereg(device_t, int, int, int); 18799497Salfredstatic void nge_miibus_statchg(device_t); 18876479Swpaul 18999497Salfredstatic void nge_setmulti(struct nge_softc *); 19099497Salfredstatic void nge_reset(struct nge_softc *); 19199497Salfredstatic int nge_list_rx_init(struct nge_softc *); 19299497Salfredstatic int nge_list_tx_init(struct nge_softc *); 19376479Swpaul 19476479Swpaul#ifdef NGE_USEIOSPACE 19576479Swpaul#define NGE_RES SYS_RES_IOPORT 19676479Swpaul#define NGE_RID NGE_PCI_LOIO 19776479Swpaul#else 19876479Swpaul#define NGE_RES SYS_RES_MEMORY 19976479Swpaul#define NGE_RID NGE_PCI_LOMEM 20076479Swpaul#endif 20176479Swpaul 20276479Swpaulstatic device_method_t nge_methods[] = { 20376479Swpaul /* Device interface */ 20476479Swpaul DEVMETHOD(device_probe, nge_probe), 20576479Swpaul DEVMETHOD(device_attach, nge_attach), 20676479Swpaul DEVMETHOD(device_detach, nge_detach), 20776479Swpaul DEVMETHOD(device_shutdown, nge_shutdown), 20876479Swpaul 20976479Swpaul /* bus interface */ 21076479Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21176479Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21276479Swpaul 21376479Swpaul /* MII interface */ 21476479Swpaul DEVMETHOD(miibus_readreg, nge_miibus_readreg), 21576479Swpaul DEVMETHOD(miibus_writereg, nge_miibus_writereg), 21676479Swpaul DEVMETHOD(miibus_statchg, nge_miibus_statchg), 21776479Swpaul 21876479Swpaul { 0, 0 } 21976479Swpaul}; 22076479Swpaul 22176479Swpaulstatic driver_t nge_driver = { 22276479Swpaul "nge", 22376479Swpaul nge_methods, 22476479Swpaul sizeof(struct nge_softc) 22576479Swpaul}; 22676479Swpaul 22776479Swpaulstatic devclass_t nge_devclass; 22876479Swpaul 229113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0); 23076479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0); 23176479Swpaul 23276479Swpaul#define NGE_SETBIT(sc, reg, x) \ 23376479Swpaul CSR_WRITE_4(sc, reg, \ 23476479Swpaul CSR_READ_4(sc, reg) | (x)) 23576479Swpaul 23676479Swpaul#define NGE_CLRBIT(sc, reg, x) \ 23776479Swpaul CSR_WRITE_4(sc, reg, \ 23876479Swpaul CSR_READ_4(sc, reg) & ~(x)) 23976479Swpaul 24076479Swpaul#define SIO_SET(x) \ 241106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x)) 24276479Swpaul 24376479Swpaul#define SIO_CLR(x) \ 244106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x)) 24576479Swpaul 24699497Salfredstatic void 247192288Syongaringe_delay(struct nge_softc *sc) 24876479Swpaul{ 24976479Swpaul int idx; 25076479Swpaul 25176479Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 25276479Swpaul CSR_READ_4(sc, NGE_CSR); 25376479Swpaul} 25476479Swpaul 25599497Salfredstatic void 256192288Syongaringe_eeprom_idle(struct nge_softc *sc) 25776479Swpaul{ 258192289Syongari int i; 25976479Swpaul 26076479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26176479Swpaul nge_delay(sc); 26276479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26376479Swpaul nge_delay(sc); 26476479Swpaul 26576479Swpaul for (i = 0; i < 25; i++) { 26676479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 26776479Swpaul nge_delay(sc); 26876479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26976479Swpaul nge_delay(sc); 27076479Swpaul } 27176479Swpaul 27276479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27376479Swpaul nge_delay(sc); 27476479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 27576479Swpaul nge_delay(sc); 27676479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 27776479Swpaul} 27876479Swpaul 27976479Swpaul/* 28076479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28176479Swpaul */ 28299497Salfredstatic void 283192288Syongaringe_eeprom_putbyte(struct nge_softc *sc, int addr) 28476479Swpaul{ 285192289Syongari int d, i; 28676479Swpaul 28776479Swpaul d = addr | NGE_EECMD_READ; 28876479Swpaul 28976479Swpaul /* 29076479Swpaul * Feed in each bit and stobe the clock. 29176479Swpaul */ 29276479Swpaul for (i = 0x400; i; i >>= 1) { 29376479Swpaul if (d & i) { 29476479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 29576479Swpaul } else { 29676479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 29776479Swpaul } 29876479Swpaul nge_delay(sc); 29976479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30076479Swpaul nge_delay(sc); 30176479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 30276479Swpaul nge_delay(sc); 30376479Swpaul } 30476479Swpaul} 30576479Swpaul 30676479Swpaul/* 30776479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 30876479Swpaul */ 30999497Salfredstatic void 310192294Syongaringe_eeprom_getword(struct nge_softc *sc, int addr, uint16_t *dest) 31176479Swpaul{ 312192289Syongari int i; 313192294Syongari uint16_t word = 0; 31476479Swpaul 31576479Swpaul /* Force EEPROM to idle state. */ 31676479Swpaul nge_eeprom_idle(sc); 31776479Swpaul 31876479Swpaul /* Enter EEPROM access mode. */ 31976479Swpaul nge_delay(sc); 32076479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 32176479Swpaul nge_delay(sc); 32276479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 32376479Swpaul nge_delay(sc); 32476479Swpaul 32576479Swpaul /* 32676479Swpaul * Send address of word we want to read. 32776479Swpaul */ 32876479Swpaul nge_eeprom_putbyte(sc, addr); 32976479Swpaul 33076479Swpaul /* 33176479Swpaul * Start reading bits from EEPROM. 33276479Swpaul */ 33376479Swpaul for (i = 0x8000; i; i >>= 1) { 33476479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 33576479Swpaul nge_delay(sc); 33676479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT) 33776479Swpaul word |= i; 33876479Swpaul nge_delay(sc); 33976479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 34076479Swpaul nge_delay(sc); 34176479Swpaul } 34276479Swpaul 34376479Swpaul /* Turn off EEPROM access mode. */ 34476479Swpaul nge_eeprom_idle(sc); 34576479Swpaul 34676479Swpaul *dest = word; 34776479Swpaul} 34876479Swpaul 34976479Swpaul/* 35076479Swpaul * Read a sequence of words from the EEPROM. 35176479Swpaul */ 35299497Salfredstatic void 353192288Syongaringe_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt, int swap) 35476479Swpaul{ 35576479Swpaul int i; 356192294Syongari uint16_t word = 0, *ptr; 35776479Swpaul 35876479Swpaul for (i = 0; i < cnt; i++) { 35976479Swpaul nge_eeprom_getword(sc, off + i, &word); 360192294Syongari ptr = (uint16_t *)(dest + (i * 2)); 36176479Swpaul if (swap) 36276479Swpaul *ptr = ntohs(word); 36376479Swpaul else 36476479Swpaul *ptr = word; 36576479Swpaul } 36676479Swpaul} 36776479Swpaul 36876479Swpaul/* 36976479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 37076479Swpaul */ 37199497Salfredstatic void 372192288Syongaringe_mii_sync(struct nge_softc *sc) 37376479Swpaul{ 374192289Syongari int i; 37576479Swpaul 37676479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 37776479Swpaul 37876479Swpaul for (i = 0; i < 32; i++) { 37976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 38076479Swpaul DELAY(1); 38176479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 38276479Swpaul DELAY(1); 38376479Swpaul } 38476479Swpaul} 38576479Swpaul 38676479Swpaul/* 38776479Swpaul * Clock a series of bits through the MII. 38876479Swpaul */ 38999497Salfredstatic void 390192294Syongaringe_mii_send(struct nge_softc *sc, uint32_t bits, int cnt) 39176479Swpaul{ 39276479Swpaul int i; 39376479Swpaul 39476479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 39576479Swpaul 39676479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 39776479Swpaul if (bits & i) { 39876479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 39976479Swpaul } else { 40076479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 40176479Swpaul } 40276479Swpaul DELAY(1); 40376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40476479Swpaul DELAY(1); 40576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 40676479Swpaul } 40776479Swpaul} 40876479Swpaul 40976479Swpaul/* 41076479Swpaul * Read an PHY register through the MII. 41176479Swpaul */ 41299497Salfredstatic int 413192288Syongaringe_mii_readreg(struct nge_softc *sc, struct nge_mii_frame *frame) 41476479Swpaul{ 415135250Swpaul int i, ack; 41676479Swpaul 41776479Swpaul /* 41876479Swpaul * Set up frame for RX. 41976479Swpaul */ 42076479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 42176479Swpaul frame->mii_opcode = NGE_MII_READOP; 42276479Swpaul frame->mii_turnaround = 0; 42376479Swpaul frame->mii_data = 0; 424192290Syongari 42576479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 42676479Swpaul 42776479Swpaul /* 42876479Swpaul * Turn on data xmit. 42976479Swpaul */ 43076479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 43176479Swpaul 43276479Swpaul nge_mii_sync(sc); 43376479Swpaul 43476479Swpaul /* 43576479Swpaul * Send command/address info. 43676479Swpaul */ 43776479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 43876479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 43976479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 44076479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 44176479Swpaul 44276479Swpaul /* Idle bit */ 44376479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 44476479Swpaul DELAY(1); 44576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 44676479Swpaul DELAY(1); 44776479Swpaul 44876479Swpaul /* Turn off xmit. */ 44976479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 45076479Swpaul /* Check for ack */ 45176479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 45276479Swpaul DELAY(1); 453109058Smbr ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 45476479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 45576479Swpaul DELAY(1); 45676479Swpaul 45776479Swpaul /* 45876479Swpaul * Now try reading data bits. If the ack failed, we still 45976479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 46076479Swpaul */ 46176479Swpaul if (ack) { 462192292Syongari for (i = 0; i < 16; i++) { 46376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 46476479Swpaul DELAY(1); 46576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 46676479Swpaul DELAY(1); 46776479Swpaul } 46876479Swpaul goto fail; 46976479Swpaul } 47076479Swpaul 47176479Swpaul for (i = 0x8000; i; i >>= 1) { 47276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 47376479Swpaul DELAY(1); 47476479Swpaul if (!ack) { 47576479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 47676479Swpaul frame->mii_data |= i; 47776479Swpaul DELAY(1); 47876479Swpaul } 47976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48076479Swpaul DELAY(1); 48176479Swpaul } 48276479Swpaul 48376479Swpaulfail: 48476479Swpaul 48576479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 48676479Swpaul DELAY(1); 48776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48876479Swpaul DELAY(1); 48976479Swpaul 49076479Swpaul if (ack) 491192292Syongari return (1); 492192292Syongari return (0); 49376479Swpaul} 49476479Swpaul 49576479Swpaul/* 49676479Swpaul * Write to a PHY register through the MII. 49776479Swpaul */ 49899497Salfredstatic int 499192288Syongaringe_mii_writereg(struct nge_softc *sc, struct nge_mii_frame *frame) 50076479Swpaul{ 50176479Swpaul 50276479Swpaul /* 50376479Swpaul * Set up frame for TX. 50476479Swpaul */ 50576479Swpaul 50676479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 50776479Swpaul frame->mii_opcode = NGE_MII_WRITEOP; 50876479Swpaul frame->mii_turnaround = NGE_MII_TURNAROUND; 509192290Syongari 51076479Swpaul /* 51176479Swpaul * Turn on data output. 51276479Swpaul */ 51376479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 51476479Swpaul 51576479Swpaul nge_mii_sync(sc); 51676479Swpaul 51776479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 51876479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 51976479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 52076479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 52176479Swpaul nge_mii_send(sc, frame->mii_turnaround, 2); 52276479Swpaul nge_mii_send(sc, frame->mii_data, 16); 52376479Swpaul 52476479Swpaul /* Idle bit. */ 52576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 52676479Swpaul DELAY(1); 52776479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 52876479Swpaul DELAY(1); 52976479Swpaul 53076479Swpaul /* 53176479Swpaul * Turn off xmit. 53276479Swpaul */ 53376479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 53476479Swpaul 535192292Syongari return (0); 53676479Swpaul} 53776479Swpaul 53899497Salfredstatic int 539192288Syongaringe_miibus_readreg(device_t dev, int phy, int reg) 54076479Swpaul{ 54176479Swpaul struct nge_softc *sc; 54276479Swpaul struct nge_mii_frame frame; 54376479Swpaul 54476479Swpaul sc = device_get_softc(dev); 54576479Swpaul 54676479Swpaul bzero((char *)&frame, sizeof(frame)); 54776479Swpaul 54876479Swpaul frame.mii_phyaddr = phy; 54976479Swpaul frame.mii_regaddr = reg; 55076479Swpaul nge_mii_readreg(sc, &frame); 55176479Swpaul 552192292Syongari return (frame.mii_data); 55376479Swpaul} 55476479Swpaul 55599497Salfredstatic int 556192288Syongaringe_miibus_writereg(device_t dev, int phy, int reg, int data) 55776479Swpaul{ 55876479Swpaul struct nge_softc *sc; 55976479Swpaul struct nge_mii_frame frame; 56076479Swpaul 56176479Swpaul sc = device_get_softc(dev); 56276479Swpaul 56376479Swpaul bzero((char *)&frame, sizeof(frame)); 56476479Swpaul 56576479Swpaul frame.mii_phyaddr = phy; 56676479Swpaul frame.mii_regaddr = reg; 56776479Swpaul frame.mii_data = data; 56876479Swpaul nge_mii_writereg(sc, &frame); 56976479Swpaul 570192292Syongari return (0); 57176479Swpaul} 57276479Swpaul 57399497Salfredstatic void 574192288Syongaringe_miibus_statchg(device_t dev) 57576479Swpaul{ 576192290Syongari int status; 57776479Swpaul struct nge_softc *sc; 57876479Swpaul struct mii_data *mii; 57976479Swpaul 58076479Swpaul sc = device_get_softc(dev); 581101540Sambrisko if (sc->nge_tbi) { 582101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 583101540Sambrisko == IFM_AUTO) { 584101540Sambrisko status = CSR_READ_4(sc, NGE_TBI_ANLPAR); 585101540Sambrisko if (status == 0 || status & NGE_TBIANAR_FDX) { 586101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 587101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 588101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 589101540Sambrisko } else { 590101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 591101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 592101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 593101540Sambrisko } 59476479Swpaul 595192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 596101540Sambrisko != IFM_FDX) { 597101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 598101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 599101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 600101540Sambrisko } else { 601101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 602101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 603101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 604101540Sambrisko } 60576479Swpaul } else { 606101540Sambrisko mii = device_get_softc(sc->nge_miibus); 60776479Swpaul 608101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 609101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 610101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 611101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 612101540Sambrisko } else { 613101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 614101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 615101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 616101540Sambrisko } 617101540Sambrisko 618101540Sambrisko /* If we have a 1000Mbps link, set the mode_1000 bit. */ 619101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 620101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 621101540Sambrisko NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 622101540Sambrisko } else { 623101540Sambrisko NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 624101540Sambrisko } 62579424Swpaul } 62676479Swpaul} 62776479Swpaul 62899497Salfredstatic void 629192288Syongaringe_setmulti(struct nge_softc *sc) 63076479Swpaul{ 63176479Swpaul struct ifnet *ifp; 63276479Swpaul struct ifmultiaddr *ifma; 633192294Syongari uint32_t h = 0, i, filtsave; 63476479Swpaul int bit, index; 63576479Swpaul 636135250Swpaul NGE_LOCK_ASSERT(sc); 637147256Sbrooks ifp = sc->nge_ifp; 63876479Swpaul 63976479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 64076479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 64176479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 64276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 64376479Swpaul return; 64476479Swpaul } 64576479Swpaul 64676479Swpaul /* 64776479Swpaul * We have to explicitly enable the multicast hash table 64876479Swpaul * on the NatSemi chip if we want to use it, which we do. 64976479Swpaul * We also have to tell it that we don't want to use the 65076479Swpaul * hash table for matching unicast addresses. 65176479Swpaul */ 65276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 65376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 65476479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 65576479Swpaul 65676479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 65776479Swpaul 65876479Swpaul /* first, zot all the existing hash bits */ 65976479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 66076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 66176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 66276479Swpaul } 66376479Swpaul 66476479Swpaul /* 66576479Swpaul * From the 11 bits returned by the crc routine, the top 7 66676479Swpaul * bits represent the 16-bit word in the mcast hash table 66776479Swpaul * that needs to be updated, and the lower 4 bits represent 66876479Swpaul * which bit within that byte needs to be set. 66976479Swpaul */ 670148654Srwatson IF_ADDR_LOCK(ifp); 67176479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 67276479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 67376479Swpaul continue; 674130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 675130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 21; 67676479Swpaul index = (h >> 4) & 0x7F; 67776479Swpaul bit = h & 0xF; 67876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 67976479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 68076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 68176479Swpaul } 682148654Srwatson IF_ADDR_UNLOCK(ifp); 68376479Swpaul 68476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 68576479Swpaul} 68676479Swpaul 68799497Salfredstatic void 688192288Syongaringe_reset(struct nge_softc *sc) 68976479Swpaul{ 690192289Syongari int i; 69176479Swpaul 69276479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 69376479Swpaul 69476479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 69576479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 69676479Swpaul break; 69776479Swpaul } 69876479Swpaul 69976479Swpaul if (i == NGE_TIMEOUT) 700162321Sglebius device_printf(sc->nge_dev, "reset never completed\n"); 70176479Swpaul 70276479Swpaul /* Wait a little while for the chip to get its brains in order. */ 70376479Swpaul DELAY(1000); 70476479Swpaul 70576479Swpaul /* 70676479Swpaul * If this is a NetSemi chip, make sure to clear 70776479Swpaul * PME mode. 70876479Swpaul */ 70976479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 71076479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 71176479Swpaul} 71276479Swpaul 71376479Swpaul/* 714108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 71576479Swpaul * IDs against our list and return a device name if we find a match. 71676479Swpaul */ 71799497Salfredstatic int 718192288Syongaringe_probe(device_t dev) 71976479Swpaul{ 72076479Swpaul struct nge_type *t; 72176479Swpaul 72276479Swpaul t = nge_devs; 72376479Swpaul 724192292Syongari while (t->nge_name != NULL) { 72576479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 72676479Swpaul (pci_get_device(dev) == t->nge_did)) { 72776479Swpaul device_set_desc(dev, t->nge_name); 728192292Syongari return (BUS_PROBE_DEFAULT); 72976479Swpaul } 73076479Swpaul t++; 73176479Swpaul } 73276479Swpaul 733192292Syongari return (ENXIO); 73476479Swpaul} 73576479Swpaul 73676479Swpaul/* 73776479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 73876479Swpaul * setup and ethernet/BPF attach. 73976479Swpaul */ 74099497Salfredstatic int 741192288Syongaringe_attach(device_t dev) 74276479Swpaul{ 74376479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 74476479Swpaul struct nge_softc *sc; 745151296Sjhb struct ifnet *ifp = NULL; 746151296Sjhb int error = 0, rid; 74776479Swpaul 74876479Swpaul sc = device_get_softc(dev); 749162321Sglebius sc->nge_dev = dev; 75076479Swpaul 751135250Swpaul NGE_LOCK_INIT(sc, device_get_nameunit(dev)); 752151296Sjhb callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0); 753151296Sjhb 75476479Swpaul /* 75576479Swpaul * Map control/status registers. 75676479Swpaul */ 75776479Swpaul pci_enable_busmaster(dev); 75876479Swpaul 75976479Swpaul rid = NGE_RID; 760127135Snjl sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE); 76176479Swpaul 76276479Swpaul if (sc->nge_res == NULL) { 763151296Sjhb device_printf(dev, "couldn't map ports/memory\n"); 76476479Swpaul error = ENXIO; 76576479Swpaul goto fail; 76676479Swpaul } 76776479Swpaul 76876479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 76976479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 77076479Swpaul 77176479Swpaul /* Allocate interrupt */ 77276479Swpaul rid = 0; 773127135Snjl sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 77476479Swpaul RF_SHAREABLE | RF_ACTIVE); 77576479Swpaul 77676479Swpaul if (sc->nge_irq == NULL) { 777151296Sjhb device_printf(dev, "couldn't map interrupt\n"); 77876479Swpaul error = ENXIO; 77976479Swpaul goto fail; 78076479Swpaul } 78176479Swpaul 78276479Swpaul /* Reset the adapter. */ 78376479Swpaul nge_reset(sc); 78476479Swpaul 78576479Swpaul /* 78676479Swpaul * Get station address from the EEPROM. 78776479Swpaul */ 78876479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 78976479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 79076479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 79176479Swpaul 79276479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 793151296Sjhb M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 79476479Swpaul 79576479Swpaul if (sc->nge_ldata == NULL) { 796151296Sjhb device_printf(dev, "no memory for list buffers!\n"); 79776479Swpaul error = ENXIO; 79876479Swpaul goto fail; 79976479Swpaul } 80076479Swpaul 801147256Sbrooks ifp = sc->nge_ifp = if_alloc(IFT_ETHER); 802147256Sbrooks if (ifp == NULL) { 803151296Sjhb device_printf(dev, "can not if_alloc()\n"); 804147256Sbrooks error = ENOSPC; 805147256Sbrooks goto fail; 806147256Sbrooks } 80776479Swpaul ifp->if_softc = sc; 808121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 80976479Swpaul ifp->if_mtu = ETHERMTU; 810135250Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 81176479Swpaul ifp->if_ioctl = nge_ioctl; 81276479Swpaul ifp->if_start = nge_start; 81376479Swpaul ifp->if_watchdog = nge_watchdog; 81476479Swpaul ifp->if_init = nge_init; 81576479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 81676479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 817106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 818150789Sglebius ifp->if_capenable = ifp->if_capabilities; 819128132Sru#ifdef DEVICE_POLLING 820128132Sru ifp->if_capabilities |= IFCAP_POLLING; 821128132Sru#endif 82276479Swpaul 82376479Swpaul /* 82476479Swpaul * Do MII setup. 82576479Swpaul */ 826150185Sru /* XXX: leaked on error */ 82776479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 828101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 829101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 830101540Sambrisko sc->nge_tbi = 1; 831101540Sambrisko device_printf(dev, "Using TBI\n"); 832192290Syongari 833101540Sambrisko sc->nge_miibus = dev; 834101540Sambrisko 835192290Syongari ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 836101540Sambrisko nge_ifmedia_sts); 837101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 838101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 839101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 840101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 841101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 842101540Sambrisko#undef ADD 843151296Sjhb device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n"); 844192290Syongari 845192290Syongari ifmedia_set(&sc->nge_ifmedia, 846101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 847192290Syongari 848101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 849192290Syongari | NGE_GPIO_GP4_OUT 850192290Syongari | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 851101540Sambrisko | NGE_GPIO_GP3_OUTENB 852101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 853192290Syongari 854101540Sambrisko } else { 855151296Sjhb device_printf(dev, "MII without any PHY!\n"); 856101540Sambrisko error = ENXIO; 857101540Sambrisko goto fail; 858101540Sambrisko } 85976479Swpaul } 86076479Swpaul 86176479Swpaul /* 86276479Swpaul * Call MI attach routine. 86376479Swpaul */ 864106937Ssam ether_ifattach(ifp, eaddr); 86576479Swpaul 866135250Swpaul /* 867135250Swpaul * Hookup IRQ last. 868135250Swpaul */ 869135250Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE, 870166901Spiso NULL, nge_intr, sc, &sc->nge_intrhand); 871135250Swpaul if (error) { 872151296Sjhb device_printf(dev, "couldn't set up irq\n"); 873151296Sjhb goto fail; 874151296Sjhb } 875151296Sjhb 876151296Sjhb return (0); 877151296Sjhb 878151296Sjhbfail: 879151296Sjhb if (sc->nge_ldata) 880151296Sjhb contigfree(sc->nge_ldata, 881151296Sjhb sizeof(struct nge_list_data), M_DEVBUF); 882151296Sjhb if (ifp) 883150185Sru if_free(ifp); 884151296Sjhb if (sc->nge_irq) 885135250Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 886151296Sjhb if (sc->nge_res) 887135250Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 888151296Sjhb NGE_LOCK_DESTROY(sc); 889192292Syongari return (error); 89076479Swpaul} 89176479Swpaul 89299497Salfredstatic int 893192288Syongaringe_detach(device_t dev) 89476479Swpaul{ 89576479Swpaul struct nge_softc *sc; 89676479Swpaul struct ifnet *ifp; 89776479Swpaul 89876479Swpaul sc = device_get_softc(dev); 899147256Sbrooks ifp = sc->nge_ifp; 90076479Swpaul 901150789Sglebius#ifdef DEVICE_POLLING 902150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 903150789Sglebius ether_poll_deregister(ifp); 904150789Sglebius#endif 905135250Swpaul NGE_LOCK(sc); 90676479Swpaul nge_reset(sc); 90776479Swpaul nge_stop(sc); 908135250Swpaul NGE_UNLOCK(sc); 909151296Sjhb callout_drain(&sc->nge_stat_ch); 910106937Ssam ether_ifdetach(ifp); 91176479Swpaul 91276479Swpaul bus_generic_detach(dev); 913101540Sambrisko if (!sc->nge_tbi) { 914101540Sambrisko device_delete_child(dev, sc->nge_miibus); 915101540Sambrisko } 91676479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 91776479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 91876479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 91976479Swpaul 92076479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 921150306Simp if_free(ifp); 92276479Swpaul 923135251Swpaul NGE_LOCK_DESTROY(sc); 924135251Swpaul 925192292Syongari return (0); 92676479Swpaul} 92776479Swpaul 92876479Swpaul/* 92976479Swpaul * Initialize the transmit descriptors. 93076479Swpaul */ 93199497Salfredstatic int 932192288Syongaringe_list_tx_init(struct nge_softc *sc) 93376479Swpaul{ 93476479Swpaul struct nge_list_data *ld; 93576479Swpaul struct nge_ring_data *cd; 93676479Swpaul int i; 93776479Swpaul 93876479Swpaul cd = &sc->nge_cdata; 93976479Swpaul ld = sc->nge_ldata; 94076479Swpaul 94176479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 94276479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 94376479Swpaul ld->nge_tx_list[i].nge_nextdesc = 94476479Swpaul &ld->nge_tx_list[0]; 94576479Swpaul ld->nge_tx_list[i].nge_next = 94676479Swpaul vtophys(&ld->nge_tx_list[0]); 94776479Swpaul } else { 94876479Swpaul ld->nge_tx_list[i].nge_nextdesc = 94976479Swpaul &ld->nge_tx_list[i + 1]; 95076479Swpaul ld->nge_tx_list[i].nge_next = 95176479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 95276479Swpaul } 95376479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 95476479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 95576479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 95676479Swpaul } 95776479Swpaul 95876479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 95976479Swpaul 960192292Syongari return (0); 96176479Swpaul} 96276479Swpaul 96376479Swpaul 96476479Swpaul/* 96576479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 96676479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 96776479Swpaul * points back to the first. 96876479Swpaul */ 96999497Salfredstatic int 970192288Syongaringe_list_rx_init(struct nge_softc *sc) 97176479Swpaul{ 97276479Swpaul struct nge_list_data *ld; 97376479Swpaul struct nge_ring_data *cd; 97476479Swpaul int i; 97576479Swpaul 97676479Swpaul ld = sc->nge_ldata; 97776479Swpaul cd = &sc->nge_cdata; 97876479Swpaul 97976479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 98076479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 981192292Syongari return (ENOBUFS); 98276479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 98376479Swpaul ld->nge_rx_list[i].nge_nextdesc = 98476479Swpaul &ld->nge_rx_list[0]; 98576479Swpaul ld->nge_rx_list[i].nge_next = 98676479Swpaul vtophys(&ld->nge_rx_list[0]); 98776479Swpaul } else { 98876479Swpaul ld->nge_rx_list[i].nge_nextdesc = 98976479Swpaul &ld->nge_rx_list[i + 1]; 99076479Swpaul ld->nge_rx_list[i].nge_next = 99176479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 99276479Swpaul } 99376479Swpaul } 99476479Swpaul 99576479Swpaul cd->nge_rx_prod = 0; 996135250Swpaul sc->nge_head = sc->nge_tail = NULL; 99776479Swpaul 998192292Syongari return (0); 99976479Swpaul} 100076479Swpaul 100176479Swpaul/* 100276479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 100376479Swpaul */ 100499497Salfredstatic int 1005192288Syongaringe_newbuf(struct nge_softc *sc, struct nge_desc *c, struct mbuf *m) 100676479Swpaul{ 100776479Swpaul 100876479Swpaul if (m == NULL) { 1009144241Ssam m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1010144241Ssam if (m == NULL) 1011135250Swpaul return (ENOBUFS); 1012135250Swpaul } else 1013135250Swpaul m->m_data = m->m_ext.ext_buf; 101476479Swpaul 1015135250Swpaul m->m_len = m->m_pkthdr.len = MCLBYTES; 101676479Swpaul 1017192294Syongari m_adj(m, sizeof(uint64_t)); 101876479Swpaul 1019144241Ssam c->nge_mbuf = m; 1020144241Ssam c->nge_ptr = vtophys(mtod(m, caddr_t)); 1021144241Ssam c->nge_ctl = m->m_len; 102276479Swpaul c->nge_extsts = 0; 102376479Swpaul 1024192292Syongari return (0); 102576479Swpaul} 102676479Swpaul 1027135250Swpaul#ifdef NGE_FIXUP_RX 1028135250Swpaulstatic __inline void 1029192288Syongaringe_fixup_rx(struct mbuf *m) 1030192290Syongari{ 1031135250Swpaul int i; 1032135250Swpaul uint16_t *src, *dst; 1033192290Syongari 1034135250Swpaul src = mtod(m, uint16_t *); 1035135250Swpaul dst = src - 1; 1036192290Syongari 1037135250Swpaul for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1038135250Swpaul *dst++ = *src++; 1039192290Syongari 1040135250Swpaul m->m_data -= ETHER_ALIGN; 1041192290Syongari 104276479Swpaul return; 1043192290Syongari} 104476479Swpaul#endif 104576479Swpaul 104676479Swpaul/* 104776479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 104876479Swpaul * the higher level protocols. 104976479Swpaul */ 105099497Salfredstatic void 1051192288Syongaringe_rxeof(struct nge_softc *sc) 105276479Swpaul{ 105376479Swpaul struct mbuf *m; 105476479Swpaul struct ifnet *ifp; 105576479Swpaul struct nge_desc *cur_rx; 105676479Swpaul int i, total_len = 0; 1057192294Syongari uint32_t rxstat; 105876479Swpaul 1059135250Swpaul NGE_LOCK_ASSERT(sc); 1060147256Sbrooks ifp = sc->nge_ifp; 106176479Swpaul i = sc->nge_cdata.nge_rx_prod; 106276479Swpaul 1063192292Syongari while (NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 1064192294Syongari uint32_t extsts; 106576479Swpaul 1066106507Ssimokawa#ifdef DEVICE_POLLING 1067150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1068106507Ssimokawa if (sc->rxcycles <= 0) 1069106507Ssimokawa break; 1070106507Ssimokawa sc->rxcycles--; 1071106507Ssimokawa } 1072150789Sglebius#endif 1073106507Ssimokawa 107476479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 107576479Swpaul rxstat = cur_rx->nge_rxstat; 107676479Swpaul extsts = cur_rx->nge_extsts; 107776479Swpaul m = cur_rx->nge_mbuf; 107876479Swpaul cur_rx->nge_mbuf = NULL; 107976479Swpaul total_len = NGE_RXBYTES(cur_rx); 108076479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 1081135250Swpaul 1082135250Swpaul if (rxstat & NGE_CMDSTS_MORE) { 1083135250Swpaul m->m_len = total_len; 1084135250Swpaul if (sc->nge_head == NULL) { 1085135250Swpaul m->m_pkthdr.len = total_len; 1086135250Swpaul sc->nge_head = sc->nge_tail = m; 1087135250Swpaul } else { 1088135250Swpaul m->m_flags &= ~M_PKTHDR; 1089135250Swpaul sc->nge_head->m_pkthdr.len += total_len; 1090135250Swpaul sc->nge_tail->m_next = m; 1091135250Swpaul sc->nge_tail = m; 1092135250Swpaul } 1093135250Swpaul nge_newbuf(sc, cur_rx, NULL); 1094135250Swpaul continue; 1095135250Swpaul } 1096135250Swpaul 109776479Swpaul /* 109876479Swpaul * If an error occurs, update stats, clear the 109976479Swpaul * status word and leave the mbuf cluster in place: 110076479Swpaul * it should simply get re-used next time this descriptor 110176479Swpaul * comes up in the ring. 110276479Swpaul */ 110376479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 110476479Swpaul ifp->if_ierrors++; 1105135250Swpaul if (sc->nge_head != NULL) { 1106135250Swpaul m_freem(sc->nge_head); 1107135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1108135250Swpaul } 110976479Swpaul nge_newbuf(sc, cur_rx, m); 111076479Swpaul continue; 111176479Swpaul } 111276479Swpaul 1113135250Swpaul /* Try conjure up a replacement mbuf. */ 1114135250Swpaul 1115135250Swpaul if (nge_newbuf(sc, cur_rx, NULL)) { 1116135250Swpaul ifp->if_ierrors++; 1117135250Swpaul if (sc->nge_head != NULL) { 1118135250Swpaul m_freem(sc->nge_head); 1119135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1120135250Swpaul } 1121135250Swpaul nge_newbuf(sc, cur_rx, m); 1122135250Swpaul continue; 1123135250Swpaul } 1124135250Swpaul 1125135250Swpaul if (sc->nge_head != NULL) { 1126135250Swpaul m->m_len = total_len; 1127135250Swpaul m->m_flags &= ~M_PKTHDR; 1128135250Swpaul sc->nge_tail->m_next = m; 1129135250Swpaul m = sc->nge_head; 1130135250Swpaul m->m_pkthdr.len += total_len; 1131135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1132135250Swpaul } else 1133135250Swpaul m->m_pkthdr.len = m->m_len = total_len; 1134135250Swpaul 113576479Swpaul /* 113676479Swpaul * Ok. NatSemi really screwed up here. This is the 113776479Swpaul * only gigE chip I know of with alignment constraints 113876479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 113976479Swpaul */ 114079562Swpaul /* 114179562Swpaul * By popular demand, ignore the alignment problems 114279562Swpaul * on the Intel x86 platform. The performance hit 114379562Swpaul * incurred due to unaligned accesses is much smaller 114479562Swpaul * than the hit produced by forcing buffer copies all 114579562Swpaul * the time, especially with jumbo frames. We still 114679562Swpaul * need to fix up the alignment everywhere else though. 114779562Swpaul */ 1148135250Swpaul#ifdef NGE_FIXUP_RX 1149135250Swpaul nge_fixup_rx(m); 115079562Swpaul#endif 115176479Swpaul 115276479Swpaul ifp->if_ipackets++; 1153135250Swpaul m->m_pkthdr.rcvif = ifp; 115476479Swpaul 115576479Swpaul /* Do IP checksum checking. */ 115678323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 115778323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 115878323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 115978323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 116078323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 116178323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 116278323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 116378323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 116478323Swpaul m->m_pkthdr.csum_flags |= 116578323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 116678323Swpaul m->m_pkthdr.csum_data = 0xffff; 116778323Swpaul } 116876479Swpaul 116976479Swpaul /* 117076479Swpaul * If we received a packet with a vlan tag, pass it 117176479Swpaul * to vlan_input() instead of ether_input(). 117276479Swpaul */ 117376479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1174162375Sandre m->m_pkthdr.ether_vtag = 1175162375Sandre ntohs(extsts & NGE_RXEXTSTS_VTCI); 1176162375Sandre m->m_flags |= M_VLANTAG; 1177106937Ssam } 1178135250Swpaul NGE_UNLOCK(sc); 1179106937Ssam (*ifp->if_input)(ifp, m); 1180135250Swpaul NGE_LOCK(sc); 118176479Swpaul } 118276479Swpaul 118376479Swpaul sc->nge_cdata.nge_rx_prod = i; 118476479Swpaul} 118576479Swpaul 118676479Swpaul/* 118776479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 118876479Swpaul * the list buffers. 118976479Swpaul */ 119076479Swpaul 119199497Salfredstatic void 1192192288Syongaringe_txeof(struct nge_softc *sc) 119376479Swpaul{ 1194128130Sru struct nge_desc *cur_tx; 119576479Swpaul struct ifnet *ifp; 1196192294Syongari uint32_t idx; 119776479Swpaul 1198135250Swpaul NGE_LOCK_ASSERT(sc); 1199147256Sbrooks ifp = sc->nge_ifp; 120076479Swpaul 120176479Swpaul /* 120276479Swpaul * Go through our tx list and free mbufs for those 120376479Swpaul * frames that have been transmitted. 120476479Swpaul */ 120576479Swpaul idx = sc->nge_cdata.nge_tx_cons; 120676479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 120776479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 120876479Swpaul 120976479Swpaul if (NGE_OWNDESC(cur_tx)) 121076479Swpaul break; 121176479Swpaul 121276479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 121376479Swpaul sc->nge_cdata.nge_tx_cnt--; 121476479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 121576479Swpaul continue; 121676479Swpaul } 121776479Swpaul 121876479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 121976479Swpaul ifp->if_oerrors++; 122076479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 122176479Swpaul ifp->if_collisions++; 122276479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 122376479Swpaul ifp->if_collisions++; 122476479Swpaul } 122576479Swpaul 122676479Swpaul ifp->if_collisions += 122776479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 122876479Swpaul 122976479Swpaul ifp->if_opackets++; 123076479Swpaul if (cur_tx->nge_mbuf != NULL) { 123176479Swpaul m_freem(cur_tx->nge_mbuf); 123276479Swpaul cur_tx->nge_mbuf = NULL; 1233148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 123476479Swpaul } 123576479Swpaul 123676479Swpaul sc->nge_cdata.nge_tx_cnt--; 123776479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 123876479Swpaul } 123976479Swpaul 124076479Swpaul sc->nge_cdata.nge_tx_cons = idx; 124176479Swpaul 1242128130Sru if (idx == sc->nge_cdata.nge_tx_prod) 1243128130Sru ifp->if_timer = 0; 124476479Swpaul} 124576479Swpaul 124699497Salfredstatic void 1247192288Syongaringe_tick(void *xsc) 124876479Swpaul{ 124976479Swpaul struct nge_softc *sc; 125076479Swpaul struct mii_data *mii; 125176479Swpaul struct ifnet *ifp; 125276479Swpaul 1253151296Sjhb sc = xsc; 1254135250Swpaul NGE_LOCK_ASSERT(sc); 1255147256Sbrooks ifp = sc->nge_ifp; 125676479Swpaul 1257101540Sambrisko if (sc->nge_tbi) { 1258101540Sambrisko if (!sc->nge_link) { 1259192290Syongari if (CSR_READ_4(sc, NGE_TBI_BMSR) 1260101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 1261137402Sphk if (bootverbose) 1262192290Syongari device_printf(sc->nge_dev, 1263151296Sjhb "gigabit link up\n"); 1264101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1265101540Sambrisko sc->nge_link++; 1266101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1267135250Swpaul nge_start_locked(ifp); 1268101540Sambrisko } 126996028Sphk } 1270101540Sambrisko } else { 1271101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1272101540Sambrisko mii_tick(mii); 1273101540Sambrisko 1274101540Sambrisko if (!sc->nge_link) { 1275101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1276101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1277101540Sambrisko sc->nge_link++; 1278192290Syongari if (IFM_SUBTYPE(mii->mii_media_active) 1279137402Sphk == IFM_1000_T && bootverbose) 1280192290Syongari device_printf(sc->nge_dev, 1281151296Sjhb "gigabit link up\n"); 1282101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1283135250Swpaul nge_start_locked(ifp); 1284101540Sambrisko } 1285101540Sambrisko } 128676479Swpaul } 1287135250Swpaul callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc); 128876479Swpaul} 128976479Swpaul 1290106507Ssimokawa#ifdef DEVICE_POLLING 1291106507Ssimokawastatic poll_handler_t nge_poll; 1292106507Ssimokawa 129399497Salfredstatic void 1294106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1295106507Ssimokawa{ 1296106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1297106507Ssimokawa 1298135250Swpaul NGE_LOCK(sc); 1299150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1300135250Swpaul NGE_UNLOCK(sc); 1301106507Ssimokawa return; 1302106507Ssimokawa } 1303106507Ssimokawa 1304106507Ssimokawa /* 1305106507Ssimokawa * On the nge, reading the status register also clears it. 1306106507Ssimokawa * So before returning to intr mode we must make sure that all 1307106507Ssimokawa * possible pending sources of interrupts have been served. 1308106507Ssimokawa * In practice this means run to completion the *eof routines, 1309106507Ssimokawa * and then call the interrupt routine 1310106507Ssimokawa */ 1311106507Ssimokawa sc->rxcycles = count; 1312106507Ssimokawa nge_rxeof(sc); 1313106507Ssimokawa nge_txeof(sc); 1314106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1315135250Swpaul nge_start_locked(ifp); 1316106507Ssimokawa 1317106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1318192294Syongari uint32_t status; 1319106507Ssimokawa 1320106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1321106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1322106507Ssimokawa 1323106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1324106507Ssimokawa nge_rxeof(sc); 1325106507Ssimokawa 1326106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1327106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1328106507Ssimokawa 1329106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1330106507Ssimokawa nge_reset(sc); 1331135250Swpaul nge_init_locked(sc); 1332106507Ssimokawa } 1333106507Ssimokawa } 1334135250Swpaul NGE_UNLOCK(sc); 1335106507Ssimokawa} 1336106507Ssimokawa#endif /* DEVICE_POLLING */ 1337106507Ssimokawa 1338106507Ssimokawastatic void 1339192288Syongaringe_intr(void *arg) 134076479Swpaul{ 134176479Swpaul struct nge_softc *sc; 134276479Swpaul struct ifnet *ifp; 1343192294Syongari uint32_t status; 134476479Swpaul 134576479Swpaul sc = arg; 1346147256Sbrooks ifp = sc->nge_ifp; 134776479Swpaul 1348135250Swpaul NGE_LOCK(sc); 1349106507Ssimokawa#ifdef DEVICE_POLLING 1350150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1351135250Swpaul NGE_UNLOCK(sc); 1352106507Ssimokawa return; 1353135250Swpaul } 1354150789Sglebius#endif 1355106507Ssimokawa 135676479Swpaul /* Supress unwanted interrupts */ 135776479Swpaul if (!(ifp->if_flags & IFF_UP)) { 135876479Swpaul nge_stop(sc); 1359135250Swpaul NGE_UNLOCK(sc); 136076479Swpaul return; 136176479Swpaul } 136276479Swpaul 136376479Swpaul /* Disable interrupts. */ 136476479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 136576479Swpaul 1366101540Sambrisko /* Data LED on for TBI mode */ 1367192292Syongari if (sc->nge_tbi) 1368101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1369101540Sambrisko | NGE_GPIO_GP3_OUT); 1370101540Sambrisko 137176479Swpaul for (;;) { 137276479Swpaul /* Reading the ISR register clears all interrupts. */ 137376479Swpaul status = CSR_READ_4(sc, NGE_ISR); 137476479Swpaul 137576479Swpaul if ((status & NGE_INTRS) == 0) 137676479Swpaul break; 137776479Swpaul 137876479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 137976479Swpaul (status & NGE_ISR_TX_ERR) || 138076479Swpaul (status & NGE_ISR_TX_OK) || 138176479Swpaul (status & NGE_ISR_TX_IDLE)) 138276479Swpaul nge_txeof(sc); 138376479Swpaul 138476479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 138579798Swpaul (status & NGE_ISR_RX_ERR) || 138683678Swpaul (status & NGE_ISR_RX_OFLOW) || 138794612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 138894612Sphk (status & NGE_ISR_RX_IDLE) || 138976479Swpaul (status & NGE_ISR_RX_OK)) 139076479Swpaul nge_rxeof(sc); 139194612Sphk 139294612Sphk if ((status & NGE_ISR_RX_IDLE)) 139394612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 139494612Sphk 139576479Swpaul if (status & NGE_ISR_SYSERR) { 139676479Swpaul nge_reset(sc); 1397148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1398135250Swpaul nge_init_locked(sc); 139976479Swpaul } 140076479Swpaul 140196028Sphk#if 0 1402192290Syongari /* 140396028Sphk * XXX: nge_tick() is not ready to be called this way 140496028Sphk * it screws up the aneg timeout because mii_tick() is 140596028Sphk * only to be called once per second. 140696028Sphk */ 140776479Swpaul if (status & NGE_IMR_PHY_INTR) { 140876479Swpaul sc->nge_link = 0; 1409151296Sjhb nge_tick(sc); 141076479Swpaul } 141196028Sphk#endif 141276479Swpaul } 141376479Swpaul 141476479Swpaul /* Re-enable interrupts. */ 141576479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 141676479Swpaul 141776479Swpaul if (ifp->if_snd.ifq_head != NULL) 1418135250Swpaul nge_start_locked(ifp); 141976479Swpaul 1420101540Sambrisko /* Data LED off for TBI mode */ 1421101540Sambrisko 1422192292Syongari if (sc->nge_tbi) 1423101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1424101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1425101540Sambrisko 1426135250Swpaul NGE_UNLOCK(sc); 142776479Swpaul} 142876479Swpaul 142976479Swpaul/* 143076479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 143176479Swpaul * pointers to the fragment pointers. 143276479Swpaul */ 143399497Salfredstatic int 1434192294Syongaringe_encap(struct nge_softc *sc, struct mbuf *m_head, uint32_t *txidx) 143576479Swpaul{ 143676479Swpaul struct nge_desc *f = NULL; 143776479Swpaul struct mbuf *m; 143876479Swpaul int frag, cur, cnt = 0; 143976479Swpaul 144076479Swpaul /* 144176479Swpaul * Start packing the mbufs in this chain into 144276479Swpaul * the fragment pointers. Stop when we run out 144376479Swpaul * of fragments or hit the end of the mbuf chain. 144476479Swpaul */ 144576479Swpaul m = m_head; 144676479Swpaul cur = frag = *txidx; 144776479Swpaul 144876479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 144976479Swpaul if (m->m_len != 0) { 145076479Swpaul if ((NGE_TX_LIST_CNT - 145176479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 1452192292Syongari return (ENOBUFS); 145376479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 145476479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 145576479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 145676479Swpaul if (cnt != 0) 145776479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 145876479Swpaul cur = frag; 145976479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 146076479Swpaul cnt++; 146176479Swpaul } 146276479Swpaul } 146376479Swpaul 146476479Swpaul if (m != NULL) 1465192292Syongari return (ENOBUFS); 146676479Swpaul 146778286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 146876479Swpaul if (m_head->m_pkthdr.csum_flags) { 146976479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 147078286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 147176479Swpaul NGE_TXEXTSTS_IPCSUM; 147276479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 147378286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 147476479Swpaul NGE_TXEXTSTS_TCPCSUM; 147576479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 147678286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 147776479Swpaul NGE_TXEXTSTS_UDPCSUM; 147876479Swpaul } 147976479Swpaul 1480162375Sandre if (m_head->m_flags & M_VLANTAG) { 148176479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1482162375Sandre (NGE_TXEXTSTS_VLANPKT|htons(m_head->m_pkthdr.ether_vtag)); 148376479Swpaul } 148476479Swpaul 148576479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 148676479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 148776479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 148876479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 148976479Swpaul *txidx = frag; 149076479Swpaul 1491192292Syongari return (0); 149276479Swpaul} 149376479Swpaul 149476479Swpaul/* 149576479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 149676479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 149776479Swpaul * copy of the pointers since the transmit list fragment pointers are 149876479Swpaul * physical addresses. 149976479Swpaul */ 150076479Swpaul 150199497Salfredstatic void 1502192288Syongaringe_start(struct ifnet *ifp) 150376479Swpaul{ 150476479Swpaul struct nge_softc *sc; 1505135250Swpaul 1506135250Swpaul sc = ifp->if_softc; 1507135250Swpaul NGE_LOCK(sc); 1508135250Swpaul nge_start_locked(ifp); 1509135250Swpaul NGE_UNLOCK(sc); 1510135250Swpaul} 1511135250Swpaul 1512135250Swpaulstatic void 1513192288Syongaringe_start_locked(struct ifnet *ifp) 1514135250Swpaul{ 1515135250Swpaul struct nge_softc *sc; 151676479Swpaul struct mbuf *m_head = NULL; 1517192294Syongari uint32_t idx; 151876479Swpaul 151976479Swpaul sc = ifp->if_softc; 152076479Swpaul 152176479Swpaul if (!sc->nge_link) 152276479Swpaul return; 152376479Swpaul 152476479Swpaul idx = sc->nge_cdata.nge_tx_prod; 152576479Swpaul 1526148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 152776479Swpaul return; 152876479Swpaul 1529192292Syongari while (sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 153076479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 153176479Swpaul if (m_head == NULL) 153276479Swpaul break; 153376479Swpaul 153476479Swpaul if (nge_encap(sc, m_head, &idx)) { 153576479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1536148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 153776479Swpaul break; 153876479Swpaul } 153976479Swpaul 154076479Swpaul /* 154176479Swpaul * If there's a BPF listener, bounce a copy of this frame 154276479Swpaul * to him. 154376479Swpaul */ 1544167190Scsjp ETHER_BPF_MTAP(ifp, m_head); 154576479Swpaul 154676479Swpaul } 154776479Swpaul 154876479Swpaul /* Transmit */ 154976479Swpaul sc->nge_cdata.nge_tx_prod = idx; 155076479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 155176479Swpaul 155276479Swpaul /* 155376479Swpaul * Set a timeout in case the chip goes out to lunch. 155476479Swpaul */ 155576479Swpaul ifp->if_timer = 5; 155676479Swpaul} 155776479Swpaul 155899497Salfredstatic void 1559192288Syongaringe_init(void *xsc) 156076479Swpaul{ 156176479Swpaul struct nge_softc *sc = xsc; 1562135250Swpaul 1563135250Swpaul NGE_LOCK(sc); 1564135250Swpaul nge_init_locked(sc); 1565135250Swpaul NGE_UNLOCK(sc); 1566135250Swpaul} 1567135250Swpaul 1568135250Swpaulstatic void 1569192288Syongaringe_init_locked(struct nge_softc *sc) 1570135250Swpaul{ 1571147256Sbrooks struct ifnet *ifp = sc->nge_ifp; 157276479Swpaul struct mii_data *mii; 157376479Swpaul 1574135250Swpaul NGE_LOCK_ASSERT(sc); 1575135250Swpaul 1576148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 157776479Swpaul return; 157876479Swpaul 157976479Swpaul /* 158076479Swpaul * Cancel pending I/O and free all RX/TX buffers. 158176479Swpaul */ 158276479Swpaul nge_stop(sc); 158376479Swpaul 1584101540Sambrisko if (sc->nge_tbi) { 1585101540Sambrisko mii = NULL; 1586101540Sambrisko } else { 1587101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1588101540Sambrisko } 158976479Swpaul 159076479Swpaul /* Set MAC address */ 159176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 159276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1593192294Syongari ((uint16_t *)IF_LLADDR(sc->nge_ifp))[0]); 159476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 159576479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1596192294Syongari ((uint16_t *)IF_LLADDR(sc->nge_ifp))[1]); 159776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 159876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1599192294Syongari ((uint16_t *)IF_LLADDR(sc->nge_ifp))[2]); 160076479Swpaul 160176479Swpaul /* Init circular RX list. */ 160276479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 1603162321Sglebius device_printf(sc->nge_dev, "initialization failed: no " 1604151296Sjhb "memory for rx buffers\n"); 160576479Swpaul nge_stop(sc); 160676479Swpaul return; 160776479Swpaul } 160876479Swpaul 160976479Swpaul /* 161076479Swpaul * Init tx descriptors. 161176479Swpaul */ 161276479Swpaul nge_list_tx_init(sc); 161376479Swpaul 161476479Swpaul /* 161576479Swpaul * For the NatSemi chip, we have to explicitly enable the 161676479Swpaul * reception of ARP frames, as well as turn on the 'perfect 161776479Swpaul * match' filter where we store the station address, otherwise 161876479Swpaul * we won't receive unicasts meant for this host. 161976479Swpaul */ 162076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 162176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 162276479Swpaul 162376479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 162476479Swpaul if (ifp->if_flags & IFF_PROMISC) { 162576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 162676479Swpaul } else { 162776479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 162876479Swpaul } 162976479Swpaul 163076479Swpaul /* 163176479Swpaul * Set the capture broadcast bit to capture broadcast frames. 163276479Swpaul */ 163376479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 163476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 163576479Swpaul } else { 163676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 163776479Swpaul } 163876479Swpaul 163976479Swpaul /* 164076479Swpaul * Load the multicast filter. 164176479Swpaul */ 164276479Swpaul nge_setmulti(sc); 164376479Swpaul 164476479Swpaul /* Turn the receive filter on */ 164576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 164676479Swpaul 164776479Swpaul /* 164876479Swpaul * Load the address of the RX and TX lists. 164976479Swpaul */ 165076479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 165176479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 165276479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 165376479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 165476479Swpaul 165576479Swpaul /* Set RX configuration */ 165676479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 165776479Swpaul /* 165876479Swpaul * Enable hardware checksum validation for all IPv4 165976479Swpaul * packets, do not reject packets with bad checksums. 166076479Swpaul */ 166178323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 166276479Swpaul 166376479Swpaul /* 166483115Sbrooks * Tell the chip to detect and strip VLAN tag info from 166583115Sbrooks * received frames. The tag will be provided in the extsts 166683115Sbrooks * field in the RX descriptors. 166776479Swpaul */ 166876479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 166976479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 167076479Swpaul 167176479Swpaul /* Set TX configuration */ 167276479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 167376479Swpaul 167476479Swpaul /* 167576479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 167676479Swpaul */ 167778323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 167876479Swpaul 167976479Swpaul /* 168083115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 168183115Sbrooks * dictated by the code in the frame encapsulation routine. 168276479Swpaul */ 168376479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 168476479Swpaul 168576479Swpaul /* Set full/half duplex mode. */ 1686101540Sambrisko if (sc->nge_tbi) { 1687192290Syongari if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1688101540Sambrisko == IFM_FDX) { 1689101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1690101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1691101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1692101540Sambrisko } else { 1693101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1694101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1695101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1696101540Sambrisko } 169776479Swpaul } else { 1698101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1699101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1700101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1701101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1702101540Sambrisko } else { 1703101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1704101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1705101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1706101540Sambrisko } 170776479Swpaul } 170876479Swpaul 1709151296Sjhb nge_tick(sc); 171096028Sphk 171176479Swpaul /* 171276479Swpaul * Enable the delivery of PHY interrupts based on 171377842Swpaul * link/speed/duplex status changes. Also enable the 171477842Swpaul * extsts field in the DMA descriptors (needed for 171577842Swpaul * TCP/IP checksum offload on transmit). 171676479Swpaul */ 171779424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 171877842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 171976479Swpaul 172076479Swpaul /* 172179562Swpaul * Configure interrupt holdoff (moderation). We can 172279562Swpaul * have the chip delay interrupt delivery for a certain 172379562Swpaul * period. Units are in 100us, and the max setting 172479562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 172579562Swpaul */ 172679562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 172779562Swpaul 172879562Swpaul /* 172976479Swpaul * Enable interrupts. 173076479Swpaul */ 173176479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1732106507Ssimokawa#ifdef DEVICE_POLLING 1733106507Ssimokawa /* 1734106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1735106507Ssimokawa * they are off otherwise. 1736106507Ssimokawa */ 1737150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1738106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1739106507Ssimokawa else 1740150789Sglebius#endif 174176479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 174276479Swpaul 174376479Swpaul /* Enable receiver and transmitter. */ 174476479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 174576479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 174676479Swpaul 1747151296Sjhb nge_ifmedia_upd_locked(ifp); 174876479Swpaul 1749148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1750148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 175176479Swpaul} 175276479Swpaul 175376479Swpaul/* 175476479Swpaul * Set media options. 175576479Swpaul */ 175699497Salfredstatic int 1757192288Syongaringe_ifmedia_upd(struct ifnet *ifp) 175876479Swpaul{ 175976479Swpaul struct nge_softc *sc; 1760151296Sjhb 1761151296Sjhb sc = ifp->if_softc; 1762151296Sjhb NGE_LOCK(sc); 1763151296Sjhb nge_ifmedia_upd_locked(ifp); 1764151296Sjhb NGE_UNLOCK(sc); 1765151296Sjhb return (0); 1766151296Sjhb} 1767151296Sjhb 1768151296Sjhbstatic void 1769192288Syongaringe_ifmedia_upd_locked(struct ifnet *ifp) 1770151296Sjhb{ 1771151296Sjhb struct nge_softc *sc; 177276479Swpaul struct mii_data *mii; 177376479Swpaul 177476479Swpaul sc = ifp->if_softc; 1775151296Sjhb NGE_LOCK_ASSERT(sc); 177676479Swpaul 1777101540Sambrisko if (sc->nge_tbi) { 1778192290Syongari if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1779101540Sambrisko == IFM_AUTO) { 1780192290Syongari CSR_WRITE_4(sc, NGE_TBI_ANAR, 1781101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 1782101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 1783101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 1784101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 1785101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 1786101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 1787192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 1788101540Sambrisko & IFM_GMASK) == IFM_FDX) { 1789101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1790101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1791101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1792101540Sambrisko 1793101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1794101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1795101540Sambrisko } else { 1796101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1797101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1798101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1799101540Sambrisko 1800101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1801101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1802101540Sambrisko } 1803192290Syongari 1804101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1805101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1806101540Sambrisko } else { 1807101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1808101540Sambrisko sc->nge_link = 0; 1809101540Sambrisko if (mii->mii_instance) { 1810101540Sambrisko struct mii_softc *miisc; 1811151296Sjhb 1812151296Sjhb LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1813101540Sambrisko mii_phy_reset(miisc); 1814101540Sambrisko } 1815101540Sambrisko mii_mediachg(mii); 181676479Swpaul } 181776479Swpaul} 181876479Swpaul 181976479Swpaul/* 182076479Swpaul * Report current media status. 182176479Swpaul */ 182299497Salfredstatic void 1823192288Syongaringe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 182476479Swpaul{ 182576479Swpaul struct nge_softc *sc; 182676479Swpaul struct mii_data *mii; 182776479Swpaul 182876479Swpaul sc = ifp->if_softc; 182976479Swpaul 1830151296Sjhb NGE_LOCK(sc); 1831101540Sambrisko if (sc->nge_tbi) { 1832101540Sambrisko ifmr->ifm_status = IFM_AVALID; 1833101540Sambrisko ifmr->ifm_active = IFM_ETHER; 183476479Swpaul 1835101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1836101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 1837192290Syongari } 1838101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 1839101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 1840101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1841101540Sambrisko ifmr->ifm_active |= IFM_NONE; 1842101540Sambrisko ifmr->ifm_status = 0; 1843151296Sjhb NGE_UNLOCK(sc); 1844101540Sambrisko return; 1845192290Syongari } 1846101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 1847101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1848101540Sambrisko == IFM_AUTO) { 1849101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 1850101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1851101540Sambrisko & NGE_TBIANAR_FDX) { 1852101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1853101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1854101540Sambrisko & NGE_TBIANAR_HDX) { 1855101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1856101540Sambrisko } 1857192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1858101540Sambrisko == IFM_FDX) 1859101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1860101540Sambrisko else 1861101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1862192290Syongari 1863101540Sambrisko } else { 1864101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1865101540Sambrisko mii_pollstat(mii); 1866101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 1867101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 1868101540Sambrisko } 1869151296Sjhb NGE_UNLOCK(sc); 187076479Swpaul} 187176479Swpaul 187299497Salfredstatic int 1873192288Syongaringe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 187476479Swpaul{ 187576479Swpaul struct nge_softc *sc = ifp->if_softc; 187676479Swpaul struct ifreq *ifr = (struct ifreq *) data; 187776479Swpaul struct mii_data *mii; 1878135250Swpaul int error = 0; 187976479Swpaul 1880192292Syongari switch (command) { 188176479Swpaul case SIOCSIFMTU: 188276479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 188376479Swpaul error = EINVAL; 188478323Swpaul else { 1885151296Sjhb NGE_LOCK(sc); 188676479Swpaul ifp->if_mtu = ifr->ifr_mtu; 188778323Swpaul /* 188878323Swpaul * Workaround: if the MTU is larger than 188978323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 189078323Swpaul * TX checksum offloading. 189178323Swpaul */ 1892129632Syar if (ifr->ifr_mtu >= 8152) { 1893129632Syar ifp->if_capenable &= ~IFCAP_TXCSUM; 189478323Swpaul ifp->if_hwassist = 0; 1895129632Syar } else { 1896129632Syar ifp->if_capenable |= IFCAP_TXCSUM; 189778323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 1898129632Syar } 1899151296Sjhb NGE_UNLOCK(sc); 190078323Swpaul } 190176479Swpaul break; 190276479Swpaul case SIOCSIFFLAGS: 1903135250Swpaul NGE_LOCK(sc); 190476479Swpaul if (ifp->if_flags & IFF_UP) { 1905148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 190676479Swpaul ifp->if_flags & IFF_PROMISC && 190776479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 190876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 190976479Swpaul NGE_RXFILTCTL_ALLPHYS| 191076479Swpaul NGE_RXFILTCTL_ALLMULTI); 1911148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 191276479Swpaul !(ifp->if_flags & IFF_PROMISC) && 191376479Swpaul sc->nge_if_flags & IFF_PROMISC) { 191476479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 191576479Swpaul NGE_RXFILTCTL_ALLPHYS); 191676479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 191776479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 191876479Swpaul NGE_RXFILTCTL_ALLMULTI); 191976479Swpaul } else { 1920148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1921135250Swpaul nge_init_locked(sc); 192276479Swpaul } 192376479Swpaul } else { 1924148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 192576479Swpaul nge_stop(sc); 192676479Swpaul } 192776479Swpaul sc->nge_if_flags = ifp->if_flags; 1928135250Swpaul NGE_UNLOCK(sc); 192976479Swpaul error = 0; 193076479Swpaul break; 193176479Swpaul case SIOCADDMULTI: 193276479Swpaul case SIOCDELMULTI: 1933135250Swpaul NGE_LOCK(sc); 193476479Swpaul nge_setmulti(sc); 1935135250Swpaul NGE_UNLOCK(sc); 193676479Swpaul error = 0; 193776479Swpaul break; 193876479Swpaul case SIOCGIFMEDIA: 193976479Swpaul case SIOCSIFMEDIA: 1940101540Sambrisko if (sc->nge_tbi) { 1941192290Syongari error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 1942101540Sambrisko command); 1943101540Sambrisko } else { 1944101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1945192290Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 1946101540Sambrisko command); 1947101540Sambrisko } 194876479Swpaul break; 1949128132Sru case SIOCSIFCAP: 1950150789Sglebius#ifdef DEVICE_POLLING 1951150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1952150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1953150789Sglebius error = ether_poll_register(nge_poll, ifp); 1954150789Sglebius if (error) 1955192292Syongari return (error); 1956150789Sglebius NGE_LOCK(sc); 1957150789Sglebius /* Disable interrupts */ 1958150789Sglebius CSR_WRITE_4(sc, NGE_IER, 0); 1959150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1960150789Sglebius NGE_UNLOCK(sc); 1961150789Sglebius return (error); 1962192290Syongari 1963150789Sglebius } 1964150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1965150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1966150789Sglebius error = ether_poll_deregister(ifp); 1967150789Sglebius /* Enable interrupts. */ 1968150789Sglebius NGE_LOCK(sc); 1969150789Sglebius CSR_WRITE_4(sc, NGE_IER, 1); 1970150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 1971150789Sglebius NGE_UNLOCK(sc); 1972150789Sglebius return (error); 1973150789Sglebius } 1974150789Sglebius#endif /* DEVICE_POLLING */ 1975128132Sru break; 197676479Swpaul default: 1977106937Ssam error = ether_ioctl(ifp, command, data); 197876479Swpaul break; 197976479Swpaul } 198076479Swpaul 1981192292Syongari return (error); 198276479Swpaul} 198376479Swpaul 198499497Salfredstatic void 1985192288Syongaringe_watchdog(struct ifnet *ifp) 198676479Swpaul{ 198776479Swpaul struct nge_softc *sc; 198876479Swpaul 198976479Swpaul sc = ifp->if_softc; 199076479Swpaul 199176479Swpaul ifp->if_oerrors++; 1992162321Sglebius if_printf(ifp, "watchdog timeout\n"); 199376479Swpaul 1994135250Swpaul NGE_LOCK(sc); 199576479Swpaul nge_stop(sc); 199676479Swpaul nge_reset(sc); 1997148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1998135250Swpaul nge_init_locked(sc); 199976479Swpaul 200076479Swpaul if (ifp->if_snd.ifq_head != NULL) 2001135250Swpaul nge_start_locked(ifp); 200276479Swpaul 2003135250Swpaul NGE_UNLOCK(sc); 200476479Swpaul} 200576479Swpaul 200676479Swpaul/* 200776479Swpaul * Stop the adapter and free any mbufs allocated to the 200876479Swpaul * RX and TX lists. 200976479Swpaul */ 201099497Salfredstatic void 2011192288Syongaringe_stop(struct nge_softc *sc) 201276479Swpaul{ 2013192289Syongari int i; 201476479Swpaul struct ifnet *ifp; 201576479Swpaul struct mii_data *mii; 201676479Swpaul 2017135250Swpaul NGE_LOCK_ASSERT(sc); 2018147256Sbrooks ifp = sc->nge_ifp; 201976479Swpaul ifp->if_timer = 0; 2020101540Sambrisko if (sc->nge_tbi) { 2021101540Sambrisko mii = NULL; 2022101540Sambrisko } else { 2023101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2024101540Sambrisko } 202576479Swpaul 2026135250Swpaul callout_stop(&sc->nge_stat_ch); 202776479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 202876479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 202976479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 203076479Swpaul DELAY(1000); 203176479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 203276479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 203376479Swpaul 2034101540Sambrisko if (!sc->nge_tbi) 2035101540Sambrisko mii_down(mii); 203676479Swpaul 203776479Swpaul sc->nge_link = 0; 203876479Swpaul 203976479Swpaul /* 204076479Swpaul * Free data in the RX lists. 204176479Swpaul */ 204276479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 204376479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 204476479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 204576479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 204676479Swpaul } 204776479Swpaul } 204876479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 204976479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 205076479Swpaul 205176479Swpaul /* 205276479Swpaul * Free the TX list buffers. 205376479Swpaul */ 205476479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 205576479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 205676479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 205776479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 205876479Swpaul } 205976479Swpaul } 206076479Swpaul 206176479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 206276479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 206376479Swpaul 2064148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 206576479Swpaul} 206676479Swpaul 206776479Swpaul/* 206876479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 206976479Swpaul * get confused by errant DMAs when rebooting. 207076479Swpaul */ 2071173839Syongaristatic int 2072192288Syongaringe_shutdown(device_t dev) 207376479Swpaul{ 207476479Swpaul struct nge_softc *sc; 207576479Swpaul 207676479Swpaul sc = device_get_softc(dev); 207776479Swpaul 2078135250Swpaul NGE_LOCK(sc); 207976479Swpaul nge_reset(sc); 208076479Swpaul nge_stop(sc); 2081135250Swpaul NGE_UNLOCK(sc); 208276479Swpaul 2083173839Syongari return (0); 208476479Swpaul} 2085