if_nge.c revision 96028
176479Swpaul/* 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 * $FreeBSD: head/sys/dev/nge/if_nge.c 96028 2002-05-04 11:15:33Z phk $ 3476479Swpaul */ 3576479Swpaul 3676479Swpaul/* 3776479Swpaul * National Semiconductor DP83820/DP83821 gigabit ethernet driver 3876479Swpaul * for FreeBSD. Datasheets are available from: 3976479Swpaul * 4076479Swpaul * http://www.national.com/ds/DP/DP83820.pdf 4176479Swpaul * http://www.national.com/ds/DP/DP83821.pdf 4276479Swpaul * 4376479Swpaul * These chips are used on several low cost gigabit ethernet NICs 4476479Swpaul * sold by D-Link, Addtron, SMC and Asante. Both parts are 4576479Swpaul * virtually the same, except the 83820 is a 64-bit/32-bit part, 4676479Swpaul * while the 83821 is 32-bit only. 4776479Swpaul * 4876479Swpaul * Many cards also use National gigE transceivers, such as the 4976479Swpaul * DP83891, DP83861 and DP83862 gigPHYTER parts. The DP83861 datasheet 5076479Swpaul * contains a full register description that applies to all of these 5176479Swpaul * components: 5276479Swpaul * 5376479Swpaul * http://www.national.com/ds/DP/DP83861.pdf 5476479Swpaul * 5576479Swpaul * Written by Bill Paul <wpaul@bsdi.com> 5676479Swpaul * BSDi Open Source Solutions 5776479Swpaul */ 5876479Swpaul 5976479Swpaul/* 6076479Swpaul * The NatSemi DP83820 and 83821 controllers are enhanced versions 6176479Swpaul * of the NatSemi MacPHYTER 10/100 devices. They support 10, 100 6276479Swpaul * and 1000Mbps speeds with 1000baseX (ten bit interface), MII and GMII 6376479Swpaul * ports. Other features include 8K TX FIFO and 32K RX FIFO, TCP/IP 6476479Swpaul * hardware checksum offload (IPv4 only), VLAN tagging and filtering, 6576479Swpaul * priority TX and RX queues, a 2048 bit multicast hash filter, 4 RX pattern 6676479Swpaul * matching buffers, one perfect address filter buffer and interrupt 6776479Swpaul * moderation. The 83820 supports both 64-bit and 32-bit addressing 6876479Swpaul * and data transfers: the 64-bit support can be toggled on or off 6976479Swpaul * via software. This affects the size of certain fields in the DMA 7076479Swpaul * descriptors. 7176479Swpaul * 7278323Swpaul * There are two bugs/misfeatures in the 83820/83821 that I have 7378323Swpaul * discovered so far: 7478323Swpaul * 7578323Swpaul * - Receive buffers must be aligned on 64-bit boundaries, which means 7678323Swpaul * you must resort to copying data in order to fix up the payload 7778323Swpaul * alignment. 7878323Swpaul * 7978323Swpaul * - In order to transmit jumbo frames larger than 8170 bytes, you have 8078323Swpaul * to turn off transmit checksum offloading, because the chip can't 8178323Swpaul * compute the checksum on an outgoing frame unless it fits entirely 8278323Swpaul * within the TX FIFO, which is only 8192 bytes in size. If you have 8378323Swpaul * TX checksum offload enabled and you transmit attempt to transmit a 8478323Swpaul * frame larger than 8170 bytes, the transmitter will wedge. 8578323Swpaul * 8678323Swpaul * To work around the latter problem, TX checksum offload is disabled 8778323Swpaul * if the user selects an MTU larger than 8152 (8170 - 18). 8876479Swpaul */ 8976479Swpaul 9076479Swpaul#include <sys/param.h> 9176479Swpaul#include <sys/systm.h> 9276479Swpaul#include <sys/sockio.h> 9376479Swpaul#include <sys/mbuf.h> 9476479Swpaul#include <sys/malloc.h> 9576479Swpaul#include <sys/kernel.h> 9676479Swpaul#include <sys/socket.h> 9776479Swpaul 9876479Swpaul#include <net/if.h> 9976479Swpaul#include <net/if_arp.h> 10076479Swpaul#include <net/ethernet.h> 10176479Swpaul#include <net/if_dl.h> 10276479Swpaul#include <net/if_media.h> 10376479Swpaul#include <net/if_types.h> 10476479Swpaul#include <net/if_vlan_var.h> 10576479Swpaul 10676479Swpaul#include <net/bpf.h> 10776479Swpaul 10876479Swpaul#include <vm/vm.h> /* for vtophys */ 10976479Swpaul#include <vm/pmap.h> /* for vtophys */ 11076479Swpaul#include <machine/clock.h> /* for DELAY */ 11176479Swpaul#include <machine/bus_pio.h> 11276479Swpaul#include <machine/bus_memio.h> 11376479Swpaul#include <machine/bus.h> 11476479Swpaul#include <machine/resource.h> 11576479Swpaul#include <sys/bus.h> 11676479Swpaul#include <sys/rman.h> 11776479Swpaul 11876479Swpaul#include <dev/mii/mii.h> 11976479Swpaul#include <dev/mii/miivar.h> 12076479Swpaul 12176479Swpaul#include <pci/pcireg.h> 12276479Swpaul#include <pci/pcivar.h> 12376479Swpaul 12476479Swpaul#define NGE_USEIOSPACE 12576479Swpaul 12676522Swpaul#include <dev/nge/if_ngereg.h> 12776479Swpaul 12876479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1); 12976479Swpaul 13076479Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 13176479Swpaul#include "miibus_if.h" 13276479Swpaul 13376479Swpaul#ifndef lint 13476479Swpaulstatic const char rcsid[] = 13576479Swpaul "$FreeBSD: head/sys/dev/nge/if_nge.c 96028 2002-05-04 11:15:33Z phk $"; 13676479Swpaul#endif 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 14992739Salfredstatic int nge_probe (device_t); 15092739Salfredstatic int nge_attach (device_t); 15192739Salfredstatic int nge_detach (device_t); 15276479Swpaul 15392739Salfredstatic int nge_alloc_jumbo_mem (struct nge_softc *); 15492739Salfredstatic void nge_free_jumbo_mem (struct nge_softc *); 15592739Salfredstatic void *nge_jalloc (struct nge_softc *); 15692739Salfredstatic void nge_jfree (caddr_t, void *); 15776479Swpaul 15892739Salfredstatic int nge_newbuf (struct nge_softc *, 15992739Salfred struct nge_desc *, struct mbuf *); 16092739Salfredstatic int nge_encap (struct nge_softc *, 16192739Salfred struct mbuf *, u_int32_t *); 16292739Salfredstatic void nge_rxeof (struct nge_softc *); 16392739Salfredstatic void nge_txeof (struct nge_softc *); 16492739Salfredstatic void nge_intr (void *); 16592739Salfredstatic void nge_tick (void *); 16692739Salfredstatic void nge_start (struct ifnet *); 16792739Salfredstatic int nge_ioctl (struct ifnet *, u_long, caddr_t); 16892739Salfredstatic void nge_init (void *); 16992739Salfredstatic void nge_stop (struct nge_softc *); 17092739Salfredstatic void nge_watchdog (struct ifnet *); 17192739Salfredstatic void nge_shutdown (device_t); 17292739Salfredstatic int nge_ifmedia_upd (struct ifnet *); 17392739Salfredstatic void nge_ifmedia_sts (struct ifnet *, struct ifmediareq *); 17476479Swpaul 17592739Salfredstatic void nge_delay (struct nge_softc *); 17692739Salfredstatic void nge_eeprom_idle (struct nge_softc *); 17792739Salfredstatic void nge_eeprom_putbyte (struct nge_softc *, int); 17892739Salfredstatic void nge_eeprom_getword (struct nge_softc *, int, u_int16_t *); 17992739Salfredstatic void nge_read_eeprom (struct nge_softc *, caddr_t, int, int, int); 18076479Swpaul 18192739Salfredstatic void nge_mii_sync (struct nge_softc *); 18292739Salfredstatic void nge_mii_send (struct nge_softc *, u_int32_t, int); 18392739Salfredstatic int nge_mii_readreg (struct nge_softc *, struct nge_mii_frame *); 18492739Salfredstatic int nge_mii_writereg (struct nge_softc *, struct nge_mii_frame *); 18576479Swpaul 18692739Salfredstatic int nge_miibus_readreg (device_t, int, int); 18792739Salfredstatic int nge_miibus_writereg (device_t, int, int, int); 18892739Salfredstatic void nge_miibus_statchg (device_t); 18976479Swpaul 19092739Salfredstatic void nge_setmulti (struct nge_softc *); 19192739Salfredstatic u_int32_t nge_crc (struct nge_softc *, caddr_t); 19292739Salfredstatic void nge_reset (struct nge_softc *); 19392739Salfredstatic int nge_list_rx_init (struct nge_softc *); 19492739Salfredstatic int nge_list_tx_init (struct nge_softc *); 19576479Swpaul 19676479Swpaul#ifdef NGE_USEIOSPACE 19776479Swpaul#define NGE_RES SYS_RES_IOPORT 19876479Swpaul#define NGE_RID NGE_PCI_LOIO 19976479Swpaul#else 20076479Swpaul#define NGE_RES SYS_RES_MEMORY 20176479Swpaul#define NGE_RID NGE_PCI_LOMEM 20276479Swpaul#endif 20376479Swpaul 20476479Swpaulstatic device_method_t nge_methods[] = { 20576479Swpaul /* Device interface */ 20676479Swpaul DEVMETHOD(device_probe, nge_probe), 20776479Swpaul DEVMETHOD(device_attach, nge_attach), 20876479Swpaul DEVMETHOD(device_detach, nge_detach), 20976479Swpaul DEVMETHOD(device_shutdown, nge_shutdown), 21076479Swpaul 21176479Swpaul /* bus interface */ 21276479Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 21376479Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21476479Swpaul 21576479Swpaul /* MII interface */ 21676479Swpaul DEVMETHOD(miibus_readreg, nge_miibus_readreg), 21776479Swpaul DEVMETHOD(miibus_writereg, nge_miibus_writereg), 21876479Swpaul DEVMETHOD(miibus_statchg, nge_miibus_statchg), 21976479Swpaul 22076479Swpaul { 0, 0 } 22176479Swpaul}; 22276479Swpaul 22376479Swpaulstatic driver_t nge_driver = { 22476479Swpaul "nge", 22576479Swpaul nge_methods, 22676479Swpaul sizeof(struct nge_softc) 22776479Swpaul}; 22876479Swpaul 22976479Swpaulstatic devclass_t nge_devclass; 23076479Swpaul 23176479SwpaulDRIVER_MODULE(if_nge, pci, nge_driver, nge_devclass, 0, 0); 23276479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0); 23376479Swpaul 23476479Swpaul#define NGE_SETBIT(sc, reg, x) \ 23576479Swpaul CSR_WRITE_4(sc, reg, \ 23676479Swpaul CSR_READ_4(sc, reg) | (x)) 23776479Swpaul 23876479Swpaul#define NGE_CLRBIT(sc, reg, x) \ 23976479Swpaul CSR_WRITE_4(sc, reg, \ 24076479Swpaul CSR_READ_4(sc, reg) & ~(x)) 24176479Swpaul 24276479Swpaul#define SIO_SET(x) \ 24376479Swpaul CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | x) 24476479Swpaul 24576479Swpaul#define SIO_CLR(x) \ 24676479Swpaul CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~x) 24776479Swpaul 24876479Swpaulstatic void nge_delay(sc) 24976479Swpaul struct nge_softc *sc; 25076479Swpaul{ 25176479Swpaul int idx; 25276479Swpaul 25376479Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 25476479Swpaul CSR_READ_4(sc, NGE_CSR); 25576479Swpaul 25676479Swpaul return; 25776479Swpaul} 25876479Swpaul 25976479Swpaulstatic void nge_eeprom_idle(sc) 26076479Swpaul struct nge_softc *sc; 26176479Swpaul{ 26276479Swpaul register int i; 26376479Swpaul 26476479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26576479Swpaul nge_delay(sc); 26676479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26776479Swpaul nge_delay(sc); 26876479Swpaul 26976479Swpaul for (i = 0; i < 25; i++) { 27076479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27176479Swpaul nge_delay(sc); 27276479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 27376479Swpaul nge_delay(sc); 27476479Swpaul } 27576479Swpaul 27676479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27776479Swpaul nge_delay(sc); 27876479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 27976479Swpaul nge_delay(sc); 28076479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 28176479Swpaul 28276479Swpaul return; 28376479Swpaul} 28476479Swpaul 28576479Swpaul/* 28676479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28776479Swpaul */ 28876479Swpaulstatic void nge_eeprom_putbyte(sc, addr) 28976479Swpaul struct nge_softc *sc; 29076479Swpaul int addr; 29176479Swpaul{ 29276479Swpaul register int d, i; 29376479Swpaul 29476479Swpaul d = addr | NGE_EECMD_READ; 29576479Swpaul 29676479Swpaul /* 29776479Swpaul * Feed in each bit and stobe the clock. 29876479Swpaul */ 29976479Swpaul for (i = 0x400; i; i >>= 1) { 30076479Swpaul if (d & i) { 30176479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 30276479Swpaul } else { 30376479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 30476479Swpaul } 30576479Swpaul nge_delay(sc); 30676479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30776479Swpaul nge_delay(sc); 30876479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 30976479Swpaul nge_delay(sc); 31076479Swpaul } 31176479Swpaul 31276479Swpaul return; 31376479Swpaul} 31476479Swpaul 31576479Swpaul/* 31676479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 31776479Swpaul */ 31876479Swpaulstatic void nge_eeprom_getword(sc, addr, dest) 31976479Swpaul struct nge_softc *sc; 32076479Swpaul int addr; 32176479Swpaul u_int16_t *dest; 32276479Swpaul{ 32376479Swpaul register int i; 32476479Swpaul u_int16_t word = 0; 32576479Swpaul 32676479Swpaul /* Force EEPROM to idle state. */ 32776479Swpaul nge_eeprom_idle(sc); 32876479Swpaul 32976479Swpaul /* Enter EEPROM access mode. */ 33076479Swpaul nge_delay(sc); 33176479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 33276479Swpaul nge_delay(sc); 33376479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 33476479Swpaul nge_delay(sc); 33576479Swpaul 33676479Swpaul /* 33776479Swpaul * Send address of word we want to read. 33876479Swpaul */ 33976479Swpaul nge_eeprom_putbyte(sc, addr); 34076479Swpaul 34176479Swpaul /* 34276479Swpaul * Start reading bits from EEPROM. 34376479Swpaul */ 34476479Swpaul for (i = 0x8000; i; i >>= 1) { 34576479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 34676479Swpaul nge_delay(sc); 34776479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT) 34876479Swpaul word |= i; 34976479Swpaul nge_delay(sc); 35076479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 35176479Swpaul nge_delay(sc); 35276479Swpaul } 35376479Swpaul 35476479Swpaul /* Turn off EEPROM access mode. */ 35576479Swpaul nge_eeprom_idle(sc); 35676479Swpaul 35776479Swpaul *dest = word; 35876479Swpaul 35976479Swpaul return; 36076479Swpaul} 36176479Swpaul 36276479Swpaul/* 36376479Swpaul * Read a sequence of words from the EEPROM. 36476479Swpaul */ 36576479Swpaulstatic void nge_read_eeprom(sc, dest, off, cnt, swap) 36676479Swpaul struct nge_softc *sc; 36776479Swpaul caddr_t dest; 36876479Swpaul int off; 36976479Swpaul int cnt; 37076479Swpaul int swap; 37176479Swpaul{ 37276479Swpaul int i; 37376479Swpaul u_int16_t word = 0, *ptr; 37476479Swpaul 37576479Swpaul for (i = 0; i < cnt; i++) { 37676479Swpaul nge_eeprom_getword(sc, off + i, &word); 37776479Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 37876479Swpaul if (swap) 37976479Swpaul *ptr = ntohs(word); 38076479Swpaul else 38176479Swpaul *ptr = word; 38276479Swpaul } 38376479Swpaul 38476479Swpaul return; 38576479Swpaul} 38676479Swpaul 38776479Swpaul/* 38876479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 38976479Swpaul */ 39076479Swpaulstatic void nge_mii_sync(sc) 39176479Swpaul struct nge_softc *sc; 39276479Swpaul{ 39376479Swpaul register int i; 39476479Swpaul 39576479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 39676479Swpaul 39776479Swpaul for (i = 0; i < 32; i++) { 39876479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 39976479Swpaul DELAY(1); 40076479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40176479Swpaul DELAY(1); 40276479Swpaul } 40376479Swpaul 40476479Swpaul return; 40576479Swpaul} 40676479Swpaul 40776479Swpaul/* 40876479Swpaul * Clock a series of bits through the MII. 40976479Swpaul */ 41076479Swpaulstatic void nge_mii_send(sc, bits, cnt) 41176479Swpaul struct nge_softc *sc; 41276479Swpaul u_int32_t bits; 41376479Swpaul int cnt; 41476479Swpaul{ 41576479Swpaul int i; 41676479Swpaul 41776479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 41876479Swpaul 41976479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 42076479Swpaul if (bits & i) { 42176479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 42276479Swpaul } else { 42376479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 42476479Swpaul } 42576479Swpaul DELAY(1); 42676479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 42776479Swpaul DELAY(1); 42876479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 42976479Swpaul } 43076479Swpaul} 43176479Swpaul 43276479Swpaul/* 43376479Swpaul * Read an PHY register through the MII. 43476479Swpaul */ 43576479Swpaulstatic int nge_mii_readreg(sc, frame) 43676479Swpaul struct nge_softc *sc; 43776479Swpaul struct nge_mii_frame *frame; 43876479Swpaul 43976479Swpaul{ 44076479Swpaul int i, ack, s; 44176479Swpaul 44276479Swpaul s = splimp(); 44376479Swpaul 44476479Swpaul /* 44576479Swpaul * Set up frame for RX. 44676479Swpaul */ 44776479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 44876479Swpaul frame->mii_opcode = NGE_MII_READOP; 44976479Swpaul frame->mii_turnaround = 0; 45076479Swpaul frame->mii_data = 0; 45176479Swpaul 45276479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 45376479Swpaul 45476479Swpaul /* 45576479Swpaul * Turn on data xmit. 45676479Swpaul */ 45776479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 45876479Swpaul 45976479Swpaul nge_mii_sync(sc); 46076479Swpaul 46176479Swpaul /* 46276479Swpaul * Send command/address info. 46376479Swpaul */ 46476479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 46576479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 46676479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 46776479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 46876479Swpaul 46976479Swpaul /* Idle bit */ 47076479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 47176479Swpaul DELAY(1); 47276479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 47376479Swpaul DELAY(1); 47476479Swpaul 47576479Swpaul /* Turn off xmit. */ 47676479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 47776479Swpaul /* Check for ack */ 47876479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 47976479Swpaul DELAY(1); 48076479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48176479Swpaul DELAY(1); 48276479Swpaul ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 48376479Swpaul 48476479Swpaul /* 48576479Swpaul * Now try reading data bits. If the ack failed, we still 48676479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 48776479Swpaul */ 48876479Swpaul if (ack) { 48976479Swpaul for(i = 0; i < 16; i++) { 49076479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 49176479Swpaul DELAY(1); 49276479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 49376479Swpaul DELAY(1); 49476479Swpaul } 49576479Swpaul goto fail; 49676479Swpaul } 49776479Swpaul 49876479Swpaul for (i = 0x8000; i; i >>= 1) { 49976479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 50076479Swpaul DELAY(1); 50176479Swpaul if (!ack) { 50276479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 50376479Swpaul frame->mii_data |= i; 50476479Swpaul DELAY(1); 50576479Swpaul } 50676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 50776479Swpaul DELAY(1); 50876479Swpaul } 50976479Swpaul 51076479Swpaulfail: 51176479Swpaul 51276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 51376479Swpaul DELAY(1); 51476479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 51576479Swpaul DELAY(1); 51676479Swpaul 51776479Swpaul splx(s); 51876479Swpaul 51976479Swpaul if (ack) 52076479Swpaul return(1); 52176479Swpaul return(0); 52276479Swpaul} 52376479Swpaul 52476479Swpaul/* 52576479Swpaul * Write to a PHY register through the MII. 52676479Swpaul */ 52776479Swpaulstatic int nge_mii_writereg(sc, frame) 52876479Swpaul struct nge_softc *sc; 52976479Swpaul struct nge_mii_frame *frame; 53076479Swpaul 53176479Swpaul{ 53276479Swpaul int s; 53376479Swpaul 53476479Swpaul s = splimp(); 53576479Swpaul /* 53676479Swpaul * Set up frame for TX. 53776479Swpaul */ 53876479Swpaul 53976479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 54076479Swpaul frame->mii_opcode = NGE_MII_WRITEOP; 54176479Swpaul frame->mii_turnaround = NGE_MII_TURNAROUND; 54276479Swpaul 54376479Swpaul /* 54476479Swpaul * Turn on data output. 54576479Swpaul */ 54676479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 54776479Swpaul 54876479Swpaul nge_mii_sync(sc); 54976479Swpaul 55076479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 55176479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 55276479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 55376479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 55476479Swpaul nge_mii_send(sc, frame->mii_turnaround, 2); 55576479Swpaul nge_mii_send(sc, frame->mii_data, 16); 55676479Swpaul 55776479Swpaul /* Idle bit. */ 55876479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 55976479Swpaul DELAY(1); 56076479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 56176479Swpaul DELAY(1); 56276479Swpaul 56376479Swpaul /* 56476479Swpaul * Turn off xmit. 56576479Swpaul */ 56676479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 56776479Swpaul 56876479Swpaul splx(s); 56976479Swpaul 57076479Swpaul return(0); 57176479Swpaul} 57276479Swpaul 57376479Swpaulstatic int nge_miibus_readreg(dev, phy, reg) 57476479Swpaul device_t dev; 57576479Swpaul int phy, reg; 57676479Swpaul{ 57776479Swpaul struct nge_softc *sc; 57876479Swpaul struct nge_mii_frame frame; 57976479Swpaul 58076479Swpaul sc = device_get_softc(dev); 58176479Swpaul 58276479Swpaul bzero((char *)&frame, sizeof(frame)); 58376479Swpaul 58476479Swpaul frame.mii_phyaddr = phy; 58576479Swpaul frame.mii_regaddr = reg; 58676479Swpaul nge_mii_readreg(sc, &frame); 58776479Swpaul 58876479Swpaul return(frame.mii_data); 58976479Swpaul} 59076479Swpaul 59176479Swpaulstatic int nge_miibus_writereg(dev, phy, reg, data) 59276479Swpaul device_t dev; 59376479Swpaul int phy, reg, data; 59476479Swpaul{ 59576479Swpaul struct nge_softc *sc; 59676479Swpaul struct nge_mii_frame frame; 59776479Swpaul 59876479Swpaul sc = device_get_softc(dev); 59976479Swpaul 60076479Swpaul bzero((char *)&frame, sizeof(frame)); 60176479Swpaul 60276479Swpaul frame.mii_phyaddr = phy; 60376479Swpaul frame.mii_regaddr = reg; 60476479Swpaul frame.mii_data = data; 60576479Swpaul nge_mii_writereg(sc, &frame); 60676479Swpaul 60776479Swpaul return(0); 60876479Swpaul} 60976479Swpaul 61076479Swpaulstatic void nge_miibus_statchg(dev) 61176479Swpaul device_t dev; 61276479Swpaul{ 61376479Swpaul struct nge_softc *sc; 61476479Swpaul struct mii_data *mii; 61576479Swpaul 61676479Swpaul sc = device_get_softc(dev); 61776479Swpaul mii = device_get_softc(sc->nge_miibus); 61876479Swpaul 61976479Swpaul if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 62076479Swpaul NGE_SETBIT(sc, NGE_TX_CFG, 62176479Swpaul (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 62276479Swpaul NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 62376479Swpaul } else { 62476479Swpaul NGE_CLRBIT(sc, NGE_TX_CFG, 62576479Swpaul (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 62676479Swpaul NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 62776479Swpaul } 62876479Swpaul 62979424Swpaul /* If we have a 1000Mbps link, set the mode_1000 bit. */ 63095673Sphk if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 63179424Swpaul IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 63279424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 63379424Swpaul } else { 63479424Swpaul NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 63579424Swpaul } 63679424Swpaul 63776479Swpaul return; 63876479Swpaul} 63976479Swpaul 64076479Swpaulstatic u_int32_t nge_crc(sc, addr) 64176479Swpaul struct nge_softc *sc; 64276479Swpaul caddr_t addr; 64376479Swpaul{ 64476479Swpaul u_int32_t crc, carry; 64576479Swpaul int i, j; 64676479Swpaul u_int8_t c; 64776479Swpaul 64876479Swpaul /* Compute CRC for the address value. */ 64976479Swpaul crc = 0xFFFFFFFF; /* initial value */ 65076479Swpaul 65176479Swpaul for (i = 0; i < 6; i++) { 65276479Swpaul c = *(addr + i); 65376479Swpaul for (j = 0; j < 8; j++) { 65476479Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 65576479Swpaul crc <<= 1; 65676479Swpaul c >>= 1; 65776479Swpaul if (carry) 65876479Swpaul crc = (crc ^ 0x04c11db6) | carry; 65976479Swpaul } 66076479Swpaul } 66176479Swpaul 66276479Swpaul /* 66376479Swpaul * return the filter bit position 66476479Swpaul */ 66576479Swpaul 66676479Swpaul return((crc >> 21) & 0x00000FFF); 66776479Swpaul} 66876479Swpaul 66976479Swpaulstatic void nge_setmulti(sc) 67076479Swpaul struct nge_softc *sc; 67176479Swpaul{ 67276479Swpaul struct ifnet *ifp; 67376479Swpaul struct ifmultiaddr *ifma; 67476479Swpaul u_int32_t h = 0, i, filtsave; 67576479Swpaul int bit, index; 67676479Swpaul 67776479Swpaul ifp = &sc->arpcom.ac_if; 67876479Swpaul 67976479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 68076479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 68176479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 68276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 68376479Swpaul return; 68476479Swpaul } 68576479Swpaul 68676479Swpaul /* 68776479Swpaul * We have to explicitly enable the multicast hash table 68876479Swpaul * on the NatSemi chip if we want to use it, which we do. 68976479Swpaul * We also have to tell it that we don't want to use the 69076479Swpaul * hash table for matching unicast addresses. 69176479Swpaul */ 69276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 69376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 69476479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 69576479Swpaul 69676479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 69776479Swpaul 69876479Swpaul /* first, zot all the existing hash bits */ 69976479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 70076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 70176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 70276479Swpaul } 70376479Swpaul 70476479Swpaul /* 70576479Swpaul * From the 11 bits returned by the crc routine, the top 7 70676479Swpaul * bits represent the 16-bit word in the mcast hash table 70776479Swpaul * that needs to be updated, and the lower 4 bits represent 70876479Swpaul * which bit within that byte needs to be set. 70976479Swpaul */ 71076479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 71176479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71276479Swpaul continue; 71376479Swpaul h = nge_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 71476479Swpaul index = (h >> 4) & 0x7F; 71576479Swpaul bit = h & 0xF; 71676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 71776479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 71876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 71976479Swpaul } 72076479Swpaul 72176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 72276479Swpaul 72376479Swpaul return; 72476479Swpaul} 72576479Swpaul 72676479Swpaulstatic void nge_reset(sc) 72776479Swpaul struct nge_softc *sc; 72876479Swpaul{ 72976479Swpaul register int i; 73076479Swpaul 73176479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 73276479Swpaul 73376479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 73476479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 73576479Swpaul break; 73676479Swpaul } 73776479Swpaul 73876479Swpaul if (i == NGE_TIMEOUT) 73976479Swpaul printf("nge%d: reset never completed\n", sc->nge_unit); 74076479Swpaul 74176479Swpaul /* Wait a little while for the chip to get its brains in order. */ 74276479Swpaul DELAY(1000); 74376479Swpaul 74476479Swpaul /* 74576479Swpaul * If this is a NetSemi chip, make sure to clear 74676479Swpaul * PME mode. 74776479Swpaul */ 74876479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 74976479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 75076479Swpaul 75176479Swpaul return; 75276479Swpaul} 75376479Swpaul 75476479Swpaul/* 75576479Swpaul * Probe for an NatSemi chip. Check the PCI vendor and device 75676479Swpaul * IDs against our list and return a device name if we find a match. 75776479Swpaul */ 75876479Swpaulstatic int nge_probe(dev) 75976479Swpaul device_t dev; 76076479Swpaul{ 76176479Swpaul struct nge_type *t; 76276479Swpaul 76376479Swpaul t = nge_devs; 76476479Swpaul 76576479Swpaul while(t->nge_name != NULL) { 76676479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 76776479Swpaul (pci_get_device(dev) == t->nge_did)) { 76876479Swpaul device_set_desc(dev, t->nge_name); 76976479Swpaul return(0); 77076479Swpaul } 77176479Swpaul t++; 77276479Swpaul } 77376479Swpaul 77476479Swpaul return(ENXIO); 77576479Swpaul} 77676479Swpaul 77776479Swpaul/* 77876479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 77976479Swpaul * setup and ethernet/BPF attach. 78076479Swpaul */ 78176479Swpaulstatic int nge_attach(dev) 78276479Swpaul device_t dev; 78376479Swpaul{ 78476479Swpaul int s; 78576479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 78676479Swpaul u_int32_t command; 78776479Swpaul struct nge_softc *sc; 78876479Swpaul struct ifnet *ifp; 78976479Swpaul int unit, error = 0, rid; 79076479Swpaul 79176479Swpaul s = splimp(); 79276479Swpaul 79376479Swpaul sc = device_get_softc(dev); 79476479Swpaul unit = device_get_unit(dev); 79576479Swpaul bzero(sc, sizeof(struct nge_softc)); 79676479Swpaul 79793818Sjhb mtx_init(&sc->nge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 79893818Sjhb MTX_DEF | MTX_RECURSE); 79976479Swpaul 80076479Swpaul /* 80176479Swpaul * Handle power management nonsense. 80276479Swpaul */ 80376479Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 80476479Swpaul u_int32_t iobase, membase, irq; 80576479Swpaul 80676479Swpaul /* Save important PCI config data. */ 80776479Swpaul iobase = pci_read_config(dev, NGE_PCI_LOIO, 4); 80876479Swpaul membase = pci_read_config(dev, NGE_PCI_LOMEM, 4); 80976479Swpaul irq = pci_read_config(dev, NGE_PCI_INTLINE, 4); 81076479Swpaul 81176479Swpaul /* Reset the power state. */ 81276479Swpaul printf("nge%d: chip is in D%d power mode " 81376479Swpaul "-- setting to D0\n", unit, 81476479Swpaul pci_get_powerstate(dev)); 81576479Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 81676479Swpaul 81776479Swpaul /* Restore PCI config data. */ 81876479Swpaul pci_write_config(dev, NGE_PCI_LOIO, iobase, 4); 81976479Swpaul pci_write_config(dev, NGE_PCI_LOMEM, membase, 4); 82076479Swpaul pci_write_config(dev, NGE_PCI_INTLINE, irq, 4); 82176479Swpaul } 82276479Swpaul 82376479Swpaul /* 82476479Swpaul * Map control/status registers. 82576479Swpaul */ 82676479Swpaul pci_enable_busmaster(dev); 82779472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 82879472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 82976479Swpaul command = pci_read_config(dev, PCIR_COMMAND, 4); 83076479Swpaul 83176479Swpaul#ifdef NGE_USEIOSPACE 83276479Swpaul if (!(command & PCIM_CMD_PORTEN)) { 83376479Swpaul printf("nge%d: failed to enable I/O ports!\n", unit); 83476479Swpaul error = ENXIO;; 83576479Swpaul goto fail; 83676479Swpaul } 83776479Swpaul#else 83876479Swpaul if (!(command & PCIM_CMD_MEMEN)) { 83976479Swpaul printf("nge%d: failed to enable memory mapping!\n", unit); 84076479Swpaul error = ENXIO;; 84176479Swpaul goto fail; 84276479Swpaul } 84376479Swpaul#endif 84476479Swpaul 84576479Swpaul rid = NGE_RID; 84676479Swpaul sc->nge_res = bus_alloc_resource(dev, NGE_RES, &rid, 84776479Swpaul 0, ~0, 1, RF_ACTIVE); 84876479Swpaul 84976479Swpaul if (sc->nge_res == NULL) { 85076479Swpaul printf("nge%d: couldn't map ports/memory\n", unit); 85176479Swpaul error = ENXIO; 85276479Swpaul goto fail; 85376479Swpaul } 85476479Swpaul 85576479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 85676479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 85776479Swpaul 85876479Swpaul /* Allocate interrupt */ 85976479Swpaul rid = 0; 86076479Swpaul sc->nge_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 86176479Swpaul RF_SHAREABLE | RF_ACTIVE); 86276479Swpaul 86376479Swpaul if (sc->nge_irq == NULL) { 86476479Swpaul printf("nge%d: couldn't map interrupt\n", unit); 86576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 86676479Swpaul error = ENXIO; 86776479Swpaul goto fail; 86876479Swpaul } 86976479Swpaul 87076479Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET, 87176479Swpaul nge_intr, sc, &sc->nge_intrhand); 87276479Swpaul 87376479Swpaul if (error) { 87476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 87576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 87676479Swpaul printf("nge%d: couldn't set up irq\n", unit); 87776479Swpaul goto fail; 87876479Swpaul } 87976479Swpaul 88076479Swpaul /* Reset the adapter. */ 88176479Swpaul nge_reset(sc); 88276479Swpaul 88376479Swpaul /* 88476479Swpaul * Get station address from the EEPROM. 88576479Swpaul */ 88676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 88776479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 88876479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 88976479Swpaul 89076479Swpaul /* 89176479Swpaul * A NatSemi chip was detected. Inform the world. 89276479Swpaul */ 89376479Swpaul printf("nge%d: Ethernet address: %6D\n", unit, eaddr, ":"); 89476479Swpaul 89576479Swpaul sc->nge_unit = unit; 89676479Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 89776479Swpaul 89876479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 89976479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 90076479Swpaul 90176479Swpaul if (sc->nge_ldata == NULL) { 90276479Swpaul printf("nge%d: no memory for list buffers!\n", unit); 90376479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 90476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 90576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 90676479Swpaul error = ENXIO; 90776479Swpaul goto fail; 90876479Swpaul } 90976479Swpaul bzero(sc->nge_ldata, sizeof(struct nge_list_data)); 91076479Swpaul 91176479Swpaul /* Try to allocate memory for jumbo buffers. */ 91276479Swpaul if (nge_alloc_jumbo_mem(sc)) { 91376479Swpaul printf("nge%d: jumbo buffer allocation failed\n", 91476479Swpaul sc->nge_unit); 91576479Swpaul contigfree(sc->nge_ldata, 91676479Swpaul sizeof(struct nge_list_data), M_DEVBUF); 91776479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 91876479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 91976479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 92076479Swpaul error = ENXIO; 92176479Swpaul goto fail; 92276479Swpaul } 92376479Swpaul 92476479Swpaul ifp = &sc->arpcom.ac_if; 92576479Swpaul ifp->if_softc = sc; 92676479Swpaul ifp->if_unit = unit; 92776479Swpaul ifp->if_name = "nge"; 92876479Swpaul ifp->if_mtu = ETHERMTU; 92976479Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 93076479Swpaul ifp->if_ioctl = nge_ioctl; 93176479Swpaul ifp->if_output = ether_output; 93276479Swpaul ifp->if_start = nge_start; 93376479Swpaul ifp->if_watchdog = nge_watchdog; 93476479Swpaul ifp->if_init = nge_init; 93576479Swpaul ifp->if_baudrate = 1000000000; 93676479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 93776479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 93883632Sjlemon ifp->if_capabilities = IFCAP_HWCSUM; 93983632Sjlemon ifp->if_capenable = ifp->if_capabilities; 94076479Swpaul 94176479Swpaul /* 94276479Swpaul * Do MII setup. 94376479Swpaul */ 94476479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 94576479Swpaul nge_ifmedia_upd, nge_ifmedia_sts)) { 94676479Swpaul printf("nge%d: MII without any PHY!\n", sc->nge_unit); 94776479Swpaul nge_free_jumbo_mem(sc); 94876479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 94976479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 95076479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 95176479Swpaul error = ENXIO; 95276479Swpaul goto fail; 95376479Swpaul } 95476479Swpaul 95576479Swpaul /* 95676479Swpaul * Call MI attach routine. 95776479Swpaul */ 95876479Swpaul ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 95976479Swpaul callout_handle_init(&sc->nge_stat_ch); 96076479Swpaul 96176479Swpaulfail: 96276479Swpaul splx(s); 96376479Swpaul mtx_destroy(&sc->nge_mtx); 96476479Swpaul return(error); 96576479Swpaul} 96676479Swpaul 96776479Swpaulstatic int nge_detach(dev) 96876479Swpaul device_t dev; 96976479Swpaul{ 97076479Swpaul struct nge_softc *sc; 97176479Swpaul struct ifnet *ifp; 97276479Swpaul int s; 97376479Swpaul 97476479Swpaul s = splimp(); 97576479Swpaul 97676479Swpaul sc = device_get_softc(dev); 97776479Swpaul ifp = &sc->arpcom.ac_if; 97876479Swpaul 97976479Swpaul nge_reset(sc); 98076479Swpaul nge_stop(sc); 98176479Swpaul ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 98276479Swpaul 98376479Swpaul bus_generic_detach(dev); 98476479Swpaul device_delete_child(dev, sc->nge_miibus); 98576479Swpaul 98676479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 98776479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 98876479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 98976479Swpaul 99076479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 99176479Swpaul nge_free_jumbo_mem(sc); 99276479Swpaul 99376479Swpaul splx(s); 99476479Swpaul mtx_destroy(&sc->nge_mtx); 99576479Swpaul 99676479Swpaul return(0); 99776479Swpaul} 99876479Swpaul 99976479Swpaul/* 100076479Swpaul * Initialize the transmit descriptors. 100176479Swpaul */ 100276479Swpaulstatic int nge_list_tx_init(sc) 100376479Swpaul struct nge_softc *sc; 100476479Swpaul{ 100576479Swpaul struct nge_list_data *ld; 100676479Swpaul struct nge_ring_data *cd; 100776479Swpaul int i; 100876479Swpaul 100976479Swpaul cd = &sc->nge_cdata; 101076479Swpaul ld = sc->nge_ldata; 101176479Swpaul 101276479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 101376479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 101476479Swpaul ld->nge_tx_list[i].nge_nextdesc = 101576479Swpaul &ld->nge_tx_list[0]; 101676479Swpaul ld->nge_tx_list[i].nge_next = 101776479Swpaul vtophys(&ld->nge_tx_list[0]); 101876479Swpaul } else { 101976479Swpaul ld->nge_tx_list[i].nge_nextdesc = 102076479Swpaul &ld->nge_tx_list[i + 1]; 102176479Swpaul ld->nge_tx_list[i].nge_next = 102276479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 102376479Swpaul } 102476479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 102576479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 102676479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 102776479Swpaul } 102876479Swpaul 102976479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 103076479Swpaul 103176479Swpaul return(0); 103276479Swpaul} 103376479Swpaul 103476479Swpaul 103576479Swpaul/* 103676479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 103776479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 103876479Swpaul * points back to the first. 103976479Swpaul */ 104076479Swpaulstatic int nge_list_rx_init(sc) 104176479Swpaul struct nge_softc *sc; 104276479Swpaul{ 104376479Swpaul struct nge_list_data *ld; 104476479Swpaul struct nge_ring_data *cd; 104576479Swpaul int i; 104676479Swpaul 104776479Swpaul ld = sc->nge_ldata; 104876479Swpaul cd = &sc->nge_cdata; 104976479Swpaul 105076479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 105176479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 105276479Swpaul return(ENOBUFS); 105376479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 105476479Swpaul ld->nge_rx_list[i].nge_nextdesc = 105576479Swpaul &ld->nge_rx_list[0]; 105676479Swpaul ld->nge_rx_list[i].nge_next = 105776479Swpaul vtophys(&ld->nge_rx_list[0]); 105876479Swpaul } else { 105976479Swpaul ld->nge_rx_list[i].nge_nextdesc = 106076479Swpaul &ld->nge_rx_list[i + 1]; 106176479Swpaul ld->nge_rx_list[i].nge_next = 106276479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 106376479Swpaul } 106476479Swpaul } 106576479Swpaul 106676479Swpaul cd->nge_rx_prod = 0; 106776479Swpaul 106876479Swpaul return(0); 106976479Swpaul} 107076479Swpaul 107176479Swpaul/* 107276479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 107376479Swpaul */ 107476479Swpaulstatic int nge_newbuf(sc, c, m) 107576479Swpaul struct nge_softc *sc; 107676479Swpaul struct nge_desc *c; 107776479Swpaul struct mbuf *m; 107876479Swpaul{ 107976479Swpaul struct mbuf *m_new = NULL; 108076479Swpaul caddr_t *buf = NULL; 108176479Swpaul 108276479Swpaul if (m == NULL) { 108376479Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 108476479Swpaul if (m_new == NULL) { 108576479Swpaul printf("nge%d: no memory for rx list " 108676479Swpaul "-- packet dropped!\n", sc->nge_unit); 108776479Swpaul return(ENOBUFS); 108876479Swpaul } 108976479Swpaul 109076479Swpaul /* Allocate the jumbo buffer */ 109176479Swpaul buf = nge_jalloc(sc); 109276479Swpaul if (buf == NULL) { 109376479Swpaul#ifdef NGE_VERBOSE 109476479Swpaul printf("nge%d: jumbo allocation failed " 109576479Swpaul "-- packet dropped!\n", sc->nge_unit); 109676479Swpaul#endif 109776479Swpaul m_freem(m_new); 109876479Swpaul return(ENOBUFS); 109976479Swpaul } 110076479Swpaul /* Attach the buffer to the mbuf */ 110176479Swpaul m_new->m_data = (void *)buf; 110278440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 110378440Swpaul MEXTADD(m_new, buf, NGE_JUMBO_FRAMELEN, nge_jfree, 110476640Swpaul (struct nge_softc *)sc, 0, EXT_NET_DRV); 110576479Swpaul } else { 110676479Swpaul m_new = m; 110778440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 110876479Swpaul m_new->m_data = m_new->m_ext.ext_buf; 110976479Swpaul } 111076479Swpaul 111176479Swpaul m_adj(m_new, sizeof(u_int64_t)); 111276479Swpaul 111376479Swpaul c->nge_mbuf = m_new; 111476479Swpaul c->nge_ptr = vtophys(mtod(m_new, caddr_t)); 111576479Swpaul c->nge_ctl = m_new->m_len; 111676479Swpaul c->nge_extsts = 0; 111776479Swpaul 111876479Swpaul return(0); 111976479Swpaul} 112076479Swpaul 112176479Swpaulstatic int nge_alloc_jumbo_mem(sc) 112276479Swpaul struct nge_softc *sc; 112376479Swpaul{ 112476479Swpaul caddr_t ptr; 112576479Swpaul register int i; 112676479Swpaul struct nge_jpool_entry *entry; 112776479Swpaul 112876479Swpaul /* Grab a big chunk o' storage. */ 112976479Swpaul sc->nge_cdata.nge_jumbo_buf = contigmalloc(NGE_JMEM, M_DEVBUF, 113076479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 113176479Swpaul 113276479Swpaul if (sc->nge_cdata.nge_jumbo_buf == NULL) { 113376479Swpaul printf("nge%d: no memory for jumbo buffers!\n", sc->nge_unit); 113476479Swpaul return(ENOBUFS); 113576479Swpaul } 113676479Swpaul 113776479Swpaul SLIST_INIT(&sc->nge_jfree_listhead); 113876479Swpaul SLIST_INIT(&sc->nge_jinuse_listhead); 113976479Swpaul 114076479Swpaul /* 114176479Swpaul * Now divide it up into 9K pieces and save the addresses 114276479Swpaul * in an array. 114376479Swpaul */ 114476479Swpaul ptr = sc->nge_cdata.nge_jumbo_buf; 114576479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 114676479Swpaul sc->nge_cdata.nge_jslots[i] = ptr; 114778440Swpaul ptr += NGE_JLEN; 114876479Swpaul entry = malloc(sizeof(struct nge_jpool_entry), 114976479Swpaul M_DEVBUF, M_NOWAIT); 115076479Swpaul if (entry == NULL) { 115176479Swpaul printf("nge%d: no memory for jumbo " 115276479Swpaul "buffer queue!\n", sc->nge_unit); 115376479Swpaul return(ENOBUFS); 115476479Swpaul } 115576479Swpaul entry->slot = i; 115676479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, 115776479Swpaul entry, jpool_entries); 115876479Swpaul } 115976479Swpaul 116076479Swpaul return(0); 116176479Swpaul} 116276479Swpaul 116376479Swpaulstatic void nge_free_jumbo_mem(sc) 116476479Swpaul struct nge_softc *sc; 116576479Swpaul{ 116676479Swpaul register int i; 116776479Swpaul struct nge_jpool_entry *entry; 116876479Swpaul 116976479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 117076479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 117178440Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 117276479Swpaul free(entry, M_DEVBUF); 117376479Swpaul } 117476479Swpaul 117576479Swpaul contigfree(sc->nge_cdata.nge_jumbo_buf, NGE_JMEM, M_DEVBUF); 117676479Swpaul 117776479Swpaul return; 117876479Swpaul} 117976479Swpaul 118076479Swpaul/* 118176479Swpaul * Allocate a jumbo buffer. 118276479Swpaul */ 118376479Swpaulstatic void *nge_jalloc(sc) 118476479Swpaul struct nge_softc *sc; 118576479Swpaul{ 118676479Swpaul struct nge_jpool_entry *entry; 118776479Swpaul 118876479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 118976479Swpaul 119076479Swpaul if (entry == NULL) { 119176479Swpaul#ifdef NGE_VERBOSE 119276479Swpaul printf("nge%d: no free jumbo buffers\n", sc->nge_unit); 119376479Swpaul#endif 119476479Swpaul return(NULL); 119576479Swpaul } 119676479Swpaul 119776479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 119876479Swpaul SLIST_INSERT_HEAD(&sc->nge_jinuse_listhead, entry, jpool_entries); 119976479Swpaul return(sc->nge_cdata.nge_jslots[entry->slot]); 120076479Swpaul} 120176479Swpaul 120276479Swpaul/* 120376479Swpaul * Release a jumbo buffer. 120476479Swpaul */ 120576479Swpaulstatic void nge_jfree(buf, args) 120676479Swpaul caddr_t buf; 120776479Swpaul void *args; 120876479Swpaul{ 120976479Swpaul struct nge_softc *sc; 121076479Swpaul int i; 121176479Swpaul struct nge_jpool_entry *entry; 121276479Swpaul 121376479Swpaul /* Extract the softc struct pointer. */ 121476479Swpaul sc = args; 121576479Swpaul 121676479Swpaul if (sc == NULL) 121776479Swpaul panic("nge_jfree: can't find softc pointer!"); 121876479Swpaul 121976479Swpaul /* calculate the slot this buffer belongs to */ 122076479Swpaul i = ((vm_offset_t)buf 122176479Swpaul - (vm_offset_t)sc->nge_cdata.nge_jumbo_buf) / NGE_JLEN; 122276479Swpaul 122376479Swpaul if ((i < 0) || (i >= NGE_JSLOTS)) 122476479Swpaul panic("nge_jfree: asked to free buffer that we don't manage!"); 122576479Swpaul 122676479Swpaul entry = SLIST_FIRST(&sc->nge_jinuse_listhead); 122776479Swpaul if (entry == NULL) 122876479Swpaul panic("nge_jfree: buffer not in use!"); 122976479Swpaul entry->slot = i; 123076479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jinuse_listhead, jpool_entries); 123176479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, entry, jpool_entries); 123276479Swpaul 123376479Swpaul return; 123476479Swpaul} 123576479Swpaul/* 123676479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 123776479Swpaul * the higher level protocols. 123876479Swpaul */ 123976479Swpaulstatic void nge_rxeof(sc) 124076479Swpaul struct nge_softc *sc; 124176479Swpaul{ 124276479Swpaul struct ether_header *eh; 124376479Swpaul struct mbuf *m; 124476479Swpaul struct ifnet *ifp; 124576479Swpaul struct nge_desc *cur_rx; 124676479Swpaul int i, total_len = 0; 124776479Swpaul u_int32_t rxstat; 124876479Swpaul 124976479Swpaul ifp = &sc->arpcom.ac_if; 125076479Swpaul i = sc->nge_cdata.nge_rx_prod; 125176479Swpaul 125276479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 125376479Swpaul struct mbuf *m0 = NULL; 125476479Swpaul u_int32_t extsts; 125576479Swpaul 125676479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 125776479Swpaul rxstat = cur_rx->nge_rxstat; 125876479Swpaul extsts = cur_rx->nge_extsts; 125976479Swpaul m = cur_rx->nge_mbuf; 126076479Swpaul cur_rx->nge_mbuf = NULL; 126176479Swpaul total_len = NGE_RXBYTES(cur_rx); 126276479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 126376479Swpaul 126476479Swpaul /* 126576479Swpaul * If an error occurs, update stats, clear the 126676479Swpaul * status word and leave the mbuf cluster in place: 126776479Swpaul * it should simply get re-used next time this descriptor 126876479Swpaul * comes up in the ring. 126976479Swpaul */ 127076479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 127176479Swpaul ifp->if_ierrors++; 127276479Swpaul nge_newbuf(sc, cur_rx, m); 127376479Swpaul continue; 127476479Swpaul } 127576479Swpaul 127676479Swpaul 127776479Swpaul /* 127876479Swpaul * Ok. NatSemi really screwed up here. This is the 127976479Swpaul * only gigE chip I know of with alignment constraints 128076479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 128176479Swpaul */ 128279562Swpaul#ifdef __i386__ 128379562Swpaul /* 128479562Swpaul * By popular demand, ignore the alignment problems 128579562Swpaul * on the Intel x86 platform. The performance hit 128679562Swpaul * incurred due to unaligned accesses is much smaller 128779562Swpaul * than the hit produced by forcing buffer copies all 128879562Swpaul * the time, especially with jumbo frames. We still 128979562Swpaul * need to fix up the alignment everywhere else though. 129079562Swpaul */ 129179562Swpaul if (nge_newbuf(sc, cur_rx, NULL) == ENOBUFS) { 129279562Swpaul#endif 129379562Swpaul m0 = m_devget(mtod(m, char *), total_len, 129479562Swpaul ETHER_ALIGN, ifp, NULL); 129579562Swpaul nge_newbuf(sc, cur_rx, m); 129679562Swpaul if (m0 == NULL) { 129779562Swpaul printf("nge%d: no receive buffers " 129879562Swpaul "available -- packet dropped!\n", 129979562Swpaul sc->nge_unit); 130079562Swpaul ifp->if_ierrors++; 130179562Swpaul continue; 130279562Swpaul } 130379562Swpaul m = m0; 130479562Swpaul#ifdef __i386__ 130579562Swpaul } else { 130679562Swpaul m->m_pkthdr.rcvif = ifp; 130779562Swpaul m->m_pkthdr.len = m->m_len = total_len; 130876479Swpaul } 130979562Swpaul#endif 131076479Swpaul 131176479Swpaul ifp->if_ipackets++; 131276479Swpaul eh = mtod(m, struct ether_header *); 131376479Swpaul 131476479Swpaul /* Remove header from mbuf and pass it on. */ 131576479Swpaul m_adj(m, sizeof(struct ether_header)); 131676479Swpaul 131776479Swpaul /* Do IP checksum checking. */ 131878323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 131978323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 132078323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 132178323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 132278323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 132378323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 132478323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 132578323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 132678323Swpaul m->m_pkthdr.csum_flags |= 132778323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 132878323Swpaul m->m_pkthdr.csum_data = 0xffff; 132978323Swpaul } 133076479Swpaul 133176479Swpaul /* 133276479Swpaul * If we received a packet with a vlan tag, pass it 133376479Swpaul * to vlan_input() instead of ether_input(). 133476479Swpaul */ 133576479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 133687276Sbrooks VLAN_INPUT_TAG(eh, m, extsts & NGE_RXEXTSTS_VTCI); 133776479Swpaul continue; 133876479Swpaul } 133976479Swpaul 134076479Swpaul ether_input(ifp, eh, m); 134176479Swpaul } 134276479Swpaul 134376479Swpaul sc->nge_cdata.nge_rx_prod = i; 134476479Swpaul 134576479Swpaul return; 134676479Swpaul} 134776479Swpaul 134876479Swpaul/* 134976479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 135076479Swpaul * the list buffers. 135176479Swpaul */ 135276479Swpaul 135376479Swpaulstatic void nge_txeof(sc) 135476479Swpaul struct nge_softc *sc; 135576479Swpaul{ 135676479Swpaul struct nge_desc *cur_tx = NULL; 135776479Swpaul struct ifnet *ifp; 135876479Swpaul u_int32_t idx; 135976479Swpaul 136076479Swpaul ifp = &sc->arpcom.ac_if; 136176479Swpaul 136276479Swpaul /* Clear the timeout timer. */ 136376479Swpaul ifp->if_timer = 0; 136476479Swpaul 136576479Swpaul /* 136676479Swpaul * Go through our tx list and free mbufs for those 136776479Swpaul * frames that have been transmitted. 136876479Swpaul */ 136976479Swpaul idx = sc->nge_cdata.nge_tx_cons; 137076479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 137176479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 137276479Swpaul 137376479Swpaul if (NGE_OWNDESC(cur_tx)) 137476479Swpaul break; 137576479Swpaul 137676479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 137776479Swpaul sc->nge_cdata.nge_tx_cnt--; 137876479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 137976479Swpaul continue; 138076479Swpaul } 138176479Swpaul 138276479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 138376479Swpaul ifp->if_oerrors++; 138476479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 138576479Swpaul ifp->if_collisions++; 138676479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 138776479Swpaul ifp->if_collisions++; 138876479Swpaul } 138976479Swpaul 139076479Swpaul ifp->if_collisions += 139176479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 139276479Swpaul 139376479Swpaul ifp->if_opackets++; 139476479Swpaul if (cur_tx->nge_mbuf != NULL) { 139576479Swpaul m_freem(cur_tx->nge_mbuf); 139676479Swpaul cur_tx->nge_mbuf = NULL; 139776479Swpaul } 139876479Swpaul 139976479Swpaul sc->nge_cdata.nge_tx_cnt--; 140076479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 140176479Swpaul ifp->if_timer = 0; 140276479Swpaul } 140376479Swpaul 140476479Swpaul sc->nge_cdata.nge_tx_cons = idx; 140576479Swpaul 140676479Swpaul if (cur_tx != NULL) 140776479Swpaul ifp->if_flags &= ~IFF_OACTIVE; 140876479Swpaul 140976479Swpaul return; 141076479Swpaul} 141176479Swpaul 141276479Swpaulstatic void nge_tick(xsc) 141376479Swpaul void *xsc; 141476479Swpaul{ 141576479Swpaul struct nge_softc *sc; 141676479Swpaul struct mii_data *mii; 141776479Swpaul struct ifnet *ifp; 141876479Swpaul int s; 141976479Swpaul 142076479Swpaul s = splimp(); 142176479Swpaul 142276479Swpaul sc = xsc; 142376479Swpaul ifp = &sc->arpcom.ac_if; 142476479Swpaul 142576479Swpaul mii = device_get_softc(sc->nge_miibus); 142676479Swpaul mii_tick(mii); 142776479Swpaul 142876479Swpaul if (!sc->nge_link) { 142976479Swpaul if (mii->mii_media_status & IFM_ACTIVE && 143076479Swpaul IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 143176479Swpaul sc->nge_link++; 143295673Sphk if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) 143376479Swpaul printf("nge%d: gigabit link up\n", 143476479Swpaul sc->nge_unit); 143576479Swpaul if (ifp->if_snd.ifq_head != NULL) 143676479Swpaul nge_start(ifp); 143796028Sphk } 143876479Swpaul } 143996028Sphk sc->nge_stat_ch = timeout(nge_tick, sc, hz); 144076479Swpaul 144176479Swpaul splx(s); 144276479Swpaul 144376479Swpaul return; 144476479Swpaul} 144576479Swpaul 144676479Swpaulstatic void nge_intr(arg) 144776479Swpaul void *arg; 144876479Swpaul{ 144976479Swpaul struct nge_softc *sc; 145076479Swpaul struct ifnet *ifp; 145176479Swpaul u_int32_t status; 145276479Swpaul 145376479Swpaul sc = arg; 145476479Swpaul ifp = &sc->arpcom.ac_if; 145576479Swpaul 145676479Swpaul /* Supress unwanted interrupts */ 145776479Swpaul if (!(ifp->if_flags & IFF_UP)) { 145876479Swpaul nge_stop(sc); 145976479Swpaul return; 146076479Swpaul } 146176479Swpaul 146276479Swpaul /* Disable interrupts. */ 146376479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 146476479Swpaul 146576479Swpaul for (;;) { 146676479Swpaul /* Reading the ISR register clears all interrupts. */ 146776479Swpaul status = CSR_READ_4(sc, NGE_ISR); 146876479Swpaul 146976479Swpaul if ((status & NGE_INTRS) == 0) 147076479Swpaul break; 147176479Swpaul 147276479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 147376479Swpaul (status & NGE_ISR_TX_ERR) || 147476479Swpaul (status & NGE_ISR_TX_OK) || 147576479Swpaul (status & NGE_ISR_TX_IDLE)) 147676479Swpaul nge_txeof(sc); 147776479Swpaul 147876479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 147979798Swpaul (status & NGE_ISR_RX_ERR) || 148083678Swpaul (status & NGE_ISR_RX_OFLOW) || 148194612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 148294612Sphk (status & NGE_ISR_RX_IDLE) || 148376479Swpaul (status & NGE_ISR_RX_OK)) 148476479Swpaul nge_rxeof(sc); 148594612Sphk 148694612Sphk if ((status & NGE_ISR_RX_IDLE)) 148794612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 148894612Sphk 148976479Swpaul if (status & NGE_ISR_SYSERR) { 149076479Swpaul nge_reset(sc); 149176479Swpaul ifp->if_flags &= ~IFF_RUNNING; 149276479Swpaul nge_init(sc); 149376479Swpaul } 149476479Swpaul 149596028Sphk#if 0 149696028Sphk /* 149796028Sphk * XXX: nge_tick() is not ready to be called this way 149896028Sphk * it screws up the aneg timeout because mii_tick() is 149996028Sphk * only to be called once per second. 150096028Sphk */ 150176479Swpaul if (status & NGE_IMR_PHY_INTR) { 150276479Swpaul sc->nge_link = 0; 150376479Swpaul nge_tick(sc); 150476479Swpaul } 150596028Sphk#endif 150676479Swpaul } 150776479Swpaul 150876479Swpaul /* Re-enable interrupts. */ 150976479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 151076479Swpaul 151176479Swpaul if (ifp->if_snd.ifq_head != NULL) 151276479Swpaul nge_start(ifp); 151376479Swpaul 151476479Swpaul return; 151576479Swpaul} 151676479Swpaul 151776479Swpaul/* 151876479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 151976479Swpaul * pointers to the fragment pointers. 152076479Swpaul */ 152176479Swpaulstatic int nge_encap(sc, m_head, txidx) 152276479Swpaul struct nge_softc *sc; 152376479Swpaul struct mbuf *m_head; 152476479Swpaul u_int32_t *txidx; 152576479Swpaul{ 152676479Swpaul struct nge_desc *f = NULL; 152776479Swpaul struct mbuf *m; 152876479Swpaul int frag, cur, cnt = 0; 152976479Swpaul struct ifvlan *ifv = NULL; 153076479Swpaul 153176479Swpaul if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && 153276479Swpaul m_head->m_pkthdr.rcvif != NULL && 153380307Sbrooks m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) 153476479Swpaul ifv = m_head->m_pkthdr.rcvif->if_softc; 153576479Swpaul 153676479Swpaul /* 153776479Swpaul * Start packing the mbufs in this chain into 153876479Swpaul * the fragment pointers. Stop when we run out 153976479Swpaul * of fragments or hit the end of the mbuf chain. 154076479Swpaul */ 154176479Swpaul m = m_head; 154276479Swpaul cur = frag = *txidx; 154376479Swpaul 154476479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 154576479Swpaul if (m->m_len != 0) { 154676479Swpaul if ((NGE_TX_LIST_CNT - 154776479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 154876479Swpaul return(ENOBUFS); 154976479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 155076479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 155176479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 155276479Swpaul if (cnt != 0) 155376479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 155476479Swpaul cur = frag; 155576479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 155676479Swpaul cnt++; 155776479Swpaul } 155876479Swpaul } 155976479Swpaul 156076479Swpaul if (m != NULL) 156176479Swpaul return(ENOBUFS); 156276479Swpaul 156378286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 156476479Swpaul if (m_head->m_pkthdr.csum_flags) { 156576479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 156678286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 156776479Swpaul NGE_TXEXTSTS_IPCSUM; 156876479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 156978286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 157076479Swpaul NGE_TXEXTSTS_TCPCSUM; 157176479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 157278286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 157376479Swpaul NGE_TXEXTSTS_UDPCSUM; 157476479Swpaul } 157576479Swpaul 157676479Swpaul if (ifv != NULL) { 157776479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 157876479Swpaul (NGE_TXEXTSTS_VLANPKT|ifv->ifv_tag); 157976479Swpaul } 158076479Swpaul 158176479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 158276479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 158376479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 158476479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 158576479Swpaul *txidx = frag; 158676479Swpaul 158776479Swpaul return(0); 158876479Swpaul} 158976479Swpaul 159076479Swpaul/* 159176479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 159276479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 159376479Swpaul * copy of the pointers since the transmit list fragment pointers are 159476479Swpaul * physical addresses. 159576479Swpaul */ 159676479Swpaul 159776479Swpaulstatic void nge_start(ifp) 159876479Swpaul struct ifnet *ifp; 159976479Swpaul{ 160076479Swpaul struct nge_softc *sc; 160176479Swpaul struct mbuf *m_head = NULL; 160276479Swpaul u_int32_t idx; 160376479Swpaul 160476479Swpaul sc = ifp->if_softc; 160576479Swpaul 160676479Swpaul if (!sc->nge_link) 160776479Swpaul return; 160876479Swpaul 160976479Swpaul idx = sc->nge_cdata.nge_tx_prod; 161076479Swpaul 161176479Swpaul if (ifp->if_flags & IFF_OACTIVE) 161276479Swpaul return; 161376479Swpaul 161476479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 161576479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 161676479Swpaul if (m_head == NULL) 161776479Swpaul break; 161876479Swpaul 161976479Swpaul if (nge_encap(sc, m_head, &idx)) { 162076479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 162176479Swpaul ifp->if_flags |= IFF_OACTIVE; 162276479Swpaul break; 162376479Swpaul } 162476479Swpaul 162576479Swpaul /* 162676479Swpaul * If there's a BPF listener, bounce a copy of this frame 162776479Swpaul * to him. 162876479Swpaul */ 162976479Swpaul if (ifp->if_bpf) 163076479Swpaul bpf_mtap(ifp, m_head); 163176479Swpaul 163276479Swpaul } 163376479Swpaul 163476479Swpaul /* Transmit */ 163576479Swpaul sc->nge_cdata.nge_tx_prod = idx; 163676479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 163776479Swpaul 163876479Swpaul /* 163976479Swpaul * Set a timeout in case the chip goes out to lunch. 164076479Swpaul */ 164176479Swpaul ifp->if_timer = 5; 164276479Swpaul 164376479Swpaul return; 164476479Swpaul} 164576479Swpaul 164676479Swpaulstatic void nge_init(xsc) 164776479Swpaul void *xsc; 164876479Swpaul{ 164976479Swpaul struct nge_softc *sc = xsc; 165076479Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 165176479Swpaul struct mii_data *mii; 165276479Swpaul int s; 165376479Swpaul 165476479Swpaul if (ifp->if_flags & IFF_RUNNING) 165576479Swpaul return; 165676479Swpaul 165776479Swpaul s = splimp(); 165876479Swpaul 165976479Swpaul /* 166076479Swpaul * Cancel pending I/O and free all RX/TX buffers. 166176479Swpaul */ 166276479Swpaul nge_stop(sc); 166376479Swpaul 166476479Swpaul mii = device_get_softc(sc->nge_miibus); 166576479Swpaul 166676479Swpaul /* Set MAC address */ 166776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 166876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 166976479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 167076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 167176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 167276479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 167376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 167476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 167576479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 167676479Swpaul 167776479Swpaul /* Init circular RX list. */ 167876479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 167976479Swpaul printf("nge%d: initialization failed: no " 168076479Swpaul "memory for rx buffers\n", sc->nge_unit); 168176479Swpaul nge_stop(sc); 168276479Swpaul (void)splx(s); 168376479Swpaul return; 168476479Swpaul } 168576479Swpaul 168676479Swpaul /* 168776479Swpaul * Init tx descriptors. 168876479Swpaul */ 168976479Swpaul nge_list_tx_init(sc); 169076479Swpaul 169176479Swpaul /* 169276479Swpaul * For the NatSemi chip, we have to explicitly enable the 169376479Swpaul * reception of ARP frames, as well as turn on the 'perfect 169476479Swpaul * match' filter where we store the station address, otherwise 169576479Swpaul * we won't receive unicasts meant for this host. 169676479Swpaul */ 169776479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 169876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 169976479Swpaul 170076479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 170176479Swpaul if (ifp->if_flags & IFF_PROMISC) { 170276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 170376479Swpaul } else { 170476479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 170576479Swpaul } 170676479Swpaul 170776479Swpaul /* 170876479Swpaul * Set the capture broadcast bit to capture broadcast frames. 170976479Swpaul */ 171076479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 171176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 171276479Swpaul } else { 171376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 171476479Swpaul } 171576479Swpaul 171676479Swpaul /* 171776479Swpaul * Load the multicast filter. 171876479Swpaul */ 171976479Swpaul nge_setmulti(sc); 172076479Swpaul 172176479Swpaul /* Turn the receive filter on */ 172276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 172376479Swpaul 172476479Swpaul /* 172576479Swpaul * Load the address of the RX and TX lists. 172676479Swpaul */ 172776479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 172876479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 172976479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 173076479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 173176479Swpaul 173276479Swpaul /* Set RX configuration */ 173376479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 173476479Swpaul /* 173576479Swpaul * Enable hardware checksum validation for all IPv4 173676479Swpaul * packets, do not reject packets with bad checksums. 173776479Swpaul */ 173878323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 173976479Swpaul 174076479Swpaul /* 174183115Sbrooks * Tell the chip to detect and strip VLAN tag info from 174283115Sbrooks * received frames. The tag will be provided in the extsts 174383115Sbrooks * field in the RX descriptors. 174476479Swpaul */ 174576479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 174676479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 174776479Swpaul 174876479Swpaul /* Set TX configuration */ 174976479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 175076479Swpaul 175176479Swpaul /* 175276479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 175376479Swpaul */ 175478323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 175576479Swpaul 175676479Swpaul /* 175783115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 175883115Sbrooks * dictated by the code in the frame encapsulation routine. 175976479Swpaul */ 176076479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 176176479Swpaul 176276479Swpaul /* Set full/half duplex mode. */ 176376479Swpaul if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 176476479Swpaul NGE_SETBIT(sc, NGE_TX_CFG, 176576479Swpaul (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 176676479Swpaul NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 176776479Swpaul } else { 176876479Swpaul NGE_CLRBIT(sc, NGE_TX_CFG, 176976479Swpaul (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 177076479Swpaul NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 177176479Swpaul } 177276479Swpaul 177396028Sphk nge_tick(sc); 177496028Sphk 177576479Swpaul /* 177676479Swpaul * Enable the delivery of PHY interrupts based on 177777842Swpaul * link/speed/duplex status changes. Also enable the 177877842Swpaul * extsts field in the DMA descriptors (needed for 177977842Swpaul * TCP/IP checksum offload on transmit). 178076479Swpaul */ 178179424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 178277842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 178376479Swpaul 178476479Swpaul /* 178579562Swpaul * Configure interrupt holdoff (moderation). We can 178679562Swpaul * have the chip delay interrupt delivery for a certain 178779562Swpaul * period. Units are in 100us, and the max setting 178879562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 178979562Swpaul */ 179079562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 179179562Swpaul 179279562Swpaul /* 179376479Swpaul * Enable interrupts. 179476479Swpaul */ 179576479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 179676479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 179776479Swpaul 179876479Swpaul /* Enable receiver and transmitter. */ 179976479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 180076479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 180176479Swpaul 180276479Swpaul nge_ifmedia_upd(ifp); 180376479Swpaul 180476479Swpaul ifp->if_flags |= IFF_RUNNING; 180576479Swpaul ifp->if_flags &= ~IFF_OACTIVE; 180676479Swpaul 180776479Swpaul (void)splx(s); 180876479Swpaul 180976479Swpaul return; 181076479Swpaul} 181176479Swpaul 181276479Swpaul/* 181376479Swpaul * Set media options. 181476479Swpaul */ 181576479Swpaulstatic int nge_ifmedia_upd(ifp) 181676479Swpaul struct ifnet *ifp; 181776479Swpaul{ 181876479Swpaul struct nge_softc *sc; 181976479Swpaul struct mii_data *mii; 182076479Swpaul 182176479Swpaul sc = ifp->if_softc; 182276479Swpaul 182376479Swpaul mii = device_get_softc(sc->nge_miibus); 182476479Swpaul sc->nge_link = 0; 182576479Swpaul if (mii->mii_instance) { 182676479Swpaul struct mii_softc *miisc; 182776479Swpaul for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 182876479Swpaul miisc = LIST_NEXT(miisc, mii_list)) 182976479Swpaul mii_phy_reset(miisc); 183076479Swpaul } 183176479Swpaul mii_mediachg(mii); 183276479Swpaul 183376479Swpaul return(0); 183476479Swpaul} 183576479Swpaul 183676479Swpaul/* 183776479Swpaul * Report current media status. 183876479Swpaul */ 183976479Swpaulstatic void nge_ifmedia_sts(ifp, ifmr) 184076479Swpaul struct ifnet *ifp; 184176479Swpaul struct ifmediareq *ifmr; 184276479Swpaul{ 184376479Swpaul struct nge_softc *sc; 184476479Swpaul struct mii_data *mii; 184576479Swpaul 184676479Swpaul sc = ifp->if_softc; 184776479Swpaul 184876479Swpaul mii = device_get_softc(sc->nge_miibus); 184976479Swpaul mii_pollstat(mii); 185076479Swpaul ifmr->ifm_active = mii->mii_media_active; 185176479Swpaul ifmr->ifm_status = mii->mii_media_status; 185276479Swpaul 185376479Swpaul return; 185476479Swpaul} 185576479Swpaul 185676479Swpaulstatic int nge_ioctl(ifp, command, data) 185776479Swpaul struct ifnet *ifp; 185876479Swpaul u_long command; 185976479Swpaul caddr_t data; 186076479Swpaul{ 186176479Swpaul struct nge_softc *sc = ifp->if_softc; 186276479Swpaul struct ifreq *ifr = (struct ifreq *) data; 186376479Swpaul struct mii_data *mii; 186476479Swpaul int s, error = 0; 186576479Swpaul 186676479Swpaul s = splimp(); 186776479Swpaul 186876479Swpaul switch(command) { 186976479Swpaul case SIOCSIFADDR: 187076479Swpaul case SIOCGIFADDR: 187176479Swpaul error = ether_ioctl(ifp, command, data); 187276479Swpaul break; 187376479Swpaul case SIOCSIFMTU: 187476479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 187576479Swpaul error = EINVAL; 187678323Swpaul else { 187776479Swpaul ifp->if_mtu = ifr->ifr_mtu; 187878323Swpaul /* 187978323Swpaul * Workaround: if the MTU is larger than 188078323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 188178323Swpaul * TX checksum offloading. 188278323Swpaul */ 188378324Swpaul if (ifr->ifr_mtu >= 8152) 188478323Swpaul ifp->if_hwassist = 0; 188578323Swpaul else 188678323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 188778323Swpaul } 188876479Swpaul break; 188976479Swpaul case SIOCSIFFLAGS: 189076479Swpaul if (ifp->if_flags & IFF_UP) { 189176479Swpaul if (ifp->if_flags & IFF_RUNNING && 189276479Swpaul ifp->if_flags & IFF_PROMISC && 189376479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 189476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 189576479Swpaul NGE_RXFILTCTL_ALLPHYS| 189676479Swpaul NGE_RXFILTCTL_ALLMULTI); 189776479Swpaul } else if (ifp->if_flags & IFF_RUNNING && 189876479Swpaul !(ifp->if_flags & IFF_PROMISC) && 189976479Swpaul sc->nge_if_flags & IFF_PROMISC) { 190076479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 190176479Swpaul NGE_RXFILTCTL_ALLPHYS); 190276479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 190376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 190476479Swpaul NGE_RXFILTCTL_ALLMULTI); 190576479Swpaul } else { 190676479Swpaul ifp->if_flags &= ~IFF_RUNNING; 190776479Swpaul nge_init(sc); 190876479Swpaul } 190976479Swpaul } else { 191076479Swpaul if (ifp->if_flags & IFF_RUNNING) 191176479Swpaul nge_stop(sc); 191276479Swpaul } 191376479Swpaul sc->nge_if_flags = ifp->if_flags; 191476479Swpaul error = 0; 191576479Swpaul break; 191676479Swpaul case SIOCADDMULTI: 191776479Swpaul case SIOCDELMULTI: 191876479Swpaul nge_setmulti(sc); 191976479Swpaul error = 0; 192076479Swpaul break; 192176479Swpaul case SIOCGIFMEDIA: 192276479Swpaul case SIOCSIFMEDIA: 192376479Swpaul mii = device_get_softc(sc->nge_miibus); 192476479Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 192576479Swpaul break; 192676479Swpaul default: 192776479Swpaul error = EINVAL; 192876479Swpaul break; 192976479Swpaul } 193076479Swpaul 193176479Swpaul (void)splx(s); 193276479Swpaul 193376479Swpaul return(error); 193476479Swpaul} 193576479Swpaul 193676479Swpaulstatic void nge_watchdog(ifp) 193776479Swpaul struct ifnet *ifp; 193876479Swpaul{ 193976479Swpaul struct nge_softc *sc; 194076479Swpaul 194176479Swpaul sc = ifp->if_softc; 194276479Swpaul 194376479Swpaul ifp->if_oerrors++; 194476479Swpaul printf("nge%d: watchdog timeout\n", sc->nge_unit); 194576479Swpaul 194676479Swpaul nge_stop(sc); 194776479Swpaul nge_reset(sc); 194876479Swpaul ifp->if_flags &= ~IFF_RUNNING; 194976479Swpaul nge_init(sc); 195076479Swpaul 195176479Swpaul if (ifp->if_snd.ifq_head != NULL) 195276479Swpaul nge_start(ifp); 195376479Swpaul 195476479Swpaul return; 195576479Swpaul} 195676479Swpaul 195776479Swpaul/* 195876479Swpaul * Stop the adapter and free any mbufs allocated to the 195976479Swpaul * RX and TX lists. 196076479Swpaul */ 196176479Swpaulstatic void nge_stop(sc) 196276479Swpaul struct nge_softc *sc; 196376479Swpaul{ 196476479Swpaul register int i; 196576479Swpaul struct ifnet *ifp; 196676479Swpaul struct mii_data *mii; 196776479Swpaul 196876479Swpaul ifp = &sc->arpcom.ac_if; 196976479Swpaul ifp->if_timer = 0; 197076479Swpaul mii = device_get_softc(sc->nge_miibus); 197176479Swpaul 197276479Swpaul untimeout(nge_tick, sc, sc->nge_stat_ch); 197376479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 197476479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 197576479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 197676479Swpaul DELAY(1000); 197776479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 197876479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 197976479Swpaul 198095722Sphk mii_down(mii); 198176479Swpaul 198276479Swpaul sc->nge_link = 0; 198376479Swpaul 198476479Swpaul /* 198576479Swpaul * Free data in the RX lists. 198676479Swpaul */ 198776479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 198876479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 198976479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 199076479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 199176479Swpaul } 199276479Swpaul } 199376479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 199476479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 199576479Swpaul 199676479Swpaul /* 199776479Swpaul * Free the TX list buffers. 199876479Swpaul */ 199976479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 200076479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 200176479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 200276479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 200376479Swpaul } 200476479Swpaul } 200576479Swpaul 200676479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 200776479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 200876479Swpaul 200976479Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 201076479Swpaul 201176479Swpaul return; 201276479Swpaul} 201376479Swpaul 201476479Swpaul/* 201576479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 201676479Swpaul * get confused by errant DMAs when rebooting. 201776479Swpaul */ 201876479Swpaulstatic void nge_shutdown(dev) 201976479Swpaul device_t dev; 202076479Swpaul{ 202176479Swpaul struct nge_softc *sc; 202276479Swpaul 202376479Swpaul sc = device_get_softc(dev); 202476479Swpaul 202576479Swpaul nge_reset(sc); 202676479Swpaul nge_stop(sc); 202776479Swpaul 202876479Swpaul return; 202976479Swpaul} 2030