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