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