if_nge.c revision 192290
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 192290 2009-05-18 06:09:10Z 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 *); 15499497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_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); 17799497Salfredstatic void nge_eeprom_getword(struct nge_softc *, int, u_int16_t *); 17899497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int); 17976479Swpaul 18099497Salfredstatic void nge_mii_sync(struct nge_softc *); 18199497Salfredstatic void nge_mii_send(struct nge_softc *, u_int32_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 return; 25576479Swpaul} 25676479Swpaul 25799497Salfredstatic void 258192288Syongaringe_eeprom_idle(struct nge_softc *sc) 25976479Swpaul{ 260192289Syongari int i; 26176479Swpaul 26276479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26376479Swpaul nge_delay(sc); 26476479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26576479Swpaul nge_delay(sc); 26676479Swpaul 26776479Swpaul for (i = 0; i < 25; i++) { 26876479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 26976479Swpaul nge_delay(sc); 27076479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 27176479Swpaul nge_delay(sc); 27276479Swpaul } 27376479Swpaul 27476479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27576479Swpaul nge_delay(sc); 27676479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 27776479Swpaul nge_delay(sc); 27876479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 27976479Swpaul 28076479Swpaul return; 28176479Swpaul} 28276479Swpaul 28376479Swpaul/* 28476479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28576479Swpaul */ 28699497Salfredstatic void 287192288Syongaringe_eeprom_putbyte(struct nge_softc *sc, int addr) 28876479Swpaul{ 289192289Syongari int d, i; 29076479Swpaul 29176479Swpaul d = addr | NGE_EECMD_READ; 29276479Swpaul 29376479Swpaul /* 29476479Swpaul * Feed in each bit and stobe the clock. 29576479Swpaul */ 29676479Swpaul for (i = 0x400; i; i >>= 1) { 29776479Swpaul if (d & i) { 29876479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 29976479Swpaul } else { 30076479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 30176479Swpaul } 30276479Swpaul nge_delay(sc); 30376479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30476479Swpaul nge_delay(sc); 30576479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 30676479Swpaul nge_delay(sc); 30776479Swpaul } 30876479Swpaul 30976479Swpaul return; 31076479Swpaul} 31176479Swpaul 31276479Swpaul/* 31376479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 31476479Swpaul */ 31599497Salfredstatic void 316192288Syongaringe_eeprom_getword(struct nge_softc *sc, int addr, u_int16_t *dest) 31776479Swpaul{ 318192289Syongari int i; 31976479Swpaul u_int16_t word = 0; 32076479Swpaul 32176479Swpaul /* Force EEPROM to idle state. */ 32276479Swpaul nge_eeprom_idle(sc); 32376479Swpaul 32476479Swpaul /* Enter EEPROM access mode. */ 32576479Swpaul nge_delay(sc); 32676479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 32776479Swpaul nge_delay(sc); 32876479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 32976479Swpaul nge_delay(sc); 33076479Swpaul 33176479Swpaul /* 33276479Swpaul * Send address of word we want to read. 33376479Swpaul */ 33476479Swpaul nge_eeprom_putbyte(sc, addr); 33576479Swpaul 33676479Swpaul /* 33776479Swpaul * Start reading bits from EEPROM. 33876479Swpaul */ 33976479Swpaul for (i = 0x8000; i; i >>= 1) { 34076479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 34176479Swpaul nge_delay(sc); 34276479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT) 34376479Swpaul word |= i; 34476479Swpaul nge_delay(sc); 34576479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 34676479Swpaul nge_delay(sc); 34776479Swpaul } 34876479Swpaul 34976479Swpaul /* Turn off EEPROM access mode. */ 35076479Swpaul nge_eeprom_idle(sc); 35176479Swpaul 35276479Swpaul *dest = word; 35376479Swpaul 35476479Swpaul return; 35576479Swpaul} 35676479Swpaul 35776479Swpaul/* 35876479Swpaul * Read a sequence of words from the EEPROM. 35976479Swpaul */ 36099497Salfredstatic void 361192288Syongaringe_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt, int swap) 36276479Swpaul{ 36376479Swpaul int i; 36476479Swpaul u_int16_t word = 0, *ptr; 36576479Swpaul 36676479Swpaul for (i = 0; i < cnt; i++) { 36776479Swpaul nge_eeprom_getword(sc, off + i, &word); 36876479Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 36976479Swpaul if (swap) 37076479Swpaul *ptr = ntohs(word); 37176479Swpaul else 37276479Swpaul *ptr = word; 37376479Swpaul } 37476479Swpaul 37576479Swpaul return; 37676479Swpaul} 37776479Swpaul 37876479Swpaul/* 37976479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 38076479Swpaul */ 38199497Salfredstatic void 382192288Syongaringe_mii_sync(struct nge_softc *sc) 38376479Swpaul{ 384192289Syongari int i; 38576479Swpaul 38676479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 38776479Swpaul 38876479Swpaul for (i = 0; i < 32; i++) { 38976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 39076479Swpaul DELAY(1); 39176479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 39276479Swpaul DELAY(1); 39376479Swpaul } 39476479Swpaul 39576479Swpaul return; 39676479Swpaul} 39776479Swpaul 39876479Swpaul/* 39976479Swpaul * Clock a series of bits through the MII. 40076479Swpaul */ 40199497Salfredstatic void 402192288Syongaringe_mii_send(struct nge_softc *sc, u_int32_t bits, int cnt) 40376479Swpaul{ 40476479Swpaul int i; 40576479Swpaul 40676479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40776479Swpaul 40876479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 40976479Swpaul if (bits & i) { 41076479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 41176479Swpaul } else { 41276479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 41376479Swpaul } 41476479Swpaul DELAY(1); 41576479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 41676479Swpaul DELAY(1); 41776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 41876479Swpaul } 41976479Swpaul} 42076479Swpaul 42176479Swpaul/* 42276479Swpaul * Read an PHY register through the MII. 42376479Swpaul */ 42499497Salfredstatic int 425192288Syongaringe_mii_readreg(struct nge_softc *sc, struct nge_mii_frame *frame) 42676479Swpaul{ 427135250Swpaul int i, ack; 42876479Swpaul 42976479Swpaul /* 43076479Swpaul * Set up frame for RX. 43176479Swpaul */ 43276479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 43376479Swpaul frame->mii_opcode = NGE_MII_READOP; 43476479Swpaul frame->mii_turnaround = 0; 43576479Swpaul frame->mii_data = 0; 436192290Syongari 43776479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 43876479Swpaul 43976479Swpaul /* 44076479Swpaul * Turn on data xmit. 44176479Swpaul */ 44276479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 44376479Swpaul 44476479Swpaul nge_mii_sync(sc); 44576479Swpaul 44676479Swpaul /* 44776479Swpaul * Send command/address info. 44876479Swpaul */ 44976479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 45076479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 45176479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 45276479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 45376479Swpaul 45476479Swpaul /* Idle bit */ 45576479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 45676479Swpaul DELAY(1); 45776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 45876479Swpaul DELAY(1); 45976479Swpaul 46076479Swpaul /* Turn off xmit. */ 46176479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 46276479Swpaul /* Check for ack */ 46376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 46476479Swpaul DELAY(1); 465109058Smbr ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 46676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 46776479Swpaul DELAY(1); 46876479Swpaul 46976479Swpaul /* 47076479Swpaul * Now try reading data bits. If the ack failed, we still 47176479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 47276479Swpaul */ 47376479Swpaul if (ack) { 47476479Swpaul for(i = 0; i < 16; i++) { 47576479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 47676479Swpaul DELAY(1); 47776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 47876479Swpaul DELAY(1); 47976479Swpaul } 48076479Swpaul goto fail; 48176479Swpaul } 48276479Swpaul 48376479Swpaul for (i = 0x8000; i; i >>= 1) { 48476479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 48576479Swpaul DELAY(1); 48676479Swpaul if (!ack) { 48776479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 48876479Swpaul frame->mii_data |= i; 48976479Swpaul DELAY(1); 49076479Swpaul } 49176479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 49276479Swpaul DELAY(1); 49376479Swpaul } 49476479Swpaul 49576479Swpaulfail: 49676479Swpaul 49776479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 49876479Swpaul DELAY(1); 49976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 50076479Swpaul DELAY(1); 50176479Swpaul 50276479Swpaul if (ack) 50376479Swpaul return(1); 50476479Swpaul return(0); 50576479Swpaul} 50676479Swpaul 50776479Swpaul/* 50876479Swpaul * Write to a PHY register through the MII. 50976479Swpaul */ 51099497Salfredstatic int 511192288Syongaringe_mii_writereg(struct nge_softc *sc, struct nge_mii_frame *frame) 51276479Swpaul{ 51376479Swpaul 51476479Swpaul /* 51576479Swpaul * Set up frame for TX. 51676479Swpaul */ 51776479Swpaul 51876479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 51976479Swpaul frame->mii_opcode = NGE_MII_WRITEOP; 52076479Swpaul frame->mii_turnaround = NGE_MII_TURNAROUND; 521192290Syongari 52276479Swpaul /* 52376479Swpaul * Turn on data output. 52476479Swpaul */ 52576479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 52676479Swpaul 52776479Swpaul nge_mii_sync(sc); 52876479Swpaul 52976479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 53076479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 53176479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 53276479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 53376479Swpaul nge_mii_send(sc, frame->mii_turnaround, 2); 53476479Swpaul nge_mii_send(sc, frame->mii_data, 16); 53576479Swpaul 53676479Swpaul /* Idle bit. */ 53776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 53876479Swpaul DELAY(1); 53976479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 54076479Swpaul DELAY(1); 54176479Swpaul 54276479Swpaul /* 54376479Swpaul * Turn off xmit. 54476479Swpaul */ 54576479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 54676479Swpaul 54776479Swpaul return(0); 54876479Swpaul} 54976479Swpaul 55099497Salfredstatic int 551192288Syongaringe_miibus_readreg(device_t dev, int phy, int reg) 55276479Swpaul{ 55376479Swpaul struct nge_softc *sc; 55476479Swpaul struct nge_mii_frame frame; 55576479Swpaul 55676479Swpaul sc = device_get_softc(dev); 55776479Swpaul 55876479Swpaul bzero((char *)&frame, sizeof(frame)); 55976479Swpaul 56076479Swpaul frame.mii_phyaddr = phy; 56176479Swpaul frame.mii_regaddr = reg; 56276479Swpaul nge_mii_readreg(sc, &frame); 56376479Swpaul 56476479Swpaul return(frame.mii_data); 56576479Swpaul} 56676479Swpaul 56799497Salfredstatic int 568192288Syongaringe_miibus_writereg(device_t dev, int phy, int reg, int data) 56976479Swpaul{ 57076479Swpaul struct nge_softc *sc; 57176479Swpaul struct nge_mii_frame frame; 57276479Swpaul 57376479Swpaul sc = device_get_softc(dev); 57476479Swpaul 57576479Swpaul bzero((char *)&frame, sizeof(frame)); 57676479Swpaul 57776479Swpaul frame.mii_phyaddr = phy; 57876479Swpaul frame.mii_regaddr = reg; 57976479Swpaul frame.mii_data = data; 58076479Swpaul nge_mii_writereg(sc, &frame); 58176479Swpaul 58276479Swpaul return(0); 58376479Swpaul} 58476479Swpaul 58599497Salfredstatic void 586192288Syongaringe_miibus_statchg(device_t dev) 58776479Swpaul{ 588192290Syongari int status; 58976479Swpaul struct nge_softc *sc; 59076479Swpaul struct mii_data *mii; 59176479Swpaul 59276479Swpaul sc = device_get_softc(dev); 593101540Sambrisko if (sc->nge_tbi) { 594101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 595101540Sambrisko == IFM_AUTO) { 596101540Sambrisko status = CSR_READ_4(sc, NGE_TBI_ANLPAR); 597101540Sambrisko if (status == 0 || status & NGE_TBIANAR_FDX) { 598101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 599101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 600101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 601101540Sambrisko } else { 602101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 603101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 604101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 605101540Sambrisko } 60676479Swpaul 607192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 608101540Sambrisko != IFM_FDX) { 609101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 610101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 611101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 612101540Sambrisko } else { 613101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 614101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 615101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 616101540Sambrisko } 61776479Swpaul } else { 618101540Sambrisko mii = device_get_softc(sc->nge_miibus); 61976479Swpaul 620101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 621101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 622101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 623101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 624101540Sambrisko } else { 625101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 626101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 627101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 628101540Sambrisko } 629101540Sambrisko 630101540Sambrisko /* If we have a 1000Mbps link, set the mode_1000 bit. */ 631101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 632101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 633101540Sambrisko NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 634101540Sambrisko } else { 635101540Sambrisko NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 636101540Sambrisko } 63779424Swpaul } 63876479Swpaul return; 63976479Swpaul} 64076479Swpaul 64199497Salfredstatic void 642192288Syongaringe_setmulti(struct nge_softc *sc) 64376479Swpaul{ 64476479Swpaul struct ifnet *ifp; 64576479Swpaul struct ifmultiaddr *ifma; 64676479Swpaul u_int32_t h = 0, i, filtsave; 64776479Swpaul int bit, index; 64876479Swpaul 649135250Swpaul NGE_LOCK_ASSERT(sc); 650147256Sbrooks ifp = sc->nge_ifp; 65176479Swpaul 65276479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 65376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 65476479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 65576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 65676479Swpaul return; 65776479Swpaul } 65876479Swpaul 65976479Swpaul /* 66076479Swpaul * We have to explicitly enable the multicast hash table 66176479Swpaul * on the NatSemi chip if we want to use it, which we do. 66276479Swpaul * We also have to tell it that we don't want to use the 66376479Swpaul * hash table for matching unicast addresses. 66476479Swpaul */ 66576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 66676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 66776479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 66876479Swpaul 66976479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 67076479Swpaul 67176479Swpaul /* first, zot all the existing hash bits */ 67276479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 67376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 67476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 67576479Swpaul } 67676479Swpaul 67776479Swpaul /* 67876479Swpaul * From the 11 bits returned by the crc routine, the top 7 67976479Swpaul * bits represent the 16-bit word in the mcast hash table 68076479Swpaul * that needs to be updated, and the lower 4 bits represent 68176479Swpaul * which bit within that byte needs to be set. 68276479Swpaul */ 683148654Srwatson IF_ADDR_LOCK(ifp); 68476479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 68576479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 68676479Swpaul continue; 687130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 688130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 21; 68976479Swpaul index = (h >> 4) & 0x7F; 69076479Swpaul bit = h & 0xF; 69176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 69276479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 69376479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 69476479Swpaul } 695148654Srwatson IF_ADDR_UNLOCK(ifp); 69676479Swpaul 69776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 69876479Swpaul 69976479Swpaul return; 70076479Swpaul} 70176479Swpaul 70299497Salfredstatic void 703192288Syongaringe_reset(struct nge_softc *sc) 70476479Swpaul{ 705192289Syongari int i; 70676479Swpaul 70776479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 70876479Swpaul 70976479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 71076479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 71176479Swpaul break; 71276479Swpaul } 71376479Swpaul 71476479Swpaul if (i == NGE_TIMEOUT) 715162321Sglebius device_printf(sc->nge_dev, "reset never completed\n"); 71676479Swpaul 71776479Swpaul /* Wait a little while for the chip to get its brains in order. */ 71876479Swpaul DELAY(1000); 71976479Swpaul 72076479Swpaul /* 72176479Swpaul * If this is a NetSemi chip, make sure to clear 72276479Swpaul * PME mode. 72376479Swpaul */ 72476479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 72576479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 72676479Swpaul 72776479Swpaul return; 72876479Swpaul} 72976479Swpaul 73076479Swpaul/* 731108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 73276479Swpaul * IDs against our list and return a device name if we find a match. 73376479Swpaul */ 73499497Salfredstatic int 735192288Syongaringe_probe(device_t dev) 73676479Swpaul{ 73776479Swpaul struct nge_type *t; 73876479Swpaul 73976479Swpaul t = nge_devs; 74076479Swpaul 74176479Swpaul while(t->nge_name != NULL) { 74276479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 74376479Swpaul (pci_get_device(dev) == t->nge_did)) { 74476479Swpaul device_set_desc(dev, t->nge_name); 745143158Simp return(BUS_PROBE_DEFAULT); 74676479Swpaul } 74776479Swpaul t++; 74876479Swpaul } 74976479Swpaul 75076479Swpaul return(ENXIO); 75176479Swpaul} 75276479Swpaul 75376479Swpaul/* 75476479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 75576479Swpaul * setup and ethernet/BPF attach. 75676479Swpaul */ 75799497Salfredstatic int 758192288Syongaringe_attach(device_t dev) 75976479Swpaul{ 76076479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 76176479Swpaul struct nge_softc *sc; 762151296Sjhb struct ifnet *ifp = NULL; 763151296Sjhb int error = 0, rid; 76476479Swpaul 76576479Swpaul sc = device_get_softc(dev); 766162321Sglebius sc->nge_dev = dev; 76776479Swpaul 768135250Swpaul NGE_LOCK_INIT(sc, device_get_nameunit(dev)); 769151296Sjhb callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0); 770151296Sjhb 77176479Swpaul /* 77276479Swpaul * Map control/status registers. 77376479Swpaul */ 77476479Swpaul pci_enable_busmaster(dev); 77576479Swpaul 77676479Swpaul rid = NGE_RID; 777127135Snjl sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE); 77876479Swpaul 77976479Swpaul if (sc->nge_res == NULL) { 780151296Sjhb device_printf(dev, "couldn't map ports/memory\n"); 78176479Swpaul error = ENXIO; 78276479Swpaul goto fail; 78376479Swpaul } 78476479Swpaul 78576479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 78676479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 78776479Swpaul 78876479Swpaul /* Allocate interrupt */ 78976479Swpaul rid = 0; 790127135Snjl sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 79176479Swpaul RF_SHAREABLE | RF_ACTIVE); 79276479Swpaul 79376479Swpaul if (sc->nge_irq == NULL) { 794151296Sjhb device_printf(dev, "couldn't map interrupt\n"); 79576479Swpaul error = ENXIO; 79676479Swpaul goto fail; 79776479Swpaul } 79876479Swpaul 79976479Swpaul /* Reset the adapter. */ 80076479Swpaul nge_reset(sc); 80176479Swpaul 80276479Swpaul /* 80376479Swpaul * Get station address from the EEPROM. 80476479Swpaul */ 80576479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 80676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 80776479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 80876479Swpaul 80976479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 810151296Sjhb M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0); 81176479Swpaul 81276479Swpaul if (sc->nge_ldata == NULL) { 813151296Sjhb device_printf(dev, "no memory for list buffers!\n"); 81476479Swpaul error = ENXIO; 81576479Swpaul goto fail; 81676479Swpaul } 81776479Swpaul 818147256Sbrooks ifp = sc->nge_ifp = if_alloc(IFT_ETHER); 819147256Sbrooks if (ifp == NULL) { 820151296Sjhb device_printf(dev, "can not if_alloc()\n"); 821147256Sbrooks error = ENOSPC; 822147256Sbrooks goto fail; 823147256Sbrooks } 82476479Swpaul ifp->if_softc = sc; 825121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 82676479Swpaul ifp->if_mtu = ETHERMTU; 827135250Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 82876479Swpaul ifp->if_ioctl = nge_ioctl; 82976479Swpaul ifp->if_start = nge_start; 83076479Swpaul ifp->if_watchdog = nge_watchdog; 83176479Swpaul ifp->if_init = nge_init; 83276479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 83376479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 834106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 835150789Sglebius ifp->if_capenable = ifp->if_capabilities; 836128132Sru#ifdef DEVICE_POLLING 837128132Sru ifp->if_capabilities |= IFCAP_POLLING; 838128132Sru#endif 83976479Swpaul 84076479Swpaul /* 84176479Swpaul * Do MII setup. 84276479Swpaul */ 843150185Sru /* XXX: leaked on error */ 84476479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 845101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 846101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 847101540Sambrisko sc->nge_tbi = 1; 848101540Sambrisko device_printf(dev, "Using TBI\n"); 849192290Syongari 850101540Sambrisko sc->nge_miibus = dev; 851101540Sambrisko 852192290Syongari ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 853101540Sambrisko nge_ifmedia_sts); 854101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 855101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 856101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 857101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 858101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 859101540Sambrisko#undef ADD 860151296Sjhb device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n"); 861192290Syongari 862192290Syongari ifmedia_set(&sc->nge_ifmedia, 863101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 864192290Syongari 865101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 866192290Syongari | NGE_GPIO_GP4_OUT 867192290Syongari | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 868101540Sambrisko | NGE_GPIO_GP3_OUTENB 869101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 870192290Syongari 871101540Sambrisko } else { 872151296Sjhb device_printf(dev, "MII without any PHY!\n"); 873101540Sambrisko error = ENXIO; 874101540Sambrisko goto fail; 875101540Sambrisko } 87676479Swpaul } 87776479Swpaul 87876479Swpaul /* 87976479Swpaul * Call MI attach routine. 88076479Swpaul */ 881106937Ssam ether_ifattach(ifp, eaddr); 88276479Swpaul 883135250Swpaul /* 884135250Swpaul * Hookup IRQ last. 885135250Swpaul */ 886135250Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE, 887166901Spiso NULL, nge_intr, sc, &sc->nge_intrhand); 888135250Swpaul if (error) { 889151296Sjhb device_printf(dev, "couldn't set up irq\n"); 890151296Sjhb goto fail; 891151296Sjhb } 892151296Sjhb 893151296Sjhb return (0); 894151296Sjhb 895151296Sjhbfail: 896151296Sjhb if (sc->nge_ldata) 897151296Sjhb contigfree(sc->nge_ldata, 898151296Sjhb sizeof(struct nge_list_data), M_DEVBUF); 899151296Sjhb if (ifp) 900150185Sru if_free(ifp); 901151296Sjhb if (sc->nge_irq) 902135250Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 903151296Sjhb if (sc->nge_res) 904135250Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 905151296Sjhb NGE_LOCK_DESTROY(sc); 90676479Swpaul return(error); 90776479Swpaul} 90876479Swpaul 90999497Salfredstatic int 910192288Syongaringe_detach(device_t dev) 91176479Swpaul{ 91276479Swpaul struct nge_softc *sc; 91376479Swpaul struct ifnet *ifp; 91476479Swpaul 91576479Swpaul sc = device_get_softc(dev); 916147256Sbrooks ifp = sc->nge_ifp; 91776479Swpaul 918150789Sglebius#ifdef DEVICE_POLLING 919150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 920150789Sglebius ether_poll_deregister(ifp); 921150789Sglebius#endif 922135250Swpaul NGE_LOCK(sc); 92376479Swpaul nge_reset(sc); 92476479Swpaul nge_stop(sc); 925135250Swpaul NGE_UNLOCK(sc); 926151296Sjhb callout_drain(&sc->nge_stat_ch); 927106937Ssam ether_ifdetach(ifp); 92876479Swpaul 92976479Swpaul bus_generic_detach(dev); 930101540Sambrisko if (!sc->nge_tbi) { 931101540Sambrisko device_delete_child(dev, sc->nge_miibus); 932101540Sambrisko } 93376479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 93476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 93576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 93676479Swpaul 93776479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 938150306Simp if_free(ifp); 93976479Swpaul 940135251Swpaul NGE_LOCK_DESTROY(sc); 941135251Swpaul 94276479Swpaul return(0); 94376479Swpaul} 94476479Swpaul 94576479Swpaul/* 94676479Swpaul * Initialize the transmit descriptors. 94776479Swpaul */ 94899497Salfredstatic int 949192288Syongaringe_list_tx_init(struct nge_softc *sc) 95076479Swpaul{ 95176479Swpaul struct nge_list_data *ld; 95276479Swpaul struct nge_ring_data *cd; 95376479Swpaul int i; 95476479Swpaul 95576479Swpaul cd = &sc->nge_cdata; 95676479Swpaul ld = sc->nge_ldata; 95776479Swpaul 95876479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 95976479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 96076479Swpaul ld->nge_tx_list[i].nge_nextdesc = 96176479Swpaul &ld->nge_tx_list[0]; 96276479Swpaul ld->nge_tx_list[i].nge_next = 96376479Swpaul vtophys(&ld->nge_tx_list[0]); 96476479Swpaul } else { 96576479Swpaul ld->nge_tx_list[i].nge_nextdesc = 96676479Swpaul &ld->nge_tx_list[i + 1]; 96776479Swpaul ld->nge_tx_list[i].nge_next = 96876479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 96976479Swpaul } 97076479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 97176479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 97276479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 97376479Swpaul } 97476479Swpaul 97576479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 97676479Swpaul 97776479Swpaul return(0); 97876479Swpaul} 97976479Swpaul 98076479Swpaul 98176479Swpaul/* 98276479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 98376479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 98476479Swpaul * points back to the first. 98576479Swpaul */ 98699497Salfredstatic int 987192288Syongaringe_list_rx_init(struct nge_softc *sc) 98876479Swpaul{ 98976479Swpaul struct nge_list_data *ld; 99076479Swpaul struct nge_ring_data *cd; 99176479Swpaul int i; 99276479Swpaul 99376479Swpaul ld = sc->nge_ldata; 99476479Swpaul cd = &sc->nge_cdata; 99576479Swpaul 99676479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 99776479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 99876479Swpaul return(ENOBUFS); 99976479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 100076479Swpaul ld->nge_rx_list[i].nge_nextdesc = 100176479Swpaul &ld->nge_rx_list[0]; 100276479Swpaul ld->nge_rx_list[i].nge_next = 100376479Swpaul vtophys(&ld->nge_rx_list[0]); 100476479Swpaul } else { 100576479Swpaul ld->nge_rx_list[i].nge_nextdesc = 100676479Swpaul &ld->nge_rx_list[i + 1]; 100776479Swpaul ld->nge_rx_list[i].nge_next = 100876479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 100976479Swpaul } 101076479Swpaul } 101176479Swpaul 101276479Swpaul cd->nge_rx_prod = 0; 1013135250Swpaul sc->nge_head = sc->nge_tail = NULL; 101476479Swpaul 101576479Swpaul return(0); 101676479Swpaul} 101776479Swpaul 101876479Swpaul/* 101976479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 102076479Swpaul */ 102199497Salfredstatic int 1022192288Syongaringe_newbuf(struct nge_softc *sc, struct nge_desc *c, struct mbuf *m) 102376479Swpaul{ 102476479Swpaul 102576479Swpaul if (m == NULL) { 1026144241Ssam m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1027144241Ssam if (m == NULL) 1028135250Swpaul return (ENOBUFS); 1029135250Swpaul } else 1030135250Swpaul m->m_data = m->m_ext.ext_buf; 103176479Swpaul 1032135250Swpaul m->m_len = m->m_pkthdr.len = MCLBYTES; 103376479Swpaul 1034144241Ssam m_adj(m, sizeof(u_int64_t)); 103576479Swpaul 1036144241Ssam c->nge_mbuf = m; 1037144241Ssam c->nge_ptr = vtophys(mtod(m, caddr_t)); 1038144241Ssam c->nge_ctl = m->m_len; 103976479Swpaul c->nge_extsts = 0; 104076479Swpaul 104176479Swpaul return(0); 104276479Swpaul} 104376479Swpaul 1044135250Swpaul#ifdef NGE_FIXUP_RX 1045135250Swpaulstatic __inline void 1046192288Syongaringe_fixup_rx(struct mbuf *m) 1047192290Syongari{ 1048135250Swpaul int i; 1049135250Swpaul uint16_t *src, *dst; 1050192290Syongari 1051135250Swpaul src = mtod(m, uint16_t *); 1052135250Swpaul dst = src - 1; 1053192290Syongari 1054135250Swpaul for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1055135250Swpaul *dst++ = *src++; 1056192290Syongari 1057135250Swpaul m->m_data -= ETHER_ALIGN; 1058192290Syongari 105976479Swpaul return; 1060192290Syongari} 106176479Swpaul#endif 106276479Swpaul 106376479Swpaul/* 106476479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 106576479Swpaul * the higher level protocols. 106676479Swpaul */ 106799497Salfredstatic void 1068192288Syongaringe_rxeof(struct nge_softc *sc) 106976479Swpaul{ 107076479Swpaul struct mbuf *m; 107176479Swpaul struct ifnet *ifp; 107276479Swpaul struct nge_desc *cur_rx; 107376479Swpaul int i, total_len = 0; 107476479Swpaul u_int32_t rxstat; 107576479Swpaul 1076135250Swpaul NGE_LOCK_ASSERT(sc); 1077147256Sbrooks ifp = sc->nge_ifp; 107876479Swpaul i = sc->nge_cdata.nge_rx_prod; 107976479Swpaul 108076479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 108176479Swpaul u_int32_t extsts; 108276479Swpaul 1083106507Ssimokawa#ifdef DEVICE_POLLING 1084150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1085106507Ssimokawa if (sc->rxcycles <= 0) 1086106507Ssimokawa break; 1087106507Ssimokawa sc->rxcycles--; 1088106507Ssimokawa } 1089150789Sglebius#endif 1090106507Ssimokawa 109176479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 109276479Swpaul rxstat = cur_rx->nge_rxstat; 109376479Swpaul extsts = cur_rx->nge_extsts; 109476479Swpaul m = cur_rx->nge_mbuf; 109576479Swpaul cur_rx->nge_mbuf = NULL; 109676479Swpaul total_len = NGE_RXBYTES(cur_rx); 109776479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 1098135250Swpaul 1099135250Swpaul if (rxstat & NGE_CMDSTS_MORE) { 1100135250Swpaul m->m_len = total_len; 1101135250Swpaul if (sc->nge_head == NULL) { 1102135250Swpaul m->m_pkthdr.len = total_len; 1103135250Swpaul sc->nge_head = sc->nge_tail = m; 1104135250Swpaul } else { 1105135250Swpaul m->m_flags &= ~M_PKTHDR; 1106135250Swpaul sc->nge_head->m_pkthdr.len += total_len; 1107135250Swpaul sc->nge_tail->m_next = m; 1108135250Swpaul sc->nge_tail = m; 1109135250Swpaul } 1110135250Swpaul nge_newbuf(sc, cur_rx, NULL); 1111135250Swpaul continue; 1112135250Swpaul } 1113135250Swpaul 111476479Swpaul /* 111576479Swpaul * If an error occurs, update stats, clear the 111676479Swpaul * status word and leave the mbuf cluster in place: 111776479Swpaul * it should simply get re-used next time this descriptor 111876479Swpaul * comes up in the ring. 111976479Swpaul */ 112076479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 112176479Swpaul ifp->if_ierrors++; 1122135250Swpaul if (sc->nge_head != NULL) { 1123135250Swpaul m_freem(sc->nge_head); 1124135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1125135250Swpaul } 112676479Swpaul nge_newbuf(sc, cur_rx, m); 112776479Swpaul continue; 112876479Swpaul } 112976479Swpaul 1130135250Swpaul /* Try conjure up a replacement mbuf. */ 1131135250Swpaul 1132135250Swpaul if (nge_newbuf(sc, cur_rx, NULL)) { 1133135250Swpaul ifp->if_ierrors++; 1134135250Swpaul if (sc->nge_head != NULL) { 1135135250Swpaul m_freem(sc->nge_head); 1136135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1137135250Swpaul } 1138135250Swpaul nge_newbuf(sc, cur_rx, m); 1139135250Swpaul continue; 1140135250Swpaul } 1141135250Swpaul 1142135250Swpaul if (sc->nge_head != NULL) { 1143135250Swpaul m->m_len = total_len; 1144135250Swpaul m->m_flags &= ~M_PKTHDR; 1145135250Swpaul sc->nge_tail->m_next = m; 1146135250Swpaul m = sc->nge_head; 1147135250Swpaul m->m_pkthdr.len += total_len; 1148135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1149135250Swpaul } else 1150135250Swpaul m->m_pkthdr.len = m->m_len = total_len; 1151135250Swpaul 115276479Swpaul /* 115376479Swpaul * Ok. NatSemi really screwed up here. This is the 115476479Swpaul * only gigE chip I know of with alignment constraints 115576479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 115676479Swpaul */ 115779562Swpaul /* 115879562Swpaul * By popular demand, ignore the alignment problems 115979562Swpaul * on the Intel x86 platform. The performance hit 116079562Swpaul * incurred due to unaligned accesses is much smaller 116179562Swpaul * than the hit produced by forcing buffer copies all 116279562Swpaul * the time, especially with jumbo frames. We still 116379562Swpaul * need to fix up the alignment everywhere else though. 116479562Swpaul */ 1165135250Swpaul#ifdef NGE_FIXUP_RX 1166135250Swpaul nge_fixup_rx(m); 116779562Swpaul#endif 116876479Swpaul 116976479Swpaul ifp->if_ipackets++; 1170135250Swpaul m->m_pkthdr.rcvif = ifp; 117176479Swpaul 117276479Swpaul /* Do IP checksum checking. */ 117378323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 117478323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 117578323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 117678323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 117778323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 117878323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 117978323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 118078323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 118178323Swpaul m->m_pkthdr.csum_flags |= 118278323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 118378323Swpaul m->m_pkthdr.csum_data = 0xffff; 118478323Swpaul } 118576479Swpaul 118676479Swpaul /* 118776479Swpaul * If we received a packet with a vlan tag, pass it 118876479Swpaul * to vlan_input() instead of ether_input(). 118976479Swpaul */ 119076479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1191162375Sandre m->m_pkthdr.ether_vtag = 1192162375Sandre ntohs(extsts & NGE_RXEXTSTS_VTCI); 1193162375Sandre m->m_flags |= M_VLANTAG; 1194106937Ssam } 1195135250Swpaul NGE_UNLOCK(sc); 1196106937Ssam (*ifp->if_input)(ifp, m); 1197135250Swpaul NGE_LOCK(sc); 119876479Swpaul } 119976479Swpaul 120076479Swpaul sc->nge_cdata.nge_rx_prod = i; 120176479Swpaul 120276479Swpaul return; 120376479Swpaul} 120476479Swpaul 120576479Swpaul/* 120676479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 120776479Swpaul * the list buffers. 120876479Swpaul */ 120976479Swpaul 121099497Salfredstatic void 1211192288Syongaringe_txeof(struct nge_softc *sc) 121276479Swpaul{ 1213128130Sru struct nge_desc *cur_tx; 121476479Swpaul struct ifnet *ifp; 121576479Swpaul u_int32_t idx; 121676479Swpaul 1217135250Swpaul NGE_LOCK_ASSERT(sc); 1218147256Sbrooks ifp = sc->nge_ifp; 121976479Swpaul 122076479Swpaul /* 122176479Swpaul * Go through our tx list and free mbufs for those 122276479Swpaul * frames that have been transmitted. 122376479Swpaul */ 122476479Swpaul idx = sc->nge_cdata.nge_tx_cons; 122576479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 122676479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 122776479Swpaul 122876479Swpaul if (NGE_OWNDESC(cur_tx)) 122976479Swpaul break; 123076479Swpaul 123176479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 123276479Swpaul sc->nge_cdata.nge_tx_cnt--; 123376479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 123476479Swpaul continue; 123576479Swpaul } 123676479Swpaul 123776479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 123876479Swpaul ifp->if_oerrors++; 123976479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 124076479Swpaul ifp->if_collisions++; 124176479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 124276479Swpaul ifp->if_collisions++; 124376479Swpaul } 124476479Swpaul 124576479Swpaul ifp->if_collisions += 124676479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 124776479Swpaul 124876479Swpaul ifp->if_opackets++; 124976479Swpaul if (cur_tx->nge_mbuf != NULL) { 125076479Swpaul m_freem(cur_tx->nge_mbuf); 125176479Swpaul cur_tx->nge_mbuf = NULL; 1252148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 125376479Swpaul } 125476479Swpaul 125576479Swpaul sc->nge_cdata.nge_tx_cnt--; 125676479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 125776479Swpaul } 125876479Swpaul 125976479Swpaul sc->nge_cdata.nge_tx_cons = idx; 126076479Swpaul 1261128130Sru if (idx == sc->nge_cdata.nge_tx_prod) 1262128130Sru ifp->if_timer = 0; 126376479Swpaul 126476479Swpaul return; 126576479Swpaul} 126676479Swpaul 126799497Salfredstatic void 1268192288Syongaringe_tick(void *xsc) 126976479Swpaul{ 127076479Swpaul struct nge_softc *sc; 127176479Swpaul struct mii_data *mii; 127276479Swpaul struct ifnet *ifp; 127376479Swpaul 1274151296Sjhb sc = xsc; 1275135250Swpaul NGE_LOCK_ASSERT(sc); 1276147256Sbrooks ifp = sc->nge_ifp; 127776479Swpaul 1278101540Sambrisko if (sc->nge_tbi) { 1279101540Sambrisko if (!sc->nge_link) { 1280192290Syongari if (CSR_READ_4(sc, NGE_TBI_BMSR) 1281101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 1282137402Sphk if (bootverbose) 1283192290Syongari device_printf(sc->nge_dev, 1284151296Sjhb "gigabit link up\n"); 1285101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1286101540Sambrisko sc->nge_link++; 1287101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1288135250Swpaul nge_start_locked(ifp); 1289101540Sambrisko } 129096028Sphk } 1291101540Sambrisko } else { 1292101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1293101540Sambrisko mii_tick(mii); 1294101540Sambrisko 1295101540Sambrisko if (!sc->nge_link) { 1296101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1297101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1298101540Sambrisko sc->nge_link++; 1299192290Syongari if (IFM_SUBTYPE(mii->mii_media_active) 1300137402Sphk == IFM_1000_T && bootverbose) 1301192290Syongari device_printf(sc->nge_dev, 1302151296Sjhb "gigabit link up\n"); 1303101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1304135250Swpaul nge_start_locked(ifp); 1305101540Sambrisko } 1306101540Sambrisko } 130776479Swpaul } 1308135250Swpaul callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc); 130976479Swpaul 131076479Swpaul return; 131176479Swpaul} 131276479Swpaul 1313106507Ssimokawa#ifdef DEVICE_POLLING 1314106507Ssimokawastatic poll_handler_t nge_poll; 1315106507Ssimokawa 131699497Salfredstatic void 1317106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1318106507Ssimokawa{ 1319106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1320106507Ssimokawa 1321135250Swpaul NGE_LOCK(sc); 1322150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1323135250Swpaul NGE_UNLOCK(sc); 1324106507Ssimokawa return; 1325106507Ssimokawa } 1326106507Ssimokawa 1327106507Ssimokawa /* 1328106507Ssimokawa * On the nge, reading the status register also clears it. 1329106507Ssimokawa * So before returning to intr mode we must make sure that all 1330106507Ssimokawa * possible pending sources of interrupts have been served. 1331106507Ssimokawa * In practice this means run to completion the *eof routines, 1332106507Ssimokawa * and then call the interrupt routine 1333106507Ssimokawa */ 1334106507Ssimokawa sc->rxcycles = count; 1335106507Ssimokawa nge_rxeof(sc); 1336106507Ssimokawa nge_txeof(sc); 1337106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1338135250Swpaul nge_start_locked(ifp); 1339106507Ssimokawa 1340106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1341106507Ssimokawa u_int32_t status; 1342106507Ssimokawa 1343106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1344106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1345106507Ssimokawa 1346106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1347106507Ssimokawa nge_rxeof(sc); 1348106507Ssimokawa 1349106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1350106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1351106507Ssimokawa 1352106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1353106507Ssimokawa nge_reset(sc); 1354135250Swpaul nge_init_locked(sc); 1355106507Ssimokawa } 1356106507Ssimokawa } 1357135250Swpaul NGE_UNLOCK(sc); 1358106507Ssimokawa} 1359106507Ssimokawa#endif /* DEVICE_POLLING */ 1360106507Ssimokawa 1361106507Ssimokawastatic void 1362192288Syongaringe_intr(void *arg) 136376479Swpaul{ 136476479Swpaul struct nge_softc *sc; 136576479Swpaul struct ifnet *ifp; 136676479Swpaul u_int32_t status; 136776479Swpaul 136876479Swpaul sc = arg; 1369147256Sbrooks ifp = sc->nge_ifp; 137076479Swpaul 1371135250Swpaul NGE_LOCK(sc); 1372106507Ssimokawa#ifdef DEVICE_POLLING 1373150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1374135250Swpaul NGE_UNLOCK(sc); 1375106507Ssimokawa return; 1376135250Swpaul } 1377150789Sglebius#endif 1378106507Ssimokawa 137976479Swpaul /* Supress unwanted interrupts */ 138076479Swpaul if (!(ifp->if_flags & IFF_UP)) { 138176479Swpaul nge_stop(sc); 1382135250Swpaul NGE_UNLOCK(sc); 138376479Swpaul return; 138476479Swpaul } 138576479Swpaul 138676479Swpaul /* Disable interrupts. */ 138776479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 138876479Swpaul 1389101540Sambrisko /* Data LED on for TBI mode */ 1390101540Sambrisko if(sc->nge_tbi) 1391101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1392101540Sambrisko | NGE_GPIO_GP3_OUT); 1393101540Sambrisko 139476479Swpaul for (;;) { 139576479Swpaul /* Reading the ISR register clears all interrupts. */ 139676479Swpaul status = CSR_READ_4(sc, NGE_ISR); 139776479Swpaul 139876479Swpaul if ((status & NGE_INTRS) == 0) 139976479Swpaul break; 140076479Swpaul 140176479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 140276479Swpaul (status & NGE_ISR_TX_ERR) || 140376479Swpaul (status & NGE_ISR_TX_OK) || 140476479Swpaul (status & NGE_ISR_TX_IDLE)) 140576479Swpaul nge_txeof(sc); 140676479Swpaul 140776479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 140879798Swpaul (status & NGE_ISR_RX_ERR) || 140983678Swpaul (status & NGE_ISR_RX_OFLOW) || 141094612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 141194612Sphk (status & NGE_ISR_RX_IDLE) || 141276479Swpaul (status & NGE_ISR_RX_OK)) 141376479Swpaul nge_rxeof(sc); 141494612Sphk 141594612Sphk if ((status & NGE_ISR_RX_IDLE)) 141694612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 141794612Sphk 141876479Swpaul if (status & NGE_ISR_SYSERR) { 141976479Swpaul nge_reset(sc); 1420148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1421135250Swpaul nge_init_locked(sc); 142276479Swpaul } 142376479Swpaul 142496028Sphk#if 0 1425192290Syongari /* 142696028Sphk * XXX: nge_tick() is not ready to be called this way 142796028Sphk * it screws up the aneg timeout because mii_tick() is 142896028Sphk * only to be called once per second. 142996028Sphk */ 143076479Swpaul if (status & NGE_IMR_PHY_INTR) { 143176479Swpaul sc->nge_link = 0; 1432151296Sjhb nge_tick(sc); 143376479Swpaul } 143496028Sphk#endif 143576479Swpaul } 143676479Swpaul 143776479Swpaul /* Re-enable interrupts. */ 143876479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 143976479Swpaul 144076479Swpaul if (ifp->if_snd.ifq_head != NULL) 1441135250Swpaul nge_start_locked(ifp); 144276479Swpaul 1443101540Sambrisko /* Data LED off for TBI mode */ 1444101540Sambrisko 1445101540Sambrisko if(sc->nge_tbi) 1446101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1447101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1448101540Sambrisko 1449135250Swpaul NGE_UNLOCK(sc); 1450135250Swpaul 145176479Swpaul return; 145276479Swpaul} 145376479Swpaul 145476479Swpaul/* 145576479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 145676479Swpaul * pointers to the fragment pointers. 145776479Swpaul */ 145899497Salfredstatic int 1459192288Syongaringe_encap(struct nge_softc *sc, struct mbuf *m_head, u_int32_t *txidx) 146076479Swpaul{ 146176479Swpaul struct nge_desc *f = NULL; 146276479Swpaul struct mbuf *m; 146376479Swpaul int frag, cur, cnt = 0; 146476479Swpaul 146576479Swpaul /* 146676479Swpaul * Start packing the mbufs in this chain into 146776479Swpaul * the fragment pointers. Stop when we run out 146876479Swpaul * of fragments or hit the end of the mbuf chain. 146976479Swpaul */ 147076479Swpaul m = m_head; 147176479Swpaul cur = frag = *txidx; 147276479Swpaul 147376479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 147476479Swpaul if (m->m_len != 0) { 147576479Swpaul if ((NGE_TX_LIST_CNT - 147676479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 147776479Swpaul return(ENOBUFS); 147876479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 147976479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 148076479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 148176479Swpaul if (cnt != 0) 148276479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 148376479Swpaul cur = frag; 148476479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 148576479Swpaul cnt++; 148676479Swpaul } 148776479Swpaul } 148876479Swpaul 148976479Swpaul if (m != NULL) 149076479Swpaul return(ENOBUFS); 149176479Swpaul 149278286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 149376479Swpaul if (m_head->m_pkthdr.csum_flags) { 149476479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 149578286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 149676479Swpaul NGE_TXEXTSTS_IPCSUM; 149776479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 149878286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 149976479Swpaul NGE_TXEXTSTS_TCPCSUM; 150076479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 150178286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 150276479Swpaul NGE_TXEXTSTS_UDPCSUM; 150376479Swpaul } 150476479Swpaul 1505162375Sandre if (m_head->m_flags & M_VLANTAG) { 150676479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1507162375Sandre (NGE_TXEXTSTS_VLANPKT|htons(m_head->m_pkthdr.ether_vtag)); 150876479Swpaul } 150976479Swpaul 151076479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 151176479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 151276479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 151376479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 151476479Swpaul *txidx = frag; 151576479Swpaul 151676479Swpaul return(0); 151776479Swpaul} 151876479Swpaul 151976479Swpaul/* 152076479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 152176479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 152276479Swpaul * copy of the pointers since the transmit list fragment pointers are 152376479Swpaul * physical addresses. 152476479Swpaul */ 152576479Swpaul 152699497Salfredstatic void 1527192288Syongaringe_start(struct ifnet *ifp) 152876479Swpaul{ 152976479Swpaul struct nge_softc *sc; 1530135250Swpaul 1531135250Swpaul sc = ifp->if_softc; 1532135250Swpaul NGE_LOCK(sc); 1533135250Swpaul nge_start_locked(ifp); 1534135250Swpaul NGE_UNLOCK(sc); 1535135250Swpaul} 1536135250Swpaul 1537135250Swpaulstatic void 1538192288Syongaringe_start_locked(struct ifnet *ifp) 1539135250Swpaul{ 1540135250Swpaul struct nge_softc *sc; 154176479Swpaul struct mbuf *m_head = NULL; 154276479Swpaul u_int32_t idx; 154376479Swpaul 154476479Swpaul sc = ifp->if_softc; 154576479Swpaul 154676479Swpaul if (!sc->nge_link) 154776479Swpaul return; 154876479Swpaul 154976479Swpaul idx = sc->nge_cdata.nge_tx_prod; 155076479Swpaul 1551148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 155276479Swpaul return; 155376479Swpaul 155476479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 155576479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 155676479Swpaul if (m_head == NULL) 155776479Swpaul break; 155876479Swpaul 155976479Swpaul if (nge_encap(sc, m_head, &idx)) { 156076479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1561148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 156276479Swpaul break; 156376479Swpaul } 156476479Swpaul 156576479Swpaul /* 156676479Swpaul * If there's a BPF listener, bounce a copy of this frame 156776479Swpaul * to him. 156876479Swpaul */ 1569167190Scsjp ETHER_BPF_MTAP(ifp, m_head); 157076479Swpaul 157176479Swpaul } 157276479Swpaul 157376479Swpaul /* Transmit */ 157476479Swpaul sc->nge_cdata.nge_tx_prod = idx; 157576479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 157676479Swpaul 157776479Swpaul /* 157876479Swpaul * Set a timeout in case the chip goes out to lunch. 157976479Swpaul */ 158076479Swpaul ifp->if_timer = 5; 158176479Swpaul 158276479Swpaul return; 158376479Swpaul} 158476479Swpaul 158599497Salfredstatic void 1586192288Syongaringe_init(void *xsc) 158776479Swpaul{ 158876479Swpaul struct nge_softc *sc = xsc; 1589135250Swpaul 1590135250Swpaul NGE_LOCK(sc); 1591135250Swpaul nge_init_locked(sc); 1592135250Swpaul NGE_UNLOCK(sc); 1593135250Swpaul} 1594135250Swpaul 1595135250Swpaulstatic void 1596192288Syongaringe_init_locked(struct nge_softc *sc) 1597135250Swpaul{ 1598147256Sbrooks struct ifnet *ifp = sc->nge_ifp; 159976479Swpaul struct mii_data *mii; 160076479Swpaul 1601135250Swpaul NGE_LOCK_ASSERT(sc); 1602135250Swpaul 1603148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 160476479Swpaul return; 160576479Swpaul 160676479Swpaul /* 160776479Swpaul * Cancel pending I/O and free all RX/TX buffers. 160876479Swpaul */ 160976479Swpaul nge_stop(sc); 161076479Swpaul 1611101540Sambrisko if (sc->nge_tbi) { 1612101540Sambrisko mii = NULL; 1613101540Sambrisko } else { 1614101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1615101540Sambrisko } 161676479Swpaul 161776479Swpaul /* Set MAC address */ 161876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 161976479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1620152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[0]); 162176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 162276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1623152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[1]); 162476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 162576479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1626152315Sru ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[2]); 162776479Swpaul 162876479Swpaul /* Init circular RX list. */ 162976479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 1630162321Sglebius device_printf(sc->nge_dev, "initialization failed: no " 1631151296Sjhb "memory for rx buffers\n"); 163276479Swpaul nge_stop(sc); 163376479Swpaul return; 163476479Swpaul } 163576479Swpaul 163676479Swpaul /* 163776479Swpaul * Init tx descriptors. 163876479Swpaul */ 163976479Swpaul nge_list_tx_init(sc); 164076479Swpaul 164176479Swpaul /* 164276479Swpaul * For the NatSemi chip, we have to explicitly enable the 164376479Swpaul * reception of ARP frames, as well as turn on the 'perfect 164476479Swpaul * match' filter where we store the station address, otherwise 164576479Swpaul * we won't receive unicasts meant for this host. 164676479Swpaul */ 164776479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 164876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 164976479Swpaul 165076479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 165176479Swpaul if (ifp->if_flags & IFF_PROMISC) { 165276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 165376479Swpaul } else { 165476479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 165576479Swpaul } 165676479Swpaul 165776479Swpaul /* 165876479Swpaul * Set the capture broadcast bit to capture broadcast frames. 165976479Swpaul */ 166076479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 166176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 166276479Swpaul } else { 166376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 166476479Swpaul } 166576479Swpaul 166676479Swpaul /* 166776479Swpaul * Load the multicast filter. 166876479Swpaul */ 166976479Swpaul nge_setmulti(sc); 167076479Swpaul 167176479Swpaul /* Turn the receive filter on */ 167276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 167376479Swpaul 167476479Swpaul /* 167576479Swpaul * Load the address of the RX and TX lists. 167676479Swpaul */ 167776479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 167876479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 167976479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 168076479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 168176479Swpaul 168276479Swpaul /* Set RX configuration */ 168376479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 168476479Swpaul /* 168576479Swpaul * Enable hardware checksum validation for all IPv4 168676479Swpaul * packets, do not reject packets with bad checksums. 168776479Swpaul */ 168878323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 168976479Swpaul 169076479Swpaul /* 169183115Sbrooks * Tell the chip to detect and strip VLAN tag info from 169283115Sbrooks * received frames. The tag will be provided in the extsts 169383115Sbrooks * field in the RX descriptors. 169476479Swpaul */ 169576479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 169676479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 169776479Swpaul 169876479Swpaul /* Set TX configuration */ 169976479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 170076479Swpaul 170176479Swpaul /* 170276479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 170376479Swpaul */ 170478323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 170576479Swpaul 170676479Swpaul /* 170783115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 170883115Sbrooks * dictated by the code in the frame encapsulation routine. 170976479Swpaul */ 171076479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 171176479Swpaul 171276479Swpaul /* Set full/half duplex mode. */ 1713101540Sambrisko if (sc->nge_tbi) { 1714192290Syongari if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1715101540Sambrisko == IFM_FDX) { 1716101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1717101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1718101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1719101540Sambrisko } else { 1720101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1721101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1722101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1723101540Sambrisko } 172476479Swpaul } else { 1725101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1726101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1727101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1728101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1729101540Sambrisko } else { 1730101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1731101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1732101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1733101540Sambrisko } 173476479Swpaul } 173576479Swpaul 1736151296Sjhb nge_tick(sc); 173796028Sphk 173876479Swpaul /* 173976479Swpaul * Enable the delivery of PHY interrupts based on 174077842Swpaul * link/speed/duplex status changes. Also enable the 174177842Swpaul * extsts field in the DMA descriptors (needed for 174277842Swpaul * TCP/IP checksum offload on transmit). 174376479Swpaul */ 174479424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 174577842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 174676479Swpaul 174776479Swpaul /* 174879562Swpaul * Configure interrupt holdoff (moderation). We can 174979562Swpaul * have the chip delay interrupt delivery for a certain 175079562Swpaul * period. Units are in 100us, and the max setting 175179562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 175279562Swpaul */ 175379562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 175479562Swpaul 175579562Swpaul /* 175676479Swpaul * Enable interrupts. 175776479Swpaul */ 175876479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1759106507Ssimokawa#ifdef DEVICE_POLLING 1760106507Ssimokawa /* 1761106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1762106507Ssimokawa * they are off otherwise. 1763106507Ssimokawa */ 1764150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1765106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1766106507Ssimokawa else 1767150789Sglebius#endif 176876479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 176976479Swpaul 177076479Swpaul /* Enable receiver and transmitter. */ 177176479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 177276479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 177376479Swpaul 1774151296Sjhb nge_ifmedia_upd_locked(ifp); 177576479Swpaul 1776148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1777148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 177876479Swpaul 177976479Swpaul return; 178076479Swpaul} 178176479Swpaul 178276479Swpaul/* 178376479Swpaul * Set media options. 178476479Swpaul */ 178599497Salfredstatic int 1786192288Syongaringe_ifmedia_upd(struct ifnet *ifp) 178776479Swpaul{ 178876479Swpaul struct nge_softc *sc; 1789151296Sjhb 1790151296Sjhb sc = ifp->if_softc; 1791151296Sjhb NGE_LOCK(sc); 1792151296Sjhb nge_ifmedia_upd_locked(ifp); 1793151296Sjhb NGE_UNLOCK(sc); 1794151296Sjhb return (0); 1795151296Sjhb} 1796151296Sjhb 1797151296Sjhbstatic void 1798192288Syongaringe_ifmedia_upd_locked(struct ifnet *ifp) 1799151296Sjhb{ 1800151296Sjhb struct nge_softc *sc; 180176479Swpaul struct mii_data *mii; 180276479Swpaul 180376479Swpaul sc = ifp->if_softc; 1804151296Sjhb NGE_LOCK_ASSERT(sc); 180576479Swpaul 1806101540Sambrisko if (sc->nge_tbi) { 1807192290Syongari if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1808101540Sambrisko == IFM_AUTO) { 1809192290Syongari CSR_WRITE_4(sc, NGE_TBI_ANAR, 1810101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 1811101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 1812101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 1813101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 1814101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 1815101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 1816192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 1817101540Sambrisko & IFM_GMASK) == IFM_FDX) { 1818101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1819101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1820101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1821101540Sambrisko 1822101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1823101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1824101540Sambrisko } else { 1825101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1826101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1827101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1828101540Sambrisko 1829101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1830101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1831101540Sambrisko } 1832192290Syongari 1833101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1834101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1835101540Sambrisko } else { 1836101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1837101540Sambrisko sc->nge_link = 0; 1838101540Sambrisko if (mii->mii_instance) { 1839101540Sambrisko struct mii_softc *miisc; 1840151296Sjhb 1841151296Sjhb LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1842101540Sambrisko mii_phy_reset(miisc); 1843101540Sambrisko } 1844101540Sambrisko mii_mediachg(mii); 184576479Swpaul } 184676479Swpaul} 184776479Swpaul 184876479Swpaul/* 184976479Swpaul * Report current media status. 185076479Swpaul */ 185199497Salfredstatic void 1852192288Syongaringe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 185376479Swpaul{ 185476479Swpaul struct nge_softc *sc; 185576479Swpaul struct mii_data *mii; 185676479Swpaul 185776479Swpaul sc = ifp->if_softc; 185876479Swpaul 1859151296Sjhb NGE_LOCK(sc); 1860101540Sambrisko if (sc->nge_tbi) { 1861101540Sambrisko ifmr->ifm_status = IFM_AVALID; 1862101540Sambrisko ifmr->ifm_active = IFM_ETHER; 186376479Swpaul 1864101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1865101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 1866192290Syongari } 1867101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 1868101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 1869101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1870101540Sambrisko ifmr->ifm_active |= IFM_NONE; 1871101540Sambrisko ifmr->ifm_status = 0; 1872151296Sjhb NGE_UNLOCK(sc); 1873101540Sambrisko return; 1874192290Syongari } 1875101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 1876101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1877101540Sambrisko == IFM_AUTO) { 1878101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 1879101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1880101540Sambrisko & NGE_TBIANAR_FDX) { 1881101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1882101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1883101540Sambrisko & NGE_TBIANAR_HDX) { 1884101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1885101540Sambrisko } 1886192290Syongari } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1887101540Sambrisko == IFM_FDX) 1888101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1889101540Sambrisko else 1890101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1891192290Syongari 1892101540Sambrisko } else { 1893101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1894101540Sambrisko mii_pollstat(mii); 1895101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 1896101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 1897101540Sambrisko } 1898151296Sjhb NGE_UNLOCK(sc); 1899101540Sambrisko 190076479Swpaul return; 190176479Swpaul} 190276479Swpaul 190399497Salfredstatic int 1904192288Syongaringe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 190576479Swpaul{ 190676479Swpaul struct nge_softc *sc = ifp->if_softc; 190776479Swpaul struct ifreq *ifr = (struct ifreq *) data; 190876479Swpaul struct mii_data *mii; 1909135250Swpaul int error = 0; 191076479Swpaul 191176479Swpaul switch(command) { 191276479Swpaul case SIOCSIFMTU: 191376479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 191476479Swpaul error = EINVAL; 191578323Swpaul else { 1916151296Sjhb NGE_LOCK(sc); 191776479Swpaul ifp->if_mtu = ifr->ifr_mtu; 191878323Swpaul /* 191978323Swpaul * Workaround: if the MTU is larger than 192078323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 192178323Swpaul * TX checksum offloading. 192278323Swpaul */ 1923129632Syar if (ifr->ifr_mtu >= 8152) { 1924129632Syar ifp->if_capenable &= ~IFCAP_TXCSUM; 192578323Swpaul ifp->if_hwassist = 0; 1926129632Syar } else { 1927129632Syar ifp->if_capenable |= IFCAP_TXCSUM; 192878323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 1929129632Syar } 1930151296Sjhb NGE_UNLOCK(sc); 193178323Swpaul } 193276479Swpaul break; 193376479Swpaul case SIOCSIFFLAGS: 1934135250Swpaul NGE_LOCK(sc); 193576479Swpaul if (ifp->if_flags & IFF_UP) { 1936148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 193776479Swpaul ifp->if_flags & IFF_PROMISC && 193876479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 193976479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 194076479Swpaul NGE_RXFILTCTL_ALLPHYS| 194176479Swpaul NGE_RXFILTCTL_ALLMULTI); 1942148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 194376479Swpaul !(ifp->if_flags & IFF_PROMISC) && 194476479Swpaul sc->nge_if_flags & IFF_PROMISC) { 194576479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 194676479Swpaul NGE_RXFILTCTL_ALLPHYS); 194776479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 194876479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 194976479Swpaul NGE_RXFILTCTL_ALLMULTI); 195076479Swpaul } else { 1951148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1952135250Swpaul nge_init_locked(sc); 195376479Swpaul } 195476479Swpaul } else { 1955148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 195676479Swpaul nge_stop(sc); 195776479Swpaul } 195876479Swpaul sc->nge_if_flags = ifp->if_flags; 1959135250Swpaul NGE_UNLOCK(sc); 196076479Swpaul error = 0; 196176479Swpaul break; 196276479Swpaul case SIOCADDMULTI: 196376479Swpaul case SIOCDELMULTI: 1964135250Swpaul NGE_LOCK(sc); 196576479Swpaul nge_setmulti(sc); 1966135250Swpaul NGE_UNLOCK(sc); 196776479Swpaul error = 0; 196876479Swpaul break; 196976479Swpaul case SIOCGIFMEDIA: 197076479Swpaul case SIOCSIFMEDIA: 1971101540Sambrisko if (sc->nge_tbi) { 1972192290Syongari error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 1973101540Sambrisko command); 1974101540Sambrisko } else { 1975101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1976192290Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 1977101540Sambrisko command); 1978101540Sambrisko } 197976479Swpaul break; 1980128132Sru case SIOCSIFCAP: 1981150789Sglebius#ifdef DEVICE_POLLING 1982150789Sglebius if (ifr->ifr_reqcap & IFCAP_POLLING && 1983150789Sglebius !(ifp->if_capenable & IFCAP_POLLING)) { 1984150789Sglebius error = ether_poll_register(nge_poll, ifp); 1985150789Sglebius if (error) 1986150789Sglebius return(error); 1987150789Sglebius NGE_LOCK(sc); 1988150789Sglebius /* Disable interrupts */ 1989150789Sglebius CSR_WRITE_4(sc, NGE_IER, 0); 1990150789Sglebius ifp->if_capenable |= IFCAP_POLLING; 1991150789Sglebius NGE_UNLOCK(sc); 1992150789Sglebius return (error); 1993192290Syongari 1994150789Sglebius } 1995150789Sglebius if (!(ifr->ifr_reqcap & IFCAP_POLLING) && 1996150789Sglebius ifp->if_capenable & IFCAP_POLLING) { 1997150789Sglebius error = ether_poll_deregister(ifp); 1998150789Sglebius /* Enable interrupts. */ 1999150789Sglebius NGE_LOCK(sc); 2000150789Sglebius CSR_WRITE_4(sc, NGE_IER, 1); 2001150789Sglebius ifp->if_capenable &= ~IFCAP_POLLING; 2002150789Sglebius NGE_UNLOCK(sc); 2003150789Sglebius return (error); 2004150789Sglebius } 2005150789Sglebius#endif /* DEVICE_POLLING */ 2006128132Sru break; 200776479Swpaul default: 2008106937Ssam error = ether_ioctl(ifp, command, data); 200976479Swpaul break; 201076479Swpaul } 201176479Swpaul 201276479Swpaul return(error); 201376479Swpaul} 201476479Swpaul 201599497Salfredstatic void 2016192288Syongaringe_watchdog(struct ifnet *ifp) 201776479Swpaul{ 201876479Swpaul struct nge_softc *sc; 201976479Swpaul 202076479Swpaul sc = ifp->if_softc; 202176479Swpaul 202276479Swpaul ifp->if_oerrors++; 2023162321Sglebius if_printf(ifp, "watchdog timeout\n"); 202476479Swpaul 2025135250Swpaul NGE_LOCK(sc); 202676479Swpaul nge_stop(sc); 202776479Swpaul nge_reset(sc); 2028148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2029135250Swpaul nge_init_locked(sc); 203076479Swpaul 203176479Swpaul if (ifp->if_snd.ifq_head != NULL) 2032135250Swpaul nge_start_locked(ifp); 203376479Swpaul 2034135250Swpaul NGE_UNLOCK(sc); 2035135250Swpaul 203676479Swpaul return; 203776479Swpaul} 203876479Swpaul 203976479Swpaul/* 204076479Swpaul * Stop the adapter and free any mbufs allocated to the 204176479Swpaul * RX and TX lists. 204276479Swpaul */ 204399497Salfredstatic void 2044192288Syongaringe_stop(struct nge_softc *sc) 204576479Swpaul{ 2046192289Syongari int i; 204776479Swpaul struct ifnet *ifp; 204876479Swpaul struct mii_data *mii; 204976479Swpaul 2050135250Swpaul NGE_LOCK_ASSERT(sc); 2051147256Sbrooks ifp = sc->nge_ifp; 205276479Swpaul ifp->if_timer = 0; 2053101540Sambrisko if (sc->nge_tbi) { 2054101540Sambrisko mii = NULL; 2055101540Sambrisko } else { 2056101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2057101540Sambrisko } 205876479Swpaul 2059135250Swpaul callout_stop(&sc->nge_stat_ch); 206076479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 206176479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 206276479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 206376479Swpaul DELAY(1000); 206476479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 206576479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 206676479Swpaul 2067101540Sambrisko if (!sc->nge_tbi) 2068101540Sambrisko mii_down(mii); 206976479Swpaul 207076479Swpaul sc->nge_link = 0; 207176479Swpaul 207276479Swpaul /* 207376479Swpaul * Free data in the RX lists. 207476479Swpaul */ 207576479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 207676479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 207776479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 207876479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 207976479Swpaul } 208076479Swpaul } 208176479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 208276479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 208376479Swpaul 208476479Swpaul /* 208576479Swpaul * Free the TX list buffers. 208676479Swpaul */ 208776479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 208876479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 208976479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 209076479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 209176479Swpaul } 209276479Swpaul } 209376479Swpaul 209476479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 209576479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 209676479Swpaul 2097148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 209876479Swpaul 209976479Swpaul return; 210076479Swpaul} 210176479Swpaul 210276479Swpaul/* 210376479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 210476479Swpaul * get confused by errant DMAs when rebooting. 210576479Swpaul */ 2106173839Syongaristatic int 2107192288Syongaringe_shutdown(device_t dev) 210876479Swpaul{ 210976479Swpaul struct nge_softc *sc; 211076479Swpaul 211176479Swpaul sc = device_get_softc(dev); 211276479Swpaul 2113135250Swpaul NGE_LOCK(sc); 211476479Swpaul nge_reset(sc); 211576479Swpaul nge_stop(sc); 2116135250Swpaul NGE_UNLOCK(sc); 211776479Swpaul 2118173839Syongari return (0); 211976479Swpaul} 2120