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