if_nge.c revision 150306
1139749Simp/*- 276479Swpaul * Copyright (c) 2001 Wind River Systems 376479Swpaul * Copyright (c) 1997, 1998, 1999, 2000, 2001 476479Swpaul * Bill Paul <wpaul@bsdi.com>. All rights reserved. 576479Swpaul * 676479Swpaul * Redistribution and use in source and binary forms, with or without 776479Swpaul * modification, are permitted provided that the following conditions 876479Swpaul * are met: 976479Swpaul * 1. Redistributions of source code must retain the above copyright 1076479Swpaul * notice, this list of conditions and the following disclaimer. 1176479Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1276479Swpaul * notice, this list of conditions and the following disclaimer in the 1376479Swpaul * documentation and/or other materials provided with the distribution. 1476479Swpaul * 3. All advertising materials mentioning features or use of this software 1576479Swpaul * must display the following acknowledgement: 1676479Swpaul * This product includes software developed by Bill Paul. 1776479Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1876479Swpaul * may be used to endorse or promote products derived from this software 1976479Swpaul * without specific prior written permission. 2076479Swpaul * 2176479Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2276479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2376479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2476479Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2576479Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2676479Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2776479Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2876479Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2976479Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3076479Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3176479Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3276479Swpaul */ 3376479Swpaul 34119418Sobrien#include <sys/cdefs.h> 35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/nge/if_nge.c 150306 2005-09-19 03:10:21Z imp $"); 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> 96129879Sphk#include <sys/module.h> 9776479Swpaul#include <sys/kernel.h> 9876479Swpaul#include <sys/socket.h> 9976479Swpaul 10076479Swpaul#include <net/if.h> 10176479Swpaul#include <net/if_arp.h> 10276479Swpaul#include <net/ethernet.h> 10376479Swpaul#include <net/if_dl.h> 10476479Swpaul#include <net/if_media.h> 10576479Swpaul#include <net/if_types.h> 10676479Swpaul#include <net/if_vlan_var.h> 10776479Swpaul 10876479Swpaul#include <net/bpf.h> 10976479Swpaul 11076479Swpaul#include <vm/vm.h> /* for vtophys */ 11176479Swpaul#include <vm/pmap.h> /* for vtophys */ 11276479Swpaul#include <machine/clock.h> /* for DELAY */ 11376479Swpaul#include <machine/bus.h> 11476479Swpaul#include <machine/resource.h> 11576479Swpaul#include <sys/bus.h> 11676479Swpaul#include <sys/rman.h> 11776479Swpaul 11876479Swpaul#include <dev/mii/mii.h> 11976479Swpaul#include <dev/mii/miivar.h> 12076479Swpaul 121119285Simp#include <dev/pci/pcireg.h> 122119285Simp#include <dev/pci/pcivar.h> 12376479Swpaul 12476479Swpaul#define NGE_USEIOSPACE 12576479Swpaul 12676522Swpaul#include <dev/nge/if_ngereg.h> 12776479Swpaul 128113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1); 129113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1); 13076479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1); 13176479Swpaul 13276479Swpaul/* "controller miibus0" required. See GENERIC if you get errors here. */ 13376479Swpaul#include "miibus_if.h" 13476479Swpaul 13576479Swpaul#define NGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 13676479Swpaul 13776479Swpaul/* 13876479Swpaul * Various supported device vendors/types and their names. 13976479Swpaul */ 14076479Swpaulstatic struct nge_type nge_devs[] = { 14176479Swpaul { NGE_VENDORID, NGE_DEVICEID, 14276479Swpaul "National Semiconductor Gigabit Ethernet" }, 14376479Swpaul { 0, 0, NULL } 14476479Swpaul}; 14576479Swpaul 14699497Salfredstatic int nge_probe(device_t); 14799497Salfredstatic int nge_attach(device_t); 14899497Salfredstatic int nge_detach(device_t); 14976479Swpaul 15099497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *); 15199497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *); 152135254Salc#ifdef NGE_FIXUP_RX 153135250Swpaulstatic __inline void nge_fixup_rx (struct mbuf *); 154135250Swpaul#endif 15599497Salfredstatic void nge_rxeof(struct nge_softc *); 15699497Salfredstatic void nge_txeof(struct nge_softc *); 15799497Salfredstatic void nge_intr(void *); 15899497Salfredstatic void nge_tick(void *); 159135250Swpaulstatic void nge_tick_locked(struct nge_softc *); 16099497Salfredstatic void nge_start(struct ifnet *); 161135250Swpaulstatic void nge_start_locked(struct ifnet *); 16299497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t); 16399497Salfredstatic void nge_init(void *); 164135250Swpaulstatic void nge_init_locked(struct nge_softc *); 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 void nge_reset(struct nge_softc *); 18899497Salfredstatic int nge_list_rx_init(struct nge_softc *); 18999497Salfredstatic int nge_list_tx_init(struct nge_softc *); 19076479Swpaul 19176479Swpaul#ifdef NGE_USEIOSPACE 19276479Swpaul#define NGE_RES SYS_RES_IOPORT 19376479Swpaul#define NGE_RID NGE_PCI_LOIO 19476479Swpaul#else 19576479Swpaul#define NGE_RES SYS_RES_MEMORY 19676479Swpaul#define NGE_RID NGE_PCI_LOMEM 19776479Swpaul#endif 19876479Swpaul 19976479Swpaulstatic device_method_t nge_methods[] = { 20076479Swpaul /* Device interface */ 20176479Swpaul DEVMETHOD(device_probe, nge_probe), 20276479Swpaul DEVMETHOD(device_attach, nge_attach), 20376479Swpaul DEVMETHOD(device_detach, nge_detach), 20476479Swpaul DEVMETHOD(device_shutdown, nge_shutdown), 20576479Swpaul 20676479Swpaul /* bus interface */ 20776479Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 20876479Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 20976479Swpaul 21076479Swpaul /* MII interface */ 21176479Swpaul DEVMETHOD(miibus_readreg, nge_miibus_readreg), 21276479Swpaul DEVMETHOD(miibus_writereg, nge_miibus_writereg), 21376479Swpaul DEVMETHOD(miibus_statchg, nge_miibus_statchg), 21476479Swpaul 21576479Swpaul { 0, 0 } 21676479Swpaul}; 21776479Swpaul 21876479Swpaulstatic driver_t nge_driver = { 21976479Swpaul "nge", 22076479Swpaul nge_methods, 22176479Swpaul sizeof(struct nge_softc) 22276479Swpaul}; 22376479Swpaul 22476479Swpaulstatic devclass_t nge_devclass; 22576479Swpaul 226113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0); 22776479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0); 22876479Swpaul 22976479Swpaul#define NGE_SETBIT(sc, reg, x) \ 23076479Swpaul CSR_WRITE_4(sc, reg, \ 23176479Swpaul CSR_READ_4(sc, reg) | (x)) 23276479Swpaul 23376479Swpaul#define NGE_CLRBIT(sc, reg, x) \ 23476479Swpaul CSR_WRITE_4(sc, reg, \ 23576479Swpaul CSR_READ_4(sc, reg) & ~(x)) 23676479Swpaul 23776479Swpaul#define SIO_SET(x) \ 238106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x)) 23976479Swpaul 24076479Swpaul#define SIO_CLR(x) \ 241106696Salfred CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x)) 24276479Swpaul 24399497Salfredstatic void 24499497Salfrednge_delay(sc) 24576479Swpaul struct nge_softc *sc; 24676479Swpaul{ 24776479Swpaul int idx; 24876479Swpaul 24976479Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 25076479Swpaul CSR_READ_4(sc, NGE_CSR); 25176479Swpaul 25276479Swpaul return; 25376479Swpaul} 25476479Swpaul 25599497Salfredstatic void 25699497Salfrednge_eeprom_idle(sc) 25776479Swpaul struct nge_softc *sc; 25876479Swpaul{ 25976479Swpaul register int i; 26076479Swpaul 26176479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 26276479Swpaul nge_delay(sc); 26376479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 26476479Swpaul nge_delay(sc); 26576479Swpaul 26676479Swpaul for (i = 0; i < 25; i++) { 26776479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 26876479Swpaul nge_delay(sc); 26976479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 27076479Swpaul nge_delay(sc); 27176479Swpaul } 27276479Swpaul 27376479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 27476479Swpaul nge_delay(sc); 27576479Swpaul SIO_CLR(NGE_MEAR_EE_CSEL); 27676479Swpaul nge_delay(sc); 27776479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0x00000000); 27876479Swpaul 27976479Swpaul return; 28076479Swpaul} 28176479Swpaul 28276479Swpaul/* 28376479Swpaul * Send a read command and address to the EEPROM, check for ACK. 28476479Swpaul */ 28599497Salfredstatic void 28699497Salfrednge_eeprom_putbyte(sc, addr) 28776479Swpaul struct nge_softc *sc; 28876479Swpaul int addr; 28976479Swpaul{ 29076479Swpaul register int d, i; 29176479Swpaul 29276479Swpaul d = addr | NGE_EECMD_READ; 29376479Swpaul 29476479Swpaul /* 29576479Swpaul * Feed in each bit and stobe the clock. 29676479Swpaul */ 29776479Swpaul for (i = 0x400; i; i >>= 1) { 29876479Swpaul if (d & i) { 29976479Swpaul SIO_SET(NGE_MEAR_EE_DIN); 30076479Swpaul } else { 30176479Swpaul SIO_CLR(NGE_MEAR_EE_DIN); 30276479Swpaul } 30376479Swpaul nge_delay(sc); 30476479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 30576479Swpaul nge_delay(sc); 30676479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 30776479Swpaul nge_delay(sc); 30876479Swpaul } 30976479Swpaul 31076479Swpaul return; 31176479Swpaul} 31276479Swpaul 31376479Swpaul/* 31476479Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 31576479Swpaul */ 31699497Salfredstatic void 31799497Salfrednge_eeprom_getword(sc, addr, dest) 31876479Swpaul struct nge_softc *sc; 31976479Swpaul int addr; 32076479Swpaul u_int16_t *dest; 32176479Swpaul{ 32276479Swpaul register int i; 32376479Swpaul u_int16_t word = 0; 32476479Swpaul 32576479Swpaul /* Force EEPROM to idle state. */ 32676479Swpaul nge_eeprom_idle(sc); 32776479Swpaul 32876479Swpaul /* Enter EEPROM access mode. */ 32976479Swpaul nge_delay(sc); 33076479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 33176479Swpaul nge_delay(sc); 33276479Swpaul SIO_SET(NGE_MEAR_EE_CSEL); 33376479Swpaul nge_delay(sc); 33476479Swpaul 33576479Swpaul /* 33676479Swpaul * Send address of word we want to read. 33776479Swpaul */ 33876479Swpaul nge_eeprom_putbyte(sc, addr); 33976479Swpaul 34076479Swpaul /* 34176479Swpaul * Start reading bits from EEPROM. 34276479Swpaul */ 34376479Swpaul for (i = 0x8000; i; i >>= 1) { 34476479Swpaul SIO_SET(NGE_MEAR_EE_CLK); 34576479Swpaul nge_delay(sc); 34676479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT) 34776479Swpaul word |= i; 34876479Swpaul nge_delay(sc); 34976479Swpaul SIO_CLR(NGE_MEAR_EE_CLK); 35076479Swpaul nge_delay(sc); 35176479Swpaul } 35276479Swpaul 35376479Swpaul /* Turn off EEPROM access mode. */ 35476479Swpaul nge_eeprom_idle(sc); 35576479Swpaul 35676479Swpaul *dest = word; 35776479Swpaul 35876479Swpaul return; 35976479Swpaul} 36076479Swpaul 36176479Swpaul/* 36276479Swpaul * Read a sequence of words from the EEPROM. 36376479Swpaul */ 36499497Salfredstatic void 36599497Salfrednge_read_eeprom(sc, dest, off, cnt, swap) 36676479Swpaul struct nge_softc *sc; 36776479Swpaul caddr_t dest; 36876479Swpaul int off; 36976479Swpaul int cnt; 37076479Swpaul int swap; 37176479Swpaul{ 37276479Swpaul int i; 37376479Swpaul u_int16_t word = 0, *ptr; 37476479Swpaul 37576479Swpaul for (i = 0; i < cnt; i++) { 37676479Swpaul nge_eeprom_getword(sc, off + i, &word); 37776479Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 37876479Swpaul if (swap) 37976479Swpaul *ptr = ntohs(word); 38076479Swpaul else 38176479Swpaul *ptr = word; 38276479Swpaul } 38376479Swpaul 38476479Swpaul return; 38576479Swpaul} 38676479Swpaul 38776479Swpaul/* 38876479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times. 38976479Swpaul */ 39099497Salfredstatic void 39199497Salfrednge_mii_sync(sc) 39276479Swpaul struct nge_softc *sc; 39376479Swpaul{ 39476479Swpaul register int i; 39576479Swpaul 39676479Swpaul SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA); 39776479Swpaul 39876479Swpaul for (i = 0; i < 32; i++) { 39976479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 40076479Swpaul DELAY(1); 40176479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 40276479Swpaul DELAY(1); 40376479Swpaul } 40476479Swpaul 40576479Swpaul return; 40676479Swpaul} 40776479Swpaul 40876479Swpaul/* 40976479Swpaul * Clock a series of bits through the MII. 41076479Swpaul */ 41199497Salfredstatic void 41299497Salfrednge_mii_send(sc, bits, cnt) 41376479Swpaul struct nge_softc *sc; 41476479Swpaul u_int32_t bits; 41576479Swpaul int cnt; 41676479Swpaul{ 41776479Swpaul int i; 41876479Swpaul 41976479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 42076479Swpaul 42176479Swpaul for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 42276479Swpaul if (bits & i) { 42376479Swpaul SIO_SET(NGE_MEAR_MII_DATA); 42476479Swpaul } else { 42576479Swpaul SIO_CLR(NGE_MEAR_MII_DATA); 42676479Swpaul } 42776479Swpaul DELAY(1); 42876479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 42976479Swpaul DELAY(1); 43076479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 43176479Swpaul } 43276479Swpaul} 43376479Swpaul 43476479Swpaul/* 43576479Swpaul * Read an PHY register through the MII. 43676479Swpaul */ 43799497Salfredstatic int 43899497Salfrednge_mii_readreg(sc, frame) 43976479Swpaul struct nge_softc *sc; 44076479Swpaul struct nge_mii_frame *frame; 44176479Swpaul 44276479Swpaul{ 443135250Swpaul int i, ack; 44476479Swpaul 44576479Swpaul /* 44676479Swpaul * Set up frame for RX. 44776479Swpaul */ 44876479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 44976479Swpaul frame->mii_opcode = NGE_MII_READOP; 45076479Swpaul frame->mii_turnaround = 0; 45176479Swpaul frame->mii_data = 0; 45276479Swpaul 45376479Swpaul CSR_WRITE_4(sc, NGE_MEAR, 0); 45476479Swpaul 45576479Swpaul /* 45676479Swpaul * Turn on data xmit. 45776479Swpaul */ 45876479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 45976479Swpaul 46076479Swpaul nge_mii_sync(sc); 46176479Swpaul 46276479Swpaul /* 46376479Swpaul * Send command/address info. 46476479Swpaul */ 46576479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 46676479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 46776479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 46876479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 46976479Swpaul 47076479Swpaul /* Idle bit */ 47176479Swpaul SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA)); 47276479Swpaul DELAY(1); 47376479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 47476479Swpaul DELAY(1); 47576479Swpaul 47676479Swpaul /* Turn off xmit. */ 47776479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 47876479Swpaul /* Check for ack */ 47976479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 48076479Swpaul DELAY(1); 481109058Smbr ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA; 48276479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 48376479Swpaul DELAY(1); 48476479Swpaul 48576479Swpaul /* 48676479Swpaul * Now try reading data bits. If the ack failed, we still 48776479Swpaul * need to clock through 16 cycles to keep the PHY(s) in sync. 48876479Swpaul */ 48976479Swpaul if (ack) { 49076479Swpaul for(i = 0; i < 16; i++) { 49176479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 49276479Swpaul DELAY(1); 49376479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 49476479Swpaul DELAY(1); 49576479Swpaul } 49676479Swpaul goto fail; 49776479Swpaul } 49876479Swpaul 49976479Swpaul for (i = 0x8000; i; i >>= 1) { 50076479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 50176479Swpaul DELAY(1); 50276479Swpaul if (!ack) { 50376479Swpaul if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA) 50476479Swpaul frame->mii_data |= i; 50576479Swpaul DELAY(1); 50676479Swpaul } 50776479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 50876479Swpaul DELAY(1); 50976479Swpaul } 51076479Swpaul 51176479Swpaulfail: 51276479Swpaul 51376479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 51476479Swpaul DELAY(1); 51576479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 51676479Swpaul DELAY(1); 51776479Swpaul 51876479Swpaul if (ack) 51976479Swpaul return(1); 52076479Swpaul return(0); 52176479Swpaul} 52276479Swpaul 52376479Swpaul/* 52476479Swpaul * Write to a PHY register through the MII. 52576479Swpaul */ 52699497Salfredstatic int 52799497Salfrednge_mii_writereg(sc, frame) 52876479Swpaul struct nge_softc *sc; 52976479Swpaul struct nge_mii_frame *frame; 53076479Swpaul 53176479Swpaul{ 53276479Swpaul 53376479Swpaul /* 53476479Swpaul * Set up frame for TX. 53576479Swpaul */ 53676479Swpaul 53776479Swpaul frame->mii_stdelim = NGE_MII_STARTDELIM; 53876479Swpaul frame->mii_opcode = NGE_MII_WRITEOP; 53976479Swpaul frame->mii_turnaround = NGE_MII_TURNAROUND; 54076479Swpaul 54176479Swpaul /* 54276479Swpaul * Turn on data output. 54376479Swpaul */ 54476479Swpaul SIO_SET(NGE_MEAR_MII_DIR); 54576479Swpaul 54676479Swpaul nge_mii_sync(sc); 54776479Swpaul 54876479Swpaul nge_mii_send(sc, frame->mii_stdelim, 2); 54976479Swpaul nge_mii_send(sc, frame->mii_opcode, 2); 55076479Swpaul nge_mii_send(sc, frame->mii_phyaddr, 5); 55176479Swpaul nge_mii_send(sc, frame->mii_regaddr, 5); 55276479Swpaul nge_mii_send(sc, frame->mii_turnaround, 2); 55376479Swpaul nge_mii_send(sc, frame->mii_data, 16); 55476479Swpaul 55576479Swpaul /* Idle bit. */ 55676479Swpaul SIO_SET(NGE_MEAR_MII_CLK); 55776479Swpaul DELAY(1); 55876479Swpaul SIO_CLR(NGE_MEAR_MII_CLK); 55976479Swpaul DELAY(1); 56076479Swpaul 56176479Swpaul /* 56276479Swpaul * Turn off xmit. 56376479Swpaul */ 56476479Swpaul SIO_CLR(NGE_MEAR_MII_DIR); 56576479Swpaul 56676479Swpaul return(0); 56776479Swpaul} 56876479Swpaul 56999497Salfredstatic int 57099497Salfrednge_miibus_readreg(dev, phy, reg) 57176479Swpaul device_t dev; 57276479Swpaul int phy, reg; 57376479Swpaul{ 57476479Swpaul struct nge_softc *sc; 57576479Swpaul struct nge_mii_frame frame; 57676479Swpaul 57776479Swpaul sc = device_get_softc(dev); 57876479Swpaul 57976479Swpaul bzero((char *)&frame, sizeof(frame)); 58076479Swpaul 58176479Swpaul frame.mii_phyaddr = phy; 58276479Swpaul frame.mii_regaddr = reg; 58376479Swpaul nge_mii_readreg(sc, &frame); 58476479Swpaul 58576479Swpaul return(frame.mii_data); 58676479Swpaul} 58776479Swpaul 58899497Salfredstatic int 58999497Salfrednge_miibus_writereg(dev, phy, reg, data) 59076479Swpaul device_t dev; 59176479Swpaul int phy, reg, data; 59276479Swpaul{ 59376479Swpaul struct nge_softc *sc; 59476479Swpaul struct nge_mii_frame frame; 59576479Swpaul 59676479Swpaul sc = device_get_softc(dev); 59776479Swpaul 59876479Swpaul bzero((char *)&frame, sizeof(frame)); 59976479Swpaul 60076479Swpaul frame.mii_phyaddr = phy; 60176479Swpaul frame.mii_regaddr = reg; 60276479Swpaul frame.mii_data = data; 60376479Swpaul nge_mii_writereg(sc, &frame); 60476479Swpaul 60576479Swpaul return(0); 60676479Swpaul} 60776479Swpaul 60899497Salfredstatic void 60999497Salfrednge_miibus_statchg(dev) 61076479Swpaul device_t dev; 61176479Swpaul{ 612101540Sambrisko int status; 61376479Swpaul struct nge_softc *sc; 61476479Swpaul struct mii_data *mii; 61576479Swpaul 61676479Swpaul sc = device_get_softc(dev); 617101540Sambrisko if (sc->nge_tbi) { 618101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 619101540Sambrisko == IFM_AUTO) { 620101540Sambrisko status = CSR_READ_4(sc, NGE_TBI_ANLPAR); 621101540Sambrisko if (status == 0 || status & NGE_TBIANAR_FDX) { 622101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 623101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 624101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 625101540Sambrisko } else { 626101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 627101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 628101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 629101540Sambrisko } 63076479Swpaul 631101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 632101540Sambrisko != IFM_FDX) { 633101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 634101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 635101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 636101540Sambrisko } else { 637101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 638101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 639101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 640101540Sambrisko } 64176479Swpaul } else { 642101540Sambrisko mii = device_get_softc(sc->nge_miibus); 64376479Swpaul 644101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 645101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 646101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 647101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 648101540Sambrisko } else { 649101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 650101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 651101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 652101540Sambrisko } 653101540Sambrisko 654101540Sambrisko /* If we have a 1000Mbps link, set the mode_1000 bit. */ 655101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 656101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) { 657101540Sambrisko NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 658101540Sambrisko } else { 659101540Sambrisko NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000); 660101540Sambrisko } 66179424Swpaul } 66276479Swpaul return; 66376479Swpaul} 66476479Swpaul 66599497Salfredstatic void 66699497Salfrednge_setmulti(sc) 66776479Swpaul struct nge_softc *sc; 66876479Swpaul{ 66976479Swpaul struct ifnet *ifp; 67076479Swpaul struct ifmultiaddr *ifma; 67176479Swpaul u_int32_t h = 0, i, filtsave; 67276479Swpaul int bit, index; 67376479Swpaul 674135250Swpaul NGE_LOCK_ASSERT(sc); 675147256Sbrooks ifp = sc->nge_ifp; 67676479Swpaul 67776479Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 67876479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 67976479Swpaul NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH); 68076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI); 68176479Swpaul return; 68276479Swpaul } 68376479Swpaul 68476479Swpaul /* 68576479Swpaul * We have to explicitly enable the multicast hash table 68676479Swpaul * on the NatSemi chip if we want to use it, which we do. 68776479Swpaul * We also have to tell it that we don't want to use the 68876479Swpaul * hash table for matching unicast addresses. 68976479Swpaul */ 69076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH); 69176479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 69276479Swpaul NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH); 69376479Swpaul 69476479Swpaul filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL); 69576479Swpaul 69676479Swpaul /* first, zot all the existing hash bits */ 69776479Swpaul for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) { 69876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i); 69976479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); 70076479Swpaul } 70176479Swpaul 70276479Swpaul /* 70376479Swpaul * From the 11 bits returned by the crc routine, the top 7 70476479Swpaul * bits represent the 16-bit word in the mcast hash table 70576479Swpaul * that needs to be updated, and the lower 4 bits represent 70676479Swpaul * which bit within that byte needs to be set. 70776479Swpaul */ 708148654Srwatson IF_ADDR_LOCK(ifp); 70976479Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 71076479Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 71176479Swpaul continue; 712130270Snaddy h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 713130270Snaddy ifma->ifma_addr), ETHER_ADDR_LEN) >> 21; 71476479Swpaul index = (h >> 4) & 0x7F; 71576479Swpaul bit = h & 0xF; 71676479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, 71776479Swpaul NGE_FILTADDR_MCAST_LO + (index * 2)); 71876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); 71976479Swpaul } 720148654Srwatson IF_ADDR_UNLOCK(ifp); 72176479Swpaul 72276479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave); 72376479Swpaul 72476479Swpaul return; 72576479Swpaul} 72676479Swpaul 72799497Salfredstatic void 72899497Salfrednge_reset(sc) 72976479Swpaul struct nge_softc *sc; 73076479Swpaul{ 73176479Swpaul register int i; 73276479Swpaul 73376479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET); 73476479Swpaul 73576479Swpaul for (i = 0; i < NGE_TIMEOUT; i++) { 73676479Swpaul if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET)) 73776479Swpaul break; 73876479Swpaul } 73976479Swpaul 74076479Swpaul if (i == NGE_TIMEOUT) 74176479Swpaul printf("nge%d: reset never completed\n", sc->nge_unit); 74276479Swpaul 74376479Swpaul /* Wait a little while for the chip to get its brains in order. */ 74476479Swpaul DELAY(1000); 74576479Swpaul 74676479Swpaul /* 74776479Swpaul * If this is a NetSemi chip, make sure to clear 74876479Swpaul * PME mode. 74976479Swpaul */ 75076479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS); 75176479Swpaul CSR_WRITE_4(sc, NGE_CLKRUN, 0); 75276479Swpaul 75376479Swpaul return; 75476479Swpaul} 75576479Swpaul 75676479Swpaul/* 757108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device 75876479Swpaul * IDs against our list and return a device name if we find a match. 75976479Swpaul */ 76099497Salfredstatic int 76199497Salfrednge_probe(dev) 76276479Swpaul device_t dev; 76376479Swpaul{ 76476479Swpaul struct nge_type *t; 76576479Swpaul 76676479Swpaul t = nge_devs; 76776479Swpaul 76876479Swpaul while(t->nge_name != NULL) { 76976479Swpaul if ((pci_get_vendor(dev) == t->nge_vid) && 77076479Swpaul (pci_get_device(dev) == t->nge_did)) { 77176479Swpaul device_set_desc(dev, t->nge_name); 772143158Simp return(BUS_PROBE_DEFAULT); 77376479Swpaul } 77476479Swpaul t++; 77576479Swpaul } 77676479Swpaul 77776479Swpaul return(ENXIO); 77876479Swpaul} 77976479Swpaul 78076479Swpaul/* 78176479Swpaul * Attach the interface. Allocate softc structures, do ifmedia 78276479Swpaul * setup and ethernet/BPF attach. 78376479Swpaul */ 78499497Salfredstatic int 78599497Salfrednge_attach(dev) 78676479Swpaul device_t dev; 78776479Swpaul{ 78876479Swpaul u_char eaddr[ETHER_ADDR_LEN]; 78976479Swpaul struct nge_softc *sc; 79076479Swpaul struct ifnet *ifp; 79176479Swpaul int unit, error = 0, rid; 792101540Sambrisko const char *sep = ""; 79376479Swpaul 79476479Swpaul sc = device_get_softc(dev); 79576479Swpaul unit = device_get_unit(dev); 79676479Swpaul bzero(sc, sizeof(struct nge_softc)); 79776479Swpaul 798135250Swpaul NGE_LOCK_INIT(sc, device_get_nameunit(dev)); 79976479Swpaul /* 80076479Swpaul * Map control/status registers. 80176479Swpaul */ 80276479Swpaul pci_enable_busmaster(dev); 80376479Swpaul 80476479Swpaul rid = NGE_RID; 805127135Snjl sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE); 80676479Swpaul 80776479Swpaul if (sc->nge_res == NULL) { 80876479Swpaul printf("nge%d: couldn't map ports/memory\n", unit); 80976479Swpaul error = ENXIO; 81076479Swpaul goto fail; 81176479Swpaul } 81276479Swpaul 81376479Swpaul sc->nge_btag = rman_get_bustag(sc->nge_res); 81476479Swpaul sc->nge_bhandle = rman_get_bushandle(sc->nge_res); 81576479Swpaul 81676479Swpaul /* Allocate interrupt */ 81776479Swpaul rid = 0; 818127135Snjl sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 81976479Swpaul RF_SHAREABLE | RF_ACTIVE); 82076479Swpaul 82176479Swpaul if (sc->nge_irq == NULL) { 82276479Swpaul printf("nge%d: couldn't map interrupt\n", unit); 82376479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 82476479Swpaul error = ENXIO; 82576479Swpaul goto fail; 82676479Swpaul } 82776479Swpaul 82876479Swpaul /* Reset the adapter. */ 82976479Swpaul nge_reset(sc); 83076479Swpaul 83176479Swpaul /* 83276479Swpaul * Get station address from the EEPROM. 83376479Swpaul */ 83476479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0); 83576479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0); 83676479Swpaul nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0); 83776479Swpaul 83876479Swpaul sc->nge_unit = unit; 83976479Swpaul 840147256Sbrooks /* XXX: leaked on error */ 84176479Swpaul sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF, 84276479Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 84376479Swpaul 84476479Swpaul if (sc->nge_ldata == NULL) { 84576479Swpaul printf("nge%d: no memory for list buffers!\n", unit); 84676479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 84776479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 84876479Swpaul error = ENXIO; 84976479Swpaul goto fail; 85076479Swpaul } 85176479Swpaul 852147256Sbrooks ifp = sc->nge_ifp = if_alloc(IFT_ETHER); 853147256Sbrooks if (ifp == NULL) { 854147256Sbrooks printf("nge%d: can not if_alloc()\n", unit); 855147256Sbrooks bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 856147256Sbrooks bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 857147256Sbrooks error = ENOSPC; 858147256Sbrooks goto fail; 859147256Sbrooks } 86076479Swpaul ifp->if_softc = sc; 861121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 86276479Swpaul ifp->if_mtu = ETHERMTU; 863135250Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 86476479Swpaul ifp->if_ioctl = nge_ioctl; 86576479Swpaul ifp->if_start = nge_start; 86676479Swpaul ifp->if_watchdog = nge_watchdog; 86776479Swpaul ifp->if_init = nge_init; 86876479Swpaul ifp->if_baudrate = 1000000000; 86976479Swpaul ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1; 87076479Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 871106937Ssam ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING; 872128132Sru#ifdef DEVICE_POLLING 873128132Sru ifp->if_capabilities |= IFCAP_POLLING; 874128132Sru#endif 87583632Sjlemon ifp->if_capenable = ifp->if_capabilities; 87676479Swpaul 87776479Swpaul /* 87876479Swpaul * Do MII setup. 87976479Swpaul */ 880150185Sru /* XXX: leaked on error */ 88176479Swpaul if (mii_phy_probe(dev, &sc->nge_miibus, 882101540Sambrisko nge_ifmedia_upd, nge_ifmedia_sts)) { 883101540Sambrisko if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) { 884101540Sambrisko sc->nge_tbi = 1; 885101540Sambrisko device_printf(dev, "Using TBI\n"); 886101540Sambrisko 887101540Sambrisko sc->nge_miibus = dev; 888101540Sambrisko 889101540Sambrisko ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd, 890101540Sambrisko nge_ifmedia_sts); 891101540Sambrisko#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL) 892101540Sambrisko#define PRINT(s) printf("%s%s", sep, s); sep = ", " 893101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0); 894101540Sambrisko device_printf(dev, " "); 895101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0); 896101540Sambrisko PRINT("1000baseSX"); 897101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0); 898101540Sambrisko PRINT("1000baseSX-FDX"); 899101540Sambrisko ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0); 900101540Sambrisko PRINT("auto"); 901101540Sambrisko 902101540Sambrisko printf("\n"); 903101540Sambrisko#undef ADD 904101540Sambrisko#undef PRINT 905101540Sambrisko ifmedia_set(&sc->nge_ifmedia, 906101540Sambrisko IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0)); 907101540Sambrisko 908101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 909101540Sambrisko | NGE_GPIO_GP4_OUT 910101540Sambrisko | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB 911101540Sambrisko | NGE_GPIO_GP3_OUTENB 912101540Sambrisko | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN); 913101540Sambrisko 914101540Sambrisko } else { 915101540Sambrisko printf("nge%d: MII without any PHY!\n", sc->nge_unit); 916150185Sru if_free(ifp); 917101540Sambrisko bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 918101540Sambrisko bus_release_resource(dev, NGE_RES, NGE_RID, 919101540Sambrisko sc->nge_res); 920101540Sambrisko error = ENXIO; 921101540Sambrisko goto fail; 922101540Sambrisko } 92376479Swpaul } 92476479Swpaul 92576479Swpaul /* 92676479Swpaul * Call MI attach routine. 92776479Swpaul */ 928106937Ssam ether_ifattach(ifp, eaddr); 929135250Swpaul callout_init(&sc->nge_stat_ch, CALLOUT_MPSAFE); 93076479Swpaul 931135250Swpaul /* 932135250Swpaul * Hookup IRQ last. 933135250Swpaul */ 934135250Swpaul error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE, 935135250Swpaul nge_intr, sc, &sc->nge_intrhand); 936135250Swpaul if (error) { 937147256Sbrooks /* XXX: resource leaks */ 938150185Sru if_free(ifp); 939135250Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 940135250Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 941135250Swpaul printf("nge%d: couldn't set up irq\n", unit); 942135250Swpaul } 943135250Swpaul 94476479Swpaulfail: 945101540Sambrisko 946135250Swpaul if (error) 947135250Swpaul NGE_LOCK_DESTROY(sc); 94876479Swpaul return(error); 94976479Swpaul} 95076479Swpaul 95199497Salfredstatic int 95299497Salfrednge_detach(dev) 95376479Swpaul device_t dev; 95476479Swpaul{ 95576479Swpaul struct nge_softc *sc; 95676479Swpaul struct ifnet *ifp; 95776479Swpaul 95876479Swpaul sc = device_get_softc(dev); 959147256Sbrooks ifp = sc->nge_ifp; 96076479Swpaul 961135250Swpaul NGE_LOCK(sc); 96276479Swpaul nge_reset(sc); 96376479Swpaul nge_stop(sc); 964135250Swpaul NGE_UNLOCK(sc); 965106937Ssam ether_ifdetach(ifp); 96676479Swpaul 96776479Swpaul bus_generic_detach(dev); 968101540Sambrisko if (!sc->nge_tbi) { 969101540Sambrisko device_delete_child(dev, sc->nge_miibus); 970101540Sambrisko } 97176479Swpaul bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand); 97276479Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq); 97376479Swpaul bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res); 97476479Swpaul 97576479Swpaul contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF); 976150306Simp if_free(ifp); 97776479Swpaul 978135251Swpaul NGE_LOCK_DESTROY(sc); 979135251Swpaul 98076479Swpaul return(0); 98176479Swpaul} 98276479Swpaul 98376479Swpaul/* 98476479Swpaul * Initialize the transmit descriptors. 98576479Swpaul */ 98699497Salfredstatic int 98799497Salfrednge_list_tx_init(sc) 98876479Swpaul struct nge_softc *sc; 98976479Swpaul{ 99076479Swpaul struct nge_list_data *ld; 99176479Swpaul struct nge_ring_data *cd; 99276479Swpaul int i; 99376479Swpaul 99476479Swpaul cd = &sc->nge_cdata; 99576479Swpaul ld = sc->nge_ldata; 99676479Swpaul 99776479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 99876479Swpaul if (i == (NGE_TX_LIST_CNT - 1)) { 99976479Swpaul ld->nge_tx_list[i].nge_nextdesc = 100076479Swpaul &ld->nge_tx_list[0]; 100176479Swpaul ld->nge_tx_list[i].nge_next = 100276479Swpaul vtophys(&ld->nge_tx_list[0]); 100376479Swpaul } else { 100476479Swpaul ld->nge_tx_list[i].nge_nextdesc = 100576479Swpaul &ld->nge_tx_list[i + 1]; 100676479Swpaul ld->nge_tx_list[i].nge_next = 100776479Swpaul vtophys(&ld->nge_tx_list[i + 1]); 100876479Swpaul } 100976479Swpaul ld->nge_tx_list[i].nge_mbuf = NULL; 101076479Swpaul ld->nge_tx_list[i].nge_ptr = 0; 101176479Swpaul ld->nge_tx_list[i].nge_ctl = 0; 101276479Swpaul } 101376479Swpaul 101476479Swpaul cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0; 101576479Swpaul 101676479Swpaul return(0); 101776479Swpaul} 101876479Swpaul 101976479Swpaul 102076479Swpaul/* 102176479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 102276479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 102376479Swpaul * points back to the first. 102476479Swpaul */ 102599497Salfredstatic int 102699497Salfrednge_list_rx_init(sc) 102776479Swpaul struct nge_softc *sc; 102876479Swpaul{ 102976479Swpaul struct nge_list_data *ld; 103076479Swpaul struct nge_ring_data *cd; 103176479Swpaul int i; 103276479Swpaul 103376479Swpaul ld = sc->nge_ldata; 103476479Swpaul cd = &sc->nge_cdata; 103576479Swpaul 103676479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 103776479Swpaul if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS) 103876479Swpaul return(ENOBUFS); 103976479Swpaul if (i == (NGE_RX_LIST_CNT - 1)) { 104076479Swpaul ld->nge_rx_list[i].nge_nextdesc = 104176479Swpaul &ld->nge_rx_list[0]; 104276479Swpaul ld->nge_rx_list[i].nge_next = 104376479Swpaul vtophys(&ld->nge_rx_list[0]); 104476479Swpaul } else { 104576479Swpaul ld->nge_rx_list[i].nge_nextdesc = 104676479Swpaul &ld->nge_rx_list[i + 1]; 104776479Swpaul ld->nge_rx_list[i].nge_next = 104876479Swpaul vtophys(&ld->nge_rx_list[i + 1]); 104976479Swpaul } 105076479Swpaul } 105176479Swpaul 105276479Swpaul cd->nge_rx_prod = 0; 1053135250Swpaul sc->nge_head = sc->nge_tail = NULL; 105476479Swpaul 105576479Swpaul return(0); 105676479Swpaul} 105776479Swpaul 105876479Swpaul/* 105976479Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 106076479Swpaul */ 106199497Salfredstatic int 106299497Salfrednge_newbuf(sc, c, m) 106376479Swpaul struct nge_softc *sc; 106476479Swpaul struct nge_desc *c; 106576479Swpaul struct mbuf *m; 106676479Swpaul{ 106776479Swpaul 106876479Swpaul if (m == NULL) { 1069144241Ssam m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1070144241Ssam if (m == NULL) 1071135250Swpaul return (ENOBUFS); 1072135250Swpaul } else 1073135250Swpaul m->m_data = m->m_ext.ext_buf; 107476479Swpaul 1075135250Swpaul m->m_len = m->m_pkthdr.len = MCLBYTES; 107676479Swpaul 1077144241Ssam m_adj(m, sizeof(u_int64_t)); 107876479Swpaul 1079144241Ssam c->nge_mbuf = m; 1080144241Ssam c->nge_ptr = vtophys(mtod(m, caddr_t)); 1081144241Ssam c->nge_ctl = m->m_len; 108276479Swpaul c->nge_extsts = 0; 108376479Swpaul 108476479Swpaul return(0); 108576479Swpaul} 108676479Swpaul 1087135250Swpaul#ifdef NGE_FIXUP_RX 1088135250Swpaulstatic __inline void 1089135250Swpaulnge_fixup_rx(m) 1090135250Swpaul struct mbuf *m; 1091135250Swpaul{ 1092135250Swpaul int i; 1093135250Swpaul uint16_t *src, *dst; 1094135250Swpaul 1095135250Swpaul src = mtod(m, uint16_t *); 1096135250Swpaul dst = src - 1; 1097135250Swpaul 1098135250Swpaul for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1099135250Swpaul *dst++ = *src++; 1100135250Swpaul 1101135250Swpaul m->m_data -= ETHER_ALIGN; 1102135250Swpaul 110376479Swpaul return; 1104135250Swpaul} 110576479Swpaul#endif 110676479Swpaul 110776479Swpaul/* 110876479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 110976479Swpaul * the higher level protocols. 111076479Swpaul */ 111199497Salfredstatic void 111299497Salfrednge_rxeof(sc) 111376479Swpaul struct nge_softc *sc; 111476479Swpaul{ 111576479Swpaul struct mbuf *m; 111676479Swpaul struct ifnet *ifp; 111776479Swpaul struct nge_desc *cur_rx; 111876479Swpaul int i, total_len = 0; 111976479Swpaul u_int32_t rxstat; 112076479Swpaul 1121135250Swpaul NGE_LOCK_ASSERT(sc); 1122147256Sbrooks ifp = sc->nge_ifp; 112376479Swpaul i = sc->nge_cdata.nge_rx_prod; 112476479Swpaul 112576479Swpaul while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) { 112676479Swpaul u_int32_t extsts; 112776479Swpaul 1128106507Ssimokawa#ifdef DEVICE_POLLING 1129128122Srwatson if (ifp->if_flags & IFF_POLLING) { 1130106507Ssimokawa if (sc->rxcycles <= 0) 1131106507Ssimokawa break; 1132106507Ssimokawa sc->rxcycles--; 1133106507Ssimokawa } 1134106507Ssimokawa#endif /* DEVICE_POLLING */ 1135106507Ssimokawa 113676479Swpaul cur_rx = &sc->nge_ldata->nge_rx_list[i]; 113776479Swpaul rxstat = cur_rx->nge_rxstat; 113876479Swpaul extsts = cur_rx->nge_extsts; 113976479Swpaul m = cur_rx->nge_mbuf; 114076479Swpaul cur_rx->nge_mbuf = NULL; 114176479Swpaul total_len = NGE_RXBYTES(cur_rx); 114276479Swpaul NGE_INC(i, NGE_RX_LIST_CNT); 1143135250Swpaul 1144135250Swpaul if (rxstat & NGE_CMDSTS_MORE) { 1145135250Swpaul m->m_len = total_len; 1146135250Swpaul if (sc->nge_head == NULL) { 1147135250Swpaul m->m_pkthdr.len = total_len; 1148135250Swpaul sc->nge_head = sc->nge_tail = m; 1149135250Swpaul } else { 1150135250Swpaul m->m_flags &= ~M_PKTHDR; 1151135250Swpaul sc->nge_head->m_pkthdr.len += total_len; 1152135250Swpaul sc->nge_tail->m_next = m; 1153135250Swpaul sc->nge_tail = m; 1154135250Swpaul } 1155135250Swpaul nge_newbuf(sc, cur_rx, NULL); 1156135250Swpaul continue; 1157135250Swpaul } 1158135250Swpaul 115976479Swpaul /* 116076479Swpaul * If an error occurs, update stats, clear the 116176479Swpaul * status word and leave the mbuf cluster in place: 116276479Swpaul * it should simply get re-used next time this descriptor 116376479Swpaul * comes up in the ring. 116476479Swpaul */ 116576479Swpaul if (!(rxstat & NGE_CMDSTS_PKT_OK)) { 116676479Swpaul ifp->if_ierrors++; 1167135250Swpaul if (sc->nge_head != NULL) { 1168135250Swpaul m_freem(sc->nge_head); 1169135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1170135250Swpaul } 117176479Swpaul nge_newbuf(sc, cur_rx, m); 117276479Swpaul continue; 117376479Swpaul } 117476479Swpaul 1175135250Swpaul /* Try conjure up a replacement mbuf. */ 1176135250Swpaul 1177135250Swpaul if (nge_newbuf(sc, cur_rx, NULL)) { 1178135250Swpaul ifp->if_ierrors++; 1179135250Swpaul if (sc->nge_head != NULL) { 1180135250Swpaul m_freem(sc->nge_head); 1181135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1182135250Swpaul } 1183135250Swpaul nge_newbuf(sc, cur_rx, m); 1184135250Swpaul continue; 1185135250Swpaul } 1186135250Swpaul 1187135250Swpaul if (sc->nge_head != NULL) { 1188135250Swpaul m->m_len = total_len; 1189135250Swpaul m->m_flags &= ~M_PKTHDR; 1190135250Swpaul sc->nge_tail->m_next = m; 1191135250Swpaul m = sc->nge_head; 1192135250Swpaul m->m_pkthdr.len += total_len; 1193135250Swpaul sc->nge_head = sc->nge_tail = NULL; 1194135250Swpaul } else 1195135250Swpaul m->m_pkthdr.len = m->m_len = total_len; 1196135250Swpaul 119776479Swpaul /* 119876479Swpaul * Ok. NatSemi really screwed up here. This is the 119976479Swpaul * only gigE chip I know of with alignment constraints 120076479Swpaul * on receive buffers. RX buffers must be 64-bit aligned. 120176479Swpaul */ 120279562Swpaul /* 120379562Swpaul * By popular demand, ignore the alignment problems 120479562Swpaul * on the Intel x86 platform. The performance hit 120579562Swpaul * incurred due to unaligned accesses is much smaller 120679562Swpaul * than the hit produced by forcing buffer copies all 120779562Swpaul * the time, especially with jumbo frames. We still 120879562Swpaul * need to fix up the alignment everywhere else though. 120979562Swpaul */ 1210135250Swpaul#ifdef NGE_FIXUP_RX 1211135250Swpaul nge_fixup_rx(m); 121279562Swpaul#endif 121376479Swpaul 121476479Swpaul ifp->if_ipackets++; 1215135250Swpaul m->m_pkthdr.rcvif = ifp; 121676479Swpaul 121776479Swpaul /* Do IP checksum checking. */ 121878323Swpaul if (extsts & NGE_RXEXTSTS_IPPKT) 121978323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 122078323Swpaul if (!(extsts & NGE_RXEXTSTS_IPCSUMERR)) 122178323Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 122278323Swpaul if ((extsts & NGE_RXEXTSTS_TCPPKT && 122378323Swpaul !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) || 122478323Swpaul (extsts & NGE_RXEXTSTS_UDPPKT && 122578323Swpaul !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) { 122678323Swpaul m->m_pkthdr.csum_flags |= 122778323Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 122878323Swpaul m->m_pkthdr.csum_data = 0xffff; 122978323Swpaul } 123076479Swpaul 123176479Swpaul /* 123276479Swpaul * If we received a packet with a vlan tag, pass it 123376479Swpaul * to vlan_input() instead of ether_input(). 123476479Swpaul */ 123576479Swpaul if (extsts & NGE_RXEXTSTS_VLANPKT) { 1236106937Ssam VLAN_INPUT_TAG(ifp, m, 1237127615Sru ntohs(extsts & NGE_RXEXTSTS_VTCI), continue); 1238106937Ssam } 1239135250Swpaul NGE_UNLOCK(sc); 1240106937Ssam (*ifp->if_input)(ifp, m); 1241135250Swpaul NGE_LOCK(sc); 124276479Swpaul } 124376479Swpaul 124476479Swpaul sc->nge_cdata.nge_rx_prod = i; 124576479Swpaul 124676479Swpaul return; 124776479Swpaul} 124876479Swpaul 124976479Swpaul/* 125076479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 125176479Swpaul * the list buffers. 125276479Swpaul */ 125376479Swpaul 125499497Salfredstatic void 125599497Salfrednge_txeof(sc) 125676479Swpaul struct nge_softc *sc; 125776479Swpaul{ 1258128130Sru struct nge_desc *cur_tx; 125976479Swpaul struct ifnet *ifp; 126076479Swpaul u_int32_t idx; 126176479Swpaul 1262135250Swpaul NGE_LOCK_ASSERT(sc); 1263147256Sbrooks ifp = sc->nge_ifp; 126476479Swpaul 126576479Swpaul /* 126676479Swpaul * Go through our tx list and free mbufs for those 126776479Swpaul * frames that have been transmitted. 126876479Swpaul */ 126976479Swpaul idx = sc->nge_cdata.nge_tx_cons; 127076479Swpaul while (idx != sc->nge_cdata.nge_tx_prod) { 127176479Swpaul cur_tx = &sc->nge_ldata->nge_tx_list[idx]; 127276479Swpaul 127376479Swpaul if (NGE_OWNDESC(cur_tx)) 127476479Swpaul break; 127576479Swpaul 127676479Swpaul if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) { 127776479Swpaul sc->nge_cdata.nge_tx_cnt--; 127876479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 127976479Swpaul continue; 128076479Swpaul } 128176479Swpaul 128276479Swpaul if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) { 128376479Swpaul ifp->if_oerrors++; 128476479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS) 128576479Swpaul ifp->if_collisions++; 128676479Swpaul if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL) 128776479Swpaul ifp->if_collisions++; 128876479Swpaul } 128976479Swpaul 129076479Swpaul ifp->if_collisions += 129176479Swpaul (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16; 129276479Swpaul 129376479Swpaul ifp->if_opackets++; 129476479Swpaul if (cur_tx->nge_mbuf != NULL) { 129576479Swpaul m_freem(cur_tx->nge_mbuf); 129676479Swpaul cur_tx->nge_mbuf = NULL; 1297148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 129876479Swpaul } 129976479Swpaul 130076479Swpaul sc->nge_cdata.nge_tx_cnt--; 130176479Swpaul NGE_INC(idx, NGE_TX_LIST_CNT); 130276479Swpaul } 130376479Swpaul 130476479Swpaul sc->nge_cdata.nge_tx_cons = idx; 130576479Swpaul 1306128130Sru if (idx == sc->nge_cdata.nge_tx_prod) 1307128130Sru ifp->if_timer = 0; 130876479Swpaul 130976479Swpaul return; 131076479Swpaul} 131176479Swpaul 131299497Salfredstatic void 131399497Salfrednge_tick(xsc) 131476479Swpaul void *xsc; 131576479Swpaul{ 131676479Swpaul struct nge_softc *sc; 1317135250Swpaul 1318135250Swpaul sc = xsc; 1319135250Swpaul 1320135250Swpaul NGE_LOCK(sc); 1321135250Swpaul nge_tick_locked(sc); 1322135250Swpaul NGE_UNLOCK(sc); 1323135250Swpaul} 1324135250Swpaul 1325135250Swpaulstatic void 1326135250Swpaulnge_tick_locked(sc) 1327135250Swpaul struct nge_softc *sc; 1328135250Swpaul{ 132976479Swpaul struct mii_data *mii; 133076479Swpaul struct ifnet *ifp; 133176479Swpaul 1332135250Swpaul NGE_LOCK_ASSERT(sc); 1333147256Sbrooks ifp = sc->nge_ifp; 133476479Swpaul 1335101540Sambrisko if (sc->nge_tbi) { 1336101540Sambrisko if (!sc->nge_link) { 1337101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) 1338101540Sambrisko & NGE_TBIBMSR_ANEG_DONE) { 1339137402Sphk if (bootverbose) 1340137402Sphk printf("nge%d: gigabit link up\n", 1341137402Sphk sc->nge_unit); 1342101540Sambrisko nge_miibus_statchg(sc->nge_miibus); 1343101540Sambrisko sc->nge_link++; 1344101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1345135250Swpaul nge_start_locked(ifp); 1346101540Sambrisko } 134796028Sphk } 1348101540Sambrisko } else { 1349101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1350101540Sambrisko mii_tick(mii); 1351101540Sambrisko 1352101540Sambrisko if (!sc->nge_link) { 1353101540Sambrisko if (mii->mii_media_status & IFM_ACTIVE && 1354101540Sambrisko IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1355101540Sambrisko sc->nge_link++; 1356101540Sambrisko if (IFM_SUBTYPE(mii->mii_media_active) 1357137402Sphk == IFM_1000_T && bootverbose) 1358101540Sambrisko printf("nge%d: gigabit link up\n", 1359101540Sambrisko sc->nge_unit); 1360101540Sambrisko if (ifp->if_snd.ifq_head != NULL) 1361135250Swpaul nge_start_locked(ifp); 1362101540Sambrisko } 1363101540Sambrisko } 136476479Swpaul } 1365135250Swpaul callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc); 136676479Swpaul 136776479Swpaul return; 136876479Swpaul} 136976479Swpaul 1370106507Ssimokawa#ifdef DEVICE_POLLING 1371106507Ssimokawastatic poll_handler_t nge_poll; 1372106507Ssimokawa 137399497Salfredstatic void 1374106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1375106507Ssimokawa{ 1376106507Ssimokawa struct nge_softc *sc = ifp->if_softc; 1377106507Ssimokawa 1378135250Swpaul NGE_LOCK(sc); 1379128132Sru if (!(ifp->if_capenable & IFCAP_POLLING)) { 1380128132Sru ether_poll_deregister(ifp); 1381128132Sru cmd = POLL_DEREGISTER; 1382128132Sru } 1383106507Ssimokawa if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 1384106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 1); 1385135250Swpaul NGE_UNLOCK(sc); 1386106507Ssimokawa return; 1387106507Ssimokawa } 1388106507Ssimokawa 1389106507Ssimokawa /* 1390106507Ssimokawa * On the nge, reading the status register also clears it. 1391106507Ssimokawa * So before returning to intr mode we must make sure that all 1392106507Ssimokawa * possible pending sources of interrupts have been served. 1393106507Ssimokawa * In practice this means run to completion the *eof routines, 1394106507Ssimokawa * and then call the interrupt routine 1395106507Ssimokawa */ 1396106507Ssimokawa sc->rxcycles = count; 1397106507Ssimokawa nge_rxeof(sc); 1398106507Ssimokawa nge_txeof(sc); 1399106507Ssimokawa if (ifp->if_snd.ifq_head != NULL) 1400135250Swpaul nge_start_locked(ifp); 1401106507Ssimokawa 1402106507Ssimokawa if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1403106507Ssimokawa u_int32_t status; 1404106507Ssimokawa 1405106507Ssimokawa /* Reading the ISR register clears all interrupts. */ 1406106507Ssimokawa status = CSR_READ_4(sc, NGE_ISR); 1407106507Ssimokawa 1408106507Ssimokawa if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW)) 1409106507Ssimokawa nge_rxeof(sc); 1410106507Ssimokawa 1411106507Ssimokawa if (status & (NGE_ISR_RX_IDLE)) 1412106507Ssimokawa NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 1413106507Ssimokawa 1414106507Ssimokawa if (status & NGE_ISR_SYSERR) { 1415106507Ssimokawa nge_reset(sc); 1416135250Swpaul nge_init_locked(sc); 1417106507Ssimokawa } 1418106507Ssimokawa } 1419135250Swpaul NGE_UNLOCK(sc); 1420106507Ssimokawa} 1421106507Ssimokawa#endif /* DEVICE_POLLING */ 1422106507Ssimokawa 1423106507Ssimokawastatic void 142499497Salfrednge_intr(arg) 142576479Swpaul void *arg; 142676479Swpaul{ 142776479Swpaul struct nge_softc *sc; 142876479Swpaul struct ifnet *ifp; 142976479Swpaul u_int32_t status; 143076479Swpaul 143176479Swpaul sc = arg; 1432147256Sbrooks ifp = sc->nge_ifp; 143376479Swpaul 1434135250Swpaul NGE_LOCK(sc); 1435106507Ssimokawa#ifdef DEVICE_POLLING 1436135250Swpaul if (ifp->if_flags & IFF_POLLING) { 1437135250Swpaul NGE_UNLOCK(sc); 1438106507Ssimokawa return; 1439135250Swpaul } 1440128132Sru if ((ifp->if_capenable & IFCAP_POLLING) && 1441128132Sru ether_poll_register(nge_poll, ifp)) { /* ok, disable interrupts */ 1442106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1443135250Swpaul NGE_UNLOCK(sc); 1444106507Ssimokawa nge_poll(ifp, 0, 1); 1445106507Ssimokawa return; 1446106507Ssimokawa } 1447106507Ssimokawa#endif /* DEVICE_POLLING */ 1448106507Ssimokawa 144976479Swpaul /* Supress unwanted interrupts */ 145076479Swpaul if (!(ifp->if_flags & IFF_UP)) { 145176479Swpaul nge_stop(sc); 1452135250Swpaul NGE_UNLOCK(sc); 145376479Swpaul return; 145476479Swpaul } 145576479Swpaul 145676479Swpaul /* Disable interrupts. */ 145776479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 145876479Swpaul 1459101540Sambrisko /* Data LED on for TBI mode */ 1460101540Sambrisko if(sc->nge_tbi) 1461101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1462101540Sambrisko | NGE_GPIO_GP3_OUT); 1463101540Sambrisko 146476479Swpaul for (;;) { 146576479Swpaul /* Reading the ISR register clears all interrupts. */ 146676479Swpaul status = CSR_READ_4(sc, NGE_ISR); 146776479Swpaul 146876479Swpaul if ((status & NGE_INTRS) == 0) 146976479Swpaul break; 147076479Swpaul 147176479Swpaul if ((status & NGE_ISR_TX_DESC_OK) || 147276479Swpaul (status & NGE_ISR_TX_ERR) || 147376479Swpaul (status & NGE_ISR_TX_OK) || 147476479Swpaul (status & NGE_ISR_TX_IDLE)) 147576479Swpaul nge_txeof(sc); 147676479Swpaul 147776479Swpaul if ((status & NGE_ISR_RX_DESC_OK) || 147879798Swpaul (status & NGE_ISR_RX_ERR) || 147983678Swpaul (status & NGE_ISR_RX_OFLOW) || 148094612Sphk (status & NGE_ISR_RX_FIFO_OFLOW) || 148194612Sphk (status & NGE_ISR_RX_IDLE) || 148276479Swpaul (status & NGE_ISR_RX_OK)) 148376479Swpaul nge_rxeof(sc); 148494612Sphk 148594612Sphk if ((status & NGE_ISR_RX_IDLE)) 148694612Sphk NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 148794612Sphk 148876479Swpaul if (status & NGE_ISR_SYSERR) { 148976479Swpaul nge_reset(sc); 1490148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1491135250Swpaul nge_init_locked(sc); 149276479Swpaul } 149376479Swpaul 149496028Sphk#if 0 149596028Sphk /* 149696028Sphk * XXX: nge_tick() is not ready to be called this way 149796028Sphk * it screws up the aneg timeout because mii_tick() is 149896028Sphk * only to be called once per second. 149996028Sphk */ 150076479Swpaul if (status & NGE_IMR_PHY_INTR) { 150176479Swpaul sc->nge_link = 0; 1502135250Swpaul nge_tick_locked(sc); 150376479Swpaul } 150496028Sphk#endif 150576479Swpaul } 150676479Swpaul 150776479Swpaul /* Re-enable interrupts. */ 150876479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 150976479Swpaul 151076479Swpaul if (ifp->if_snd.ifq_head != NULL) 1511135250Swpaul nge_start_locked(ifp); 151276479Swpaul 1513101540Sambrisko /* Data LED off for TBI mode */ 1514101540Sambrisko 1515101540Sambrisko if(sc->nge_tbi) 1516101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1517101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1518101540Sambrisko 1519135250Swpaul NGE_UNLOCK(sc); 1520135250Swpaul 152176479Swpaul return; 152276479Swpaul} 152376479Swpaul 152476479Swpaul/* 152576479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 152676479Swpaul * pointers to the fragment pointers. 152776479Swpaul */ 152899497Salfredstatic int 152999497Salfrednge_encap(sc, m_head, txidx) 153076479Swpaul struct nge_softc *sc; 153176479Swpaul struct mbuf *m_head; 153276479Swpaul u_int32_t *txidx; 153376479Swpaul{ 153476479Swpaul struct nge_desc *f = NULL; 153576479Swpaul struct mbuf *m; 153676479Swpaul int frag, cur, cnt = 0; 1537106937Ssam struct m_tag *mtag; 153876479Swpaul 153976479Swpaul /* 154076479Swpaul * Start packing the mbufs in this chain into 154176479Swpaul * the fragment pointers. Stop when we run out 154276479Swpaul * of fragments or hit the end of the mbuf chain. 154376479Swpaul */ 154476479Swpaul m = m_head; 154576479Swpaul cur = frag = *txidx; 154676479Swpaul 154776479Swpaul for (m = m_head; m != NULL; m = m->m_next) { 154876479Swpaul if (m->m_len != 0) { 154976479Swpaul if ((NGE_TX_LIST_CNT - 155076479Swpaul (sc->nge_cdata.nge_tx_cnt + cnt)) < 2) 155176479Swpaul return(ENOBUFS); 155276479Swpaul f = &sc->nge_ldata->nge_tx_list[frag]; 155376479Swpaul f->nge_ctl = NGE_CMDSTS_MORE | m->m_len; 155476479Swpaul f->nge_ptr = vtophys(mtod(m, vm_offset_t)); 155576479Swpaul if (cnt != 0) 155676479Swpaul f->nge_ctl |= NGE_CMDSTS_OWN; 155776479Swpaul cur = frag; 155876479Swpaul NGE_INC(frag, NGE_TX_LIST_CNT); 155976479Swpaul cnt++; 156076479Swpaul } 156176479Swpaul } 156276479Swpaul 156376479Swpaul if (m != NULL) 156476479Swpaul return(ENOBUFS); 156576479Swpaul 156678286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0; 156776479Swpaul if (m_head->m_pkthdr.csum_flags) { 156876479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_IP) 156978286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 157076479Swpaul NGE_TXEXTSTS_IPCSUM; 157176479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 157278286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 157376479Swpaul NGE_TXEXTSTS_TCPCSUM; 157476479Swpaul if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 157578286Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |= 157676479Swpaul NGE_TXEXTSTS_UDPCSUM; 157776479Swpaul } 157876479Swpaul 1579147256Sbrooks mtag = VLAN_OUTPUT_TAG(sc->nge_ifp, m_head); 1580106937Ssam if (mtag != NULL) { 158176479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_extsts |= 1582127615Sru (NGE_TXEXTSTS_VLANPKT|htons(VLAN_TAG_VALUE(mtag))); 158376479Swpaul } 158476479Swpaul 158576479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head; 158676479Swpaul sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE; 158776479Swpaul sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN; 158876479Swpaul sc->nge_cdata.nge_tx_cnt += cnt; 158976479Swpaul *txidx = frag; 159076479Swpaul 159176479Swpaul return(0); 159276479Swpaul} 159376479Swpaul 159476479Swpaul/* 159576479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 159676479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 159776479Swpaul * copy of the pointers since the transmit list fragment pointers are 159876479Swpaul * physical addresses. 159976479Swpaul */ 160076479Swpaul 160199497Salfredstatic void 160299497Salfrednge_start(ifp) 160376479Swpaul struct ifnet *ifp; 160476479Swpaul{ 160576479Swpaul struct nge_softc *sc; 1606135250Swpaul 1607135250Swpaul sc = ifp->if_softc; 1608135250Swpaul NGE_LOCK(sc); 1609135250Swpaul nge_start_locked(ifp); 1610135250Swpaul NGE_UNLOCK(sc); 1611135250Swpaul} 1612135250Swpaul 1613135250Swpaulstatic void 1614135250Swpaulnge_start_locked(ifp) 1615135250Swpaul struct ifnet *ifp; 1616135250Swpaul{ 1617135250Swpaul struct nge_softc *sc; 161876479Swpaul struct mbuf *m_head = NULL; 161976479Swpaul u_int32_t idx; 162076479Swpaul 162176479Swpaul sc = ifp->if_softc; 162276479Swpaul 162376479Swpaul if (!sc->nge_link) 162476479Swpaul return; 162576479Swpaul 162676479Swpaul idx = sc->nge_cdata.nge_tx_prod; 162776479Swpaul 1628148887Srwatson if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 162976479Swpaul return; 163076479Swpaul 163176479Swpaul while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) { 163276479Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 163376479Swpaul if (m_head == NULL) 163476479Swpaul break; 163576479Swpaul 163676479Swpaul if (nge_encap(sc, m_head, &idx)) { 163776479Swpaul IF_PREPEND(&ifp->if_snd, m_head); 1638148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 163976479Swpaul break; 164076479Swpaul } 164176479Swpaul 164276479Swpaul /* 164376479Swpaul * If there's a BPF listener, bounce a copy of this frame 164476479Swpaul * to him. 164576479Swpaul */ 1646106937Ssam BPF_MTAP(ifp, m_head); 164776479Swpaul 164876479Swpaul } 164976479Swpaul 165076479Swpaul /* Transmit */ 165176479Swpaul sc->nge_cdata.nge_tx_prod = idx; 165276479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE); 165376479Swpaul 165476479Swpaul /* 165576479Swpaul * Set a timeout in case the chip goes out to lunch. 165676479Swpaul */ 165776479Swpaul ifp->if_timer = 5; 165876479Swpaul 165976479Swpaul return; 166076479Swpaul} 166176479Swpaul 166299497Salfredstatic void 166399497Salfrednge_init(xsc) 166476479Swpaul void *xsc; 166576479Swpaul{ 166676479Swpaul struct nge_softc *sc = xsc; 1667135250Swpaul 1668135250Swpaul NGE_LOCK(sc); 1669135250Swpaul nge_init_locked(sc); 1670135250Swpaul NGE_UNLOCK(sc); 1671135250Swpaul} 1672135250Swpaul 1673135250Swpaulstatic void 1674135250Swpaulnge_init_locked(sc) 1675135250Swpaul struct nge_softc *sc; 1676135250Swpaul{ 1677147256Sbrooks struct ifnet *ifp = sc->nge_ifp; 167876479Swpaul struct mii_data *mii; 167976479Swpaul 1680135250Swpaul NGE_LOCK_ASSERT(sc); 1681135250Swpaul 1682148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 168376479Swpaul return; 168476479Swpaul 168576479Swpaul /* 168676479Swpaul * Cancel pending I/O and free all RX/TX buffers. 168776479Swpaul */ 168876479Swpaul nge_stop(sc); 168976479Swpaul 1690101540Sambrisko if (sc->nge_tbi) { 1691101540Sambrisko mii = NULL; 1692101540Sambrisko } else { 1693101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1694101540Sambrisko } 169576479Swpaul 169676479Swpaul /* Set MAC address */ 169776479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0); 169876479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1699147256Sbrooks ((u_int16_t *)IFP2ENADDR(sc->nge_ifp))[0]); 170076479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1); 170176479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1702147256Sbrooks ((u_int16_t *)IFP2ENADDR(sc->nge_ifp))[1]); 170376479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2); 170476479Swpaul CSR_WRITE_4(sc, NGE_RXFILT_DATA, 1705147256Sbrooks ((u_int16_t *)IFP2ENADDR(sc->nge_ifp))[2]); 170676479Swpaul 170776479Swpaul /* Init circular RX list. */ 170876479Swpaul if (nge_list_rx_init(sc) == ENOBUFS) { 170976479Swpaul printf("nge%d: initialization failed: no " 171076479Swpaul "memory for rx buffers\n", sc->nge_unit); 171176479Swpaul nge_stop(sc); 171276479Swpaul return; 171376479Swpaul } 171476479Swpaul 171576479Swpaul /* 171676479Swpaul * Init tx descriptors. 171776479Swpaul */ 171876479Swpaul nge_list_tx_init(sc); 171976479Swpaul 172076479Swpaul /* 172176479Swpaul * For the NatSemi chip, we have to explicitly enable the 172276479Swpaul * reception of ARP frames, as well as turn on the 'perfect 172376479Swpaul * match' filter where we store the station address, otherwise 172476479Swpaul * we won't receive unicasts meant for this host. 172576479Swpaul */ 172676479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP); 172776479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT); 172876479Swpaul 172976479Swpaul /* If we want promiscuous mode, set the allframes bit. */ 173076479Swpaul if (ifp->if_flags & IFF_PROMISC) { 173176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 173276479Swpaul } else { 173376479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS); 173476479Swpaul } 173576479Swpaul 173676479Swpaul /* 173776479Swpaul * Set the capture broadcast bit to capture broadcast frames. 173876479Swpaul */ 173976479Swpaul if (ifp->if_flags & IFF_BROADCAST) { 174076479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 174176479Swpaul } else { 174276479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD); 174376479Swpaul } 174476479Swpaul 174576479Swpaul /* 174676479Swpaul * Load the multicast filter. 174776479Swpaul */ 174876479Swpaul nge_setmulti(sc); 174976479Swpaul 175076479Swpaul /* Turn the receive filter on */ 175176479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE); 175276479Swpaul 175376479Swpaul /* 175476479Swpaul * Load the address of the RX and TX lists. 175576479Swpaul */ 175676479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 175776479Swpaul vtophys(&sc->nge_ldata->nge_rx_list[0])); 175876479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 175976479Swpaul vtophys(&sc->nge_ldata->nge_tx_list[0])); 176076479Swpaul 176176479Swpaul /* Set RX configuration */ 176276479Swpaul CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG); 176376479Swpaul /* 176476479Swpaul * Enable hardware checksum validation for all IPv4 176576479Swpaul * packets, do not reject packets with bad checksums. 176676479Swpaul */ 176778323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB); 176876479Swpaul 176976479Swpaul /* 177083115Sbrooks * Tell the chip to detect and strip VLAN tag info from 177183115Sbrooks * received frames. The tag will be provided in the extsts 177283115Sbrooks * field in the RX descriptors. 177376479Swpaul */ 177476479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL, 177576479Swpaul NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB); 177676479Swpaul 177776479Swpaul /* Set TX configuration */ 177876479Swpaul CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG); 177976479Swpaul 178076479Swpaul /* 178176479Swpaul * Enable TX IPv4 checksumming on a per-packet basis. 178276479Swpaul */ 178378323Swpaul CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT); 178476479Swpaul 178576479Swpaul /* 178683115Sbrooks * Tell the chip to insert VLAN tags on a per-packet basis as 178783115Sbrooks * dictated by the code in the frame encapsulation routine. 178876479Swpaul */ 178976479Swpaul NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT); 179076479Swpaul 179176479Swpaul /* Set full/half duplex mode. */ 1792101540Sambrisko if (sc->nge_tbi) { 1793101540Sambrisko if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1794101540Sambrisko == IFM_FDX) { 1795101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1796101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1797101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1798101540Sambrisko } else { 1799101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1800101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1801101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1802101540Sambrisko } 180376479Swpaul } else { 1804101540Sambrisko if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1805101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1806101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1807101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1808101540Sambrisko } else { 1809101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1810101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1811101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1812101540Sambrisko } 181376479Swpaul } 181476479Swpaul 1815135250Swpaul nge_tick_locked(sc); 181696028Sphk 181776479Swpaul /* 181876479Swpaul * Enable the delivery of PHY interrupts based on 181977842Swpaul * link/speed/duplex status changes. Also enable the 182077842Swpaul * extsts field in the DMA descriptors (needed for 182177842Swpaul * TCP/IP checksum offload on transmit). 182276479Swpaul */ 182379424Swpaul NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD| 182477842Swpaul NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB); 182576479Swpaul 182676479Swpaul /* 182779562Swpaul * Configure interrupt holdoff (moderation). We can 182879562Swpaul * have the chip delay interrupt delivery for a certain 182979562Swpaul * period. Units are in 100us, and the max setting 183079562Swpaul * is 25500us (0xFF x 100us). Default is a 100us holdoff. 183179562Swpaul */ 183279562Swpaul CSR_WRITE_4(sc, NGE_IHR, 0x01); 183379562Swpaul 183479562Swpaul /* 183576479Swpaul * Enable interrupts. 183676479Swpaul */ 183776479Swpaul CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS); 1838106507Ssimokawa#ifdef DEVICE_POLLING 1839106507Ssimokawa /* 1840106507Ssimokawa * ... only enable interrupts if we are not polling, make sure 1841106507Ssimokawa * they are off otherwise. 1842106507Ssimokawa */ 1843128122Srwatson if (ifp->if_flags & IFF_POLLING) 1844106507Ssimokawa CSR_WRITE_4(sc, NGE_IER, 0); 1845106507Ssimokawa else 1846106507Ssimokawa#endif /* DEVICE_POLLING */ 184776479Swpaul CSR_WRITE_4(sc, NGE_IER, 1); 184876479Swpaul 184976479Swpaul /* Enable receiver and transmitter. */ 185076479Swpaul NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 185176479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE); 185276479Swpaul 185376479Swpaul nge_ifmedia_upd(ifp); 185476479Swpaul 1855148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1856148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 185776479Swpaul 185876479Swpaul return; 185976479Swpaul} 186076479Swpaul 186176479Swpaul/* 186276479Swpaul * Set media options. 186376479Swpaul */ 186499497Salfredstatic int 186599497Salfrednge_ifmedia_upd(ifp) 186676479Swpaul struct ifnet *ifp; 186776479Swpaul{ 186876479Swpaul struct nge_softc *sc; 186976479Swpaul struct mii_data *mii; 187076479Swpaul 187176479Swpaul sc = ifp->if_softc; 187276479Swpaul 1873101540Sambrisko if (sc->nge_tbi) { 1874101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1875101540Sambrisko == IFM_AUTO) { 1876101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 1877101540Sambrisko CSR_READ_4(sc, NGE_TBI_ANAR) 1878101540Sambrisko | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX 1879101540Sambrisko | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2); 1880101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG 1881101540Sambrisko | NGE_TBIBMCR_RESTART_ANEG); 1882101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG); 1883101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media 1884101540Sambrisko & IFM_GMASK) == IFM_FDX) { 1885101540Sambrisko NGE_SETBIT(sc, NGE_TX_CFG, 1886101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1887101540Sambrisko NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1888101540Sambrisko 1889101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1890101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1891101540Sambrisko } else { 1892101540Sambrisko NGE_CLRBIT(sc, NGE_TX_CFG, 1893101540Sambrisko (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR)); 1894101540Sambrisko NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX); 1895101540Sambrisko 1896101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_ANAR, 0); 1897101540Sambrisko CSR_WRITE_4(sc, NGE_TBI_BMCR, 0); 1898101540Sambrisko } 1899101540Sambrisko 1900101540Sambrisko CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO) 1901101540Sambrisko & ~NGE_GPIO_GP3_OUT); 1902101540Sambrisko } else { 1903101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1904101540Sambrisko sc->nge_link = 0; 1905101540Sambrisko if (mii->mii_instance) { 1906101540Sambrisko struct mii_softc *miisc; 1907101540Sambrisko for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; 1908101540Sambrisko miisc = LIST_NEXT(miisc, mii_list)) 1909101540Sambrisko mii_phy_reset(miisc); 1910101540Sambrisko } 1911101540Sambrisko mii_mediachg(mii); 191276479Swpaul } 191376479Swpaul 191476479Swpaul return(0); 191576479Swpaul} 191676479Swpaul 191776479Swpaul/* 191876479Swpaul * Report current media status. 191976479Swpaul */ 192099497Salfredstatic void 192199497Salfrednge_ifmedia_sts(ifp, ifmr) 192276479Swpaul struct ifnet *ifp; 192376479Swpaul struct ifmediareq *ifmr; 192476479Swpaul{ 192576479Swpaul struct nge_softc *sc; 192676479Swpaul struct mii_data *mii; 192776479Swpaul 192876479Swpaul sc = ifp->if_softc; 192976479Swpaul 1930101540Sambrisko if (sc->nge_tbi) { 1931101540Sambrisko ifmr->ifm_status = IFM_AVALID; 1932101540Sambrisko ifmr->ifm_active = IFM_ETHER; 193376479Swpaul 1934101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1935101540Sambrisko ifmr->ifm_status |= IFM_ACTIVE; 1936101540Sambrisko } 1937101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK) 1938101540Sambrisko ifmr->ifm_active |= IFM_LOOP; 1939101540Sambrisko if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) { 1940101540Sambrisko ifmr->ifm_active |= IFM_NONE; 1941101540Sambrisko ifmr->ifm_status = 0; 1942101540Sambrisko return; 1943101540Sambrisko } 1944101540Sambrisko ifmr->ifm_active |= IFM_1000_SX; 1945101540Sambrisko if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) 1946101540Sambrisko == IFM_AUTO) { 1947101540Sambrisko ifmr->ifm_active |= IFM_AUTO; 1948101540Sambrisko if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1949101540Sambrisko & NGE_TBIANAR_FDX) { 1950101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1951101540Sambrisko }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR) 1952101540Sambrisko & NGE_TBIANAR_HDX) { 1953101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1954101540Sambrisko } 1955101540Sambrisko } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) 1956101540Sambrisko == IFM_FDX) 1957101540Sambrisko ifmr->ifm_active |= IFM_FDX; 1958101540Sambrisko else 1959101540Sambrisko ifmr->ifm_active |= IFM_HDX; 1960101540Sambrisko 1961101540Sambrisko } else { 1962101540Sambrisko mii = device_get_softc(sc->nge_miibus); 1963101540Sambrisko mii_pollstat(mii); 1964101540Sambrisko ifmr->ifm_active = mii->mii_media_active; 1965101540Sambrisko ifmr->ifm_status = mii->mii_media_status; 1966101540Sambrisko } 1967101540Sambrisko 196876479Swpaul return; 196976479Swpaul} 197076479Swpaul 197199497Salfredstatic int 197299497Salfrednge_ioctl(ifp, command, data) 197376479Swpaul struct ifnet *ifp; 197476479Swpaul u_long command; 197576479Swpaul caddr_t data; 197676479Swpaul{ 197776479Swpaul struct nge_softc *sc = ifp->if_softc; 197876479Swpaul struct ifreq *ifr = (struct ifreq *) data; 197976479Swpaul struct mii_data *mii; 1980135250Swpaul int error = 0; 198176479Swpaul 198276479Swpaul switch(command) { 198376479Swpaul case SIOCSIFMTU: 198476479Swpaul if (ifr->ifr_mtu > NGE_JUMBO_MTU) 198576479Swpaul error = EINVAL; 198678323Swpaul else { 198776479Swpaul ifp->if_mtu = ifr->ifr_mtu; 198878323Swpaul /* 198978323Swpaul * Workaround: if the MTU is larger than 199078323Swpaul * 8152 (TX FIFO size minus 64 minus 18), turn off 199178323Swpaul * TX checksum offloading. 199278323Swpaul */ 1993129632Syar if (ifr->ifr_mtu >= 8152) { 1994129632Syar ifp->if_capenable &= ~IFCAP_TXCSUM; 199578323Swpaul ifp->if_hwassist = 0; 1996129632Syar } else { 1997129632Syar ifp->if_capenable |= IFCAP_TXCSUM; 199878323Swpaul ifp->if_hwassist = NGE_CSUM_FEATURES; 1999129632Syar } 200078323Swpaul } 200176479Swpaul break; 200276479Swpaul case SIOCSIFFLAGS: 2003135250Swpaul NGE_LOCK(sc); 200476479Swpaul if (ifp->if_flags & IFF_UP) { 2005148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING && 200676479Swpaul ifp->if_flags & IFF_PROMISC && 200776479Swpaul !(sc->nge_if_flags & IFF_PROMISC)) { 200876479Swpaul NGE_SETBIT(sc, NGE_RXFILT_CTL, 200976479Swpaul NGE_RXFILTCTL_ALLPHYS| 201076479Swpaul NGE_RXFILTCTL_ALLMULTI); 2011148887Srwatson } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 201276479Swpaul !(ifp->if_flags & IFF_PROMISC) && 201376479Swpaul sc->nge_if_flags & IFF_PROMISC) { 201476479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 201576479Swpaul NGE_RXFILTCTL_ALLPHYS); 201676479Swpaul if (!(ifp->if_flags & IFF_ALLMULTI)) 201776479Swpaul NGE_CLRBIT(sc, NGE_RXFILT_CTL, 201876479Swpaul NGE_RXFILTCTL_ALLMULTI); 201976479Swpaul } else { 2020148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2021135250Swpaul nge_init_locked(sc); 202276479Swpaul } 202376479Swpaul } else { 2024148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 202576479Swpaul nge_stop(sc); 202676479Swpaul } 202776479Swpaul sc->nge_if_flags = ifp->if_flags; 2028135250Swpaul NGE_UNLOCK(sc); 202976479Swpaul error = 0; 203076479Swpaul break; 203176479Swpaul case SIOCADDMULTI: 203276479Swpaul case SIOCDELMULTI: 2033135250Swpaul NGE_LOCK(sc); 203476479Swpaul nge_setmulti(sc); 2035135250Swpaul NGE_UNLOCK(sc); 203676479Swpaul error = 0; 203776479Swpaul break; 203876479Swpaul case SIOCGIFMEDIA: 203976479Swpaul case SIOCSIFMEDIA: 2040101540Sambrisko if (sc->nge_tbi) { 2041101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia, 2042101540Sambrisko command); 2043101540Sambrisko } else { 2044101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2045101540Sambrisko error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, 2046101540Sambrisko command); 2047101540Sambrisko } 204876479Swpaul break; 2049128132Sru case SIOCSIFCAP: 2050129633Syar ifp->if_capenable &= ~IFCAP_POLLING; 2051129633Syar ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING; 2052128132Sru break; 205376479Swpaul default: 2054106937Ssam error = ether_ioctl(ifp, command, data); 205576479Swpaul break; 205676479Swpaul } 205776479Swpaul 205876479Swpaul return(error); 205976479Swpaul} 206076479Swpaul 206199497Salfredstatic void 206299497Salfrednge_watchdog(ifp) 206376479Swpaul struct ifnet *ifp; 206476479Swpaul{ 206576479Swpaul struct nge_softc *sc; 206676479Swpaul 206776479Swpaul sc = ifp->if_softc; 206876479Swpaul 206976479Swpaul ifp->if_oerrors++; 207076479Swpaul printf("nge%d: watchdog timeout\n", sc->nge_unit); 207176479Swpaul 2072135250Swpaul NGE_LOCK(sc); 207376479Swpaul nge_stop(sc); 207476479Swpaul nge_reset(sc); 2075148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2076135250Swpaul nge_init_locked(sc); 207776479Swpaul 207876479Swpaul if (ifp->if_snd.ifq_head != NULL) 2079135250Swpaul nge_start_locked(ifp); 208076479Swpaul 2081135250Swpaul NGE_UNLOCK(sc); 2082135250Swpaul 208376479Swpaul return; 208476479Swpaul} 208576479Swpaul 208676479Swpaul/* 208776479Swpaul * Stop the adapter and free any mbufs allocated to the 208876479Swpaul * RX and TX lists. 208976479Swpaul */ 209099497Salfredstatic void 209199497Salfrednge_stop(sc) 209276479Swpaul struct nge_softc *sc; 209376479Swpaul{ 209476479Swpaul register int i; 209576479Swpaul struct ifnet *ifp; 209676479Swpaul struct mii_data *mii; 209776479Swpaul 2098135250Swpaul NGE_LOCK_ASSERT(sc); 2099147256Sbrooks ifp = sc->nge_ifp; 210076479Swpaul ifp->if_timer = 0; 2101101540Sambrisko if (sc->nge_tbi) { 2102101540Sambrisko mii = NULL; 2103101540Sambrisko } else { 2104101540Sambrisko mii = device_get_softc(sc->nge_miibus); 2105101540Sambrisko } 210676479Swpaul 2107135250Swpaul callout_stop(&sc->nge_stat_ch); 2108106507Ssimokawa#ifdef DEVICE_POLLING 2109106507Ssimokawa ether_poll_deregister(ifp); 2110106507Ssimokawa#endif 211176479Swpaul CSR_WRITE_4(sc, NGE_IER, 0); 211276479Swpaul CSR_WRITE_4(sc, NGE_IMR, 0); 211376479Swpaul NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE); 211476479Swpaul DELAY(1000); 211576479Swpaul CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0); 211676479Swpaul CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0); 211776479Swpaul 2118101540Sambrisko if (!sc->nge_tbi) 2119101540Sambrisko mii_down(mii); 212076479Swpaul 212176479Swpaul sc->nge_link = 0; 212276479Swpaul 212376479Swpaul /* 212476479Swpaul * Free data in the RX lists. 212576479Swpaul */ 212676479Swpaul for (i = 0; i < NGE_RX_LIST_CNT; i++) { 212776479Swpaul if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) { 212876479Swpaul m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf); 212976479Swpaul sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL; 213076479Swpaul } 213176479Swpaul } 213276479Swpaul bzero((char *)&sc->nge_ldata->nge_rx_list, 213376479Swpaul sizeof(sc->nge_ldata->nge_rx_list)); 213476479Swpaul 213576479Swpaul /* 213676479Swpaul * Free the TX list buffers. 213776479Swpaul */ 213876479Swpaul for (i = 0; i < NGE_TX_LIST_CNT; i++) { 213976479Swpaul if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) { 214076479Swpaul m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf); 214176479Swpaul sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL; 214276479Swpaul } 214376479Swpaul } 214476479Swpaul 214576479Swpaul bzero((char *)&sc->nge_ldata->nge_tx_list, 214676479Swpaul sizeof(sc->nge_ldata->nge_tx_list)); 214776479Swpaul 2148148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 214976479Swpaul 215076479Swpaul return; 215176479Swpaul} 215276479Swpaul 215376479Swpaul/* 215476479Swpaul * Stop all chip I/O so that the kernel's probe routines don't 215576479Swpaul * get confused by errant DMAs when rebooting. 215676479Swpaul */ 215799497Salfredstatic void 215899497Salfrednge_shutdown(dev) 215976479Swpaul device_t dev; 216076479Swpaul{ 216176479Swpaul struct nge_softc *sc; 216276479Swpaul 216376479Swpaul sc = device_get_softc(dev); 216476479Swpaul 2165135250Swpaul NGE_LOCK(sc); 216676479Swpaul nge_reset(sc); 216776479Swpaul nge_stop(sc); 2168135250Swpaul NGE_UNLOCK(sc); 216976479Swpaul 217076479Swpaul return; 217176479Swpaul} 2172