if_nge.c revision 113506
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 3476479Swpaul/* 3576479Swpaul * National Semiconductor DP83820/DP83821 gigabit ethernet driver 3676479Swpaul * for FreeBSD. Datasheets are available from: 3776479Swpaul * 3876479Swpaul * http://www.national.com/ds/DP/DP83820.pdf 3976479Swpaul * http://www.national.com/ds/DP/DP83821.pdf 4076479Swpaul * 4176479Swpaul * These chips are used on several low cost gigabit ethernet NICs 4276479Swpaul * sold by D-Link, Addtron, SMC and Asante. Both parts are 4376479Swpaul * virtually the same, except the 83820 is a 64-bit/32-bit part, 4476479Swpaul * while the 83821 is 32-bit only. 4576479Swpaul * 4676479Swpaul * Many cards also use National gigE transceivers, such as the 4776479Swpaul * DP83891, DP83861 and DP83862 gigPHYTER parts. The DP83861 datasheet 4876479Swpaul * contains a full register description that applies to all of these 4976479Swpaul * components: 5076479Swpaul * 5176479Swpaul * http://www.national.com/ds/DP/DP83861.pdf 5276479Swpaul * 5376479Swpaul * Written by Bill Paul <wpaul@bsdi.com> 5476479Swpaul * BSDi Open Source Solutions 5576479Swpaul */ 5676479Swpaul 5776479Swpaul/* 5876479Swpaul * The NatSemi DP83820 and 83821 controllers are enhanced versions 5976479Swpaul * of the NatSemi MacPHYTER 10/100 devices. They support 10, 100 6076479Swpaul * and 1000Mbps speeds with 1000baseX (ten bit interface), MII and GMII 6176479Swpaul * ports. Other features include 8K TX FIFO and 32K RX FIFO, TCP/IP 6276479Swpaul * hardware checksum offload (IPv4 only), VLAN tagging and filtering, 6376479Swpaul * priority TX and RX queues, a 2048 bit multicast hash filter, 4 RX pattern 6476479Swpaul * matching buffers, one perfect address filter buffer and interrupt 6576479Swpaul * moderation. The 83820 supports both 64-bit and 32-bit addressing 6676479Swpaul * and data transfers: the 64-bit support can be toggled on or off 6776479Swpaul * via software. This affects the size of certain fields in the DMA 6876479Swpaul * descriptors. 6976479Swpaul * 7078323Swpaul * There are two bugs/misfeatures in the 83820/83821 that I have 7178323Swpaul * discovered so far: 7278323Swpaul * 7378323Swpaul * - Receive buffers must be aligned on 64-bit boundaries, which means 7478323Swpaul * you must resort to copying data in order to fix up the payload 7578323Swpaul * alignment. 7678323Swpaul * 7778323Swpaul * - In order to transmit jumbo frames larger than 8170 bytes, you have 7878323Swpaul * to turn off transmit checksum offloading, because the chip can't 7978323Swpaul * compute the checksum on an outgoing frame unless it fits entirely 8078323Swpaul * within the TX FIFO, which is only 8192 bytes in size. If you have 8178323Swpaul * TX checksum offload enabled and you transmit attempt to transmit a 8278323Swpaul * frame larger than 8170 bytes, the transmitter will wedge. 8378323Swpaul * 8478323Swpaul * To work around the latter problem, TX checksum offload is disabled 8578323Swpaul * if the user selects an MTU larger than 8152 (8170 - 18). 8676479Swpaul */ 8776479Swpaul 88113038Sobrien#include <sys/cdefs.h> 89113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/nge/if_nge.c 113506 2003-04-15 06:37:30Z mdodd $"); 90113038Sobrien 9176479Swpaul#include <sys/param.h> 9276479Swpaul#include <sys/systm.h> 9376479Swpaul#include <sys/sockio.h> 9476479Swpaul#include <sys/mbuf.h> 9576479Swpaul#include <sys/malloc.h> 9676479Swpaul#include <sys/kernel.h> 9776479Swpaul#include <sys/socket.h> 9876479Swpaul 9976479Swpaul#include <net/if.h> 10076479Swpaul#include <net/if_arp.h> 10176479Swpaul#include <net/ethernet.h> 10276479Swpaul#include <net/if_dl.h> 10376479Swpaul#include <net/if_media.h> 10476479Swpaul#include <net/if_types.h> 10576479Swpaul#include <net/if_vlan_var.h> 10676479Swpaul 10776479Swpaul#include <net/bpf.h> 10876479Swpaul 10976479Swpaul#include <vm/vm.h> /* for vtophys */ 11076479Swpaul#include <vm/pmap.h> /* for vtophys */ 11176479Swpaul#include <machine/clock.h> /* for DELAY */ 11276479Swpaul#include <machine/bus_pio.h> 11376479Swpaul#include <machine/bus_memio.h> 11476479Swpaul#include <machine/bus.h> 11576479Swpaul#include <machine/resource.h> 11676479Swpaul#include <sys/bus.h> 11776479Swpaul#include <sys/rman.h> 11876479Swpaul 11976479Swpaul#include <dev/mii/mii.h> 12076479Swpaul#include <dev/mii/miivar.h> 12176479Swpaul 12276479Swpaul#include <pci/pcireg.h> 12376479Swpaul#include <pci/pcivar.h> 12476479Swpaul 12576479Swpaul#define NGE_USEIOSPACE 12676479Swpaul 12776522Swpaul#include <dev/nge/if_ngereg.h> 12876479Swpaul 129113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1); 130113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1); 13176479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1); 13276479Swpaul 13376479Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 13476479Swpaul#include "miibus_if.h" 13576479Swpaul 13676479Swpaul#define NGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 13776479Swpaul 13876479Swpaul/* 13976479Swpaul * Various supported device vendors/types and their names. 14076479Swpaul */ 14176479Swpaulstatic struct nge_type nge_devs[] = { 14276479Swpaul { NGE_VENDORID, NGE_DEVICEID, 14376479Swpaul "National Semiconductor Gigabit Ethernet" }, 14476479Swpaul { 0, 0, NULL } 14576479Swpaul}; 14676479Swpaul 14799497Salfredstatic int nge_probe(device_t); 14899497Salfredstatic int nge_attach(device_t); 14999497Salfredstatic int nge_detach(device_t); 15076479Swpaul 15199497Salfredstatic int nge_alloc_jumbo_mem(struct nge_softc *); 15299497Salfredstatic void nge_free_jumbo_mem(struct nge_softc *); 15399497Salfredstatic void *nge_jalloc(struct nge_softc *); 15499497Salfredstatic void nge_jfree(void *, void *); 15576479Swpaul 15699497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *); 15799497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *); 15899497Salfredstatic void nge_rxeof(struct nge_softc *); 15999497Salfredstatic void nge_txeof(struct nge_softc *); 16099497Salfredstatic void nge_intr(void *); 16199497Salfredstatic void nge_tick(void *); 16299497Salfredstatic void nge_start(struct ifnet *); 16399497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t); 16499497Salfredstatic void nge_init(void *); 16599497Salfredstatic void nge_stop(struct nge_softc *); 16699497Salfredstatic void nge_watchdog(struct ifnet *); 16799497Salfredstatic void nge_shutdown(device_t); 16899497Salfredstatic int nge_ifmedia_upd(struct ifnet *); 16999497Salfredstatic void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 17076479Swpaul 17199497Salfredstatic void nge_delay(struct nge_softc *); 17299497Salfredstatic void nge_eeprom_idle(struct nge_softc *); 17399497Salfredstatic void nge_eeprom_putbyte(struct nge_softc *, int); 17499497Salfredstatic void nge_eeprom_getword(struct nge_softc *, int, u_int16_t *); 17599497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int); 17676479Swpaul 17799497Salfredstatic void nge_mii_sync(struct nge_softc *); 17899497Salfredstatic void nge_mii_send(struct nge_softc *, u_int32_t, int); 17999497Salfredstatic int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *); 18099497Salfredstatic int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *); 18176479Swpaul 18299497Salfredstatic int nge_miibus_readreg(device_t, int, int); 18399497Salfredstatic int nge_miibus_writereg(device_t, int, int, int); 18499497Salfredstatic void nge_miibus_statchg(device_t); 18576479Swpaul 18699497Salfredstatic void nge_setmulti(struct nge_softc *); 18799497Salfredstatic u_int32_t nge_crc(struct nge_softc *, caddr_t); 18899497Salfredstatic void nge_reset(struct nge_softc *); 18999497Salfredstatic int nge_list_rx_init(struct nge_softc *); 19099497Salfredstatic int nge_list_tx_init(struct nge_softc *); 19176479Swpaul 19276479Swpaul#ifdef NGE_USEIOSPACE 19376479Swpaul#define NGE_RES SYS_RES_IOPORT 19476479Swpaul#define NGE_RID NGE_PCI_LOIO 19576479Swpaul#else 19676479Swpaul#define NGE_RES SYS_RES_MEMORY 19776479Swpaul#define NGE_RID NGE_PCI_LOMEM 19876479Swpaul#endif 19976479Swpaul 20076479Swpaulstatic device_method_t nge_methods[] = { 20176479Swpaul /* Device interface */ 20276479Swpaul DEVMETHOD(device_probe, nge_probe), 20376479Swpaul DEVMETHOD(device_attach, nge_attach), 20476479Swpaul DEVMETHOD(device_detach, nge_detach), 20576479Swpaul DEVMETHOD(device_shutdown, nge_shutdown), 20676479Swpaul 20776479Swpaul /* bus interface */ 20876479Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 20976479Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 21076479Swpaul 21176479Swpaul /* MII interface */ 21276479Swpaul DEVMETHOD(miibus_readreg, nge_miibus_readreg), 21376479Swpaul DEVMETHOD(miibus_writereg, nge_miibus_writereg), 21476479Swpaul DEVMETHOD(miibus_statchg, nge_miibus_statchg), 21576479Swpaul 21676479Swpaul { 0, 0 } 21776479Swpaul}; 21876479Swpaul 21976479Swpaulstatic driver_t nge_driver = { 22076479Swpaul "nge", 22176479Swpaul nge_methods, 22276479Swpaul sizeof(struct nge_softc) 22376479Swpaul}; 22476479Swpaul 22576479Swpaulstatic devclass_t nge_devclass; 22676479Swpaul 227113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0); 22876479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0); 22976479Swpaul 23076479Swpaul#define NGE_SETBIT(sc, reg, x) \ 23176479Swpaul CSR_WRITE_4(sc, reg, \ 23276479Swpaul CSR_READ_4(sc, reg) | (x)) 23376479Swpaul 23476479Swpaul#define NGE_CLRBIT(sc, reg, x) \ 23576479Swpaul CSR_WRITE_4(sc, reg, \ 23676479Swpaul CSR_READ_4(sc, reg) & ~(x)) 23776479Swpaul 23876479Swpaul#define SIO_SET(x) \ 239106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x)) 24076479Swpaul 24176479Swpaul#define SIO_CLR(x) \ 242106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x)) 24376479Swpaul 24499497Salfredstatic void 24599497Salfrednge_delay(sc) 24676479Swpaul struct nge_softc *sc; 24776479Swpaul{ 24876479Swpaul int idx; 24976479Swpaul 25076479Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 25176479Swpaul CSR_READ_4(sc, NGE_CSR); 25276479Swpaul 25376479Swpaul return; 25476479Swpaul} 25576479Swpaul 25699497Salfredstatic void 25799497Salfrednge_eeprom_idle(sc) 25876479Swpaul struct nge_softc *sc; 25976479Swpaul{ 26076479Swpaul register int i; 26176479Swpaul 26276479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26376479Swpaul nge_delay(sc); 26476479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26576479Swpaul nge_delay(sc); 26676479Swpaul 26776479Swpaul for (i = 0; i < 25; i++) { 26876479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 26976479Swpaul nge_delay(sc); 27076479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 27176479Swpaul nge_delay(sc); 27276479Swpaul } 27376479Swpaul 27476479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27576479Swpaul nge_delay(sc); 27676479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 27776479Swpaul nge_delay(sc); 27876479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 27976479Swpaul 28076479Swpaul return; 28176479Swpaul} 28276479Swpaul 28376479Swpaul/* 28476479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28576479Swpaul */ 28699497Salfredstatic void 28799497Salfrednge_eeprom_putbyte(sc, addr) 28876479Swpaul struct nge_softc *sc; 28976479Swpaul int addr; 29076479Swpaul{ 29176479Swpaul register int d, i; 29276479Swpaul 29376479Swpaul d = addr | NGE_EECMD_READ; 29476479Swpaul 29576479Swpaul /* 29676479Swpaul * Feed in each bit and stobe the clock. 29776479Swpaul */ 29876479Swpaul for (i = 0x400; i; i >>= 1) { 29976479Swpaul if (d & i) { 30076479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 30176479Swpaul } else { 30276479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 30376479Swpaul } 30476479Swpaul nge_delay(sc); 30576479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30676479Swpaul nge_delay(sc); 30776479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 30876479Swpaul nge_delay(sc); 30976479Swpaul } 31076479Swpaul 31176479Swpaul return; 31276479Swpaul} 31376479Swpaul 31476479Swpaul/* 31576479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 31676479Swpaul */ 31799497Salfredstatic void 31899497Salfrednge_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 */ 36599497Salfredstatic void 36699497Salfrednge_read_eeprom(sc, dest, off, cnt, swap) 36776479Swpaul struct nge_softc *sc; 36876479Swpaul caddr_t dest; 36976479Swpaul int off; 37076479Swpaul int cnt; 37176479Swpaul int swap; 37276479Swpaul{ 37376479Swpaul int i; 37476479Swpaul u_int16_t word = 0, *ptr; 37576479Swpaul 37676479Swpaul for (i = 0; i < cnt; i++) { 37776479Swpaul nge_eeprom_getword(sc, off + i, &word); 37876479Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 37976479Swpaul if (swap) 38076479Swpaul *ptr = ntohs(word); 38176479Swpaul else 38276479Swpaul *ptr = word; 38376479Swpaul } 38476479Swpaul 38576479Swpaul return; 38676479Swpaul} 38776479Swpaul 38876479Swpaul/* 38976479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 39076479Swpaul */ 39199497Salfredstatic void 39299497Salfrednge_mii_sync(sc) 39376479Swpaul struct nge_softc *sc; 39476479Swpaul{ 39576479Swpaul register int i; 39676479Swpaul 39776479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 39876479Swpaul 39976479Swpaul for (i = 0; i < 32; i++) { 40076479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 40176479Swpaul DELAY(1); 40276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40376479Swpaul DELAY(1); 40476479Swpaul } 40576479Swpaul 40676479Swpaul return; 40776479Swpaul} 40876479Swpaul 40976479Swpaul/* 41076479Swpaul * Clock a series of bits through the MII. 41176479Swpaul */ 41299497Salfredstatic void 41399497Salfrednge_mii_send(sc, bits, cnt) 41476479Swpaul struct nge_softc *sc; 41576479Swpaul u_int32_t bits; 41676479Swpaul int cnt; 41776479Swpaul{ 41876479Swpaul int i; 41976479Swpaul 42076479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 42176479Swpaul 42276479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 42376479Swpaul if (bits & i) { 42476479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 42576479Swpaul } else { 42676479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 42776479Swpaul } 42876479Swpaul DELAY(1); 42976479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 43076479Swpaul DELAY(1); 43176479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 43276479Swpaul } 43376479Swpaul} 43476479Swpaul 43576479Swpaul/* 43676479Swpaul * Read an PHY register through the MII. 43776479Swpaul */ 43899497Salfredstatic int 43999497Salfrednge_mii_readreg(sc, frame) 44076479Swpaul struct nge_softc *sc; 44176479Swpaul struct nge_mii_frame *frame; 44276479Swpaul 44376479Swpaul{ 44476479Swpaul int i, ack, s; 44576479Swpaul 44676479Swpaul s = splimp(); 44776479Swpaul 44876479Swpaul /* 44976479Swpaul * Set up frame for RX. 45076479Swpaul */ 45176479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 45276479Swpaul frame->mii_opcode = NGE_MII_READOP; 45376479Swpaul frame->mii_turnaround = 0; 45476479Swpaul frame->mii_data = 0; 45576479Swpaul 45676479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 45776479Swpaul 45876479Swpaul /* 45976479Swpaul * Turn on data xmit. 46076479Swpaul */ 46176479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 46276479Swpaul 46376479Swpaul nge_mii_sync(sc); 46476479Swpaul 46576479Swpaul /* 46676479Swpaul * Send command/address info. 46776479Swpaul */ 46876479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 46976479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 47076479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 47176479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 47276479Swpaul 47376479Swpaul /* Idle bit */ 47476479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 47576479Swpaul DELAY(1); 47676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 47776479Swpaul DELAY(1); 47876479Swpaul 47976479Swpaul /* Turn off xmit. */ 48076479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 48176479Swpaul /* Check for ack */ 48276479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 48376479Swpaul DELAY(1); 484109058Smbr ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 48576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48676479Swpaul DELAY(1); 48776479Swpaul 48876479Swpaul /* 48976479Swpaul * Now try reading data bits. If the ack failed, we still 49076479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 49176479Swpaul */ 49276479Swpaul if (ack) { 49376479Swpaul for(i = 0; i < 16; i++) { 49476479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 49576479Swpaul DELAY(1); 49676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 49776479Swpaul DELAY(1); 49876479Swpaul } 49976479Swpaul goto fail; 50076479Swpaul } 50176479Swpaul 50276479Swpaul for (i = 0x8000; i; i >>= 1) { 50376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 50476479Swpaul DELAY(1); 50576479Swpaul if (!ack) { 50676479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 50776479Swpaul frame->mii_data |= i; 50876479Swpaul DELAY(1); 50976479Swpaul } 51076479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 51176479Swpaul DELAY(1); 51276479Swpaul } 51376479Swpaul 51476479Swpaulfail: 51576479Swpaul 51676479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 51776479Swpaul DELAY(1); 51876479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 51976479Swpaul DELAY(1); 52076479Swpaul 52176479Swpaul splx(s); 52276479Swpaul 52376479Swpaul if (ack) 52476479Swpaul return(1); 52576479Swpaul return(0); 52676479Swpaul} 52776479Swpaul 52876479Swpaul/* 52976479Swpaul * Write to a PHY register through the MII. 53076479Swpaul */ 53199497Salfredstatic int 53299497Salfrednge_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 57899497Salfredstatic int 57999497Salfrednge_miibus_readreg(dev, phy, reg) 58076479Swpaul device_t dev; 58176479Swpaul int phy, reg; 58276479Swpaul{ 58376479Swpaul struct nge_softc *sc; 58476479Swpaul struct nge_mii_frame frame; 58576479Swpaul 58676479Swpaul sc = device_get_softc(dev); 58776479Swpaul 58876479Swpaul bzero((char *)&frame, sizeof(frame)); 58976479Swpaul 59076479Swpaul frame.mii_phyaddr = phy; 59176479Swpaul frame.mii_regaddr = reg; 59276479Swpaul nge_mii_readreg(sc, &frame); 59376479Swpaul 59476479Swpaul return(frame.mii_data); 59576479Swpaul} 59676479Swpaul 59799497Salfredstatic int 59899497Salfrednge_miibus_writereg(dev, phy, reg, data) 59976479Swpaul device_t dev; 60076479Swpaul int phy, reg, data; 60176479Swpaul{ 60276479Swpaul struct nge_softc *sc; 60376479Swpaul struct nge_mii_frame frame; 60476479Swpaul 60576479Swpaul sc = device_get_softc(dev); 60676479Swpaul 60776479Swpaul bzero((char *)&frame, sizeof(frame)); 60876479Swpaul 60976479Swpaul frame.mii_phyaddr = phy; 61076479Swpaul frame.mii_regaddr = reg; 61176479Swpaul frame.mii_data = data; 61276479Swpaul nge_mii_writereg(sc, &frame); 61376479Swpaul 61476479Swpaul return(0); 61576479Swpaul} 61676479Swpaul 61799497Salfredstatic void 61899497Salfrednge_miibus_statchg(dev) 61976479Swpaul device_t dev; 62076479Swpaul{ 621101540Sambrisko int status; 62276479Swpaul struct nge_softc *sc; 62376479Swpaul struct mii_data *mii; 62476479Swpaul 62576479Swpaul sc = device_get_softc(dev); 626101540Sambrisko if (sc->nge_tbi) { 627101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 628101540Sambrisko == IFM_AUTO) { 629101540Sambrisko status = CSR_READ_4(sc, NGE_TBI_ANLPAR); 630101540Sambrisko if (status == 0 || status & NGE_TBIANAR_FDX) { 631101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 632101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 633101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 634101540Sambrisko } else { 635101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 636101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 637101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 638101540Sambrisko } 63976479Swpaul 640101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 641101540Sambrisko != IFM_FDX) { 642101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 643101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 644101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 645101540Sambrisko } else { 646101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 647101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 648101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 649101540Sambrisko } 65076479Swpaul } else { 651101540Sambrisko mii = device_get_softc(sc->nge_miibus); 65276479Swpaul 653101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 654101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 655101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 656101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 657101540Sambrisko } else { 658101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 659101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 660101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 661101540Sambrisko } 662101540Sambrisko 663101540Sambrisko /* If we have a 1000Mbps link, set the mode_1000 bit. */ 664101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 665101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 666101540Sambrisko NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 667101540Sambrisko } else { 668101540Sambrisko NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 669101540Sambrisko } 67079424Swpaul } 67176479Swpaul return; 67276479Swpaul} 67376479Swpaul 67499497Salfredstatic u_int32_t 67599497Salfrednge_crc(sc, addr) 67676479Swpaul struct nge_softc *sc; 67776479Swpaul caddr_t addr; 67876479Swpaul{ 67976479Swpaul u_int32_t crc, carry; 68076479Swpaul int i, j; 68176479Swpaul u_int8_t c; 68276479Swpaul 68376479Swpaul /* Compute CRC for the address value. */ 68476479Swpaul crc = 0xFFFFFFFF; /* initial value */ 68576479Swpaul 68676479Swpaul for (i = 0; i < 6; i++) { 68776479Swpaul c = *(addr + i); 68876479Swpaul for (j = 0; j < 8; j++) { 68976479Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 69076479Swpaul crc <<= 1; 69176479Swpaul c >>= 1; 69276479Swpaul if (carry) 69376479Swpaul crc = (crc ^ 0x04c11db6) | carry; 69476479Swpaul } 69576479Swpaul } 69676479Swpaul 69776479Swpaul /* 69876479Swpaul * return the filter bit position 69976479Swpaul */ 70076479Swpaul 70176479Swpaul return((crc >> 21) & 0x00000FFF); 70276479Swpaul} 70376479Swpaul 70499497Salfredstatic void 70599497Salfrednge_setmulti(sc) 70676479Swpaul struct nge_softc *sc; 70776479Swpaul{ 70876479Swpaul struct ifnet *ifp; 70976479Swpaul struct ifmultiaddr *ifma; 71076479Swpaul u_int32_t h = 0, i, filtsave; 71176479Swpaul int bit, index; 71276479Swpaul 71376479Swpaul ifp = &sc->arpcom.ac_if; 71476479Swpaul 71576479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 71676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 71776479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 71876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 71976479Swpaul return; 72076479Swpaul } 72176479Swpaul 72276479Swpaul /* 72376479Swpaul * We have to explicitly enable the multicast hash table 72476479Swpaul * on the NatSemi chip if we want to use it, which we do. 72576479Swpaul * We also have to tell it that we don't want to use the 72676479Swpaul * hash table for matching unicast addresses. 72776479Swpaul */ 72876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 72976479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 73076479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 73176479Swpaul 73276479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 73376479Swpaul 73476479Swpaul /* first, zot all the existing hash bits */ 73576479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 73676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 73776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 73876479Swpaul } 73976479Swpaul 74076479Swpaul /* 74176479Swpaul * From the 11 bits returned by the crc routine, the top 7 74276479Swpaul * bits represent the 16-bit word in the mcast hash table 74376479Swpaul * that needs to be updated, and the lower 4 bits represent 74476479Swpaul * which bit within that byte needs to be set. 74576479Swpaul */ 74676479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 74776479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 74876479Swpaul continue; 74976479Swpaul h = nge_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 75076479Swpaul index = (h >> 4) & 0x7F; 75176479Swpaul bit = h & 0xF; 75276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 75376479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 75476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 75576479Swpaul } 75676479Swpaul 75776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 75876479Swpaul 75976479Swpaul return; 76076479Swpaul} 76176479Swpaul 76299497Salfredstatic void 76399497Salfrednge_reset(sc) 76476479Swpaul struct nge_softc *sc; 76576479Swpaul{ 76676479Swpaul register int i; 76776479Swpaul 76876479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 76976479Swpaul 77076479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 77176479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 77276479Swpaul break; 77376479Swpaul } 77476479Swpaul 77576479Swpaul if (i == NGE_TIMEOUT) 77676479Swpaul printf("nge%d: reset never completed\n", sc->nge_unit); 77776479Swpaul 77876479Swpaul /* Wait a little while for the chip to get its brains in order. */ 77976479Swpaul DELAY(1000); 78076479Swpaul 78176479Swpaul /* 78276479Swpaul * If this is a NetSemi chip, make sure to clear 78376479Swpaul * PME mode. 78476479Swpaul */ 78576479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 78676479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 78776479Swpaul 78876479Swpaul return; 78976479Swpaul} 79076479Swpaul 79176479Swpaul/* 792108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 79376479Swpaul * IDs against our list and return a device name if we find a match. 79476479Swpaul */ 79599497Salfredstatic int 79699497Salfrednge_probe(dev) 79776479Swpaul device_t dev; 79876479Swpaul{ 79976479Swpaul struct nge_type *t; 80076479Swpaul 80176479Swpaul t = nge_devs; 80276479Swpaul 80376479Swpaul while(t->nge_name != NULL) { 80476479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 80576479Swpaul (pci_get_device(dev) == t->nge_did)) { 80676479Swpaul device_set_desc(dev, t->nge_name); 80776479Swpaul return(0); 80876479Swpaul } 80976479Swpaul t++; 81076479Swpaul } 81176479Swpaul 81276479Swpaul return(ENXIO); 81376479Swpaul} 81476479Swpaul 81576479Swpaul/* 81676479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 81776479Swpaul * setup and ethernet/BPF attach. 81876479Swpaul */ 81999497Salfredstatic int 82099497Salfrednge_attach(dev) 82176479Swpaul device_t dev; 82276479Swpaul{ 82376479Swpaul int s; 82476479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 82576479Swpaul u_int32_t command; 82676479Swpaul struct nge_softc *sc; 82776479Swpaul struct ifnet *ifp; 82876479Swpaul int unit, error = 0, rid; 829101540Sambrisko const char *sep = ""; 83076479Swpaul 83176479Swpaul s = splimp(); 83276479Swpaul 83376479Swpaul sc = device_get_softc(dev); 83476479Swpaul unit = device_get_unit(dev); 83576479Swpaul bzero(sc, sizeof(struct nge_softc)); 83676479Swpaul 83793818Sjhb mtx_init(&sc->nge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 83893818Sjhb MTX_DEF | MTX_RECURSE); 83976479Swpaul 84076479Swpaul /* 84176479Swpaul * Handle power management nonsense. 84276479Swpaul */ 84376479Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 84476479Swpaul u_int32_t iobase, membase, irq; 84576479Swpaul 84676479Swpaul /* Save important PCI config data. */ 84776479Swpaul iobase = pci_read_config(dev, NGE_PCI_LOIO, 4); 84876479Swpaul membase = pci_read_config(dev, NGE_PCI_LOMEM, 4); 84976479Swpaul irq = pci_read_config(dev, NGE_PCI_INTLINE, 4); 85076479Swpaul 85176479Swpaul /* Reset the power state. */ 85276479Swpaul printf("nge%d: chip is in D%d power mode " 85376479Swpaul "-- setting to D0\n", unit, 85476479Swpaul pci_get_powerstate(dev)); 85576479Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 85676479Swpaul 85776479Swpaul /* Restore PCI config data. */ 85876479Swpaul pci_write_config(dev, NGE_PCI_LOIO, iobase, 4); 85976479Swpaul pci_write_config(dev, NGE_PCI_LOMEM, membase, 4); 86076479Swpaul pci_write_config(dev, NGE_PCI_INTLINE, irq, 4); 86176479Swpaul } 86276479Swpaul 86376479Swpaul /* 86476479Swpaul * Map control/status registers. 86576479Swpaul */ 86676479Swpaul pci_enable_busmaster(dev); 86779472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 86879472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 86976479Swpaul command = pci_read_config(dev, PCIR_COMMAND, 4); 87076479Swpaul 87176479Swpaul#ifdef NGE_USEIOSPACE 87276479Swpaul if (!(command & PCIM_CMD_PORTEN)) { 87376479Swpaul printf("nge%d: failed to enable I/O ports!\n", unit); 87476479Swpaul error = ENXIO;; 87576479Swpaul goto fail; 87676479Swpaul } 87776479Swpaul#else 87876479Swpaul if (!(command & PCIM_CMD_MEMEN)) { 87976479Swpaul printf("nge%d: failed to enable memory mapping!\n", unit); 88076479Swpaul error = ENXIO;; 88176479Swpaul goto fail; 88276479Swpaul } 88376479Swpaul#endif 88476479Swpaul 88576479Swpaul rid = NGE_RID; 88676479Swpaul sc->nge_res = bus_alloc_resource(dev, NGE_RES, &rid, 88776479Swpaul 0, ~0, 1, RF_ACTIVE); 88876479Swpaul 88976479Swpaul if (sc->nge_res == NULL) { 89076479Swpaul printf("nge%d: couldn't map ports/memory\n", unit); 89176479Swpaul error = ENXIO; 89276479Swpaul goto fail; 89376479Swpaul } 89476479Swpaul 89576479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 89676479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 89776479Swpaul 89876479Swpaul /* Allocate interrupt */ 89976479Swpaul rid = 0; 90076479Swpaul sc->nge_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 90176479Swpaul RF_SHAREABLE | RF_ACTIVE); 90276479Swpaul 90376479Swpaul if (sc->nge_irq == NULL) { 90476479Swpaul printf("nge%d: couldn't map interrupt\n", unit); 90576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 90676479Swpaul error = ENXIO; 90776479Swpaul goto fail; 90876479Swpaul } 90976479Swpaul 91076479Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET, 91176479Swpaul nge_intr, sc, &sc->nge_intrhand); 91276479Swpaul 91376479Swpaul if (error) { 91476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 91576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 91676479Swpaul printf("nge%d: couldn't set up irq\n", unit); 91776479Swpaul goto fail; 91876479Swpaul } 91976479Swpaul 92076479Swpaul /* Reset the adapter. */ 92176479Swpaul nge_reset(sc); 92276479Swpaul 92376479Swpaul /* 92476479Swpaul * Get station address from the EEPROM. 92576479Swpaul */ 92676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 92776479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 92876479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 92976479Swpaul 93076479Swpaul /* 93176479Swpaul * A NatSemi chip was detected. Inform the world. 93276479Swpaul */ 93376479Swpaul printf("nge%d: Ethernet address: %6D\n", unit, eaddr, ":"); 93476479Swpaul 93576479Swpaul sc->nge_unit = unit; 93676479Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 93776479Swpaul 93876479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 93976479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 94076479Swpaul 94176479Swpaul if (sc->nge_ldata == NULL) { 94276479Swpaul printf("nge%d: no memory for list buffers!\n", unit); 94376479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 94476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 94576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 94676479Swpaul error = ENXIO; 94776479Swpaul goto fail; 94876479Swpaul } 94976479Swpaul bzero(sc->nge_ldata, sizeof(struct nge_list_data)); 95076479Swpaul 95176479Swpaul /* Try to allocate memory for jumbo buffers. */ 95276479Swpaul if (nge_alloc_jumbo_mem(sc)) { 95376479Swpaul printf("nge%d: jumbo buffer allocation failed\n", 95476479Swpaul sc->nge_unit); 95576479Swpaul contigfree(sc->nge_ldata, 95676479Swpaul sizeof(struct nge_list_data), M_DEVBUF); 95776479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 95876479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 95976479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 96076479Swpaul error = ENXIO; 96176479Swpaul goto fail; 96276479Swpaul } 96376479Swpaul 96476479Swpaul ifp = &sc->arpcom.ac_if; 96576479Swpaul ifp->if_softc = sc; 96676479Swpaul ifp->if_unit = unit; 96776479Swpaul ifp->if_name = "nge"; 96876479Swpaul ifp->if_mtu = ETHERMTU; 96976479Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 97076479Swpaul ifp->if_ioctl = nge_ioctl; 97176479Swpaul ifp->if_output = ether_output; 97276479Swpaul ifp->if_start = nge_start; 97376479Swpaul ifp->if_watchdog = nge_watchdog; 97476479Swpaul ifp->if_init = nge_init; 97576479Swpaul ifp->if_baudrate = 1000000000; 97676479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 97776479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 978106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 97983632Sjlemon ifp->if_capenable = ifp->if_capabilities; 98076479Swpaul 98176479Swpaul /* 98276479Swpaul * Do MII setup. 98376479Swpaul */ 98476479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 985101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 986101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 987101540Sambrisko sc->nge_tbi = 1; 988101540Sambrisko device_printf(dev, "Using TBI\n"); 989101540Sambrisko 990101540Sambrisko sc->nge_miibus = dev; 991101540Sambrisko 992101540Sambrisko ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 993101540Sambrisko nge_ifmedia_sts); 994101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 995101540Sambrisko#define PRINT(s) printf("%s%s", sep, s); sep = ", " 996101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 997101540Sambrisko device_printf(dev, " "); 998101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 999101540Sambrisko PRINT("1000baseSX"); 1000101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 1001101540Sambrisko PRINT("1000baseSX-FDX"); 1002101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 1003101540Sambrisko PRINT("auto"); 1004101540Sambrisko 1005101540Sambrisko printf("\n"); 1006101540Sambrisko#undef ADD 1007101540Sambrisko#undef PRINT 1008101540Sambrisko ifmedia_set(&sc->nge_ifmedia, 1009101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 1010101540Sambrisko 1011101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1012101540Sambrisko | NGE_GPIO_GP4_OUT 1013101540Sambrisko | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 1014101540Sambrisko | NGE_GPIO_GP3_OUTENB 1015101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 1016101540Sambrisko 1017101540Sambrisko } else { 1018101540Sambrisko printf("nge%d: MII without any PHY!\n", sc->nge_unit); 1019101540Sambrisko nge_free_jumbo_mem(sc); 1020101540Sambrisko bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 1021101540Sambrisko bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 1022101540Sambrisko bus_release_resource(dev, NGE_RES, NGE_RID, 1023101540Sambrisko sc->nge_res); 1024101540Sambrisko error = ENXIO; 1025101540Sambrisko goto fail; 1026101540Sambrisko } 102776479Swpaul } 102876479Swpaul 102976479Swpaul /* 103076479Swpaul * Call MI attach routine. 103176479Swpaul */ 1032106937Ssam ether_ifattach(ifp, eaddr); 103376479Swpaul callout_handle_init(&sc->nge_stat_ch); 103476479Swpaul 103576479Swpaulfail: 1036101540Sambrisko 103776479Swpaul splx(s); 103876479Swpaul mtx_destroy(&sc->nge_mtx); 103976479Swpaul return(error); 104076479Swpaul} 104176479Swpaul 104299497Salfredstatic int 104399497Salfrednge_detach(dev) 104476479Swpaul device_t dev; 104576479Swpaul{ 104676479Swpaul struct nge_softc *sc; 104776479Swpaul struct ifnet *ifp; 104876479Swpaul int s; 104976479Swpaul 105076479Swpaul s = splimp(); 105176479Swpaul 105276479Swpaul sc = device_get_softc(dev); 105376479Swpaul ifp = &sc->arpcom.ac_if; 105476479Swpaul 105576479Swpaul nge_reset(sc); 105676479Swpaul nge_stop(sc); 1057106937Ssam ether_ifdetach(ifp); 105876479Swpaul 105976479Swpaul bus_generic_detach(dev); 1060101540Sambrisko if (!sc->nge_tbi) { 1061101540Sambrisko device_delete_child(dev, sc->nge_miibus); 1062101540Sambrisko } 106376479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 106476479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 106576479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 106676479Swpaul 106776479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 106876479Swpaul nge_free_jumbo_mem(sc); 106976479Swpaul 107076479Swpaul splx(s); 107176479Swpaul mtx_destroy(&sc->nge_mtx); 107276479Swpaul 107376479Swpaul return(0); 107476479Swpaul} 107576479Swpaul 107676479Swpaul/* 107776479Swpaul * Initialize the transmit descriptors. 107876479Swpaul */ 107999497Salfredstatic int 108099497Salfrednge_list_tx_init(sc) 108176479Swpaul struct nge_softc *sc; 108276479Swpaul{ 108376479Swpaul struct nge_list_data *ld; 108476479Swpaul struct nge_ring_data *cd; 108576479Swpaul int i; 108676479Swpaul 108776479Swpaul cd = &sc->nge_cdata; 108876479Swpaul ld = sc->nge_ldata; 108976479Swpaul 109076479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 109176479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 109276479Swpaul ld->nge_tx_list[i].nge_nextdesc = 109376479Swpaul &ld->nge_tx_list[0]; 109476479Swpaul ld->nge_tx_list[i].nge_next = 109576479Swpaul vtophys(&ld->nge_tx_list[0]); 109676479Swpaul } else { 109776479Swpaul ld->nge_tx_list[i].nge_nextdesc = 109876479Swpaul &ld->nge_tx_list[i + 1]; 109976479Swpaul ld->nge_tx_list[i].nge_next = 110076479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 110176479Swpaul } 110276479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 110376479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 110476479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 110576479Swpaul } 110676479Swpaul 110776479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 110876479Swpaul 110976479Swpaul return(0); 111076479Swpaul} 111176479Swpaul 111276479Swpaul 111376479Swpaul/* 111476479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 111576479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 111676479Swpaul * points back to the first. 111776479Swpaul */ 111899497Salfredstatic int 111999497Salfrednge_list_rx_init(sc) 112076479Swpaul struct nge_softc *sc; 112176479Swpaul{ 112276479Swpaul struct nge_list_data *ld; 112376479Swpaul struct nge_ring_data *cd; 112476479Swpaul int i; 112576479Swpaul 112676479Swpaul ld = sc->nge_ldata; 112776479Swpaul cd = &sc->nge_cdata; 112876479Swpaul 112976479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 113076479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 113176479Swpaul return(ENOBUFS); 113276479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 113376479Swpaul ld->nge_rx_list[i].nge_nextdesc = 113476479Swpaul &ld->nge_rx_list[0]; 113576479Swpaul ld->nge_rx_list[i].nge_next = 113676479Swpaul vtophys(&ld->nge_rx_list[0]); 113776479Swpaul } else { 113876479Swpaul ld->nge_rx_list[i].nge_nextdesc = 113976479Swpaul &ld->nge_rx_list[i + 1]; 114076479Swpaul ld->nge_rx_list[i].nge_next = 114176479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 114276479Swpaul } 114376479Swpaul } 114476479Swpaul 114576479Swpaul cd->nge_rx_prod = 0; 114676479Swpaul 114776479Swpaul return(0); 114876479Swpaul} 114976479Swpaul 115076479Swpaul/* 115176479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 115276479Swpaul */ 115399497Salfredstatic int 115499497Salfrednge_newbuf(sc, c, m) 115576479Swpaul struct nge_softc *sc; 115676479Swpaul struct nge_desc *c; 115776479Swpaul struct mbuf *m; 115876479Swpaul{ 115976479Swpaul struct mbuf *m_new = NULL; 116076479Swpaul caddr_t *buf = NULL; 116176479Swpaul 116276479Swpaul if (m == NULL) { 1163111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 116476479Swpaul if (m_new == NULL) { 116576479Swpaul printf("nge%d: no memory for rx list " 116676479Swpaul "-- packet dropped!\n", sc->nge_unit); 116776479Swpaul return(ENOBUFS); 116876479Swpaul } 116976479Swpaul 117076479Swpaul /* Allocate the jumbo buffer */ 117176479Swpaul buf = nge_jalloc(sc); 117276479Swpaul if (buf == NULL) { 117376479Swpaul#ifdef NGE_VERBOSE 117476479Swpaul printf("nge%d: jumbo allocation failed " 117576479Swpaul "-- packet dropped!\n", sc->nge_unit); 117676479Swpaul#endif 117776479Swpaul m_freem(m_new); 117876479Swpaul return(ENOBUFS); 117976479Swpaul } 118076479Swpaul /* Attach the buffer to the mbuf */ 118176479Swpaul m_new->m_data = (void *)buf; 118278440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 118378440Swpaul MEXTADD(m_new, buf, NGE_JUMBO_FRAMELEN, nge_jfree, 118476640Swpaul (struct nge_softc *)sc, 0, EXT_NET_DRV); 118576479Swpaul } else { 118676479Swpaul m_new = m; 118778440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 118876479Swpaul m_new->m_data = m_new->m_ext.ext_buf; 118976479Swpaul } 119076479Swpaul 119176479Swpaul m_adj(m_new, sizeof(u_int64_t)); 119276479Swpaul 119376479Swpaul c->nge_mbuf = m_new; 119476479Swpaul c->nge_ptr = vtophys(mtod(m_new, caddr_t)); 119576479Swpaul c->nge_ctl = m_new->m_len; 119676479Swpaul c->nge_extsts = 0; 119776479Swpaul 119876479Swpaul return(0); 119976479Swpaul} 120076479Swpaul 120199497Salfredstatic int 120299497Salfrednge_alloc_jumbo_mem(sc) 120376479Swpaul struct nge_softc *sc; 120476479Swpaul{ 120576479Swpaul caddr_t ptr; 120676479Swpaul register int i; 120776479Swpaul struct nge_jpool_entry *entry; 120876479Swpaul 120976479Swpaul /* Grab a big chunk o' storage. */ 121076479Swpaul sc->nge_cdata.nge_jumbo_buf = contigmalloc(NGE_JMEM, M_DEVBUF, 121176479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 121276479Swpaul 121376479Swpaul if (sc->nge_cdata.nge_jumbo_buf == NULL) { 121476479Swpaul printf("nge%d: no memory for jumbo buffers!\n", sc->nge_unit); 121576479Swpaul return(ENOBUFS); 121676479Swpaul } 121776479Swpaul 121876479Swpaul SLIST_INIT(&sc->nge_jfree_listhead); 121976479Swpaul SLIST_INIT(&sc->nge_jinuse_listhead); 122076479Swpaul 122176479Swpaul /* 122276479Swpaul * Now divide it up into 9K pieces and save the addresses 122376479Swpaul * in an array. 122476479Swpaul */ 122576479Swpaul ptr = sc->nge_cdata.nge_jumbo_buf; 122676479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 122776479Swpaul sc->nge_cdata.nge_jslots[i] = ptr; 122878440Swpaul ptr += NGE_JLEN; 122976479Swpaul entry = malloc(sizeof(struct nge_jpool_entry), 123076479Swpaul M_DEVBUF, M_NOWAIT); 123176479Swpaul if (entry == NULL) { 123276479Swpaul printf("nge%d: no memory for jumbo " 123376479Swpaul "buffer queue!\n", sc->nge_unit); 123476479Swpaul return(ENOBUFS); 123576479Swpaul } 123676479Swpaul entry->slot = i; 123776479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, 123876479Swpaul entry, jpool_entries); 123976479Swpaul } 124076479Swpaul 124176479Swpaul return(0); 124276479Swpaul} 124376479Swpaul 124499497Salfredstatic void 124599497Salfrednge_free_jumbo_mem(sc) 124676479Swpaul struct nge_softc *sc; 124776479Swpaul{ 124876479Swpaul register int i; 124976479Swpaul struct nge_jpool_entry *entry; 125076479Swpaul 125176479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 125276479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 125378440Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 125476479Swpaul free(entry, M_DEVBUF); 125576479Swpaul } 125676479Swpaul 125776479Swpaul contigfree(sc->nge_cdata.nge_jumbo_buf, NGE_JMEM, M_DEVBUF); 125876479Swpaul 125976479Swpaul return; 126076479Swpaul} 126176479Swpaul 126276479Swpaul/* 126376479Swpaul * Allocate a jumbo buffer. 126476479Swpaul */ 126599497Salfredstatic void * 126699497Salfrednge_jalloc(sc) 126776479Swpaul struct nge_softc *sc; 126876479Swpaul{ 126976479Swpaul struct nge_jpool_entry *entry; 127076479Swpaul 127176479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 127276479Swpaul 127376479Swpaul if (entry == NULL) { 127476479Swpaul#ifdef NGE_VERBOSE 127576479Swpaul printf("nge%d: no free jumbo buffers\n", sc->nge_unit); 127676479Swpaul#endif 127776479Swpaul return(NULL); 127876479Swpaul } 127976479Swpaul 128076479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 128176479Swpaul SLIST_INSERT_HEAD(&sc->nge_jinuse_listhead, entry, jpool_entries); 128276479Swpaul return(sc->nge_cdata.nge_jslots[entry->slot]); 128376479Swpaul} 128476479Swpaul 128576479Swpaul/* 128676479Swpaul * Release a jumbo buffer. 128776479Swpaul */ 128899497Salfredstatic void 128999497Salfrednge_jfree(buf, args) 129099004Salfred void *buf; 129176479Swpaul void *args; 129276479Swpaul{ 129376479Swpaul struct nge_softc *sc; 129476479Swpaul int i; 129576479Swpaul struct nge_jpool_entry *entry; 129676479Swpaul 129776479Swpaul /* Extract the softc struct pointer. */ 129876479Swpaul sc = args; 129976479Swpaul 130076479Swpaul if (sc == NULL) 130176479Swpaul panic("nge_jfree: can't find softc pointer!"); 130276479Swpaul 130376479Swpaul /* calculate the slot this buffer belongs to */ 130476479Swpaul i = ((vm_offset_t)buf 130576479Swpaul - (vm_offset_t)sc->nge_cdata.nge_jumbo_buf) / NGE_JLEN; 130676479Swpaul 130776479Swpaul if ((i < 0) || (i >= NGE_JSLOTS)) 130876479Swpaul panic("nge_jfree: asked to free buffer that we don't manage!"); 130976479Swpaul 131076479Swpaul entry = SLIST_FIRST(&sc->nge_jinuse_listhead); 131176479Swpaul if (entry == NULL) 131276479Swpaul panic("nge_jfree: buffer not in use!"); 131376479Swpaul entry->slot = i; 131476479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jinuse_listhead, jpool_entries); 131576479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, entry, jpool_entries); 131676479Swpaul 131776479Swpaul return; 131876479Swpaul} 131976479Swpaul/* 132076479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 132176479Swpaul * the higher level protocols. 132276479Swpaul */ 132399497Salfredstatic void 132499497Salfrednge_rxeof(sc) 132576479Swpaul struct nge_softc *sc; 132676479Swpaul{ 132776479Swpaul struct mbuf *m; 132876479Swpaul struct ifnet *ifp; 132976479Swpaul struct nge_desc *cur_rx; 133076479Swpaul int i, total_len = 0; 133176479Swpaul u_int32_t rxstat; 133276479Swpaul 133376479Swpaul ifp = &sc->arpcom.ac_if; 133476479Swpaul i = sc->nge_cdata.nge_rx_prod; 133576479Swpaul 133676479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 133776479Swpaul struct mbuf *m0 = NULL; 133876479Swpaul u_int32_t extsts; 133976479Swpaul 1340106507Ssimokawa#ifdef DEVICE_POLLING 1341106507Ssimokawa if (ifp->if_ipending & IFF_POLLING) { 1342106507Ssimokawa if (sc->rxcycles <= 0) 1343106507Ssimokawa break; 1344106507Ssimokawa sc->rxcycles--; 1345106507Ssimokawa } 1346106507Ssimokawa#endif /* DEVICE_POLLING */ 1347106507Ssimokawa 134876479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 134976479Swpaul rxstat = cur_rx->nge_rxstat; 135076479Swpaul extsts = cur_rx->nge_extsts; 135176479Swpaul m = cur_rx->nge_mbuf; 135276479Swpaul cur_rx->nge_mbuf = NULL; 135376479Swpaul total_len = NGE_RXBYTES(cur_rx); 135476479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 135576479Swpaul /* 135676479Swpaul * If an error occurs, update stats, clear the 135776479Swpaul * status word and leave the mbuf cluster in place: 135876479Swpaul * it should simply get re-used next time this descriptor 135976479Swpaul * comes up in the ring. 136076479Swpaul */ 136176479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 136276479Swpaul ifp->if_ierrors++; 136376479Swpaul nge_newbuf(sc, cur_rx, m); 136476479Swpaul continue; 136576479Swpaul } 136676479Swpaul 136776479Swpaul /* 136876479Swpaul * Ok. NatSemi really screwed up here. This is the 136976479Swpaul * only gigE chip I know of with alignment constraints 137076479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 137176479Swpaul */ 137279562Swpaul#ifdef __i386__ 137379562Swpaul /* 137479562Swpaul * By popular demand, ignore the alignment problems 137579562Swpaul * on the Intel x86 platform. The performance hit 137679562Swpaul * incurred due to unaligned accesses is much smaller 137779562Swpaul * than the hit produced by forcing buffer copies all 137879562Swpaul * the time, especially with jumbo frames. We still 137979562Swpaul * need to fix up the alignment everywhere else though. 138079562Swpaul */ 138179562Swpaul if (nge_newbuf(sc, cur_rx, NULL) == ENOBUFS) { 138279562Swpaul#endif 138379562Swpaul m0 = m_devget(mtod(m, char *), total_len, 138479562Swpaul ETHER_ALIGN, ifp, NULL); 138579562Swpaul nge_newbuf(sc, cur_rx, m); 138679562Swpaul if (m0 == NULL) { 138779562Swpaul printf("nge%d: no receive buffers " 138879562Swpaul "available -- packet dropped!\n", 138979562Swpaul sc->nge_unit); 139079562Swpaul ifp->if_ierrors++; 139179562Swpaul continue; 139279562Swpaul } 139379562Swpaul m = m0; 139479562Swpaul#ifdef __i386__ 139579562Swpaul } else { 139679562Swpaul m->m_pkthdr.rcvif = ifp; 139779562Swpaul m->m_pkthdr.len = m->m_len = total_len; 139876479Swpaul } 139979562Swpaul#endif 140076479Swpaul 140176479Swpaul ifp->if_ipackets++; 140276479Swpaul 140376479Swpaul /* Do IP checksum checking. */ 140478323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 140578323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 140678323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 140778323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 140878323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 140978323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 141078323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 141178323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 141278323Swpaul m->m_pkthdr.csum_flags |= 141378323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 141478323Swpaul m->m_pkthdr.csum_data = 0xffff; 141578323Swpaul } 141676479Swpaul 141776479Swpaul /* 141876479Swpaul * If we received a packet with a vlan tag, pass it 141976479Swpaul * to vlan_input() instead of ether_input(). 142076479Swpaul */ 142176479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1422106937Ssam VLAN_INPUT_TAG(ifp, m, 1423106937Ssam extsts & NGE_RXEXTSTS_VTCI, continue); 1424106937Ssam } 142576479Swpaul 1426106937Ssam (*ifp->if_input)(ifp, m); 142776479Swpaul } 142876479Swpaul 142976479Swpaul sc->nge_cdata.nge_rx_prod = i; 143076479Swpaul 143176479Swpaul return; 143276479Swpaul} 143376479Swpaul 143476479Swpaul/* 143576479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 143676479Swpaul * the list buffers. 143776479Swpaul */ 143876479Swpaul 143999497Salfredstatic void 144099497Salfrednge_txeof(sc) 144176479Swpaul struct nge_softc *sc; 144276479Swpaul{ 144376479Swpaul struct nge_desc *cur_tx = NULL; 144476479Swpaul struct ifnet *ifp; 144576479Swpaul u_int32_t idx; 144676479Swpaul 144776479Swpaul ifp = &sc->arpcom.ac_if; 144876479Swpaul 144976479Swpaul /* Clear the timeout timer. */ 145076479Swpaul ifp->if_timer = 0; 145176479Swpaul 145276479Swpaul /* 145376479Swpaul * Go through our tx list and free mbufs for those 145476479Swpaul * frames that have been transmitted. 145576479Swpaul */ 145676479Swpaul idx = sc->nge_cdata.nge_tx_cons; 145776479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 145876479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 145976479Swpaul 146076479Swpaul if (NGE_OWNDESC(cur_tx)) 146176479Swpaul break; 146276479Swpaul 146376479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 146476479Swpaul sc->nge_cdata.nge_tx_cnt--; 146576479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 146676479Swpaul continue; 146776479Swpaul } 146876479Swpaul 146976479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 147076479Swpaul ifp->if_oerrors++; 147176479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 147276479Swpaul ifp->if_collisions++; 147376479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 147476479Swpaul ifp->if_collisions++; 147576479Swpaul } 147676479Swpaul 147776479Swpaul ifp->if_collisions += 147876479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 147976479Swpaul 148076479Swpaul ifp->if_opackets++; 148176479Swpaul if (cur_tx->nge_mbuf != NULL) { 148276479Swpaul m_freem(cur_tx->nge_mbuf); 148376479Swpaul cur_tx->nge_mbuf = NULL; 148476479Swpaul } 148576479Swpaul 148676479Swpaul sc->nge_cdata.nge_tx_cnt--; 148776479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 148876479Swpaul ifp->if_timer = 0; 148976479Swpaul } 149076479Swpaul 149176479Swpaul sc->nge_cdata.nge_tx_cons = idx; 149276479Swpaul 149376479Swpaul if (cur_tx != NULL) 149476479Swpaul ifp->if_flags &= ~IFF_OACTIVE; 149576479Swpaul 149676479Swpaul return; 149776479Swpaul} 149876479Swpaul 149999497Salfredstatic void 150099497Salfrednge_tick(xsc) 150176479Swpaul void *xsc; 150276479Swpaul{ 150376479Swpaul struct nge_softc *sc; 150476479Swpaul struct mii_data *mii; 150576479Swpaul struct ifnet *ifp; 150676479Swpaul int s; 150776479Swpaul 150876479Swpaul s = splimp(); 150976479Swpaul 151076479Swpaul sc = xsc; 151176479Swpaul ifp = &sc->arpcom.ac_if; 151276479Swpaul 1513101540Sambrisko if (sc->nge_tbi) { 1514101540Sambrisko if (!sc->nge_link) { 1515101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) 1516101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 151776479Swpaul printf("nge%d: gigabit link up\n", 151876479Swpaul sc->nge_unit); 1519101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1520101540Sambrisko sc->nge_link++; 1521101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1522101540Sambrisko nge_start(ifp); 1523101540Sambrisko } 152496028Sphk } 1525101540Sambrisko } else { 1526101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1527101540Sambrisko mii_tick(mii); 1528101540Sambrisko 1529101540Sambrisko if (!sc->nge_link) { 1530101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1531101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1532101540Sambrisko sc->nge_link++; 1533101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) 1534101540Sambrisko == IFM_1000_T) 1535101540Sambrisko printf("nge%d: gigabit link up\n", 1536101540Sambrisko sc->nge_unit); 1537101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1538101540Sambrisko nge_start(ifp); 1539101540Sambrisko } 1540101540Sambrisko } 154176479Swpaul } 154296028Sphk sc->nge_stat_ch = timeout(nge_tick, sc, hz); 154376479Swpaul 154476479Swpaul splx(s); 154576479Swpaul 154676479Swpaul return; 154776479Swpaul} 154876479Swpaul 1549106507Ssimokawa#ifdef DEVICE_POLLING 1550106507Ssimokawastatic poll_handler_t nge_poll; 1551106507Ssimokawa 155299497Salfredstatic void 1553106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1554106507Ssimokawa{ 1555106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1556106507Ssimokawa 1557106507Ssimokawa if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 1558106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 1); 1559106507Ssimokawa return; 1560106507Ssimokawa } 1561106507Ssimokawa 1562106507Ssimokawa /* 1563106507Ssimokawa * On the nge, reading the status register also clears it. 1564106507Ssimokawa * So before returning to intr mode we must make sure that all 1565106507Ssimokawa * possible pending sources of interrupts have been served. 1566106507Ssimokawa * In practice this means run to completion the *eof routines, 1567106507Ssimokawa * and then call the interrupt routine 1568106507Ssimokawa */ 1569106507Ssimokawa sc->rxcycles = count; 1570106507Ssimokawa nge_rxeof(sc); 1571106507Ssimokawa nge_txeof(sc); 1572106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1573106507Ssimokawa nge_start(ifp); 1574106507Ssimokawa 1575106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1576106507Ssimokawa u_int32_t status; 1577106507Ssimokawa 1578106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1579106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1580106507Ssimokawa 1581106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1582106507Ssimokawa nge_rxeof(sc); 1583106507Ssimokawa 1584106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1585106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1586106507Ssimokawa 1587106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1588106507Ssimokawa nge_reset(sc); 1589106507Ssimokawa nge_init(sc); 1590106507Ssimokawa } 1591106507Ssimokawa } 1592106507Ssimokawa} 1593106507Ssimokawa#endif /* DEVICE_POLLING */ 1594106507Ssimokawa 1595106507Ssimokawastatic void 159699497Salfrednge_intr(arg) 159776479Swpaul void *arg; 159876479Swpaul{ 159976479Swpaul struct nge_softc *sc; 160076479Swpaul struct ifnet *ifp; 160176479Swpaul u_int32_t status; 160276479Swpaul 160376479Swpaul sc = arg; 160476479Swpaul ifp = &sc->arpcom.ac_if; 160576479Swpaul 1606106507Ssimokawa#ifdef DEVICE_POLLING 1607106507Ssimokawa if (ifp->if_ipending & IFF_POLLING) 1608106507Ssimokawa return; 1609106507Ssimokawa if (ether_poll_register(nge_poll, ifp)) { /* ok, disable interrupts */ 1610106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1611106507Ssimokawa nge_poll(ifp, 0, 1); 1612106507Ssimokawa return; 1613106507Ssimokawa } 1614106507Ssimokawa#endif /* DEVICE_POLLING */ 1615106507Ssimokawa 161676479Swpaul /* Supress unwanted interrupts */ 161776479Swpaul if (!(ifp->if_flags & IFF_UP)) { 161876479Swpaul nge_stop(sc); 161976479Swpaul return; 162076479Swpaul } 162176479Swpaul 162276479Swpaul /* Disable interrupts. */ 162376479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 162476479Swpaul 1625101540Sambrisko /* Data LED on for TBI mode */ 1626101540Sambrisko if(sc->nge_tbi) 1627101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1628101540Sambrisko | NGE_GPIO_GP3_OUT); 1629101540Sambrisko 163076479Swpaul for (;;) { 163176479Swpaul /* Reading the ISR register clears all interrupts. */ 163276479Swpaul status = CSR_READ_4(sc, NGE_ISR); 163376479Swpaul 163476479Swpaul if ((status & NGE_INTRS) == 0) 163576479Swpaul break; 163676479Swpaul 163776479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 163876479Swpaul (status & NGE_ISR_TX_ERR) || 163976479Swpaul (status & NGE_ISR_TX_OK) || 164076479Swpaul (status & NGE_ISR_TX_IDLE)) 164176479Swpaul nge_txeof(sc); 164276479Swpaul 164376479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 164479798Swpaul (status & NGE_ISR_RX_ERR) || 164583678Swpaul (status & NGE_ISR_RX_OFLOW) || 164694612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 164794612Sphk (status & NGE_ISR_RX_IDLE) || 164876479Swpaul (status & NGE_ISR_RX_OK)) 164976479Swpaul nge_rxeof(sc); 165094612Sphk 165194612Sphk if ((status & NGE_ISR_RX_IDLE)) 165294612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 165394612Sphk 165476479Swpaul if (status & NGE_ISR_SYSERR) { 165576479Swpaul nge_reset(sc); 165676479Swpaul ifp->if_flags &= ~IFF_RUNNING; 165776479Swpaul nge_init(sc); 165876479Swpaul } 165976479Swpaul 166096028Sphk#if 0 166196028Sphk /* 166296028Sphk * XXX: nge_tick() is not ready to be called this way 166396028Sphk * it screws up the aneg timeout because mii_tick() is 166496028Sphk * only to be called once per second. 166596028Sphk */ 166676479Swpaul if (status & NGE_IMR_PHY_INTR) { 166776479Swpaul sc->nge_link = 0; 166876479Swpaul nge_tick(sc); 166976479Swpaul } 167096028Sphk#endif 167176479Swpaul } 167276479Swpaul 167376479Swpaul /* Re-enable interrupts. */ 167476479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 167576479Swpaul 167676479Swpaul if (ifp->if_snd.ifq_head != NULL) 167776479Swpaul nge_start(ifp); 167876479Swpaul 1679101540Sambrisko /* Data LED off for TBI mode */ 1680101540Sambrisko 1681101540Sambrisko if(sc->nge_tbi) 1682101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1683101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1684101540Sambrisko 168576479Swpaul return; 168676479Swpaul} 168776479Swpaul 168876479Swpaul/* 168976479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 169076479Swpaul * pointers to the fragment pointers. 169176479Swpaul */ 169299497Salfredstatic int 169399497Salfrednge_encap(sc, m_head, txidx) 169476479Swpaul struct nge_softc *sc; 169576479Swpaul struct mbuf *m_head; 169676479Swpaul u_int32_t *txidx; 169776479Swpaul{ 169876479Swpaul struct nge_desc *f = NULL; 169976479Swpaul struct mbuf *m; 170076479Swpaul int frag, cur, cnt = 0; 1701106937Ssam struct m_tag *mtag; 170276479Swpaul 170376479Swpaul /* 170476479Swpaul * Start packing the mbufs in this chain into 170576479Swpaul * the fragment pointers. Stop when we run out 170676479Swpaul * of fragments or hit the end of the mbuf chain. 170776479Swpaul */ 170876479Swpaul m = m_head; 170976479Swpaul cur = frag = *txidx; 171076479Swpaul 171176479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 171276479Swpaul if (m->m_len != 0) { 171376479Swpaul if ((NGE_TX_LIST_CNT - 171476479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 171576479Swpaul return(ENOBUFS); 171676479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 171776479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 171876479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 171976479Swpaul if (cnt != 0) 172076479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 172176479Swpaul cur = frag; 172276479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 172376479Swpaul cnt++; 172476479Swpaul } 172576479Swpaul } 172676479Swpaul 172776479Swpaul if (m != NULL) 172876479Swpaul return(ENOBUFS); 172976479Swpaul 173078286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 173176479Swpaul if (m_head->m_pkthdr.csum_flags) { 173276479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 173378286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 173476479Swpaul NGE_TXEXTSTS_IPCSUM; 173576479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 173678286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 173776479Swpaul NGE_TXEXTSTS_TCPCSUM; 173876479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 173978286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 174076479Swpaul NGE_TXEXTSTS_UDPCSUM; 174176479Swpaul } 174276479Swpaul 1743106937Ssam mtag = VLAN_OUTPUT_TAG(&sc->arpcom.ac_if, m); 1744106937Ssam if (mtag != NULL) { 174576479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1746106937Ssam (NGE_TXEXTSTS_VLANPKT|VLAN_TAG_VALUE(mtag)); 174776479Swpaul } 174876479Swpaul 174976479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 175076479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 175176479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 175276479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 175376479Swpaul *txidx = frag; 175476479Swpaul 175576479Swpaul return(0); 175676479Swpaul} 175776479Swpaul 175876479Swpaul/* 175976479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 176076479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 176176479Swpaul * copy of the pointers since the transmit list fragment pointers are 176276479Swpaul * physical addresses. 176376479Swpaul */ 176476479Swpaul 176599497Salfredstatic void 176699497Salfrednge_start(ifp) 176776479Swpaul struct ifnet *ifp; 176876479Swpaul{ 176976479Swpaul struct nge_softc *sc; 177076479Swpaul struct mbuf *m_head = NULL; 177176479Swpaul u_int32_t idx; 177276479Swpaul 177376479Swpaul sc = ifp->if_softc; 177476479Swpaul 177576479Swpaul if (!sc->nge_link) 177676479Swpaul return; 177776479Swpaul 177876479Swpaul idx = sc->nge_cdata.nge_tx_prod; 177976479Swpaul 178076479Swpaul if (ifp->if_flags & IFF_OACTIVE) 178176479Swpaul return; 178276479Swpaul 178376479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 178476479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 178576479Swpaul if (m_head == NULL) 178676479Swpaul break; 178776479Swpaul 178876479Swpaul if (nge_encap(sc, m_head, &idx)) { 178976479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 179076479Swpaul ifp->if_flags |= IFF_OACTIVE; 179176479Swpaul break; 179276479Swpaul } 179376479Swpaul 179476479Swpaul /* 179576479Swpaul * If there's a BPF listener, bounce a copy of this frame 179676479Swpaul * to him. 179776479Swpaul */ 1798106937Ssam BPF_MTAP(ifp, m_head); 179976479Swpaul 180076479Swpaul } 180176479Swpaul 180276479Swpaul /* Transmit */ 180376479Swpaul sc->nge_cdata.nge_tx_prod = idx; 180476479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 180576479Swpaul 180676479Swpaul /* 180776479Swpaul * Set a timeout in case the chip goes out to lunch. 180876479Swpaul */ 180976479Swpaul ifp->if_timer = 5; 181076479Swpaul 181176479Swpaul return; 181276479Swpaul} 181376479Swpaul 181499497Salfredstatic void 181599497Salfrednge_init(xsc) 181676479Swpaul void *xsc; 181776479Swpaul{ 181876479Swpaul struct nge_softc *sc = xsc; 181976479Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 182076479Swpaul struct mii_data *mii; 182176479Swpaul int s; 182276479Swpaul 182376479Swpaul if (ifp->if_flags & IFF_RUNNING) 182476479Swpaul return; 182576479Swpaul 182676479Swpaul s = splimp(); 182776479Swpaul 182876479Swpaul /* 182976479Swpaul * Cancel pending I/O and free all RX/TX buffers. 183076479Swpaul */ 183176479Swpaul nge_stop(sc); 183276479Swpaul 1833101540Sambrisko if (sc->nge_tbi) { 1834101540Sambrisko mii = NULL; 1835101540Sambrisko } else { 1836101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1837101540Sambrisko } 183876479Swpaul 183976479Swpaul /* Set MAC address */ 184076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 184176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 184276479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 184376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 184476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 184576479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 184676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 184776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 184876479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 184976479Swpaul 185076479Swpaul /* Init circular RX list. */ 185176479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 185276479Swpaul printf("nge%d: initialization failed: no " 185376479Swpaul "memory for rx buffers\n", sc->nge_unit); 185476479Swpaul nge_stop(sc); 185576479Swpaul (void)splx(s); 185676479Swpaul return; 185776479Swpaul } 185876479Swpaul 185976479Swpaul /* 186076479Swpaul * Init tx descriptors. 186176479Swpaul */ 186276479Swpaul nge_list_tx_init(sc); 186376479Swpaul 186476479Swpaul /* 186576479Swpaul * For the NatSemi chip, we have to explicitly enable the 186676479Swpaul * reception of ARP frames, as well as turn on the 'perfect 186776479Swpaul * match' filter where we store the station address, otherwise 186876479Swpaul * we won't receive unicasts meant for this host. 186976479Swpaul */ 187076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 187176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 187276479Swpaul 187376479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 187476479Swpaul if (ifp->if_flags & IFF_PROMISC) { 187576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 187676479Swpaul } else { 187776479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 187876479Swpaul } 187976479Swpaul 188076479Swpaul /* 188176479Swpaul * Set the capture broadcast bit to capture broadcast frames. 188276479Swpaul */ 188376479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 188476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 188576479Swpaul } else { 188676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 188776479Swpaul } 188876479Swpaul 188976479Swpaul /* 189076479Swpaul * Load the multicast filter. 189176479Swpaul */ 189276479Swpaul nge_setmulti(sc); 189376479Swpaul 189476479Swpaul /* Turn the receive filter on */ 189576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 189676479Swpaul 189776479Swpaul /* 189876479Swpaul * Load the address of the RX and TX lists. 189976479Swpaul */ 190076479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 190176479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 190276479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 190376479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 190476479Swpaul 190576479Swpaul /* Set RX configuration */ 190676479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 190776479Swpaul /* 190876479Swpaul * Enable hardware checksum validation for all IPv4 190976479Swpaul * packets, do not reject packets with bad checksums. 191076479Swpaul */ 191178323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 191276479Swpaul 191376479Swpaul /* 191483115Sbrooks * Tell the chip to detect and strip VLAN tag info from 191583115Sbrooks * received frames. The tag will be provided in the extsts 191683115Sbrooks * field in the RX descriptors. 191776479Swpaul */ 191876479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 191976479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 192076479Swpaul 192176479Swpaul /* Set TX configuration */ 192276479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 192376479Swpaul 192476479Swpaul /* 192576479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 192676479Swpaul */ 192778323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 192876479Swpaul 192976479Swpaul /* 193083115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 193183115Sbrooks * dictated by the code in the frame encapsulation routine. 193276479Swpaul */ 193376479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 193476479Swpaul 193576479Swpaul /* Set full/half duplex mode. */ 1936101540Sambrisko if (sc->nge_tbi) { 1937101540Sambrisko if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1938101540Sambrisko == IFM_FDX) { 1939101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1940101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1941101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1942101540Sambrisko } else { 1943101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1944101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1945101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1946101540Sambrisko } 194776479Swpaul } else { 1948101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1949101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1950101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1951101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1952101540Sambrisko } else { 1953101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1954101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1955101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1956101540Sambrisko } 195776479Swpaul } 195876479Swpaul 195996028Sphk nge_tick(sc); 196096028Sphk 196176479Swpaul /* 196276479Swpaul * Enable the delivery of PHY interrupts based on 196377842Swpaul * link/speed/duplex status changes. Also enable the 196477842Swpaul * extsts field in the DMA descriptors (needed for 196577842Swpaul * TCP/IP checksum offload on transmit). 196676479Swpaul */ 196779424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 196877842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 196976479Swpaul 197076479Swpaul /* 197179562Swpaul * Configure interrupt holdoff (moderation). We can 197279562Swpaul * have the chip delay interrupt delivery for a certain 197379562Swpaul * period. Units are in 100us, and the max setting 197479562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 197579562Swpaul */ 197679562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 197779562Swpaul 197879562Swpaul /* 197976479Swpaul * Enable interrupts. 198076479Swpaul */ 198176479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1982106507Ssimokawa#ifdef DEVICE_POLLING 1983106507Ssimokawa /* 1984106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1985106507Ssimokawa * they are off otherwise. 1986106507Ssimokawa */ 1987106507Ssimokawa if (ifp->if_ipending & IFF_POLLING) 1988106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1989106507Ssimokawa else 1990106507Ssimokawa#endif /* DEVICE_POLLING */ 199176479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 199276479Swpaul 199376479Swpaul /* Enable receiver and transmitter. */ 199476479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 199576479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 199676479Swpaul 199776479Swpaul nge_ifmedia_upd(ifp); 199876479Swpaul 199976479Swpaul ifp->if_flags |= IFF_RUNNING; 200076479Swpaul ifp->if_flags &= ~IFF_OACTIVE; 200176479Swpaul 200276479Swpaul (void)splx(s); 200376479Swpaul 200476479Swpaul return; 200576479Swpaul} 200676479Swpaul 200776479Swpaul/* 200876479Swpaul * Set media options. 200976479Swpaul */ 201099497Salfredstatic int 201199497Salfrednge_ifmedia_upd(ifp) 201276479Swpaul struct ifnet *ifp; 201376479Swpaul{ 201476479Swpaul struct nge_softc *sc; 201576479Swpaul struct mii_data *mii; 201676479Swpaul 201776479Swpaul sc = ifp->if_softc; 201876479Swpaul 2019101540Sambrisko if (sc->nge_tbi) { 2020101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 2021101540Sambrisko == IFM_AUTO) { 2022101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 2023101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 2024101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 2025101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 2026101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 2027101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 2028101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 2029101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 2030101540Sambrisko & IFM_GMASK) == IFM_FDX) { 2031101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 2032101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 2033101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 2034101540Sambrisko 2035101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 2036101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 2037101540Sambrisko } else { 2038101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 2039101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 2040101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 2041101540Sambrisko 2042101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 2043101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 2044101540Sambrisko } 2045101540Sambrisko 2046101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 2047101540Sambrisko & ~NGE_GPIO_GP3_OUT); 2048101540Sambrisko } else { 2049101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2050101540Sambrisko sc->nge_link = 0; 2051101540Sambrisko if (mii->mii_instance) { 2052101540Sambrisko struct mii_softc *miisc; 2053101540Sambrisko for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2054101540Sambrisko miisc = LIST_NEXT(miisc, mii_list)) 2055101540Sambrisko mii_phy_reset(miisc); 2056101540Sambrisko } 2057101540Sambrisko mii_mediachg(mii); 205876479Swpaul } 205976479Swpaul 206076479Swpaul return(0); 206176479Swpaul} 206276479Swpaul 206376479Swpaul/* 206476479Swpaul * Report current media status. 206576479Swpaul */ 206699497Salfredstatic void 206799497Salfrednge_ifmedia_sts(ifp, ifmr) 206876479Swpaul struct ifnet *ifp; 206976479Swpaul struct ifmediareq *ifmr; 207076479Swpaul{ 207176479Swpaul struct nge_softc *sc; 207276479Swpaul struct mii_data *mii; 207376479Swpaul 207476479Swpaul sc = ifp->if_softc; 207576479Swpaul 2076101540Sambrisko if (sc->nge_tbi) { 2077101540Sambrisko ifmr->ifm_status = IFM_AVALID; 2078101540Sambrisko ifmr->ifm_active = IFM_ETHER; 207976479Swpaul 2080101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 2081101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 2082101540Sambrisko } 2083101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 2084101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 2085101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 2086101540Sambrisko ifmr->ifm_active |= IFM_NONE; 2087101540Sambrisko ifmr->ifm_status = 0; 2088101540Sambrisko return; 2089101540Sambrisko } 2090101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 2091101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 2092101540Sambrisko == IFM_AUTO) { 2093101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 2094101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 2095101540Sambrisko & NGE_TBIANAR_FDX) { 2096101540Sambrisko ifmr->ifm_active |= IFM_FDX; 2097101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 2098101540Sambrisko & NGE_TBIANAR_HDX) { 2099101540Sambrisko ifmr->ifm_active |= IFM_HDX; 2100101540Sambrisko } 2101101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 2102101540Sambrisko == IFM_FDX) 2103101540Sambrisko ifmr->ifm_active |= IFM_FDX; 2104101540Sambrisko else 2105101540Sambrisko ifmr->ifm_active |= IFM_HDX; 2106101540Sambrisko 2107101540Sambrisko } else { 2108101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2109101540Sambrisko mii_pollstat(mii); 2110101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 2111101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 2112101540Sambrisko } 2113101540Sambrisko 211476479Swpaul return; 211576479Swpaul} 211676479Swpaul 211799497Salfredstatic int 211899497Salfrednge_ioctl(ifp, command, data) 211976479Swpaul struct ifnet *ifp; 212076479Swpaul u_long command; 212176479Swpaul caddr_t data; 212276479Swpaul{ 212376479Swpaul struct nge_softc *sc = ifp->if_softc; 212476479Swpaul struct ifreq *ifr = (struct ifreq *) data; 212576479Swpaul struct mii_data *mii; 212676479Swpaul int s, error = 0; 212776479Swpaul 212876479Swpaul s = splimp(); 212976479Swpaul 213076479Swpaul switch(command) { 213176479Swpaul case SIOCSIFMTU: 213276479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 213376479Swpaul error = EINVAL; 213478323Swpaul else { 213576479Swpaul ifp->if_mtu = ifr->ifr_mtu; 213678323Swpaul /* 213778323Swpaul * Workaround: if the MTU is larger than 213878323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 213978323Swpaul * TX checksum offloading. 214078323Swpaul */ 214178324Swpaul if (ifr->ifr_mtu >= 8152) 214278323Swpaul ifp->if_hwassist = 0; 214378323Swpaul else 214478323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 214578323Swpaul } 214676479Swpaul break; 214776479Swpaul case SIOCSIFFLAGS: 214876479Swpaul if (ifp->if_flags & IFF_UP) { 214976479Swpaul if (ifp->if_flags & IFF_RUNNING && 215076479Swpaul ifp->if_flags & IFF_PROMISC && 215176479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 215276479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 215376479Swpaul NGE_RXFILTCTL_ALLPHYS| 215476479Swpaul NGE_RXFILTCTL_ALLMULTI); 215576479Swpaul } else if (ifp->if_flags & IFF_RUNNING && 215676479Swpaul !(ifp->if_flags & IFF_PROMISC) && 215776479Swpaul sc->nge_if_flags & IFF_PROMISC) { 215876479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 215976479Swpaul NGE_RXFILTCTL_ALLPHYS); 216076479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 216176479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 216276479Swpaul NGE_RXFILTCTL_ALLMULTI); 216376479Swpaul } else { 216476479Swpaul ifp->if_flags &= ~IFF_RUNNING; 216576479Swpaul nge_init(sc); 216676479Swpaul } 216776479Swpaul } else { 216876479Swpaul if (ifp->if_flags & IFF_RUNNING) 216976479Swpaul nge_stop(sc); 217076479Swpaul } 217176479Swpaul sc->nge_if_flags = ifp->if_flags; 217276479Swpaul error = 0; 217376479Swpaul break; 217476479Swpaul case SIOCADDMULTI: 217576479Swpaul case SIOCDELMULTI: 217676479Swpaul nge_setmulti(sc); 217776479Swpaul error = 0; 217876479Swpaul break; 217976479Swpaul case SIOCGIFMEDIA: 218076479Swpaul case SIOCSIFMEDIA: 2181101540Sambrisko if (sc->nge_tbi) { 2182101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 2183101540Sambrisko command); 2184101540Sambrisko } else { 2185101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2186101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 2187101540Sambrisko command); 2188101540Sambrisko } 218976479Swpaul break; 219076479Swpaul default: 2191106937Ssam error = ether_ioctl(ifp, command, data); 219276479Swpaul break; 219376479Swpaul } 219476479Swpaul 219576479Swpaul (void)splx(s); 219676479Swpaul 219776479Swpaul return(error); 219876479Swpaul} 219976479Swpaul 220099497Salfredstatic void 220199497Salfrednge_watchdog(ifp) 220276479Swpaul struct ifnet *ifp; 220376479Swpaul{ 220476479Swpaul struct nge_softc *sc; 220576479Swpaul 220676479Swpaul sc = ifp->if_softc; 220776479Swpaul 220876479Swpaul ifp->if_oerrors++; 220976479Swpaul printf("nge%d: watchdog timeout\n", sc->nge_unit); 221076479Swpaul 221176479Swpaul nge_stop(sc); 221276479Swpaul nge_reset(sc); 221376479Swpaul ifp->if_flags &= ~IFF_RUNNING; 221476479Swpaul nge_init(sc); 221576479Swpaul 221676479Swpaul if (ifp->if_snd.ifq_head != NULL) 221776479Swpaul nge_start(ifp); 221876479Swpaul 221976479Swpaul return; 222076479Swpaul} 222176479Swpaul 222276479Swpaul/* 222376479Swpaul * Stop the adapter and free any mbufs allocated to the 222476479Swpaul * RX and TX lists. 222576479Swpaul */ 222699497Salfredstatic void 222799497Salfrednge_stop(sc) 222876479Swpaul struct nge_softc *sc; 222976479Swpaul{ 223076479Swpaul register int i; 223176479Swpaul struct ifnet *ifp; 223276479Swpaul struct mii_data *mii; 223376479Swpaul 223476479Swpaul ifp = &sc->arpcom.ac_if; 223576479Swpaul ifp->if_timer = 0; 2236101540Sambrisko if (sc->nge_tbi) { 2237101540Sambrisko mii = NULL; 2238101540Sambrisko } else { 2239101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2240101540Sambrisko } 224176479Swpaul 224276479Swpaul untimeout(nge_tick, sc, sc->nge_stat_ch); 2243106507Ssimokawa#ifdef DEVICE_POLLING 2244106507Ssimokawa ether_poll_deregister(ifp); 2245106507Ssimokawa#endif 224676479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 224776479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 224876479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 224976479Swpaul DELAY(1000); 225076479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 225176479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 225276479Swpaul 2253101540Sambrisko if (!sc->nge_tbi) 2254101540Sambrisko mii_down(mii); 225576479Swpaul 225676479Swpaul sc->nge_link = 0; 225776479Swpaul 225876479Swpaul /* 225976479Swpaul * Free data in the RX lists. 226076479Swpaul */ 226176479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 226276479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 226376479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 226476479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 226576479Swpaul } 226676479Swpaul } 226776479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 226876479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 226976479Swpaul 227076479Swpaul /* 227176479Swpaul * Free the TX list buffers. 227276479Swpaul */ 227376479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 227476479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 227576479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 227676479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 227776479Swpaul } 227876479Swpaul } 227976479Swpaul 228076479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 228176479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 228276479Swpaul 228376479Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 228476479Swpaul 228576479Swpaul return; 228676479Swpaul} 228776479Swpaul 228876479Swpaul/* 228976479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 229076479Swpaul * get confused by errant DMAs when rebooting. 229176479Swpaul */ 229299497Salfredstatic void 229399497Salfrednge_shutdown(dev) 229476479Swpaul device_t dev; 229576479Swpaul{ 229676479Swpaul struct nge_softc *sc; 229776479Swpaul 229876479Swpaul sc = device_get_softc(dev); 229976479Swpaul 230076479Swpaul nge_reset(sc); 230176479Swpaul nge_stop(sc); 230276479Swpaul 230376479Swpaul return; 230476479Swpaul} 2305