if_nge.c revision 128130
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 34119418Sobrien#include <sys/cdefs.h> 35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/nge/if_nge.c 128130 2004-04-11 18:28:14Z ru $"); 36119418Sobrien 3776479Swpaul/* 3876479Swpaul * National Semiconductor DP83820/DP83821 gigabit ethernet driver 3976479Swpaul * for FreeBSD. Datasheets are available from: 4076479Swpaul * 4176479Swpaul * http://www.national.com/ds/DP/DP83820.pdf 4276479Swpaul * http://www.national.com/ds/DP/DP83821.pdf 4376479Swpaul * 4476479Swpaul * These chips are used on several low cost gigabit ethernet NICs 4576479Swpaul * sold by D-Link, Addtron, SMC and Asante. Both parts are 4676479Swpaul * virtually the same, except the 83820 is a 64-bit/32-bit part, 4776479Swpaul * while the 83821 is 32-bit only. 4876479Swpaul * 4976479Swpaul * Many cards also use National gigE transceivers, such as the 5076479Swpaul * DP83891, DP83861 and DP83862 gigPHYTER parts. The DP83861 datasheet 5176479Swpaul * contains a full register description that applies to all of these 5276479Swpaul * components: 5376479Swpaul * 5476479Swpaul * http://www.national.com/ds/DP/DP83861.pdf 5576479Swpaul * 5676479Swpaul * Written by Bill Paul <wpaul@bsdi.com> 5776479Swpaul * BSDi Open Source Solutions 5876479Swpaul */ 5976479Swpaul 6076479Swpaul/* 6176479Swpaul * The NatSemi DP83820 and 83821 controllers are enhanced versions 6276479Swpaul * of the NatSemi MacPHYTER 10/100 devices. They support 10, 100 6376479Swpaul * and 1000Mbps speeds with 1000baseX (ten bit interface), MII and GMII 6476479Swpaul * ports. Other features include 8K TX FIFO and 32K RX FIFO, TCP/IP 6576479Swpaul * hardware checksum offload (IPv4 only), VLAN tagging and filtering, 6676479Swpaul * priority TX and RX queues, a 2048 bit multicast hash filter, 4 RX pattern 6776479Swpaul * matching buffers, one perfect address filter buffer and interrupt 6876479Swpaul * moderation. The 83820 supports both 64-bit and 32-bit addressing 6976479Swpaul * and data transfers: the 64-bit support can be toggled on or off 7076479Swpaul * via software. This affects the size of certain fields in the DMA 7176479Swpaul * descriptors. 7276479Swpaul * 7378323Swpaul * There are two bugs/misfeatures in the 83820/83821 that I have 7478323Swpaul * discovered so far: 7578323Swpaul * 7678323Swpaul * - Receive buffers must be aligned on 64-bit boundaries, which means 7778323Swpaul * you must resort to copying data in order to fix up the payload 7878323Swpaul * alignment. 7978323Swpaul * 8078323Swpaul * - In order to transmit jumbo frames larger than 8170 bytes, you have 8178323Swpaul * to turn off transmit checksum offloading, because the chip can't 8278323Swpaul * compute the checksum on an outgoing frame unless it fits entirely 8378323Swpaul * within the TX FIFO, which is only 8192 bytes in size. If you have 8478323Swpaul * TX checksum offload enabled and you transmit attempt to transmit a 8578323Swpaul * frame larger than 8170 bytes, the transmitter will wedge. 8678323Swpaul * 8778323Swpaul * To work around the latter problem, TX checksum offload is disabled 8878323Swpaul * if the user selects an MTU larger than 8152 (8170 - 18). 8976479Swpaul */ 9076479Swpaul 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 122119285Simp#include <dev/pci/pcireg.h> 123119285Simp#include <dev/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 *); 187123289Sobrienstatic uint32_t nge_mchash(const uint8_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 675122625Sobriennge_mchash(addr) 676123289Sobrien const uint8_t *addr; 67776479Swpaul{ 678123289Sobrien uint32_t crc, carry; 679123289Sobrien int idx, bit; 680123289Sobrien uint8_t data; 68176479Swpaul 68276479Swpaul /* Compute CRC for the address value. */ 68376479Swpaul crc = 0xFFFFFFFF; /* initial value */ 68476479Swpaul 685122625Sobrien for (idx = 0; idx < 6; idx++) { 686122625Sobrien for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { 687122625Sobrien carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); 68876479Swpaul crc <<= 1; 68976479Swpaul if (carry) 69076479Swpaul crc = (crc ^ 0x04c11db6) | carry; 69176479Swpaul } 69276479Swpaul } 69376479Swpaul 69476479Swpaul /* 69576479Swpaul * return the filter bit position 69676479Swpaul */ 69776479Swpaul 69876479Swpaul return((crc >> 21) & 0x00000FFF); 69976479Swpaul} 70076479Swpaul 70199497Salfredstatic void 70299497Salfrednge_setmulti(sc) 70376479Swpaul struct nge_softc *sc; 70476479Swpaul{ 70576479Swpaul struct ifnet *ifp; 70676479Swpaul struct ifmultiaddr *ifma; 70776479Swpaul u_int32_t h = 0, i, filtsave; 70876479Swpaul int bit, index; 70976479Swpaul 71076479Swpaul ifp = &sc->arpcom.ac_if; 71176479Swpaul 71276479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 71376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 71476479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 71576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 71676479Swpaul return; 71776479Swpaul } 71876479Swpaul 71976479Swpaul /* 72076479Swpaul * We have to explicitly enable the multicast hash table 72176479Swpaul * on the NatSemi chip if we want to use it, which we do. 72276479Swpaul * We also have to tell it that we don't want to use the 72376479Swpaul * hash table for matching unicast addresses. 72476479Swpaul */ 72576479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 72676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 72776479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 72876479Swpaul 72976479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 73076479Swpaul 73176479Swpaul /* first, zot all the existing hash bits */ 73276479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 73376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 73476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 73576479Swpaul } 73676479Swpaul 73776479Swpaul /* 73876479Swpaul * From the 11 bits returned by the crc routine, the top 7 73976479Swpaul * bits represent the 16-bit word in the mcast hash table 74076479Swpaul * that needs to be updated, and the lower 4 bits represent 74176479Swpaul * which bit within that byte needs to be set. 74276479Swpaul */ 74376479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 74476479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 74576479Swpaul continue; 746122625Sobrien h = nge_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 74776479Swpaul index = (h >> 4) & 0x7F; 74876479Swpaul bit = h & 0xF; 74976479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 75076479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 75176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 75276479Swpaul } 75376479Swpaul 75476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 75576479Swpaul 75676479Swpaul return; 75776479Swpaul} 75876479Swpaul 75999497Salfredstatic void 76099497Salfrednge_reset(sc) 76176479Swpaul struct nge_softc *sc; 76276479Swpaul{ 76376479Swpaul register int i; 76476479Swpaul 76576479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 76676479Swpaul 76776479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 76876479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 76976479Swpaul break; 77076479Swpaul } 77176479Swpaul 77276479Swpaul if (i == NGE_TIMEOUT) 77376479Swpaul printf("nge%d: reset never completed\n", sc->nge_unit); 77476479Swpaul 77576479Swpaul /* Wait a little while for the chip to get its brains in order. */ 77676479Swpaul DELAY(1000); 77776479Swpaul 77876479Swpaul /* 77976479Swpaul * If this is a NetSemi chip, make sure to clear 78076479Swpaul * PME mode. 78176479Swpaul */ 78276479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 78376479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 78476479Swpaul 78576479Swpaul return; 78676479Swpaul} 78776479Swpaul 78876479Swpaul/* 789108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 79076479Swpaul * IDs against our list and return a device name if we find a match. 79176479Swpaul */ 79299497Salfredstatic int 79399497Salfrednge_probe(dev) 79476479Swpaul device_t dev; 79576479Swpaul{ 79676479Swpaul struct nge_type *t; 79776479Swpaul 79876479Swpaul t = nge_devs; 79976479Swpaul 80076479Swpaul while(t->nge_name != NULL) { 80176479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 80276479Swpaul (pci_get_device(dev) == t->nge_did)) { 80376479Swpaul device_set_desc(dev, t->nge_name); 80476479Swpaul return(0); 80576479Swpaul } 80676479Swpaul t++; 80776479Swpaul } 80876479Swpaul 80976479Swpaul return(ENXIO); 81076479Swpaul} 81176479Swpaul 81276479Swpaul/* 81376479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 81476479Swpaul * setup and ethernet/BPF attach. 81576479Swpaul */ 81699497Salfredstatic int 81799497Salfrednge_attach(dev) 81876479Swpaul device_t dev; 81976479Swpaul{ 82076479Swpaul int s; 82176479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 82276479Swpaul struct nge_softc *sc; 82376479Swpaul struct ifnet *ifp; 82476479Swpaul int unit, error = 0, rid; 825101540Sambrisko const char *sep = ""; 82676479Swpaul 82776479Swpaul s = splimp(); 82876479Swpaul 82976479Swpaul sc = device_get_softc(dev); 83076479Swpaul unit = device_get_unit(dev); 83176479Swpaul bzero(sc, sizeof(struct nge_softc)); 83276479Swpaul 83393818Sjhb mtx_init(&sc->nge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 83493818Sjhb MTX_DEF | MTX_RECURSE); 835117198Simp#ifndef BURN_BRIDGES 83676479Swpaul /* 83776479Swpaul * Handle power management nonsense. 83876479Swpaul */ 83976479Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 84076479Swpaul u_int32_t iobase, membase, irq; 84176479Swpaul 84276479Swpaul /* Save important PCI config data. */ 84376479Swpaul iobase = pci_read_config(dev, NGE_PCI_LOIO, 4); 84476479Swpaul membase = pci_read_config(dev, NGE_PCI_LOMEM, 4); 84576479Swpaul irq = pci_read_config(dev, NGE_PCI_INTLINE, 4); 84676479Swpaul 84776479Swpaul /* Reset the power state. */ 84876479Swpaul printf("nge%d: chip is in D%d power mode " 84976479Swpaul "-- setting to D0\n", unit, 85076479Swpaul pci_get_powerstate(dev)); 85176479Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 85276479Swpaul 85376479Swpaul /* Restore PCI config data. */ 85476479Swpaul pci_write_config(dev, NGE_PCI_LOIO, iobase, 4); 85576479Swpaul pci_write_config(dev, NGE_PCI_LOMEM, membase, 4); 85676479Swpaul pci_write_config(dev, NGE_PCI_INTLINE, irq, 4); 85776479Swpaul } 858117198Simp#endif 85976479Swpaul /* 86076479Swpaul * Map control/status registers. 86176479Swpaul */ 86276479Swpaul pci_enable_busmaster(dev); 86376479Swpaul 86476479Swpaul rid = NGE_RID; 865127135Snjl sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE); 86676479Swpaul 86776479Swpaul if (sc->nge_res == NULL) { 86876479Swpaul printf("nge%d: couldn't map ports/memory\n", unit); 86976479Swpaul error = ENXIO; 87076479Swpaul goto fail; 87176479Swpaul } 87276479Swpaul 87376479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 87476479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 87576479Swpaul 87676479Swpaul /* Allocate interrupt */ 87776479Swpaul rid = 0; 878127135Snjl sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 87976479Swpaul RF_SHAREABLE | RF_ACTIVE); 88076479Swpaul 88176479Swpaul if (sc->nge_irq == NULL) { 88276479Swpaul printf("nge%d: couldn't map interrupt\n", unit); 88376479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 88476479Swpaul error = ENXIO; 88576479Swpaul goto fail; 88676479Swpaul } 88776479Swpaul 88876479Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET, 88976479Swpaul nge_intr, sc, &sc->nge_intrhand); 89076479Swpaul 89176479Swpaul if (error) { 89276479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 89376479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 89476479Swpaul printf("nge%d: couldn't set up irq\n", unit); 89576479Swpaul goto fail; 89676479Swpaul } 89776479Swpaul 89876479Swpaul /* Reset the adapter. */ 89976479Swpaul nge_reset(sc); 90076479Swpaul 90176479Swpaul /* 90276479Swpaul * Get station address from the EEPROM. 90376479Swpaul */ 90476479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 90576479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 90676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 90776479Swpaul 90876479Swpaul sc->nge_unit = unit; 90976479Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 91076479Swpaul 91176479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 91276479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 91376479Swpaul 91476479Swpaul if (sc->nge_ldata == NULL) { 91576479Swpaul printf("nge%d: no memory for list buffers!\n", unit); 91676479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 91776479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 91876479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 91976479Swpaul error = ENXIO; 92076479Swpaul goto fail; 92176479Swpaul } 92276479Swpaul bzero(sc->nge_ldata, sizeof(struct nge_list_data)); 92376479Swpaul 92476479Swpaul /* Try to allocate memory for jumbo buffers. */ 92576479Swpaul if (nge_alloc_jumbo_mem(sc)) { 92676479Swpaul printf("nge%d: jumbo buffer allocation failed\n", 92776479Swpaul sc->nge_unit); 92876479Swpaul contigfree(sc->nge_ldata, 92976479Swpaul sizeof(struct nge_list_data), M_DEVBUF); 93076479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 93176479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 93276479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 93376479Swpaul error = ENXIO; 93476479Swpaul goto fail; 93576479Swpaul } 93676479Swpaul 93776479Swpaul ifp = &sc->arpcom.ac_if; 93876479Swpaul ifp->if_softc = sc; 939121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 94076479Swpaul ifp->if_mtu = ETHERMTU; 94176479Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 94276479Swpaul ifp->if_ioctl = nge_ioctl; 94376479Swpaul ifp->if_output = ether_output; 94476479Swpaul ifp->if_start = nge_start; 94576479Swpaul ifp->if_watchdog = nge_watchdog; 94676479Swpaul ifp->if_init = nge_init; 94776479Swpaul ifp->if_baudrate = 1000000000; 94876479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 94976479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 950106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 95183632Sjlemon ifp->if_capenable = ifp->if_capabilities; 95276479Swpaul 95376479Swpaul /* 95476479Swpaul * Do MII setup. 95576479Swpaul */ 95676479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 957101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 958101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 959101540Sambrisko sc->nge_tbi = 1; 960101540Sambrisko device_printf(dev, "Using TBI\n"); 961101540Sambrisko 962101540Sambrisko sc->nge_miibus = dev; 963101540Sambrisko 964101540Sambrisko ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 965101540Sambrisko nge_ifmedia_sts); 966101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 967101540Sambrisko#define PRINT(s) printf("%s%s", sep, s); sep = ", " 968101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 969101540Sambrisko device_printf(dev, " "); 970101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 971101540Sambrisko PRINT("1000baseSX"); 972101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 973101540Sambrisko PRINT("1000baseSX-FDX"); 974101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 975101540Sambrisko PRINT("auto"); 976101540Sambrisko 977101540Sambrisko printf("\n"); 978101540Sambrisko#undef ADD 979101540Sambrisko#undef PRINT 980101540Sambrisko ifmedia_set(&sc->nge_ifmedia, 981101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 982101540Sambrisko 983101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 984101540Sambrisko | NGE_GPIO_GP4_OUT 985101540Sambrisko | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 986101540Sambrisko | NGE_GPIO_GP3_OUTENB 987101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 988101540Sambrisko 989101540Sambrisko } else { 990101540Sambrisko printf("nge%d: MII without any PHY!\n", sc->nge_unit); 991101540Sambrisko nge_free_jumbo_mem(sc); 992101540Sambrisko bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 993101540Sambrisko bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 994101540Sambrisko bus_release_resource(dev, NGE_RES, NGE_RID, 995101540Sambrisko sc->nge_res); 996101540Sambrisko error = ENXIO; 997101540Sambrisko goto fail; 998101540Sambrisko } 99976479Swpaul } 100076479Swpaul 100176479Swpaul /* 100276479Swpaul * Call MI attach routine. 100376479Swpaul */ 1004106937Ssam ether_ifattach(ifp, eaddr); 100576479Swpaul callout_handle_init(&sc->nge_stat_ch); 100676479Swpaul 100776479Swpaulfail: 1008101540Sambrisko 100976479Swpaul splx(s); 101076479Swpaul mtx_destroy(&sc->nge_mtx); 101176479Swpaul return(error); 101276479Swpaul} 101376479Swpaul 101499497Salfredstatic int 101599497Salfrednge_detach(dev) 101676479Swpaul device_t dev; 101776479Swpaul{ 101876479Swpaul struct nge_softc *sc; 101976479Swpaul struct ifnet *ifp; 102076479Swpaul int s; 102176479Swpaul 102276479Swpaul s = splimp(); 102376479Swpaul 102476479Swpaul sc = device_get_softc(dev); 102576479Swpaul ifp = &sc->arpcom.ac_if; 102676479Swpaul 102776479Swpaul nge_reset(sc); 102876479Swpaul nge_stop(sc); 1029106937Ssam ether_ifdetach(ifp); 103076479Swpaul 103176479Swpaul bus_generic_detach(dev); 1032101540Sambrisko if (!sc->nge_tbi) { 1033101540Sambrisko device_delete_child(dev, sc->nge_miibus); 1034101540Sambrisko } 103576479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 103676479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 103776479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 103876479Swpaul 103976479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 104076479Swpaul nge_free_jumbo_mem(sc); 104176479Swpaul 104276479Swpaul splx(s); 104376479Swpaul mtx_destroy(&sc->nge_mtx); 104476479Swpaul 104576479Swpaul return(0); 104676479Swpaul} 104776479Swpaul 104876479Swpaul/* 104976479Swpaul * Initialize the transmit descriptors. 105076479Swpaul */ 105199497Salfredstatic int 105299497Salfrednge_list_tx_init(sc) 105376479Swpaul struct nge_softc *sc; 105476479Swpaul{ 105576479Swpaul struct nge_list_data *ld; 105676479Swpaul struct nge_ring_data *cd; 105776479Swpaul int i; 105876479Swpaul 105976479Swpaul cd = &sc->nge_cdata; 106076479Swpaul ld = sc->nge_ldata; 106176479Swpaul 106276479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 106376479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 106476479Swpaul ld->nge_tx_list[i].nge_nextdesc = 106576479Swpaul &ld->nge_tx_list[0]; 106676479Swpaul ld->nge_tx_list[i].nge_next = 106776479Swpaul vtophys(&ld->nge_tx_list[0]); 106876479Swpaul } else { 106976479Swpaul ld->nge_tx_list[i].nge_nextdesc = 107076479Swpaul &ld->nge_tx_list[i + 1]; 107176479Swpaul ld->nge_tx_list[i].nge_next = 107276479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 107376479Swpaul } 107476479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 107576479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 107676479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 107776479Swpaul } 107876479Swpaul 107976479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 108076479Swpaul 108176479Swpaul return(0); 108276479Swpaul} 108376479Swpaul 108476479Swpaul 108576479Swpaul/* 108676479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 108776479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 108876479Swpaul * points back to the first. 108976479Swpaul */ 109099497Salfredstatic int 109199497Salfrednge_list_rx_init(sc) 109276479Swpaul struct nge_softc *sc; 109376479Swpaul{ 109476479Swpaul struct nge_list_data *ld; 109576479Swpaul struct nge_ring_data *cd; 109676479Swpaul int i; 109776479Swpaul 109876479Swpaul ld = sc->nge_ldata; 109976479Swpaul cd = &sc->nge_cdata; 110076479Swpaul 110176479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 110276479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 110376479Swpaul return(ENOBUFS); 110476479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 110576479Swpaul ld->nge_rx_list[i].nge_nextdesc = 110676479Swpaul &ld->nge_rx_list[0]; 110776479Swpaul ld->nge_rx_list[i].nge_next = 110876479Swpaul vtophys(&ld->nge_rx_list[0]); 110976479Swpaul } else { 111076479Swpaul ld->nge_rx_list[i].nge_nextdesc = 111176479Swpaul &ld->nge_rx_list[i + 1]; 111276479Swpaul ld->nge_rx_list[i].nge_next = 111376479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 111476479Swpaul } 111576479Swpaul } 111676479Swpaul 111776479Swpaul cd->nge_rx_prod = 0; 111876479Swpaul 111976479Swpaul return(0); 112076479Swpaul} 112176479Swpaul 112276479Swpaul/* 112376479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 112476479Swpaul */ 112599497Salfredstatic int 112699497Salfrednge_newbuf(sc, c, m) 112776479Swpaul struct nge_softc *sc; 112876479Swpaul struct nge_desc *c; 112976479Swpaul struct mbuf *m; 113076479Swpaul{ 113176479Swpaul struct mbuf *m_new = NULL; 113276479Swpaul caddr_t *buf = NULL; 113376479Swpaul 113476479Swpaul if (m == NULL) { 1135111119Simp MGETHDR(m_new, M_DONTWAIT, MT_DATA); 113676479Swpaul if (m_new == NULL) { 113776479Swpaul printf("nge%d: no memory for rx list " 113876479Swpaul "-- packet dropped!\n", sc->nge_unit); 113976479Swpaul return(ENOBUFS); 114076479Swpaul } 114176479Swpaul 114276479Swpaul /* Allocate the jumbo buffer */ 114376479Swpaul buf = nge_jalloc(sc); 114476479Swpaul if (buf == NULL) { 114576479Swpaul#ifdef NGE_VERBOSE 114676479Swpaul printf("nge%d: jumbo allocation failed " 114776479Swpaul "-- packet dropped!\n", sc->nge_unit); 114876479Swpaul#endif 114976479Swpaul m_freem(m_new); 115076479Swpaul return(ENOBUFS); 115176479Swpaul } 115276479Swpaul /* Attach the buffer to the mbuf */ 115376479Swpaul m_new->m_data = (void *)buf; 115478440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 115578440Swpaul MEXTADD(m_new, buf, NGE_JUMBO_FRAMELEN, nge_jfree, 115676640Swpaul (struct nge_softc *)sc, 0, EXT_NET_DRV); 115776479Swpaul } else { 115876479Swpaul m_new = m; 115978440Swpaul m_new->m_len = m_new->m_pkthdr.len = NGE_JUMBO_FRAMELEN; 116076479Swpaul m_new->m_data = m_new->m_ext.ext_buf; 116176479Swpaul } 116276479Swpaul 116376479Swpaul m_adj(m_new, sizeof(u_int64_t)); 116476479Swpaul 116576479Swpaul c->nge_mbuf = m_new; 116676479Swpaul c->nge_ptr = vtophys(mtod(m_new, caddr_t)); 116776479Swpaul c->nge_ctl = m_new->m_len; 116876479Swpaul c->nge_extsts = 0; 116976479Swpaul 117076479Swpaul return(0); 117176479Swpaul} 117276479Swpaul 117399497Salfredstatic int 117499497Salfrednge_alloc_jumbo_mem(sc) 117576479Swpaul struct nge_softc *sc; 117676479Swpaul{ 117776479Swpaul caddr_t ptr; 117876479Swpaul register int i; 117976479Swpaul struct nge_jpool_entry *entry; 118076479Swpaul 118176479Swpaul /* Grab a big chunk o' storage. */ 118276479Swpaul sc->nge_cdata.nge_jumbo_buf = contigmalloc(NGE_JMEM, M_DEVBUF, 118376479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 118476479Swpaul 118576479Swpaul if (sc->nge_cdata.nge_jumbo_buf == NULL) { 118676479Swpaul printf("nge%d: no memory for jumbo buffers!\n", sc->nge_unit); 118776479Swpaul return(ENOBUFS); 118876479Swpaul } 118976479Swpaul 119076479Swpaul SLIST_INIT(&sc->nge_jfree_listhead); 119176479Swpaul SLIST_INIT(&sc->nge_jinuse_listhead); 119276479Swpaul 119376479Swpaul /* 119476479Swpaul * Now divide it up into 9K pieces and save the addresses 119576479Swpaul * in an array. 119676479Swpaul */ 119776479Swpaul ptr = sc->nge_cdata.nge_jumbo_buf; 119876479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 119976479Swpaul sc->nge_cdata.nge_jslots[i] = ptr; 120078440Swpaul ptr += NGE_JLEN; 120176479Swpaul entry = malloc(sizeof(struct nge_jpool_entry), 120276479Swpaul M_DEVBUF, M_NOWAIT); 120376479Swpaul if (entry == NULL) { 120476479Swpaul printf("nge%d: no memory for jumbo " 120576479Swpaul "buffer queue!\n", sc->nge_unit); 120676479Swpaul return(ENOBUFS); 120776479Swpaul } 120876479Swpaul entry->slot = i; 120976479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, 121076479Swpaul entry, jpool_entries); 121176479Swpaul } 121276479Swpaul 121376479Swpaul return(0); 121476479Swpaul} 121576479Swpaul 121699497Salfredstatic void 121799497Salfrednge_free_jumbo_mem(sc) 121876479Swpaul struct nge_softc *sc; 121976479Swpaul{ 122076479Swpaul register int i; 122176479Swpaul struct nge_jpool_entry *entry; 122276479Swpaul 122376479Swpaul for (i = 0; i < NGE_JSLOTS; i++) { 122476479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 122578440Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 122676479Swpaul free(entry, M_DEVBUF); 122776479Swpaul } 122876479Swpaul 122976479Swpaul contigfree(sc->nge_cdata.nge_jumbo_buf, NGE_JMEM, M_DEVBUF); 123076479Swpaul 123176479Swpaul return; 123276479Swpaul} 123376479Swpaul 123476479Swpaul/* 123576479Swpaul * Allocate a jumbo buffer. 123676479Swpaul */ 123799497Salfredstatic void * 123899497Salfrednge_jalloc(sc) 123976479Swpaul struct nge_softc *sc; 124076479Swpaul{ 124176479Swpaul struct nge_jpool_entry *entry; 124276479Swpaul 124376479Swpaul entry = SLIST_FIRST(&sc->nge_jfree_listhead); 124476479Swpaul 124576479Swpaul if (entry == NULL) { 124676479Swpaul#ifdef NGE_VERBOSE 124776479Swpaul printf("nge%d: no free jumbo buffers\n", sc->nge_unit); 124876479Swpaul#endif 124976479Swpaul return(NULL); 125076479Swpaul } 125176479Swpaul 125276479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jfree_listhead, jpool_entries); 125376479Swpaul SLIST_INSERT_HEAD(&sc->nge_jinuse_listhead, entry, jpool_entries); 125476479Swpaul return(sc->nge_cdata.nge_jslots[entry->slot]); 125576479Swpaul} 125676479Swpaul 125776479Swpaul/* 125876479Swpaul * Release a jumbo buffer. 125976479Swpaul */ 126099497Salfredstatic void 126199497Salfrednge_jfree(buf, args) 126299004Salfred void *buf; 126376479Swpaul void *args; 126476479Swpaul{ 126576479Swpaul struct nge_softc *sc; 126676479Swpaul int i; 126776479Swpaul struct nge_jpool_entry *entry; 126876479Swpaul 126976479Swpaul /* Extract the softc struct pointer. */ 127076479Swpaul sc = args; 127176479Swpaul 127276479Swpaul if (sc == NULL) 127376479Swpaul panic("nge_jfree: can't find softc pointer!"); 127476479Swpaul 127576479Swpaul /* calculate the slot this buffer belongs to */ 127676479Swpaul i = ((vm_offset_t)buf 127776479Swpaul - (vm_offset_t)sc->nge_cdata.nge_jumbo_buf) / NGE_JLEN; 127876479Swpaul 127976479Swpaul if ((i < 0) || (i >= NGE_JSLOTS)) 128076479Swpaul panic("nge_jfree: asked to free buffer that we don't manage!"); 128176479Swpaul 128276479Swpaul entry = SLIST_FIRST(&sc->nge_jinuse_listhead); 128376479Swpaul if (entry == NULL) 128476479Swpaul panic("nge_jfree: buffer not in use!"); 128576479Swpaul entry->slot = i; 128676479Swpaul SLIST_REMOVE_HEAD(&sc->nge_jinuse_listhead, jpool_entries); 128776479Swpaul SLIST_INSERT_HEAD(&sc->nge_jfree_listhead, entry, jpool_entries); 128876479Swpaul 128976479Swpaul return; 129076479Swpaul} 129176479Swpaul/* 129276479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 129376479Swpaul * the higher level protocols. 129476479Swpaul */ 129599497Salfredstatic void 129699497Salfrednge_rxeof(sc) 129776479Swpaul struct nge_softc *sc; 129876479Swpaul{ 129976479Swpaul struct mbuf *m; 130076479Swpaul struct ifnet *ifp; 130176479Swpaul struct nge_desc *cur_rx; 130276479Swpaul int i, total_len = 0; 130376479Swpaul u_int32_t rxstat; 130476479Swpaul 130576479Swpaul ifp = &sc->arpcom.ac_if; 130676479Swpaul i = sc->nge_cdata.nge_rx_prod; 130776479Swpaul 130876479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 130976479Swpaul struct mbuf *m0 = NULL; 131076479Swpaul u_int32_t extsts; 131176479Swpaul 1312106507Ssimokawa#ifdef DEVICE_POLLING 1313128122Srwatson if (ifp->if_flags & IFF_POLLING) { 1314106507Ssimokawa if (sc->rxcycles <= 0) 1315106507Ssimokawa break; 1316106507Ssimokawa sc->rxcycles--; 1317106507Ssimokawa } 1318106507Ssimokawa#endif /* DEVICE_POLLING */ 1319106507Ssimokawa 132076479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 132176479Swpaul rxstat = cur_rx->nge_rxstat; 132276479Swpaul extsts = cur_rx->nge_extsts; 132376479Swpaul m = cur_rx->nge_mbuf; 132476479Swpaul cur_rx->nge_mbuf = NULL; 132576479Swpaul total_len = NGE_RXBYTES(cur_rx); 132676479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 132776479Swpaul /* 132876479Swpaul * If an error occurs, update stats, clear the 132976479Swpaul * status word and leave the mbuf cluster in place: 133076479Swpaul * it should simply get re-used next time this descriptor 133176479Swpaul * comes up in the ring. 133276479Swpaul */ 133376479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 133476479Swpaul ifp->if_ierrors++; 133576479Swpaul nge_newbuf(sc, cur_rx, m); 133676479Swpaul continue; 133776479Swpaul } 133876479Swpaul 133976479Swpaul /* 134076479Swpaul * Ok. NatSemi really screwed up here. This is the 134176479Swpaul * only gigE chip I know of with alignment constraints 134276479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 134376479Swpaul */ 134479562Swpaul#ifdef __i386__ 134579562Swpaul /* 134679562Swpaul * By popular demand, ignore the alignment problems 134779562Swpaul * on the Intel x86 platform. The performance hit 134879562Swpaul * incurred due to unaligned accesses is much smaller 134979562Swpaul * than the hit produced by forcing buffer copies all 135079562Swpaul * the time, especially with jumbo frames. We still 135179562Swpaul * need to fix up the alignment everywhere else though. 135279562Swpaul */ 135379562Swpaul if (nge_newbuf(sc, cur_rx, NULL) == ENOBUFS) { 135479562Swpaul#endif 135579562Swpaul m0 = m_devget(mtod(m, char *), total_len, 135679562Swpaul ETHER_ALIGN, ifp, NULL); 135779562Swpaul nge_newbuf(sc, cur_rx, m); 135879562Swpaul if (m0 == NULL) { 135979562Swpaul printf("nge%d: no receive buffers " 136079562Swpaul "available -- packet dropped!\n", 136179562Swpaul sc->nge_unit); 136279562Swpaul ifp->if_ierrors++; 136379562Swpaul continue; 136479562Swpaul } 136579562Swpaul m = m0; 136679562Swpaul#ifdef __i386__ 136779562Swpaul } else { 136879562Swpaul m->m_pkthdr.rcvif = ifp; 136979562Swpaul m->m_pkthdr.len = m->m_len = total_len; 137076479Swpaul } 137179562Swpaul#endif 137276479Swpaul 137376479Swpaul ifp->if_ipackets++; 137476479Swpaul 137576479Swpaul /* Do IP checksum checking. */ 137678323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 137778323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 137878323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 137978323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 138078323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 138178323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 138278323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 138378323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 138478323Swpaul m->m_pkthdr.csum_flags |= 138578323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 138678323Swpaul m->m_pkthdr.csum_data = 0xffff; 138778323Swpaul } 138876479Swpaul 138976479Swpaul /* 139076479Swpaul * If we received a packet with a vlan tag, pass it 139176479Swpaul * to vlan_input() instead of ether_input(). 139276479Swpaul */ 139376479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1394106937Ssam VLAN_INPUT_TAG(ifp, m, 1395127615Sru ntohs(extsts & NGE_RXEXTSTS_VTCI), continue); 1396106937Ssam } 139776479Swpaul 1398106937Ssam (*ifp->if_input)(ifp, m); 139976479Swpaul } 140076479Swpaul 140176479Swpaul sc->nge_cdata.nge_rx_prod = i; 140276479Swpaul 140376479Swpaul return; 140476479Swpaul} 140576479Swpaul 140676479Swpaul/* 140776479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 140876479Swpaul * the list buffers. 140976479Swpaul */ 141076479Swpaul 141199497Salfredstatic void 141299497Salfrednge_txeof(sc) 141376479Swpaul struct nge_softc *sc; 141476479Swpaul{ 1415128130Sru struct nge_desc *cur_tx; 141676479Swpaul struct ifnet *ifp; 141776479Swpaul u_int32_t idx; 141876479Swpaul 141976479Swpaul ifp = &sc->arpcom.ac_if; 142076479Swpaul 142176479Swpaul /* 142276479Swpaul * Go through our tx list and free mbufs for those 142376479Swpaul * frames that have been transmitted. 142476479Swpaul */ 142576479Swpaul idx = sc->nge_cdata.nge_tx_cons; 142676479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 142776479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 142876479Swpaul 142976479Swpaul if (NGE_OWNDESC(cur_tx)) 143076479Swpaul break; 143176479Swpaul 143276479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 143376479Swpaul sc->nge_cdata.nge_tx_cnt--; 143476479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 143576479Swpaul continue; 143676479Swpaul } 143776479Swpaul 143876479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 143976479Swpaul ifp->if_oerrors++; 144076479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 144176479Swpaul ifp->if_collisions++; 144276479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 144376479Swpaul ifp->if_collisions++; 144476479Swpaul } 144576479Swpaul 144676479Swpaul ifp->if_collisions += 144776479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 144876479Swpaul 144976479Swpaul ifp->if_opackets++; 145076479Swpaul if (cur_tx->nge_mbuf != NULL) { 145176479Swpaul m_freem(cur_tx->nge_mbuf); 145276479Swpaul cur_tx->nge_mbuf = NULL; 1453128130Sru ifp->if_flags &= ~IFF_OACTIVE; 145476479Swpaul } 145576479Swpaul 145676479Swpaul sc->nge_cdata.nge_tx_cnt--; 145776479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 145876479Swpaul } 145976479Swpaul 146076479Swpaul sc->nge_cdata.nge_tx_cons = idx; 146176479Swpaul 1462128130Sru if (idx == sc->nge_cdata.nge_tx_prod) 1463128130Sru ifp->if_timer = 0; 146476479Swpaul 146576479Swpaul return; 146676479Swpaul} 146776479Swpaul 146899497Salfredstatic void 146999497Salfrednge_tick(xsc) 147076479Swpaul void *xsc; 147176479Swpaul{ 147276479Swpaul struct nge_softc *sc; 147376479Swpaul struct mii_data *mii; 147476479Swpaul struct ifnet *ifp; 147576479Swpaul int s; 147676479Swpaul 147776479Swpaul s = splimp(); 147876479Swpaul 147976479Swpaul sc = xsc; 148076479Swpaul ifp = &sc->arpcom.ac_if; 148176479Swpaul 1482101540Sambrisko if (sc->nge_tbi) { 1483101540Sambrisko if (!sc->nge_link) { 1484101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) 1485101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 148676479Swpaul printf("nge%d: gigabit link up\n", 148776479Swpaul sc->nge_unit); 1488101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1489101540Sambrisko sc->nge_link++; 1490101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1491101540Sambrisko nge_start(ifp); 1492101540Sambrisko } 149396028Sphk } 1494101540Sambrisko } else { 1495101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1496101540Sambrisko mii_tick(mii); 1497101540Sambrisko 1498101540Sambrisko if (!sc->nge_link) { 1499101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1500101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1501101540Sambrisko sc->nge_link++; 1502101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) 1503101540Sambrisko == IFM_1000_T) 1504101540Sambrisko printf("nge%d: gigabit link up\n", 1505101540Sambrisko sc->nge_unit); 1506101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1507101540Sambrisko nge_start(ifp); 1508101540Sambrisko } 1509101540Sambrisko } 151076479Swpaul } 151196028Sphk sc->nge_stat_ch = timeout(nge_tick, sc, hz); 151276479Swpaul 151376479Swpaul splx(s); 151476479Swpaul 151576479Swpaul return; 151676479Swpaul} 151776479Swpaul 1518106507Ssimokawa#ifdef DEVICE_POLLING 1519106507Ssimokawastatic poll_handler_t nge_poll; 1520106507Ssimokawa 152199497Salfredstatic void 1522106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1523106507Ssimokawa{ 1524106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1525106507Ssimokawa 1526106507Ssimokawa if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 1527106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 1); 1528106507Ssimokawa return; 1529106507Ssimokawa } 1530106507Ssimokawa 1531106507Ssimokawa /* 1532106507Ssimokawa * On the nge, reading the status register also clears it. 1533106507Ssimokawa * So before returning to intr mode we must make sure that all 1534106507Ssimokawa * possible pending sources of interrupts have been served. 1535106507Ssimokawa * In practice this means run to completion the *eof routines, 1536106507Ssimokawa * and then call the interrupt routine 1537106507Ssimokawa */ 1538106507Ssimokawa sc->rxcycles = count; 1539106507Ssimokawa nge_rxeof(sc); 1540106507Ssimokawa nge_txeof(sc); 1541106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1542106507Ssimokawa nge_start(ifp); 1543106507Ssimokawa 1544106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1545106507Ssimokawa u_int32_t status; 1546106507Ssimokawa 1547106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1548106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1549106507Ssimokawa 1550106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1551106507Ssimokawa nge_rxeof(sc); 1552106507Ssimokawa 1553106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1554106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1555106507Ssimokawa 1556106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1557106507Ssimokawa nge_reset(sc); 1558106507Ssimokawa nge_init(sc); 1559106507Ssimokawa } 1560106507Ssimokawa } 1561106507Ssimokawa} 1562106507Ssimokawa#endif /* DEVICE_POLLING */ 1563106507Ssimokawa 1564106507Ssimokawastatic void 156599497Salfrednge_intr(arg) 156676479Swpaul void *arg; 156776479Swpaul{ 156876479Swpaul struct nge_softc *sc; 156976479Swpaul struct ifnet *ifp; 157076479Swpaul u_int32_t status; 157176479Swpaul 157276479Swpaul sc = arg; 157376479Swpaul ifp = &sc->arpcom.ac_if; 157476479Swpaul 1575106507Ssimokawa#ifdef DEVICE_POLLING 1576128122Srwatson if (ifp->if_flags & IFF_POLLING) 1577106507Ssimokawa return; 1578106507Ssimokawa if (ether_poll_register(nge_poll, ifp)) { /* ok, disable interrupts */ 1579106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1580106507Ssimokawa nge_poll(ifp, 0, 1); 1581106507Ssimokawa return; 1582106507Ssimokawa } 1583106507Ssimokawa#endif /* DEVICE_POLLING */ 1584106507Ssimokawa 158576479Swpaul /* Supress unwanted interrupts */ 158676479Swpaul if (!(ifp->if_flags & IFF_UP)) { 158776479Swpaul nge_stop(sc); 158876479Swpaul return; 158976479Swpaul } 159076479Swpaul 159176479Swpaul /* Disable interrupts. */ 159276479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 159376479Swpaul 1594101540Sambrisko /* Data LED on for TBI mode */ 1595101540Sambrisko if(sc->nge_tbi) 1596101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1597101540Sambrisko | NGE_GPIO_GP3_OUT); 1598101540Sambrisko 159976479Swpaul for (;;) { 160076479Swpaul /* Reading the ISR register clears all interrupts. */ 160176479Swpaul status = CSR_READ_4(sc, NGE_ISR); 160276479Swpaul 160376479Swpaul if ((status & NGE_INTRS) == 0) 160476479Swpaul break; 160576479Swpaul 160676479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 160776479Swpaul (status & NGE_ISR_TX_ERR) || 160876479Swpaul (status & NGE_ISR_TX_OK) || 160976479Swpaul (status & NGE_ISR_TX_IDLE)) 161076479Swpaul nge_txeof(sc); 161176479Swpaul 161276479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 161379798Swpaul (status & NGE_ISR_RX_ERR) || 161483678Swpaul (status & NGE_ISR_RX_OFLOW) || 161594612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 161694612Sphk (status & NGE_ISR_RX_IDLE) || 161776479Swpaul (status & NGE_ISR_RX_OK)) 161876479Swpaul nge_rxeof(sc); 161994612Sphk 162094612Sphk if ((status & NGE_ISR_RX_IDLE)) 162194612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 162294612Sphk 162376479Swpaul if (status & NGE_ISR_SYSERR) { 162476479Swpaul nge_reset(sc); 162576479Swpaul ifp->if_flags &= ~IFF_RUNNING; 162676479Swpaul nge_init(sc); 162776479Swpaul } 162876479Swpaul 162996028Sphk#if 0 163096028Sphk /* 163196028Sphk * XXX: nge_tick() is not ready to be called this way 163296028Sphk * it screws up the aneg timeout because mii_tick() is 163396028Sphk * only to be called once per second. 163496028Sphk */ 163576479Swpaul if (status & NGE_IMR_PHY_INTR) { 163676479Swpaul sc->nge_link = 0; 163776479Swpaul nge_tick(sc); 163876479Swpaul } 163996028Sphk#endif 164076479Swpaul } 164176479Swpaul 164276479Swpaul /* Re-enable interrupts. */ 164376479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 164476479Swpaul 164576479Swpaul if (ifp->if_snd.ifq_head != NULL) 164676479Swpaul nge_start(ifp); 164776479Swpaul 1648101540Sambrisko /* Data LED off for TBI mode */ 1649101540Sambrisko 1650101540Sambrisko if(sc->nge_tbi) 1651101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1652101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1653101540Sambrisko 165476479Swpaul return; 165576479Swpaul} 165676479Swpaul 165776479Swpaul/* 165876479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 165976479Swpaul * pointers to the fragment pointers. 166076479Swpaul */ 166199497Salfredstatic int 166299497Salfrednge_encap(sc, m_head, txidx) 166376479Swpaul struct nge_softc *sc; 166476479Swpaul struct mbuf *m_head; 166576479Swpaul u_int32_t *txidx; 166676479Swpaul{ 166776479Swpaul struct nge_desc *f = NULL; 166876479Swpaul struct mbuf *m; 166976479Swpaul int frag, cur, cnt = 0; 1670106937Ssam struct m_tag *mtag; 167176479Swpaul 167276479Swpaul /* 167376479Swpaul * Start packing the mbufs in this chain into 167476479Swpaul * the fragment pointers. Stop when we run out 167576479Swpaul * of fragments or hit the end of the mbuf chain. 167676479Swpaul */ 167776479Swpaul m = m_head; 167876479Swpaul cur = frag = *txidx; 167976479Swpaul 168076479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 168176479Swpaul if (m->m_len != 0) { 168276479Swpaul if ((NGE_TX_LIST_CNT - 168376479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 168476479Swpaul return(ENOBUFS); 168576479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 168676479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 168776479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 168876479Swpaul if (cnt != 0) 168976479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 169076479Swpaul cur = frag; 169176479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 169276479Swpaul cnt++; 169376479Swpaul } 169476479Swpaul } 169576479Swpaul 169676479Swpaul if (m != NULL) 169776479Swpaul return(ENOBUFS); 169876479Swpaul 169978286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 170076479Swpaul if (m_head->m_pkthdr.csum_flags) { 170176479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 170278286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 170376479Swpaul NGE_TXEXTSTS_IPCSUM; 170476479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 170578286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 170676479Swpaul NGE_TXEXTSTS_TCPCSUM; 170776479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 170878286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 170976479Swpaul NGE_TXEXTSTS_UDPCSUM; 171076479Swpaul } 171176479Swpaul 1712106937Ssam mtag = VLAN_OUTPUT_TAG(&sc->arpcom.ac_if, m); 1713106937Ssam if (mtag != NULL) { 171476479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1715127615Sru (NGE_TXEXTSTS_VLANPKT|htons(VLAN_TAG_VALUE(mtag))); 171676479Swpaul } 171776479Swpaul 171876479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 171976479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 172076479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 172176479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 172276479Swpaul *txidx = frag; 172376479Swpaul 172476479Swpaul return(0); 172576479Swpaul} 172676479Swpaul 172776479Swpaul/* 172876479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 172976479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 173076479Swpaul * copy of the pointers since the transmit list fragment pointers are 173176479Swpaul * physical addresses. 173276479Swpaul */ 173376479Swpaul 173499497Salfredstatic void 173599497Salfrednge_start(ifp) 173676479Swpaul struct ifnet *ifp; 173776479Swpaul{ 173876479Swpaul struct nge_softc *sc; 173976479Swpaul struct mbuf *m_head = NULL; 174076479Swpaul u_int32_t idx; 174176479Swpaul 174276479Swpaul sc = ifp->if_softc; 174376479Swpaul 174476479Swpaul if (!sc->nge_link) 174576479Swpaul return; 174676479Swpaul 174776479Swpaul idx = sc->nge_cdata.nge_tx_prod; 174876479Swpaul 174976479Swpaul if (ifp->if_flags & IFF_OACTIVE) 175076479Swpaul return; 175176479Swpaul 175276479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 175376479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 175476479Swpaul if (m_head == NULL) 175576479Swpaul break; 175676479Swpaul 175776479Swpaul if (nge_encap(sc, m_head, &idx)) { 175876479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 175976479Swpaul ifp->if_flags |= IFF_OACTIVE; 176076479Swpaul break; 176176479Swpaul } 176276479Swpaul 176376479Swpaul /* 176476479Swpaul * If there's a BPF listener, bounce a copy of this frame 176576479Swpaul * to him. 176676479Swpaul */ 1767106937Ssam BPF_MTAP(ifp, m_head); 176876479Swpaul 176976479Swpaul } 177076479Swpaul 177176479Swpaul /* Transmit */ 177276479Swpaul sc->nge_cdata.nge_tx_prod = idx; 177376479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 177476479Swpaul 177576479Swpaul /* 177676479Swpaul * Set a timeout in case the chip goes out to lunch. 177776479Swpaul */ 177876479Swpaul ifp->if_timer = 5; 177976479Swpaul 178076479Swpaul return; 178176479Swpaul} 178276479Swpaul 178399497Salfredstatic void 178499497Salfrednge_init(xsc) 178576479Swpaul void *xsc; 178676479Swpaul{ 178776479Swpaul struct nge_softc *sc = xsc; 178876479Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 178976479Swpaul struct mii_data *mii; 179076479Swpaul int s; 179176479Swpaul 179276479Swpaul if (ifp->if_flags & IFF_RUNNING) 179376479Swpaul return; 179476479Swpaul 179576479Swpaul s = splimp(); 179676479Swpaul 179776479Swpaul /* 179876479Swpaul * Cancel pending I/O and free all RX/TX buffers. 179976479Swpaul */ 180076479Swpaul nge_stop(sc); 180176479Swpaul 1802101540Sambrisko if (sc->nge_tbi) { 1803101540Sambrisko mii = NULL; 1804101540Sambrisko } else { 1805101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1806101540Sambrisko } 180776479Swpaul 180876479Swpaul /* Set MAC address */ 180976479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 181076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 181176479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 181276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 181376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 181476479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 181576479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 181676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 181776479Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 181876479Swpaul 181976479Swpaul /* Init circular RX list. */ 182076479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 182176479Swpaul printf("nge%d: initialization failed: no " 182276479Swpaul "memory for rx buffers\n", sc->nge_unit); 182376479Swpaul nge_stop(sc); 182476479Swpaul (void)splx(s); 182576479Swpaul return; 182676479Swpaul } 182776479Swpaul 182876479Swpaul /* 182976479Swpaul * Init tx descriptors. 183076479Swpaul */ 183176479Swpaul nge_list_tx_init(sc); 183276479Swpaul 183376479Swpaul /* 183476479Swpaul * For the NatSemi chip, we have to explicitly enable the 183576479Swpaul * reception of ARP frames, as well as turn on the 'perfect 183676479Swpaul * match' filter where we store the station address, otherwise 183776479Swpaul * we won't receive unicasts meant for this host. 183876479Swpaul */ 183976479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 184076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 184176479Swpaul 184276479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 184376479Swpaul if (ifp->if_flags & IFF_PROMISC) { 184476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 184576479Swpaul } else { 184676479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 184776479Swpaul } 184876479Swpaul 184976479Swpaul /* 185076479Swpaul * Set the capture broadcast bit to capture broadcast frames. 185176479Swpaul */ 185276479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 185376479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 185476479Swpaul } else { 185576479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 185676479Swpaul } 185776479Swpaul 185876479Swpaul /* 185976479Swpaul * Load the multicast filter. 186076479Swpaul */ 186176479Swpaul nge_setmulti(sc); 186276479Swpaul 186376479Swpaul /* Turn the receive filter on */ 186476479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 186576479Swpaul 186676479Swpaul /* 186776479Swpaul * Load the address of the RX and TX lists. 186876479Swpaul */ 186976479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 187076479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 187176479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 187276479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 187376479Swpaul 187476479Swpaul /* Set RX configuration */ 187576479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 187676479Swpaul /* 187776479Swpaul * Enable hardware checksum validation for all IPv4 187876479Swpaul * packets, do not reject packets with bad checksums. 187976479Swpaul */ 188078323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 188176479Swpaul 188276479Swpaul /* 188383115Sbrooks * Tell the chip to detect and strip VLAN tag info from 188483115Sbrooks * received frames. The tag will be provided in the extsts 188583115Sbrooks * field in the RX descriptors. 188676479Swpaul */ 188776479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 188876479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 188976479Swpaul 189076479Swpaul /* Set TX configuration */ 189176479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 189276479Swpaul 189376479Swpaul /* 189476479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 189576479Swpaul */ 189678323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 189776479Swpaul 189876479Swpaul /* 189983115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 190083115Sbrooks * dictated by the code in the frame encapsulation routine. 190176479Swpaul */ 190276479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 190376479Swpaul 190476479Swpaul /* Set full/half duplex mode. */ 1905101540Sambrisko if (sc->nge_tbi) { 1906101540Sambrisko if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1907101540Sambrisko == IFM_FDX) { 1908101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1909101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1910101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1911101540Sambrisko } else { 1912101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1913101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1914101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1915101540Sambrisko } 191676479Swpaul } else { 1917101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1918101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1919101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1920101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1921101540Sambrisko } else { 1922101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1923101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1924101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1925101540Sambrisko } 192676479Swpaul } 192776479Swpaul 192896028Sphk nge_tick(sc); 192996028Sphk 193076479Swpaul /* 193176479Swpaul * Enable the delivery of PHY interrupts based on 193277842Swpaul * link/speed/duplex status changes. Also enable the 193377842Swpaul * extsts field in the DMA descriptors (needed for 193477842Swpaul * TCP/IP checksum offload on transmit). 193576479Swpaul */ 193679424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 193777842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 193876479Swpaul 193976479Swpaul /* 194079562Swpaul * Configure interrupt holdoff (moderation). We can 194179562Swpaul * have the chip delay interrupt delivery for a certain 194279562Swpaul * period. Units are in 100us, and the max setting 194379562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 194479562Swpaul */ 194579562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 194679562Swpaul 194779562Swpaul /* 194876479Swpaul * Enable interrupts. 194976479Swpaul */ 195076479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1951106507Ssimokawa#ifdef DEVICE_POLLING 1952106507Ssimokawa /* 1953106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1954106507Ssimokawa * they are off otherwise. 1955106507Ssimokawa */ 1956128122Srwatson if (ifp->if_flags & IFF_POLLING) 1957106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1958106507Ssimokawa else 1959106507Ssimokawa#endif /* DEVICE_POLLING */ 196076479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 196176479Swpaul 196276479Swpaul /* Enable receiver and transmitter. */ 196376479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 196476479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 196576479Swpaul 196676479Swpaul nge_ifmedia_upd(ifp); 196776479Swpaul 196876479Swpaul ifp->if_flags |= IFF_RUNNING; 196976479Swpaul ifp->if_flags &= ~IFF_OACTIVE; 197076479Swpaul 197176479Swpaul (void)splx(s); 197276479Swpaul 197376479Swpaul return; 197476479Swpaul} 197576479Swpaul 197676479Swpaul/* 197776479Swpaul * Set media options. 197876479Swpaul */ 197999497Salfredstatic int 198099497Salfrednge_ifmedia_upd(ifp) 198176479Swpaul struct ifnet *ifp; 198276479Swpaul{ 198376479Swpaul struct nge_softc *sc; 198476479Swpaul struct mii_data *mii; 198576479Swpaul 198676479Swpaul sc = ifp->if_softc; 198776479Swpaul 1988101540Sambrisko if (sc->nge_tbi) { 1989101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1990101540Sambrisko == IFM_AUTO) { 1991101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 1992101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 1993101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 1994101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 1995101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 1996101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 1997101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 1998101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 1999101540Sambrisko & IFM_GMASK) == IFM_FDX) { 2000101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 2001101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 2002101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 2003101540Sambrisko 2004101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 2005101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 2006101540Sambrisko } else { 2007101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 2008101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 2009101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 2010101540Sambrisko 2011101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 2012101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 2013101540Sambrisko } 2014101540Sambrisko 2015101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 2016101540Sambrisko & ~NGE_GPIO_GP3_OUT); 2017101540Sambrisko } else { 2018101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2019101540Sambrisko sc->nge_link = 0; 2020101540Sambrisko if (mii->mii_instance) { 2021101540Sambrisko struct mii_softc *miisc; 2022101540Sambrisko for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 2023101540Sambrisko miisc = LIST_NEXT(miisc, mii_list)) 2024101540Sambrisko mii_phy_reset(miisc); 2025101540Sambrisko } 2026101540Sambrisko mii_mediachg(mii); 202776479Swpaul } 202876479Swpaul 202976479Swpaul return(0); 203076479Swpaul} 203176479Swpaul 203276479Swpaul/* 203376479Swpaul * Report current media status. 203476479Swpaul */ 203599497Salfredstatic void 203699497Salfrednge_ifmedia_sts(ifp, ifmr) 203776479Swpaul struct ifnet *ifp; 203876479Swpaul struct ifmediareq *ifmr; 203976479Swpaul{ 204076479Swpaul struct nge_softc *sc; 204176479Swpaul struct mii_data *mii; 204276479Swpaul 204376479Swpaul sc = ifp->if_softc; 204476479Swpaul 2045101540Sambrisko if (sc->nge_tbi) { 2046101540Sambrisko ifmr->ifm_status = IFM_AVALID; 2047101540Sambrisko ifmr->ifm_active = IFM_ETHER; 204876479Swpaul 2049101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 2050101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 2051101540Sambrisko } 2052101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 2053101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 2054101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 2055101540Sambrisko ifmr->ifm_active |= IFM_NONE; 2056101540Sambrisko ifmr->ifm_status = 0; 2057101540Sambrisko return; 2058101540Sambrisko } 2059101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 2060101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 2061101540Sambrisko == IFM_AUTO) { 2062101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 2063101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 2064101540Sambrisko & NGE_TBIANAR_FDX) { 2065101540Sambrisko ifmr->ifm_active |= IFM_FDX; 2066101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 2067101540Sambrisko & NGE_TBIANAR_HDX) { 2068101540Sambrisko ifmr->ifm_active |= IFM_HDX; 2069101540Sambrisko } 2070101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 2071101540Sambrisko == IFM_FDX) 2072101540Sambrisko ifmr->ifm_active |= IFM_FDX; 2073101540Sambrisko else 2074101540Sambrisko ifmr->ifm_active |= IFM_HDX; 2075101540Sambrisko 2076101540Sambrisko } else { 2077101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2078101540Sambrisko mii_pollstat(mii); 2079101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 2080101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 2081101540Sambrisko } 2082101540Sambrisko 208376479Swpaul return; 208476479Swpaul} 208576479Swpaul 208699497Salfredstatic int 208799497Salfrednge_ioctl(ifp, command, data) 208876479Swpaul struct ifnet *ifp; 208976479Swpaul u_long command; 209076479Swpaul caddr_t data; 209176479Swpaul{ 209276479Swpaul struct nge_softc *sc = ifp->if_softc; 209376479Swpaul struct ifreq *ifr = (struct ifreq *) data; 209476479Swpaul struct mii_data *mii; 209576479Swpaul int s, error = 0; 209676479Swpaul 209776479Swpaul s = splimp(); 209876479Swpaul 209976479Swpaul switch(command) { 210076479Swpaul case SIOCSIFMTU: 210176479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 210276479Swpaul error = EINVAL; 210378323Swpaul else { 210476479Swpaul ifp->if_mtu = ifr->ifr_mtu; 210578323Swpaul /* 210678323Swpaul * Workaround: if the MTU is larger than 210778323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 210878323Swpaul * TX checksum offloading. 210978323Swpaul */ 211078324Swpaul if (ifr->ifr_mtu >= 8152) 211178323Swpaul ifp->if_hwassist = 0; 211278323Swpaul else 211378323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 211478323Swpaul } 211576479Swpaul break; 211676479Swpaul case SIOCSIFFLAGS: 211776479Swpaul if (ifp->if_flags & IFF_UP) { 211876479Swpaul if (ifp->if_flags & IFF_RUNNING && 211976479Swpaul ifp->if_flags & IFF_PROMISC && 212076479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 212176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 212276479Swpaul NGE_RXFILTCTL_ALLPHYS| 212376479Swpaul NGE_RXFILTCTL_ALLMULTI); 212476479Swpaul } else if (ifp->if_flags & IFF_RUNNING && 212576479Swpaul !(ifp->if_flags & IFF_PROMISC) && 212676479Swpaul sc->nge_if_flags & IFF_PROMISC) { 212776479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 212876479Swpaul NGE_RXFILTCTL_ALLPHYS); 212976479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 213076479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 213176479Swpaul NGE_RXFILTCTL_ALLMULTI); 213276479Swpaul } else { 213376479Swpaul ifp->if_flags &= ~IFF_RUNNING; 213476479Swpaul nge_init(sc); 213576479Swpaul } 213676479Swpaul } else { 213776479Swpaul if (ifp->if_flags & IFF_RUNNING) 213876479Swpaul nge_stop(sc); 213976479Swpaul } 214076479Swpaul sc->nge_if_flags = ifp->if_flags; 214176479Swpaul error = 0; 214276479Swpaul break; 214376479Swpaul case SIOCADDMULTI: 214476479Swpaul case SIOCDELMULTI: 214576479Swpaul nge_setmulti(sc); 214676479Swpaul error = 0; 214776479Swpaul break; 214876479Swpaul case SIOCGIFMEDIA: 214976479Swpaul case SIOCSIFMEDIA: 2150101540Sambrisko if (sc->nge_tbi) { 2151101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 2152101540Sambrisko command); 2153101540Sambrisko } else { 2154101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2155101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 2156101540Sambrisko command); 2157101540Sambrisko } 215876479Swpaul break; 215976479Swpaul default: 2160106937Ssam error = ether_ioctl(ifp, command, data); 216176479Swpaul break; 216276479Swpaul } 216376479Swpaul 216476479Swpaul (void)splx(s); 216576479Swpaul 216676479Swpaul return(error); 216776479Swpaul} 216876479Swpaul 216999497Salfredstatic void 217099497Salfrednge_watchdog(ifp) 217176479Swpaul struct ifnet *ifp; 217276479Swpaul{ 217376479Swpaul struct nge_softc *sc; 217476479Swpaul 217576479Swpaul sc = ifp->if_softc; 217676479Swpaul 217776479Swpaul ifp->if_oerrors++; 217876479Swpaul printf("nge%d: watchdog timeout\n", sc->nge_unit); 217976479Swpaul 218076479Swpaul nge_stop(sc); 218176479Swpaul nge_reset(sc); 218276479Swpaul ifp->if_flags &= ~IFF_RUNNING; 218376479Swpaul nge_init(sc); 218476479Swpaul 218576479Swpaul if (ifp->if_snd.ifq_head != NULL) 218676479Swpaul nge_start(ifp); 218776479Swpaul 218876479Swpaul return; 218976479Swpaul} 219076479Swpaul 219176479Swpaul/* 219276479Swpaul * Stop the adapter and free any mbufs allocated to the 219376479Swpaul * RX and TX lists. 219476479Swpaul */ 219599497Salfredstatic void 219699497Salfrednge_stop(sc) 219776479Swpaul struct nge_softc *sc; 219876479Swpaul{ 219976479Swpaul register int i; 220076479Swpaul struct ifnet *ifp; 220176479Swpaul struct mii_data *mii; 220276479Swpaul 220376479Swpaul ifp = &sc->arpcom.ac_if; 220476479Swpaul ifp->if_timer = 0; 2205101540Sambrisko if (sc->nge_tbi) { 2206101540Sambrisko mii = NULL; 2207101540Sambrisko } else { 2208101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2209101540Sambrisko } 221076479Swpaul 221176479Swpaul untimeout(nge_tick, sc, sc->nge_stat_ch); 2212106507Ssimokawa#ifdef DEVICE_POLLING 2213106507Ssimokawa ether_poll_deregister(ifp); 2214106507Ssimokawa#endif 221576479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 221676479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 221776479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 221876479Swpaul DELAY(1000); 221976479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 222076479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 222176479Swpaul 2222101540Sambrisko if (!sc->nge_tbi) 2223101540Sambrisko mii_down(mii); 222476479Swpaul 222576479Swpaul sc->nge_link = 0; 222676479Swpaul 222776479Swpaul /* 222876479Swpaul * Free data in the RX lists. 222976479Swpaul */ 223076479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 223176479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 223276479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 223376479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 223476479Swpaul } 223576479Swpaul } 223676479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 223776479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 223876479Swpaul 223976479Swpaul /* 224076479Swpaul * Free the TX list buffers. 224176479Swpaul */ 224276479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 224376479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 224476479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 224576479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 224676479Swpaul } 224776479Swpaul } 224876479Swpaul 224976479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 225076479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 225176479Swpaul 225276479Swpaul ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 225376479Swpaul 225476479Swpaul return; 225576479Swpaul} 225676479Swpaul 225776479Swpaul/* 225876479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 225976479Swpaul * get confused by errant DMAs when rebooting. 226076479Swpaul */ 226199497Salfredstatic void 226299497Salfrednge_shutdown(dev) 226376479Swpaul device_t dev; 226476479Swpaul{ 226576479Swpaul struct nge_softc *sc; 226676479Swpaul 226776479Swpaul sc = device_get_softc(dev); 226876479Swpaul 226976479Swpaul nge_reset(sc); 227076479Swpaul nge_stop(sc); 227176479Swpaul 227276479Swpaul return; 227376479Swpaul} 2274