if_nge.c revision 152315
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 152315 2005-11-11 16:04:59Z ru $");
36119418Sobrien
3776479Swpaul/*
3876479Swpaul * National Semiconductor DP83820/DP83821 gigabit ethernet driver
3976479Swpaul * for FreeBSD. Datasheets are available from:
4076479Swpaul *
4176479Swpaul * http://www.national.com/ds/DP/DP83820.pdf
4276479Swpaul * http://www.national.com/ds/DP/DP83821.pdf
4376479Swpaul *
4476479Swpaul * These chips are used on several low cost gigabit ethernet NICs
4576479Swpaul * sold by D-Link, Addtron, SMC and Asante. Both parts are
4676479Swpaul * virtually the same, except the 83820 is a 64-bit/32-bit part,
4776479Swpaul * while the 83821 is 32-bit only.
4876479Swpaul *
4976479Swpaul * Many cards also use National gigE transceivers, such as the
5076479Swpaul * DP83891, DP83861 and DP83862 gigPHYTER parts. The DP83861 datasheet
5176479Swpaul * contains a full register description that applies to all of these
5276479Swpaul * components:
5376479Swpaul *
5476479Swpaul * http://www.national.com/ds/DP/DP83861.pdf
5576479Swpaul *
5676479Swpaul * Written by Bill Paul <wpaul@bsdi.com>
5776479Swpaul * BSDi Open Source Solutions
5876479Swpaul */
5976479Swpaul
6076479Swpaul/*
6176479Swpaul * The NatSemi DP83820 and 83821 controllers are enhanced versions
6276479Swpaul * of the NatSemi MacPHYTER 10/100 devices. They support 10, 100
6376479Swpaul * and 1000Mbps speeds with 1000baseX (ten bit interface), MII and GMII
6476479Swpaul * ports. Other features include 8K TX FIFO and 32K RX FIFO, TCP/IP
6576479Swpaul * hardware checksum offload (IPv4 only), VLAN tagging and filtering,
6676479Swpaul * priority TX and RX queues, a 2048 bit multicast hash filter, 4 RX pattern
6776479Swpaul * matching buffers, one perfect address filter buffer and interrupt
6876479Swpaul * moderation. The 83820 supports both 64-bit and 32-bit addressing
6976479Swpaul * and data transfers: the 64-bit support can be toggled on or off
7076479Swpaul * via software. This affects the size of certain fields in the DMA
7176479Swpaul * descriptors.
7276479Swpaul *
7378323Swpaul * There are two bugs/misfeatures in the 83820/83821 that I have
7478323Swpaul * discovered so far:
7578323Swpaul *
7678323Swpaul * - Receive buffers must be aligned on 64-bit boundaries, which means
7778323Swpaul *   you must resort to copying data in order to fix up the payload
7878323Swpaul *   alignment.
7978323Swpaul *
8078323Swpaul * - In order to transmit jumbo frames larger than 8170 bytes, you have
8178323Swpaul *   to turn off transmit checksum offloading, because the chip can't
8278323Swpaul *   compute the checksum on an outgoing frame unless it fits entirely
8378323Swpaul *   within the TX FIFO, which is only 8192 bytes in size. If you have
8478323Swpaul *   TX checksum offload enabled and you transmit attempt to transmit a
8578323Swpaul *   frame larger than 8170 bytes, the transmitter will wedge.
8678323Swpaul *
8778323Swpaul * To work around the latter problem, TX checksum offload is disabled
8878323Swpaul * if the user selects an MTU larger than 8152 (8170 - 18).
8976479Swpaul */
9076479Swpaul
91150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS
92150968Sglebius#include "opt_device_polling.h"
93150968Sglebius#endif
94150968Sglebius
9576479Swpaul#include <sys/param.h>
9676479Swpaul#include <sys/systm.h>
9776479Swpaul#include <sys/sockio.h>
9876479Swpaul#include <sys/mbuf.h>
9976479Swpaul#include <sys/malloc.h>
100129879Sphk#include <sys/module.h>
10176479Swpaul#include <sys/kernel.h>
10276479Swpaul#include <sys/socket.h>
10376479Swpaul
10476479Swpaul#include <net/if.h>
10576479Swpaul#include <net/if_arp.h>
10676479Swpaul#include <net/ethernet.h>
10776479Swpaul#include <net/if_dl.h>
10876479Swpaul#include <net/if_media.h>
10976479Swpaul#include <net/if_types.h>
11076479Swpaul#include <net/if_vlan_var.h>
11176479Swpaul
11276479Swpaul#include <net/bpf.h>
11376479Swpaul
11476479Swpaul#include <vm/vm.h>              /* for vtophys */
11576479Swpaul#include <vm/pmap.h>            /* for vtophys */
11676479Swpaul#include <machine/clock.h>      /* for DELAY */
11776479Swpaul#include <machine/bus.h>
11876479Swpaul#include <machine/resource.h>
11976479Swpaul#include <sys/bus.h>
12076479Swpaul#include <sys/rman.h>
12176479Swpaul
12276479Swpaul#include <dev/mii/mii.h>
12376479Swpaul#include <dev/mii/miivar.h>
12476479Swpaul
125119285Simp#include <dev/pci/pcireg.h>
126119285Simp#include <dev/pci/pcivar.h>
12776479Swpaul
12876479Swpaul#define NGE_USEIOSPACE
12976479Swpaul
13076522Swpaul#include <dev/nge/if_ngereg.h>
13176479Swpaul
132113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1);
133113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1);
13476479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1);
13576479Swpaul
136151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
13776479Swpaul#include "miibus_if.h"
13876479Swpaul
13976479Swpaul#define NGE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
14076479Swpaul
14176479Swpaul/*
14276479Swpaul * Various supported device vendors/types and their names.
14376479Swpaul */
14476479Swpaulstatic struct nge_type nge_devs[] = {
14576479Swpaul	{ NGE_VENDORID, NGE_DEVICEID,
14676479Swpaul	    "National Semiconductor Gigabit Ethernet" },
14776479Swpaul	{ 0, 0, NULL }
14876479Swpaul};
14976479Swpaul
15099497Salfredstatic int nge_probe(device_t);
15199497Salfredstatic int nge_attach(device_t);
15299497Salfredstatic int nge_detach(device_t);
15376479Swpaul
15499497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *);
15599497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *);
156135254Salc#ifdef NGE_FIXUP_RX
157135250Swpaulstatic __inline void nge_fixup_rx (struct mbuf *);
158135250Swpaul#endif
15999497Salfredstatic void nge_rxeof(struct nge_softc *);
16099497Salfredstatic void nge_txeof(struct nge_softc *);
16199497Salfredstatic void nge_intr(void *);
16299497Salfredstatic void nge_tick(void *);
16399497Salfredstatic void nge_start(struct ifnet *);
164135250Swpaulstatic void nge_start_locked(struct ifnet *);
16599497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t);
16699497Salfredstatic void nge_init(void *);
167135250Swpaulstatic void nge_init_locked(struct nge_softc *);
16899497Salfredstatic void nge_stop(struct nge_softc *);
16999497Salfredstatic void nge_watchdog(struct ifnet *);
17099497Salfredstatic void nge_shutdown(device_t);
17199497Salfredstatic int nge_ifmedia_upd(struct ifnet *);
172151296Sjhbstatic void nge_ifmedia_upd_locked(struct ifnet *);
17399497Salfredstatic void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
17476479Swpaul
17599497Salfredstatic void nge_delay(struct nge_softc *);
17699497Salfredstatic void nge_eeprom_idle(struct nge_softc *);
17799497Salfredstatic void nge_eeprom_putbyte(struct nge_softc *, int);
17899497Salfredstatic void nge_eeprom_getword(struct nge_softc *, int, u_int16_t *);
17999497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int);
18076479Swpaul
18199497Salfredstatic void nge_mii_sync(struct nge_softc *);
18299497Salfredstatic void nge_mii_send(struct nge_softc *, u_int32_t, int);
18399497Salfredstatic int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *);
18499497Salfredstatic int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *);
18576479Swpaul
18699497Salfredstatic int nge_miibus_readreg(device_t, int, int);
18799497Salfredstatic int nge_miibus_writereg(device_t, int, int, int);
18899497Salfredstatic void nge_miibus_statchg(device_t);
18976479Swpaul
19099497Salfredstatic void nge_setmulti(struct nge_softc *);
19199497Salfredstatic void nge_reset(struct nge_softc *);
19299497Salfredstatic int nge_list_rx_init(struct nge_softc *);
19399497Salfredstatic int nge_list_tx_init(struct nge_softc *);
19476479Swpaul
19576479Swpaul#ifdef NGE_USEIOSPACE
19676479Swpaul#define NGE_RES			SYS_RES_IOPORT
19776479Swpaul#define NGE_RID			NGE_PCI_LOIO
19876479Swpaul#else
19976479Swpaul#define NGE_RES			SYS_RES_MEMORY
20076479Swpaul#define NGE_RID			NGE_PCI_LOMEM
20176479Swpaul#endif
20276479Swpaul
20376479Swpaulstatic device_method_t nge_methods[] = {
20476479Swpaul	/* Device interface */
20576479Swpaul	DEVMETHOD(device_probe,		nge_probe),
20676479Swpaul	DEVMETHOD(device_attach,	nge_attach),
20776479Swpaul	DEVMETHOD(device_detach,	nge_detach),
20876479Swpaul	DEVMETHOD(device_shutdown,	nge_shutdown),
20976479Swpaul
21076479Swpaul	/* bus interface */
21176479Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
21276479Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
21376479Swpaul
21476479Swpaul	/* MII interface */
21576479Swpaul	DEVMETHOD(miibus_readreg,	nge_miibus_readreg),
21676479Swpaul	DEVMETHOD(miibus_writereg,	nge_miibus_writereg),
21776479Swpaul	DEVMETHOD(miibus_statchg,	nge_miibus_statchg),
21876479Swpaul
21976479Swpaul	{ 0, 0 }
22076479Swpaul};
22176479Swpaul
22276479Swpaulstatic driver_t nge_driver = {
22376479Swpaul	"nge",
22476479Swpaul	nge_methods,
22576479Swpaul	sizeof(struct nge_softc)
22676479Swpaul};
22776479Swpaul
22876479Swpaulstatic devclass_t nge_devclass;
22976479Swpaul
230113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0);
23176479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0);
23276479Swpaul
23376479Swpaul#define NGE_SETBIT(sc, reg, x)				\
23476479Swpaul	CSR_WRITE_4(sc, reg,				\
23576479Swpaul		CSR_READ_4(sc, reg) | (x))
23676479Swpaul
23776479Swpaul#define NGE_CLRBIT(sc, reg, x)				\
23876479Swpaul	CSR_WRITE_4(sc, reg,				\
23976479Swpaul		CSR_READ_4(sc, reg) & ~(x))
24076479Swpaul
24176479Swpaul#define SIO_SET(x)					\
242106696Salfred	CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x))
24376479Swpaul
24476479Swpaul#define SIO_CLR(x)					\
245106696Salfred	CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x))
24676479Swpaul
24799497Salfredstatic void
24899497Salfrednge_delay(sc)
24976479Swpaul	struct nge_softc	*sc;
25076479Swpaul{
25176479Swpaul	int			idx;
25276479Swpaul
25376479Swpaul	for (idx = (300 / 33) + 1; idx > 0; idx--)
25476479Swpaul		CSR_READ_4(sc, NGE_CSR);
25576479Swpaul
25676479Swpaul	return;
25776479Swpaul}
25876479Swpaul
25999497Salfredstatic void
26099497Salfrednge_eeprom_idle(sc)
26176479Swpaul	struct nge_softc	*sc;
26276479Swpaul{
26376479Swpaul	register int		i;
26476479Swpaul
26576479Swpaul	SIO_SET(NGE_MEAR_EE_CSEL);
26676479Swpaul	nge_delay(sc);
26776479Swpaul	SIO_SET(NGE_MEAR_EE_CLK);
26876479Swpaul	nge_delay(sc);
26976479Swpaul
27076479Swpaul	for (i = 0; i < 25; i++) {
27176479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
27276479Swpaul		nge_delay(sc);
27376479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
27476479Swpaul		nge_delay(sc);
27576479Swpaul	}
27676479Swpaul
27776479Swpaul	SIO_CLR(NGE_MEAR_EE_CLK);
27876479Swpaul	nge_delay(sc);
27976479Swpaul	SIO_CLR(NGE_MEAR_EE_CSEL);
28076479Swpaul	nge_delay(sc);
28176479Swpaul	CSR_WRITE_4(sc, NGE_MEAR, 0x00000000);
28276479Swpaul
28376479Swpaul	return;
28476479Swpaul}
28576479Swpaul
28676479Swpaul/*
28776479Swpaul * Send a read command and address to the EEPROM, check for ACK.
28876479Swpaul */
28999497Salfredstatic void
29099497Salfrednge_eeprom_putbyte(sc, addr)
29176479Swpaul	struct nge_softc	*sc;
29276479Swpaul	int			addr;
29376479Swpaul{
29476479Swpaul	register int		d, i;
29576479Swpaul
29676479Swpaul	d = addr | NGE_EECMD_READ;
29776479Swpaul
29876479Swpaul	/*
29976479Swpaul	 * Feed in each bit and stobe the clock.
30076479Swpaul	 */
30176479Swpaul	for (i = 0x400; i; i >>= 1) {
30276479Swpaul		if (d & i) {
30376479Swpaul			SIO_SET(NGE_MEAR_EE_DIN);
30476479Swpaul		} else {
30576479Swpaul			SIO_CLR(NGE_MEAR_EE_DIN);
30676479Swpaul		}
30776479Swpaul		nge_delay(sc);
30876479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
30976479Swpaul		nge_delay(sc);
31076479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
31176479Swpaul		nge_delay(sc);
31276479Swpaul	}
31376479Swpaul
31476479Swpaul	return;
31576479Swpaul}
31676479Swpaul
31776479Swpaul/*
31876479Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
31976479Swpaul */
32099497Salfredstatic void
32199497Salfrednge_eeprom_getword(sc, addr, dest)
32276479Swpaul	struct nge_softc	*sc;
32376479Swpaul	int			addr;
32476479Swpaul	u_int16_t		*dest;
32576479Swpaul{
32676479Swpaul	register int		i;
32776479Swpaul	u_int16_t		word = 0;
32876479Swpaul
32976479Swpaul	/* Force EEPROM to idle state. */
33076479Swpaul	nge_eeprom_idle(sc);
33176479Swpaul
33276479Swpaul	/* Enter EEPROM access mode. */
33376479Swpaul	nge_delay(sc);
33476479Swpaul	SIO_CLR(NGE_MEAR_EE_CLK);
33576479Swpaul	nge_delay(sc);
33676479Swpaul	SIO_SET(NGE_MEAR_EE_CSEL);
33776479Swpaul	nge_delay(sc);
33876479Swpaul
33976479Swpaul	/*
34076479Swpaul	 * Send address of word we want to read.
34176479Swpaul	 */
34276479Swpaul	nge_eeprom_putbyte(sc, addr);
34376479Swpaul
34476479Swpaul	/*
34576479Swpaul	 * Start reading bits from EEPROM.
34676479Swpaul	 */
34776479Swpaul	for (i = 0x8000; i; i >>= 1) {
34876479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
34976479Swpaul		nge_delay(sc);
35076479Swpaul		if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT)
35176479Swpaul			word |= i;
35276479Swpaul		nge_delay(sc);
35376479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
35476479Swpaul		nge_delay(sc);
35576479Swpaul	}
35676479Swpaul
35776479Swpaul	/* Turn off EEPROM access mode. */
35876479Swpaul	nge_eeprom_idle(sc);
35976479Swpaul
36076479Swpaul	*dest = word;
36176479Swpaul
36276479Swpaul	return;
36376479Swpaul}
36476479Swpaul
36576479Swpaul/*
36676479Swpaul * Read a sequence of words from the EEPROM.
36776479Swpaul */
36899497Salfredstatic void
36999497Salfrednge_read_eeprom(sc, dest, off, cnt, swap)
37076479Swpaul	struct nge_softc	*sc;
37176479Swpaul	caddr_t			dest;
37276479Swpaul	int			off;
37376479Swpaul	int			cnt;
37476479Swpaul	int			swap;
37576479Swpaul{
37676479Swpaul	int			i;
37776479Swpaul	u_int16_t		word = 0, *ptr;
37876479Swpaul
37976479Swpaul	for (i = 0; i < cnt; i++) {
38076479Swpaul		nge_eeprom_getword(sc, off + i, &word);
38176479Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
38276479Swpaul		if (swap)
38376479Swpaul			*ptr = ntohs(word);
38476479Swpaul		else
38576479Swpaul			*ptr = word;
38676479Swpaul	}
38776479Swpaul
38876479Swpaul	return;
38976479Swpaul}
39076479Swpaul
39176479Swpaul/*
39276479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
39376479Swpaul */
39499497Salfredstatic void
39599497Salfrednge_mii_sync(sc)
39676479Swpaul	struct nge_softc		*sc;
39776479Swpaul{
39876479Swpaul	register int		i;
39976479Swpaul
40076479Swpaul	SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA);
40176479Swpaul
40276479Swpaul	for (i = 0; i < 32; i++) {
40376479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
40476479Swpaul		DELAY(1);
40576479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
40676479Swpaul		DELAY(1);
40776479Swpaul	}
40876479Swpaul
40976479Swpaul	return;
41076479Swpaul}
41176479Swpaul
41276479Swpaul/*
41376479Swpaul * Clock a series of bits through the MII.
41476479Swpaul */
41599497Salfredstatic void
41699497Salfrednge_mii_send(sc, bits, cnt)
41776479Swpaul	struct nge_softc		*sc;
41876479Swpaul	u_int32_t		bits;
41976479Swpaul	int			cnt;
42076479Swpaul{
42176479Swpaul	int			i;
42276479Swpaul
42376479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
42476479Swpaul
42576479Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
42676479Swpaul                if (bits & i) {
42776479Swpaul			SIO_SET(NGE_MEAR_MII_DATA);
42876479Swpaul                } else {
42976479Swpaul			SIO_CLR(NGE_MEAR_MII_DATA);
43076479Swpaul                }
43176479Swpaul		DELAY(1);
43276479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
43376479Swpaul		DELAY(1);
43476479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
43576479Swpaul	}
43676479Swpaul}
43776479Swpaul
43876479Swpaul/*
43976479Swpaul * Read an PHY register through the MII.
44076479Swpaul */
44199497Salfredstatic int
44299497Salfrednge_mii_readreg(sc, frame)
44376479Swpaul	struct nge_softc		*sc;
44476479Swpaul	struct nge_mii_frame	*frame;
44576479Swpaul
44676479Swpaul{
447135250Swpaul	int			i, ack;
44876479Swpaul
44976479Swpaul	/*
45076479Swpaul	 * Set up frame for RX.
45176479Swpaul	 */
45276479Swpaul	frame->mii_stdelim = NGE_MII_STARTDELIM;
45376479Swpaul	frame->mii_opcode = NGE_MII_READOP;
45476479Swpaul	frame->mii_turnaround = 0;
45576479Swpaul	frame->mii_data = 0;
45676479Swpaul
45776479Swpaul	CSR_WRITE_4(sc, NGE_MEAR, 0);
45876479Swpaul
45976479Swpaul	/*
46076479Swpaul 	 * Turn on data xmit.
46176479Swpaul	 */
46276479Swpaul	SIO_SET(NGE_MEAR_MII_DIR);
46376479Swpaul
46476479Swpaul	nge_mii_sync(sc);
46576479Swpaul
46676479Swpaul	/*
46776479Swpaul	 * Send command/address info.
46876479Swpaul	 */
46976479Swpaul	nge_mii_send(sc, frame->mii_stdelim, 2);
47076479Swpaul	nge_mii_send(sc, frame->mii_opcode, 2);
47176479Swpaul	nge_mii_send(sc, frame->mii_phyaddr, 5);
47276479Swpaul	nge_mii_send(sc, frame->mii_regaddr, 5);
47376479Swpaul
47476479Swpaul	/* Idle bit */
47576479Swpaul	SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA));
47676479Swpaul	DELAY(1);
47776479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
47876479Swpaul	DELAY(1);
47976479Swpaul
48076479Swpaul	/* Turn off xmit. */
48176479Swpaul	SIO_CLR(NGE_MEAR_MII_DIR);
48276479Swpaul	/* Check for ack */
48376479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
48476479Swpaul	DELAY(1);
485109058Smbr	ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA;
48676479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
48776479Swpaul	DELAY(1);
48876479Swpaul
48976479Swpaul	/*
49076479Swpaul	 * Now try reading data bits. If the ack failed, we still
49176479Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
49276479Swpaul	 */
49376479Swpaul	if (ack) {
49476479Swpaul		for(i = 0; i < 16; i++) {
49576479Swpaul			SIO_CLR(NGE_MEAR_MII_CLK);
49676479Swpaul			DELAY(1);
49776479Swpaul			SIO_SET(NGE_MEAR_MII_CLK);
49876479Swpaul			DELAY(1);
49976479Swpaul		}
50076479Swpaul		goto fail;
50176479Swpaul	}
50276479Swpaul
50376479Swpaul	for (i = 0x8000; i; i >>= 1) {
50476479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
50576479Swpaul		DELAY(1);
50676479Swpaul		if (!ack) {
50776479Swpaul			if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA)
50876479Swpaul				frame->mii_data |= i;
50976479Swpaul			DELAY(1);
51076479Swpaul		}
51176479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
51276479Swpaul		DELAY(1);
51376479Swpaul	}
51476479Swpaul
51576479Swpaulfail:
51676479Swpaul
51776479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
51876479Swpaul	DELAY(1);
51976479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
52076479Swpaul	DELAY(1);
52176479Swpaul
52276479Swpaul	if (ack)
52376479Swpaul		return(1);
52476479Swpaul	return(0);
52576479Swpaul}
52676479Swpaul
52776479Swpaul/*
52876479Swpaul * Write to a PHY register through the MII.
52976479Swpaul */
53099497Salfredstatic int
53199497Salfrednge_mii_writereg(sc, frame)
53276479Swpaul	struct nge_softc		*sc;
53376479Swpaul	struct nge_mii_frame	*frame;
53476479Swpaul
53576479Swpaul{
53676479Swpaul
53776479Swpaul	/*
53876479Swpaul	 * Set up frame for TX.
53976479Swpaul	 */
54076479Swpaul
54176479Swpaul	frame->mii_stdelim = NGE_MII_STARTDELIM;
54276479Swpaul	frame->mii_opcode = NGE_MII_WRITEOP;
54376479Swpaul	frame->mii_turnaround = NGE_MII_TURNAROUND;
54476479Swpaul
54576479Swpaul	/*
54676479Swpaul 	 * Turn on data output.
54776479Swpaul	 */
54876479Swpaul	SIO_SET(NGE_MEAR_MII_DIR);
54976479Swpaul
55076479Swpaul	nge_mii_sync(sc);
55176479Swpaul
55276479Swpaul	nge_mii_send(sc, frame->mii_stdelim, 2);
55376479Swpaul	nge_mii_send(sc, frame->mii_opcode, 2);
55476479Swpaul	nge_mii_send(sc, frame->mii_phyaddr, 5);
55576479Swpaul	nge_mii_send(sc, frame->mii_regaddr, 5);
55676479Swpaul	nge_mii_send(sc, frame->mii_turnaround, 2);
55776479Swpaul	nge_mii_send(sc, frame->mii_data, 16);
55876479Swpaul
55976479Swpaul	/* Idle bit. */
56076479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
56176479Swpaul	DELAY(1);
56276479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
56376479Swpaul	DELAY(1);
56476479Swpaul
56576479Swpaul	/*
56676479Swpaul	 * Turn off xmit.
56776479Swpaul	 */
56876479Swpaul	SIO_CLR(NGE_MEAR_MII_DIR);
56976479Swpaul
57076479Swpaul	return(0);
57176479Swpaul}
57276479Swpaul
57399497Salfredstatic int
57499497Salfrednge_miibus_readreg(dev, phy, reg)
57576479Swpaul	device_t		dev;
57676479Swpaul	int			phy, reg;
57776479Swpaul{
57876479Swpaul	struct nge_softc	*sc;
57976479Swpaul	struct nge_mii_frame	frame;
58076479Swpaul
58176479Swpaul	sc = device_get_softc(dev);
58276479Swpaul
58376479Swpaul	bzero((char *)&frame, sizeof(frame));
58476479Swpaul
58576479Swpaul	frame.mii_phyaddr = phy;
58676479Swpaul	frame.mii_regaddr = reg;
58776479Swpaul	nge_mii_readreg(sc, &frame);
58876479Swpaul
58976479Swpaul	return(frame.mii_data);
59076479Swpaul}
59176479Swpaul
59299497Salfredstatic int
59399497Salfrednge_miibus_writereg(dev, phy, reg, data)
59476479Swpaul	device_t		dev;
59576479Swpaul	int			phy, reg, data;
59676479Swpaul{
59776479Swpaul	struct nge_softc	*sc;
59876479Swpaul	struct nge_mii_frame	frame;
59976479Swpaul
60076479Swpaul	sc = device_get_softc(dev);
60176479Swpaul
60276479Swpaul	bzero((char *)&frame, sizeof(frame));
60376479Swpaul
60476479Swpaul	frame.mii_phyaddr = phy;
60576479Swpaul	frame.mii_regaddr = reg;
60676479Swpaul	frame.mii_data = data;
60776479Swpaul	nge_mii_writereg(sc, &frame);
60876479Swpaul
60976479Swpaul	return(0);
61076479Swpaul}
61176479Swpaul
61299497Salfredstatic void
61399497Salfrednge_miibus_statchg(dev)
61476479Swpaul	device_t		dev;
61576479Swpaul{
616101540Sambrisko	int			status;
61776479Swpaul	struct nge_softc	*sc;
61876479Swpaul	struct mii_data		*mii;
61976479Swpaul
62076479Swpaul	sc = device_get_softc(dev);
621101540Sambrisko	if (sc->nge_tbi) {
622101540Sambrisko		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
623101540Sambrisko		    == IFM_AUTO) {
624101540Sambrisko			status = CSR_READ_4(sc, NGE_TBI_ANLPAR);
625101540Sambrisko			if (status == 0 || status & NGE_TBIANAR_FDX) {
626101540Sambrisko				NGE_SETBIT(sc, NGE_TX_CFG,
627101540Sambrisko				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
628101540Sambrisko				NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
629101540Sambrisko			} else {
630101540Sambrisko				NGE_CLRBIT(sc, NGE_TX_CFG,
631101540Sambrisko				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
632101540Sambrisko				NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
633101540Sambrisko			}
63476479Swpaul
635101540Sambrisko		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
636101540Sambrisko			!= IFM_FDX) {
637101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
638101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
639101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
640101540Sambrisko		} else {
641101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
642101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
643101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
644101540Sambrisko		}
64576479Swpaul	} else {
646101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
64776479Swpaul
648101540Sambrisko		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
649101540Sambrisko		        NGE_SETBIT(sc, NGE_TX_CFG,
650101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
651101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
652101540Sambrisko		} else {
653101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
654101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
655101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
656101540Sambrisko		}
657101540Sambrisko
658101540Sambrisko		/* If we have a 1000Mbps link, set the mode_1000 bit. */
659101540Sambrisko		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
660101540Sambrisko		    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
661101540Sambrisko			NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
662101540Sambrisko		} else {
663101540Sambrisko			NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
664101540Sambrisko		}
66579424Swpaul	}
66676479Swpaul	return;
66776479Swpaul}
66876479Swpaul
66999497Salfredstatic void
67099497Salfrednge_setmulti(sc)
67176479Swpaul	struct nge_softc	*sc;
67276479Swpaul{
67376479Swpaul	struct ifnet		*ifp;
67476479Swpaul	struct ifmultiaddr	*ifma;
67576479Swpaul	u_int32_t		h = 0, i, filtsave;
67676479Swpaul	int			bit, index;
67776479Swpaul
678135250Swpaul	NGE_LOCK_ASSERT(sc);
679147256Sbrooks	ifp = sc->nge_ifp;
68076479Swpaul
68176479Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
68276479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL,
68376479Swpaul		    NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH);
68476479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI);
68576479Swpaul		return;
68676479Swpaul	}
68776479Swpaul
68876479Swpaul	/*
68976479Swpaul	 * We have to explicitly enable the multicast hash table
69076479Swpaul	 * on the NatSemi chip if we want to use it, which we do.
69176479Swpaul	 * We also have to tell it that we don't want to use the
69276479Swpaul	 * hash table for matching unicast addresses.
69376479Swpaul	 */
69476479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH);
69576479Swpaul	NGE_CLRBIT(sc, NGE_RXFILT_CTL,
69676479Swpaul	    NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH);
69776479Swpaul
69876479Swpaul	filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL);
69976479Swpaul
70076479Swpaul	/* first, zot all the existing hash bits */
70176479Swpaul	for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) {
70276479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i);
70376479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0);
70476479Swpaul	}
70576479Swpaul
70676479Swpaul	/*
70776479Swpaul	 * From the 11 bits returned by the crc routine, the top 7
70876479Swpaul	 * bits represent the 16-bit word in the mcast hash table
70976479Swpaul	 * that needs to be updated, and the lower 4 bits represent
71076479Swpaul	 * which bit within that byte needs to be set.
71176479Swpaul	 */
712148654Srwatson	IF_ADDR_LOCK(ifp);
71376479Swpaul	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
71476479Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
71576479Swpaul			continue;
716130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
717130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 21;
71876479Swpaul		index = (h >> 4) & 0x7F;
71976479Swpaul		bit = h & 0xF;
72076479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_CTL,
72176479Swpaul		    NGE_FILTADDR_MCAST_LO + (index * 2));
72276479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit));
72376479Swpaul	}
724148654Srwatson	IF_ADDR_UNLOCK(ifp);
72576479Swpaul
72676479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave);
72776479Swpaul
72876479Swpaul	return;
72976479Swpaul}
73076479Swpaul
73199497Salfredstatic void
73299497Salfrednge_reset(sc)
73376479Swpaul	struct nge_softc	*sc;
73476479Swpaul{
73576479Swpaul	register int		i;
73676479Swpaul
73776479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET);
73876479Swpaul
73976479Swpaul	for (i = 0; i < NGE_TIMEOUT; i++) {
74076479Swpaul		if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET))
74176479Swpaul			break;
74276479Swpaul	}
74376479Swpaul
74476479Swpaul	if (i == NGE_TIMEOUT)
745151296Sjhb		if_printf(sc->nge_ifp, "reset never completed\n");
74676479Swpaul
74776479Swpaul	/* Wait a little while for the chip to get its brains in order. */
74876479Swpaul	DELAY(1000);
74976479Swpaul
75076479Swpaul	/*
75176479Swpaul	 * If this is a NetSemi chip, make sure to clear
75276479Swpaul	 * PME mode.
75376479Swpaul	 */
75476479Swpaul	CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS);
75576479Swpaul	CSR_WRITE_4(sc, NGE_CLKRUN, 0);
75676479Swpaul
75776479Swpaul        return;
75876479Swpaul}
75976479Swpaul
76076479Swpaul/*
761108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device
76276479Swpaul * IDs against our list and return a device name if we find a match.
76376479Swpaul */
76499497Salfredstatic int
76599497Salfrednge_probe(dev)
76676479Swpaul	device_t		dev;
76776479Swpaul{
76876479Swpaul	struct nge_type		*t;
76976479Swpaul
77076479Swpaul	t = nge_devs;
77176479Swpaul
77276479Swpaul	while(t->nge_name != NULL) {
77376479Swpaul		if ((pci_get_vendor(dev) == t->nge_vid) &&
77476479Swpaul		    (pci_get_device(dev) == t->nge_did)) {
77576479Swpaul			device_set_desc(dev, t->nge_name);
776143158Simp			return(BUS_PROBE_DEFAULT);
77776479Swpaul		}
77876479Swpaul		t++;
77976479Swpaul	}
78076479Swpaul
78176479Swpaul	return(ENXIO);
78276479Swpaul}
78376479Swpaul
78476479Swpaul/*
78576479Swpaul * Attach the interface. Allocate softc structures, do ifmedia
78676479Swpaul * setup and ethernet/BPF attach.
78776479Swpaul */
78899497Salfredstatic int
78999497Salfrednge_attach(dev)
79076479Swpaul	device_t		dev;
79176479Swpaul{
79276479Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
79376479Swpaul	struct nge_softc	*sc;
794151296Sjhb	struct ifnet		*ifp = NULL;
795151296Sjhb	int			error = 0, rid;
79676479Swpaul
79776479Swpaul	sc = device_get_softc(dev);
79876479Swpaul
799135250Swpaul	NGE_LOCK_INIT(sc, device_get_nameunit(dev));
800151296Sjhb	callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0);
801151296Sjhb
80276479Swpaul	/*
80376479Swpaul	 * Map control/status registers.
80476479Swpaul	 */
80576479Swpaul	pci_enable_busmaster(dev);
80676479Swpaul
80776479Swpaul	rid = NGE_RID;
808127135Snjl	sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE);
80976479Swpaul
81076479Swpaul	if (sc->nge_res == NULL) {
811151296Sjhb		device_printf(dev, "couldn't map ports/memory\n");
81276479Swpaul		error = ENXIO;
81376479Swpaul		goto fail;
81476479Swpaul	}
81576479Swpaul
81676479Swpaul	sc->nge_btag = rman_get_bustag(sc->nge_res);
81776479Swpaul	sc->nge_bhandle = rman_get_bushandle(sc->nge_res);
81876479Swpaul
81976479Swpaul	/* Allocate interrupt */
82076479Swpaul	rid = 0;
821127135Snjl	sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
82276479Swpaul	    RF_SHAREABLE | RF_ACTIVE);
82376479Swpaul
82476479Swpaul	if (sc->nge_irq == NULL) {
825151296Sjhb		device_printf(dev, "couldn't map interrupt\n");
82676479Swpaul		error = ENXIO;
82776479Swpaul		goto fail;
82876479Swpaul	}
82976479Swpaul
83076479Swpaul	/* Reset the adapter. */
83176479Swpaul	nge_reset(sc);
83276479Swpaul
83376479Swpaul	/*
83476479Swpaul	 * Get station address from the EEPROM.
83576479Swpaul	 */
83676479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0);
83776479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0);
83876479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0);
83976479Swpaul
84076479Swpaul	sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF,
841151296Sjhb	    M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
84276479Swpaul
84376479Swpaul	if (sc->nge_ldata == NULL) {
844151296Sjhb		device_printf(dev, "no memory for list buffers!\n");
84576479Swpaul		error = ENXIO;
84676479Swpaul		goto fail;
84776479Swpaul	}
84876479Swpaul
849147256Sbrooks	ifp = sc->nge_ifp = if_alloc(IFT_ETHER);
850147256Sbrooks	if (ifp == NULL) {
851151296Sjhb		device_printf(dev, "can not if_alloc()\n");
852147256Sbrooks		error = ENOSPC;
853147256Sbrooks		goto fail;
854147256Sbrooks	}
85576479Swpaul	ifp->if_softc = sc;
856121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
85776479Swpaul	ifp->if_mtu = ETHERMTU;
858135250Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
85976479Swpaul	ifp->if_ioctl = nge_ioctl;
86076479Swpaul	ifp->if_start = nge_start;
86176479Swpaul	ifp->if_watchdog = nge_watchdog;
86276479Swpaul	ifp->if_init = nge_init;
86376479Swpaul	ifp->if_baudrate = 1000000000;
86476479Swpaul	ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1;
86576479Swpaul	ifp->if_hwassist = NGE_CSUM_FEATURES;
866106937Ssam	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING;
867150789Sglebius	ifp->if_capenable = ifp->if_capabilities;
868128132Sru#ifdef DEVICE_POLLING
869128132Sru	ifp->if_capabilities |= IFCAP_POLLING;
870128132Sru#endif
87176479Swpaul
87276479Swpaul	/*
87376479Swpaul	 * Do MII setup.
87476479Swpaul	 */
875150185Sru	/* XXX: leaked on error */
87676479Swpaul	if (mii_phy_probe(dev, &sc->nge_miibus,
877101540Sambrisko			  nge_ifmedia_upd, nge_ifmedia_sts)) {
878101540Sambrisko		if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) {
879101540Sambrisko			sc->nge_tbi = 1;
880101540Sambrisko			device_printf(dev, "Using TBI\n");
881101540Sambrisko
882101540Sambrisko			sc->nge_miibus = dev;
883101540Sambrisko
884101540Sambrisko			ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd,
885101540Sambrisko				nge_ifmedia_sts);
886101540Sambrisko#define	ADD(m, c)	ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL)
887101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0);
888101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0);
889101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0);
890101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0);
891101540Sambrisko#undef ADD
892151296Sjhb			device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n");
893151296Sjhb
894101540Sambrisko			ifmedia_set(&sc->nge_ifmedia,
895101540Sambrisko				IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0));
896101540Sambrisko
897101540Sambrisko			CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
898101540Sambrisko				| NGE_GPIO_GP4_OUT
899101540Sambrisko				| NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB
900101540Sambrisko				| NGE_GPIO_GP3_OUTENB
901101540Sambrisko				| NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
902101540Sambrisko
903101540Sambrisko		} else {
904151296Sjhb			device_printf(dev, "MII without any PHY!\n");
905101540Sambrisko			error = ENXIO;
906101540Sambrisko			goto fail;
907101540Sambrisko		}
90876479Swpaul	}
90976479Swpaul
91076479Swpaul	/*
91176479Swpaul	 * Call MI attach routine.
91276479Swpaul	 */
913106937Ssam	ether_ifattach(ifp, eaddr);
91476479Swpaul
915135250Swpaul	/*
916135250Swpaul	 * Hookup IRQ last.
917135250Swpaul	 */
918135250Swpaul	error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE,
919135250Swpaul	    nge_intr, sc, &sc->nge_intrhand);
920135250Swpaul	if (error) {
921151296Sjhb		device_printf(dev, "couldn't set up irq\n");
922151296Sjhb		goto fail;
923151296Sjhb	}
924151296Sjhb
925151296Sjhb	return (0);
926151296Sjhb
927151296Sjhbfail:
928151296Sjhb	if (sc->nge_ldata)
929151296Sjhb		contigfree(sc->nge_ldata,
930151296Sjhb		  sizeof(struct nge_list_data), M_DEVBUF);
931151296Sjhb	if (ifp)
932150185Sru		if_free(ifp);
933151296Sjhb	if (sc->nge_irq)
934135250Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
935151296Sjhb	if (sc->nge_res)
936135250Swpaul		bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
937151296Sjhb	NGE_LOCK_DESTROY(sc);
93876479Swpaul	return(error);
93976479Swpaul}
94076479Swpaul
94199497Salfredstatic int
94299497Salfrednge_detach(dev)
94376479Swpaul	device_t		dev;
94476479Swpaul{
94576479Swpaul	struct nge_softc	*sc;
94676479Swpaul	struct ifnet		*ifp;
94776479Swpaul
94876479Swpaul	sc = device_get_softc(dev);
949147256Sbrooks	ifp = sc->nge_ifp;
95076479Swpaul
951150789Sglebius#ifdef DEVICE_POLLING
952150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
953150789Sglebius		ether_poll_deregister(ifp);
954150789Sglebius#endif
955135250Swpaul	NGE_LOCK(sc);
95676479Swpaul	nge_reset(sc);
95776479Swpaul	nge_stop(sc);
958135250Swpaul	NGE_UNLOCK(sc);
959151296Sjhb	callout_drain(&sc->nge_stat_ch);
960106937Ssam	ether_ifdetach(ifp);
96176479Swpaul
96276479Swpaul	bus_generic_detach(dev);
963101540Sambrisko	if (!sc->nge_tbi) {
964101540Sambrisko		device_delete_child(dev, sc->nge_miibus);
965101540Sambrisko	}
96676479Swpaul	bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
96776479Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
96876479Swpaul	bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
96976479Swpaul
97076479Swpaul	contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF);
971150306Simp	if_free(ifp);
97276479Swpaul
973135251Swpaul	NGE_LOCK_DESTROY(sc);
974135251Swpaul
97576479Swpaul	return(0);
97676479Swpaul}
97776479Swpaul
97876479Swpaul/*
97976479Swpaul * Initialize the transmit descriptors.
98076479Swpaul */
98199497Salfredstatic int
98299497Salfrednge_list_tx_init(sc)
98376479Swpaul	struct nge_softc	*sc;
98476479Swpaul{
98576479Swpaul	struct nge_list_data	*ld;
98676479Swpaul	struct nge_ring_data	*cd;
98776479Swpaul	int			i;
98876479Swpaul
98976479Swpaul	cd = &sc->nge_cdata;
99076479Swpaul	ld = sc->nge_ldata;
99176479Swpaul
99276479Swpaul	for (i = 0; i < NGE_TX_LIST_CNT; i++) {
99376479Swpaul		if (i == (NGE_TX_LIST_CNT - 1)) {
99476479Swpaul			ld->nge_tx_list[i].nge_nextdesc =
99576479Swpaul			    &ld->nge_tx_list[0];
99676479Swpaul			ld->nge_tx_list[i].nge_next =
99776479Swpaul			    vtophys(&ld->nge_tx_list[0]);
99876479Swpaul		} else {
99976479Swpaul			ld->nge_tx_list[i].nge_nextdesc =
100076479Swpaul			    &ld->nge_tx_list[i + 1];
100176479Swpaul			ld->nge_tx_list[i].nge_next =
100276479Swpaul			    vtophys(&ld->nge_tx_list[i + 1]);
100376479Swpaul		}
100476479Swpaul		ld->nge_tx_list[i].nge_mbuf = NULL;
100576479Swpaul		ld->nge_tx_list[i].nge_ptr = 0;
100676479Swpaul		ld->nge_tx_list[i].nge_ctl = 0;
100776479Swpaul	}
100876479Swpaul
100976479Swpaul	cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0;
101076479Swpaul
101176479Swpaul	return(0);
101276479Swpaul}
101376479Swpaul
101476479Swpaul
101576479Swpaul/*
101676479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
101776479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
101876479Swpaul * points back to the first.
101976479Swpaul */
102099497Salfredstatic int
102199497Salfrednge_list_rx_init(sc)
102276479Swpaul	struct nge_softc	*sc;
102376479Swpaul{
102476479Swpaul	struct nge_list_data	*ld;
102576479Swpaul	struct nge_ring_data	*cd;
102676479Swpaul	int			i;
102776479Swpaul
102876479Swpaul	ld = sc->nge_ldata;
102976479Swpaul	cd = &sc->nge_cdata;
103076479Swpaul
103176479Swpaul	for (i = 0; i < NGE_RX_LIST_CNT; i++) {
103276479Swpaul		if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS)
103376479Swpaul			return(ENOBUFS);
103476479Swpaul		if (i == (NGE_RX_LIST_CNT - 1)) {
103576479Swpaul			ld->nge_rx_list[i].nge_nextdesc =
103676479Swpaul			    &ld->nge_rx_list[0];
103776479Swpaul			ld->nge_rx_list[i].nge_next =
103876479Swpaul			    vtophys(&ld->nge_rx_list[0]);
103976479Swpaul		} else {
104076479Swpaul			ld->nge_rx_list[i].nge_nextdesc =
104176479Swpaul			    &ld->nge_rx_list[i + 1];
104276479Swpaul			ld->nge_rx_list[i].nge_next =
104376479Swpaul			    vtophys(&ld->nge_rx_list[i + 1]);
104476479Swpaul		}
104576479Swpaul	}
104676479Swpaul
104776479Swpaul	cd->nge_rx_prod = 0;
1048135250Swpaul	sc->nge_head = sc->nge_tail = NULL;
104976479Swpaul
105076479Swpaul	return(0);
105176479Swpaul}
105276479Swpaul
105376479Swpaul/*
105476479Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
105576479Swpaul */
105699497Salfredstatic int
105799497Salfrednge_newbuf(sc, c, m)
105876479Swpaul	struct nge_softc	*sc;
105976479Swpaul	struct nge_desc		*c;
106076479Swpaul	struct mbuf		*m;
106176479Swpaul{
106276479Swpaul
106376479Swpaul	if (m == NULL) {
1064144241Ssam		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1065144241Ssam		if (m == NULL)
1066135250Swpaul			return (ENOBUFS);
1067135250Swpaul	} else
1068135250Swpaul		m->m_data = m->m_ext.ext_buf;
106976479Swpaul
1070135250Swpaul	m->m_len = m->m_pkthdr.len = MCLBYTES;
107176479Swpaul
1072144241Ssam	m_adj(m, sizeof(u_int64_t));
107376479Swpaul
1074144241Ssam	c->nge_mbuf = m;
1075144241Ssam	c->nge_ptr = vtophys(mtod(m, caddr_t));
1076144241Ssam	c->nge_ctl = m->m_len;
107776479Swpaul	c->nge_extsts = 0;
107876479Swpaul
107976479Swpaul	return(0);
108076479Swpaul}
108176479Swpaul
1082135250Swpaul#ifdef NGE_FIXUP_RX
1083135250Swpaulstatic __inline void
1084135250Swpaulnge_fixup_rx(m)
1085135250Swpaul	struct mbuf		*m;
1086135250Swpaul{
1087135250Swpaul        int			i;
1088135250Swpaul        uint16_t		*src, *dst;
1089135250Swpaul
1090135250Swpaul	src = mtod(m, uint16_t *);
1091135250Swpaul	dst = src - 1;
1092135250Swpaul
1093135250Swpaul	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1094135250Swpaul		*dst++ = *src++;
1095135250Swpaul
1096135250Swpaul	m->m_data -= ETHER_ALIGN;
1097135250Swpaul
109876479Swpaul	return;
1099135250Swpaul}
110076479Swpaul#endif
110176479Swpaul
110276479Swpaul/*
110376479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
110476479Swpaul * the higher level protocols.
110576479Swpaul */
110699497Salfredstatic void
110799497Salfrednge_rxeof(sc)
110876479Swpaul	struct nge_softc	*sc;
110976479Swpaul{
111076479Swpaul        struct mbuf		*m;
111176479Swpaul        struct ifnet		*ifp;
111276479Swpaul	struct nge_desc		*cur_rx;
111376479Swpaul	int			i, total_len = 0;
111476479Swpaul	u_int32_t		rxstat;
111576479Swpaul
1116135250Swpaul	NGE_LOCK_ASSERT(sc);
1117147256Sbrooks	ifp = sc->nge_ifp;
111876479Swpaul	i = sc->nge_cdata.nge_rx_prod;
111976479Swpaul
112076479Swpaul	while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) {
112176479Swpaul		u_int32_t		extsts;
112276479Swpaul
1123106507Ssimokawa#ifdef DEVICE_POLLING
1124150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
1125106507Ssimokawa			if (sc->rxcycles <= 0)
1126106507Ssimokawa				break;
1127106507Ssimokawa			sc->rxcycles--;
1128106507Ssimokawa		}
1129150789Sglebius#endif
1130106507Ssimokawa
113176479Swpaul		cur_rx = &sc->nge_ldata->nge_rx_list[i];
113276479Swpaul		rxstat = cur_rx->nge_rxstat;
113376479Swpaul		extsts = cur_rx->nge_extsts;
113476479Swpaul		m = cur_rx->nge_mbuf;
113576479Swpaul		cur_rx->nge_mbuf = NULL;
113676479Swpaul		total_len = NGE_RXBYTES(cur_rx);
113776479Swpaul		NGE_INC(i, NGE_RX_LIST_CNT);
1138135250Swpaul
1139135250Swpaul		if (rxstat & NGE_CMDSTS_MORE) {
1140135250Swpaul			m->m_len = total_len;
1141135250Swpaul			if (sc->nge_head == NULL) {
1142135250Swpaul				m->m_pkthdr.len = total_len;
1143135250Swpaul				sc->nge_head = sc->nge_tail = m;
1144135250Swpaul			} else {
1145135250Swpaul				m->m_flags &= ~M_PKTHDR;
1146135250Swpaul				sc->nge_head->m_pkthdr.len += total_len;
1147135250Swpaul				sc->nge_tail->m_next = m;
1148135250Swpaul				sc->nge_tail = m;
1149135250Swpaul			}
1150135250Swpaul			nge_newbuf(sc, cur_rx, NULL);
1151135250Swpaul			continue;
1152135250Swpaul		}
1153135250Swpaul
115476479Swpaul		/*
115576479Swpaul		 * If an error occurs, update stats, clear the
115676479Swpaul		 * status word and leave the mbuf cluster in place:
115776479Swpaul		 * it should simply get re-used next time this descriptor
115876479Swpaul	 	 * comes up in the ring.
115976479Swpaul		 */
116076479Swpaul		if (!(rxstat & NGE_CMDSTS_PKT_OK)) {
116176479Swpaul			ifp->if_ierrors++;
1162135250Swpaul			if (sc->nge_head != NULL) {
1163135250Swpaul				m_freem(sc->nge_head);
1164135250Swpaul				sc->nge_head = sc->nge_tail = NULL;
1165135250Swpaul			}
116676479Swpaul			nge_newbuf(sc, cur_rx, m);
116776479Swpaul			continue;
116876479Swpaul		}
116976479Swpaul
1170135250Swpaul		/* Try conjure up a replacement mbuf. */
1171135250Swpaul
1172135250Swpaul		if (nge_newbuf(sc, cur_rx, NULL)) {
1173135250Swpaul			ifp->if_ierrors++;
1174135250Swpaul			if (sc->nge_head != NULL) {
1175135250Swpaul				m_freem(sc->nge_head);
1176135250Swpaul				sc->nge_head = sc->nge_tail = NULL;
1177135250Swpaul			}
1178135250Swpaul			nge_newbuf(sc, cur_rx, m);
1179135250Swpaul			continue;
1180135250Swpaul		}
1181135250Swpaul
1182135250Swpaul		if (sc->nge_head != NULL) {
1183135250Swpaul			m->m_len = total_len;
1184135250Swpaul			m->m_flags &= ~M_PKTHDR;
1185135250Swpaul			sc->nge_tail->m_next = m;
1186135250Swpaul			m = sc->nge_head;
1187135250Swpaul			m->m_pkthdr.len += total_len;
1188135250Swpaul			sc->nge_head = sc->nge_tail = NULL;
1189135250Swpaul		} else
1190135250Swpaul			m->m_pkthdr.len = m->m_len = total_len;
1191135250Swpaul
119276479Swpaul		/*
119376479Swpaul		 * Ok. NatSemi really screwed up here. This is the
119476479Swpaul		 * only gigE chip I know of with alignment constraints
119576479Swpaul		 * on receive buffers. RX buffers must be 64-bit aligned.
119676479Swpaul		 */
119779562Swpaul		/*
119879562Swpaul		 * By popular demand, ignore the alignment problems
119979562Swpaul		 * on the Intel x86 platform. The performance hit
120079562Swpaul		 * incurred due to unaligned accesses is much smaller
120179562Swpaul		 * than the hit produced by forcing buffer copies all
120279562Swpaul		 * the time, especially with jumbo frames. We still
120379562Swpaul		 * need to fix up the alignment everywhere else though.
120479562Swpaul		 */
1205135250Swpaul#ifdef NGE_FIXUP_RX
1206135250Swpaul		nge_fixup_rx(m);
120779562Swpaul#endif
120876479Swpaul
120976479Swpaul		ifp->if_ipackets++;
1210135250Swpaul		m->m_pkthdr.rcvif = ifp;
121176479Swpaul
121276479Swpaul		/* Do IP checksum checking. */
121378323Swpaul		if (extsts & NGE_RXEXTSTS_IPPKT)
121478323Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
121578323Swpaul		if (!(extsts & NGE_RXEXTSTS_IPCSUMERR))
121678323Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
121778323Swpaul		if ((extsts & NGE_RXEXTSTS_TCPPKT &&
121878323Swpaul		    !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) ||
121978323Swpaul		    (extsts & NGE_RXEXTSTS_UDPPKT &&
122078323Swpaul		    !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) {
122178323Swpaul			m->m_pkthdr.csum_flags |=
122278323Swpaul			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
122378323Swpaul			m->m_pkthdr.csum_data = 0xffff;
122478323Swpaul		}
122576479Swpaul
122676479Swpaul		/*
122776479Swpaul		 * If we received a packet with a vlan tag, pass it
122876479Swpaul		 * to vlan_input() instead of ether_input().
122976479Swpaul		 */
123076479Swpaul		if (extsts & NGE_RXEXTSTS_VLANPKT) {
1231106937Ssam			VLAN_INPUT_TAG(ifp, m,
1232127615Sru			    ntohs(extsts & NGE_RXEXTSTS_VTCI), continue);
1233106937Ssam		}
1234135250Swpaul		NGE_UNLOCK(sc);
1235106937Ssam		(*ifp->if_input)(ifp, m);
1236135250Swpaul		NGE_LOCK(sc);
123776479Swpaul	}
123876479Swpaul
123976479Swpaul	sc->nge_cdata.nge_rx_prod = i;
124076479Swpaul
124176479Swpaul	return;
124276479Swpaul}
124376479Swpaul
124476479Swpaul/*
124576479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
124676479Swpaul * the list buffers.
124776479Swpaul */
124876479Swpaul
124999497Salfredstatic void
125099497Salfrednge_txeof(sc)
125176479Swpaul	struct nge_softc	*sc;
125276479Swpaul{
1253128130Sru	struct nge_desc		*cur_tx;
125476479Swpaul	struct ifnet		*ifp;
125576479Swpaul	u_int32_t		idx;
125676479Swpaul
1257135250Swpaul	NGE_LOCK_ASSERT(sc);
1258147256Sbrooks	ifp = sc->nge_ifp;
125976479Swpaul
126076479Swpaul	/*
126176479Swpaul	 * Go through our tx list and free mbufs for those
126276479Swpaul	 * frames that have been transmitted.
126376479Swpaul	 */
126476479Swpaul	idx = sc->nge_cdata.nge_tx_cons;
126576479Swpaul	while (idx != sc->nge_cdata.nge_tx_prod) {
126676479Swpaul		cur_tx = &sc->nge_ldata->nge_tx_list[idx];
126776479Swpaul
126876479Swpaul		if (NGE_OWNDESC(cur_tx))
126976479Swpaul			break;
127076479Swpaul
127176479Swpaul		if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) {
127276479Swpaul			sc->nge_cdata.nge_tx_cnt--;
127376479Swpaul			NGE_INC(idx, NGE_TX_LIST_CNT);
127476479Swpaul			continue;
127576479Swpaul		}
127676479Swpaul
127776479Swpaul		if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) {
127876479Swpaul			ifp->if_oerrors++;
127976479Swpaul			if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS)
128076479Swpaul				ifp->if_collisions++;
128176479Swpaul			if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL)
128276479Swpaul				ifp->if_collisions++;
128376479Swpaul		}
128476479Swpaul
128576479Swpaul		ifp->if_collisions +=
128676479Swpaul		    (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16;
128776479Swpaul
128876479Swpaul		ifp->if_opackets++;
128976479Swpaul		if (cur_tx->nge_mbuf != NULL) {
129076479Swpaul			m_freem(cur_tx->nge_mbuf);
129176479Swpaul			cur_tx->nge_mbuf = NULL;
1292148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
129376479Swpaul		}
129476479Swpaul
129576479Swpaul		sc->nge_cdata.nge_tx_cnt--;
129676479Swpaul		NGE_INC(idx, NGE_TX_LIST_CNT);
129776479Swpaul	}
129876479Swpaul
129976479Swpaul	sc->nge_cdata.nge_tx_cons = idx;
130076479Swpaul
1301128130Sru	if (idx == sc->nge_cdata.nge_tx_prod)
1302128130Sru		ifp->if_timer = 0;
130376479Swpaul
130476479Swpaul	return;
130576479Swpaul}
130676479Swpaul
130799497Salfredstatic void
130899497Salfrednge_tick(xsc)
130976479Swpaul	void			*xsc;
131076479Swpaul{
131176479Swpaul	struct nge_softc	*sc;
131276479Swpaul	struct mii_data		*mii;
131376479Swpaul	struct ifnet		*ifp;
131476479Swpaul
1315151296Sjhb	sc = xsc;
1316135250Swpaul	NGE_LOCK_ASSERT(sc);
1317147256Sbrooks	ifp = sc->nge_ifp;
131876479Swpaul
1319101540Sambrisko	if (sc->nge_tbi) {
1320101540Sambrisko		if (!sc->nge_link) {
1321101540Sambrisko			if (CSR_READ_4(sc, NGE_TBI_BMSR)
1322101540Sambrisko			    & NGE_TBIBMSR_ANEG_DONE) {
1323137402Sphk				if (bootverbose)
1324151296Sjhb					if_printf(sc->nge_ifp,
1325151296Sjhb					    "gigabit link up\n");
1326101540Sambrisko				nge_miibus_statchg(sc->nge_miibus);
1327101540Sambrisko				sc->nge_link++;
1328101540Sambrisko				if (ifp->if_snd.ifq_head != NULL)
1329135250Swpaul					nge_start_locked(ifp);
1330101540Sambrisko			}
133196028Sphk		}
1332101540Sambrisko	} else {
1333101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1334101540Sambrisko		mii_tick(mii);
1335101540Sambrisko
1336101540Sambrisko		if (!sc->nge_link) {
1337101540Sambrisko			if (mii->mii_media_status & IFM_ACTIVE &&
1338101540Sambrisko			    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1339101540Sambrisko				sc->nge_link++;
1340101540Sambrisko				if (IFM_SUBTYPE(mii->mii_media_active)
1341137402Sphk				    == IFM_1000_T && bootverbose)
1342151296Sjhb					if_printf(sc->nge_ifp,
1343151296Sjhb					    "gigabit link up\n");
1344101540Sambrisko				if (ifp->if_snd.ifq_head != NULL)
1345135250Swpaul					nge_start_locked(ifp);
1346101540Sambrisko			}
1347101540Sambrisko		}
134876479Swpaul	}
1349135250Swpaul	callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc);
135076479Swpaul
135176479Swpaul	return;
135276479Swpaul}
135376479Swpaul
1354106507Ssimokawa#ifdef DEVICE_POLLING
1355106507Ssimokawastatic poll_handler_t nge_poll;
1356106507Ssimokawa
135799497Salfredstatic void
1358106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1359106507Ssimokawa{
1360106507Ssimokawa	struct  nge_softc *sc = ifp->if_softc;
1361106507Ssimokawa
1362135250Swpaul	NGE_LOCK(sc);
1363150789Sglebius	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1364135250Swpaul		NGE_UNLOCK(sc);
1365106507Ssimokawa		return;
1366106507Ssimokawa	}
1367106507Ssimokawa
1368106507Ssimokawa	/*
1369106507Ssimokawa	 * On the nge, reading the status register also clears it.
1370106507Ssimokawa	 * So before returning to intr mode we must make sure that all
1371106507Ssimokawa	 * possible pending sources of interrupts have been served.
1372106507Ssimokawa	 * In practice this means run to completion the *eof routines,
1373106507Ssimokawa	 * and then call the interrupt routine
1374106507Ssimokawa	 */
1375106507Ssimokawa	sc->rxcycles = count;
1376106507Ssimokawa	nge_rxeof(sc);
1377106507Ssimokawa	nge_txeof(sc);
1378106507Ssimokawa	if (ifp->if_snd.ifq_head != NULL)
1379135250Swpaul		nge_start_locked(ifp);
1380106507Ssimokawa
1381106507Ssimokawa	if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
1382106507Ssimokawa		u_int32_t	status;
1383106507Ssimokawa
1384106507Ssimokawa		/* Reading the ISR register clears all interrupts. */
1385106507Ssimokawa		status = CSR_READ_4(sc, NGE_ISR);
1386106507Ssimokawa
1387106507Ssimokawa		if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW))
1388106507Ssimokawa			nge_rxeof(sc);
1389106507Ssimokawa
1390106507Ssimokawa		if (status & (NGE_ISR_RX_IDLE))
1391106507Ssimokawa			NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
1392106507Ssimokawa
1393106507Ssimokawa		if (status & NGE_ISR_SYSERR) {
1394106507Ssimokawa			nge_reset(sc);
1395135250Swpaul			nge_init_locked(sc);
1396106507Ssimokawa		}
1397106507Ssimokawa	}
1398135250Swpaul	NGE_UNLOCK(sc);
1399106507Ssimokawa}
1400106507Ssimokawa#endif /* DEVICE_POLLING */
1401106507Ssimokawa
1402106507Ssimokawastatic void
140399497Salfrednge_intr(arg)
140476479Swpaul	void			*arg;
140576479Swpaul{
140676479Swpaul	struct nge_softc	*sc;
140776479Swpaul	struct ifnet		*ifp;
140876479Swpaul	u_int32_t		status;
140976479Swpaul
141076479Swpaul	sc = arg;
1411147256Sbrooks	ifp = sc->nge_ifp;
141276479Swpaul
1413135250Swpaul	NGE_LOCK(sc);
1414106507Ssimokawa#ifdef DEVICE_POLLING
1415150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING) {
1416135250Swpaul		NGE_UNLOCK(sc);
1417106507Ssimokawa		return;
1418135250Swpaul	}
1419150789Sglebius#endif
1420106507Ssimokawa
142176479Swpaul	/* Supress unwanted interrupts */
142276479Swpaul	if (!(ifp->if_flags & IFF_UP)) {
142376479Swpaul		nge_stop(sc);
1424135250Swpaul		NGE_UNLOCK(sc);
142576479Swpaul		return;
142676479Swpaul	}
142776479Swpaul
142876479Swpaul	/* Disable interrupts. */
142976479Swpaul	CSR_WRITE_4(sc, NGE_IER, 0);
143076479Swpaul
1431101540Sambrisko	/* Data LED on for TBI mode */
1432101540Sambrisko	if(sc->nge_tbi)
1433101540Sambrisko		 CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1434101540Sambrisko			     | NGE_GPIO_GP3_OUT);
1435101540Sambrisko
143676479Swpaul	for (;;) {
143776479Swpaul		/* Reading the ISR register clears all interrupts. */
143876479Swpaul		status = CSR_READ_4(sc, NGE_ISR);
143976479Swpaul
144076479Swpaul		if ((status & NGE_INTRS) == 0)
144176479Swpaul			break;
144276479Swpaul
144376479Swpaul		if ((status & NGE_ISR_TX_DESC_OK) ||
144476479Swpaul		    (status & NGE_ISR_TX_ERR) ||
144576479Swpaul		    (status & NGE_ISR_TX_OK) ||
144676479Swpaul		    (status & NGE_ISR_TX_IDLE))
144776479Swpaul			nge_txeof(sc);
144876479Swpaul
144976479Swpaul		if ((status & NGE_ISR_RX_DESC_OK) ||
145079798Swpaul		    (status & NGE_ISR_RX_ERR) ||
145183678Swpaul		    (status & NGE_ISR_RX_OFLOW) ||
145294612Sphk		    (status & NGE_ISR_RX_FIFO_OFLOW) ||
145394612Sphk		    (status & NGE_ISR_RX_IDLE) ||
145476479Swpaul		    (status & NGE_ISR_RX_OK))
145576479Swpaul			nge_rxeof(sc);
145694612Sphk
145794612Sphk		if ((status & NGE_ISR_RX_IDLE))
145894612Sphk			NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
145994612Sphk
146076479Swpaul		if (status & NGE_ISR_SYSERR) {
146176479Swpaul			nge_reset(sc);
1462148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1463135250Swpaul			nge_init_locked(sc);
146476479Swpaul		}
146576479Swpaul
146696028Sphk#if 0
146796028Sphk		/*
146896028Sphk		 * XXX: nge_tick() is not ready to be called this way
146996028Sphk		 * it screws up the aneg timeout because mii_tick() is
147096028Sphk		 * only to be called once per second.
147196028Sphk		 */
147276479Swpaul		if (status & NGE_IMR_PHY_INTR) {
147376479Swpaul			sc->nge_link = 0;
1474151296Sjhb			nge_tick(sc);
147576479Swpaul		}
147696028Sphk#endif
147776479Swpaul	}
147876479Swpaul
147976479Swpaul	/* Re-enable interrupts. */
148076479Swpaul	CSR_WRITE_4(sc, NGE_IER, 1);
148176479Swpaul
148276479Swpaul	if (ifp->if_snd.ifq_head != NULL)
1483135250Swpaul		nge_start_locked(ifp);
148476479Swpaul
1485101540Sambrisko	/* Data LED off for TBI mode */
1486101540Sambrisko
1487101540Sambrisko	if(sc->nge_tbi)
1488101540Sambrisko		CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1489101540Sambrisko			    & ~NGE_GPIO_GP3_OUT);
1490101540Sambrisko
1491135250Swpaul	NGE_UNLOCK(sc);
1492135250Swpaul
149376479Swpaul	return;
149476479Swpaul}
149576479Swpaul
149676479Swpaul/*
149776479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
149876479Swpaul * pointers to the fragment pointers.
149976479Swpaul */
150099497Salfredstatic int
150199497Salfrednge_encap(sc, m_head, txidx)
150276479Swpaul	struct nge_softc	*sc;
150376479Swpaul	struct mbuf		*m_head;
150476479Swpaul	u_int32_t		*txidx;
150576479Swpaul{
150676479Swpaul	struct nge_desc		*f = NULL;
150776479Swpaul	struct mbuf		*m;
150876479Swpaul	int			frag, cur, cnt = 0;
1509106937Ssam	struct m_tag		*mtag;
151076479Swpaul
151176479Swpaul	/*
151276479Swpaul 	 * Start packing the mbufs in this chain into
151376479Swpaul	 * the fragment pointers. Stop when we run out
151476479Swpaul 	 * of fragments or hit the end of the mbuf chain.
151576479Swpaul	 */
151676479Swpaul	m = m_head;
151776479Swpaul	cur = frag = *txidx;
151876479Swpaul
151976479Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
152076479Swpaul		if (m->m_len != 0) {
152176479Swpaul			if ((NGE_TX_LIST_CNT -
152276479Swpaul			    (sc->nge_cdata.nge_tx_cnt + cnt)) < 2)
152376479Swpaul				return(ENOBUFS);
152476479Swpaul			f = &sc->nge_ldata->nge_tx_list[frag];
152576479Swpaul			f->nge_ctl = NGE_CMDSTS_MORE | m->m_len;
152676479Swpaul			f->nge_ptr = vtophys(mtod(m, vm_offset_t));
152776479Swpaul			if (cnt != 0)
152876479Swpaul				f->nge_ctl |= NGE_CMDSTS_OWN;
152976479Swpaul			cur = frag;
153076479Swpaul			NGE_INC(frag, NGE_TX_LIST_CNT);
153176479Swpaul			cnt++;
153276479Swpaul		}
153376479Swpaul	}
153476479Swpaul
153576479Swpaul	if (m != NULL)
153676479Swpaul		return(ENOBUFS);
153776479Swpaul
153878286Swpaul	sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0;
153976479Swpaul	if (m_head->m_pkthdr.csum_flags) {
154076479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_IP)
154178286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
154276479Swpaul			    NGE_TXEXTSTS_IPCSUM;
154376479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
154478286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
154576479Swpaul			    NGE_TXEXTSTS_TCPCSUM;
154676479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
154778286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
154876479Swpaul			    NGE_TXEXTSTS_UDPCSUM;
154976479Swpaul	}
155076479Swpaul
1551147256Sbrooks	mtag = VLAN_OUTPUT_TAG(sc->nge_ifp, m_head);
1552106937Ssam	if (mtag != NULL) {
155376479Swpaul		sc->nge_ldata->nge_tx_list[cur].nge_extsts |=
1554127615Sru		    (NGE_TXEXTSTS_VLANPKT|htons(VLAN_TAG_VALUE(mtag)));
155576479Swpaul	}
155676479Swpaul
155776479Swpaul	sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head;
155876479Swpaul	sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE;
155976479Swpaul	sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN;
156076479Swpaul	sc->nge_cdata.nge_tx_cnt += cnt;
156176479Swpaul	*txidx = frag;
156276479Swpaul
156376479Swpaul	return(0);
156476479Swpaul}
156576479Swpaul
156676479Swpaul/*
156776479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
156876479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
156976479Swpaul * copy of the pointers since the transmit list fragment pointers are
157076479Swpaul * physical addresses.
157176479Swpaul */
157276479Swpaul
157399497Salfredstatic void
157499497Salfrednge_start(ifp)
157576479Swpaul	struct ifnet		*ifp;
157676479Swpaul{
157776479Swpaul	struct nge_softc	*sc;
1578135250Swpaul
1579135250Swpaul	sc = ifp->if_softc;
1580135250Swpaul	NGE_LOCK(sc);
1581135250Swpaul	nge_start_locked(ifp);
1582135250Swpaul	NGE_UNLOCK(sc);
1583135250Swpaul}
1584135250Swpaul
1585135250Swpaulstatic void
1586135250Swpaulnge_start_locked(ifp)
1587135250Swpaul	struct ifnet		*ifp;
1588135250Swpaul{
1589135250Swpaul	struct nge_softc	*sc;
159076479Swpaul	struct mbuf		*m_head = NULL;
159176479Swpaul	u_int32_t		idx;
159276479Swpaul
159376479Swpaul	sc = ifp->if_softc;
159476479Swpaul
159576479Swpaul	if (!sc->nge_link)
159676479Swpaul		return;
159776479Swpaul
159876479Swpaul	idx = sc->nge_cdata.nge_tx_prod;
159976479Swpaul
1600148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
160176479Swpaul		return;
160276479Swpaul
160376479Swpaul	while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) {
160476479Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
160576479Swpaul		if (m_head == NULL)
160676479Swpaul			break;
160776479Swpaul
160876479Swpaul		if (nge_encap(sc, m_head, &idx)) {
160976479Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1610148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
161176479Swpaul			break;
161276479Swpaul		}
161376479Swpaul
161476479Swpaul		/*
161576479Swpaul		 * If there's a BPF listener, bounce a copy of this frame
161676479Swpaul		 * to him.
161776479Swpaul		 */
1618106937Ssam		BPF_MTAP(ifp, m_head);
161976479Swpaul
162076479Swpaul	}
162176479Swpaul
162276479Swpaul	/* Transmit */
162376479Swpaul	sc->nge_cdata.nge_tx_prod = idx;
162476479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE);
162576479Swpaul
162676479Swpaul	/*
162776479Swpaul	 * Set a timeout in case the chip goes out to lunch.
162876479Swpaul	 */
162976479Swpaul	ifp->if_timer = 5;
163076479Swpaul
163176479Swpaul	return;
163276479Swpaul}
163376479Swpaul
163499497Salfredstatic void
163599497Salfrednge_init(xsc)
163676479Swpaul	void			*xsc;
163776479Swpaul{
163876479Swpaul	struct nge_softc	*sc = xsc;
1639135250Swpaul
1640135250Swpaul	NGE_LOCK(sc);
1641135250Swpaul	nge_init_locked(sc);
1642135250Swpaul	NGE_UNLOCK(sc);
1643135250Swpaul}
1644135250Swpaul
1645135250Swpaulstatic void
1646135250Swpaulnge_init_locked(sc)
1647135250Swpaul	struct nge_softc	*sc;
1648135250Swpaul{
1649147256Sbrooks	struct ifnet		*ifp = sc->nge_ifp;
165076479Swpaul	struct mii_data		*mii;
165176479Swpaul
1652135250Swpaul	NGE_LOCK_ASSERT(sc);
1653135250Swpaul
1654148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
165576479Swpaul		return;
165676479Swpaul
165776479Swpaul	/*
165876479Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
165976479Swpaul	 */
166076479Swpaul	nge_stop(sc);
166176479Swpaul
1662101540Sambrisko	if (sc->nge_tbi) {
1663101540Sambrisko		mii = NULL;
1664101540Sambrisko	} else {
1665101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1666101540Sambrisko	}
166776479Swpaul
166876479Swpaul	/* Set MAC address */
166976479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0);
167076479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1671152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[0]);
167276479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1);
167376479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1674152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[1]);
167576479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2);
167676479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1677152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[2]);
167876479Swpaul
167976479Swpaul	/* Init circular RX list. */
168076479Swpaul	if (nge_list_rx_init(sc) == ENOBUFS) {
1681151296Sjhb		if_printf(sc->nge_ifp, "initialization failed: no "
1682151296Sjhb			"memory for rx buffers\n");
168376479Swpaul		nge_stop(sc);
168476479Swpaul		return;
168576479Swpaul	}
168676479Swpaul
168776479Swpaul	/*
168876479Swpaul	 * Init tx descriptors.
168976479Swpaul	 */
169076479Swpaul	nge_list_tx_init(sc);
169176479Swpaul
169276479Swpaul	/*
169376479Swpaul	 * For the NatSemi chip, we have to explicitly enable the
169476479Swpaul	 * reception of ARP frames, as well as turn on the 'perfect
169576479Swpaul	 * match' filter where we store the station address, otherwise
169676479Swpaul	 * we won't receive unicasts meant for this host.
169776479Swpaul	 */
169876479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP);
169976479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT);
170076479Swpaul
170176479Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
170276479Swpaul	if (ifp->if_flags & IFF_PROMISC) {
170376479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS);
170476479Swpaul	} else {
170576479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS);
170676479Swpaul	}
170776479Swpaul
170876479Swpaul	/*
170976479Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
171076479Swpaul	 */
171176479Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
171276479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD);
171376479Swpaul	} else {
171476479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD);
171576479Swpaul	}
171676479Swpaul
171776479Swpaul	/*
171876479Swpaul	 * Load the multicast filter.
171976479Swpaul	 */
172076479Swpaul	nge_setmulti(sc);
172176479Swpaul
172276479Swpaul	/* Turn the receive filter on */
172376479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE);
172476479Swpaul
172576479Swpaul	/*
172676479Swpaul	 * Load the address of the RX and TX lists.
172776479Swpaul	 */
172876479Swpaul	CSR_WRITE_4(sc, NGE_RX_LISTPTR,
172976479Swpaul	    vtophys(&sc->nge_ldata->nge_rx_list[0]));
173076479Swpaul	CSR_WRITE_4(sc, NGE_TX_LISTPTR,
173176479Swpaul	    vtophys(&sc->nge_ldata->nge_tx_list[0]));
173276479Swpaul
173376479Swpaul	/* Set RX configuration */
173476479Swpaul	CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG);
173576479Swpaul	/*
173676479Swpaul	 * Enable hardware checksum validation for all IPv4
173776479Swpaul	 * packets, do not reject packets with bad checksums.
173876479Swpaul	 */
173978323Swpaul	CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB);
174076479Swpaul
174176479Swpaul	/*
174283115Sbrooks	 * Tell the chip to detect and strip VLAN tag info from
174383115Sbrooks	 * received frames. The tag will be provided in the extsts
174483115Sbrooks	 * field in the RX descriptors.
174576479Swpaul	 */
174676479Swpaul	NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL,
174776479Swpaul	    NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB);
174876479Swpaul
174976479Swpaul	/* Set TX configuration */
175076479Swpaul	CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG);
175176479Swpaul
175276479Swpaul	/*
175376479Swpaul	 * Enable TX IPv4 checksumming on a per-packet basis.
175476479Swpaul	 */
175578323Swpaul	CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT);
175676479Swpaul
175776479Swpaul	/*
175883115Sbrooks	 * Tell the chip to insert VLAN tags on a per-packet basis as
175983115Sbrooks	 * dictated by the code in the frame encapsulation routine.
176076479Swpaul	 */
176176479Swpaul	NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT);
176276479Swpaul
176376479Swpaul	/* Set full/half duplex mode. */
1764101540Sambrisko	if (sc->nge_tbi) {
1765101540Sambrisko		if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
1766101540Sambrisko		    == IFM_FDX) {
1767101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1768101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1769101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1770101540Sambrisko		} else {
1771101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1772101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1773101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1774101540Sambrisko		}
177576479Swpaul	} else {
1776101540Sambrisko		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
1777101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1778101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1779101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1780101540Sambrisko		} else {
1781101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1782101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1783101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1784101540Sambrisko		}
178576479Swpaul	}
178676479Swpaul
1787151296Sjhb	nge_tick(sc);
178896028Sphk
178976479Swpaul	/*
179076479Swpaul	 * Enable the delivery of PHY interrupts based on
179177842Swpaul	 * link/speed/duplex status changes. Also enable the
179277842Swpaul	 * extsts field in the DMA descriptors (needed for
179377842Swpaul	 * TCP/IP checksum offload on transmit).
179476479Swpaul	 */
179579424Swpaul	NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD|
179677842Swpaul	    NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB);
179776479Swpaul
179876479Swpaul	/*
179979562Swpaul	 * Configure interrupt holdoff (moderation). We can
180079562Swpaul	 * have the chip delay interrupt delivery for a certain
180179562Swpaul	 * period. Units are in 100us, and the max setting
180279562Swpaul	 * is 25500us (0xFF x 100us). Default is a 100us holdoff.
180379562Swpaul	 */
180479562Swpaul	CSR_WRITE_4(sc, NGE_IHR, 0x01);
180579562Swpaul
180679562Swpaul	/*
180776479Swpaul	 * Enable interrupts.
180876479Swpaul	 */
180976479Swpaul	CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS);
1810106507Ssimokawa#ifdef DEVICE_POLLING
1811106507Ssimokawa	/*
1812106507Ssimokawa	 * ... only enable interrupts if we are not polling, make sure
1813106507Ssimokawa	 * they are off otherwise.
1814106507Ssimokawa	 */
1815150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1816106507Ssimokawa		CSR_WRITE_4(sc, NGE_IER, 0);
1817106507Ssimokawa	else
1818150789Sglebius#endif
181976479Swpaul	CSR_WRITE_4(sc, NGE_IER, 1);
182076479Swpaul
182176479Swpaul	/* Enable receiver and transmitter. */
182276479Swpaul	NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
182376479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
182476479Swpaul
1825151296Sjhb	nge_ifmedia_upd_locked(ifp);
182676479Swpaul
1827148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1828148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
182976479Swpaul
183076479Swpaul	return;
183176479Swpaul}
183276479Swpaul
183376479Swpaul/*
183476479Swpaul * Set media options.
183576479Swpaul */
183699497Salfredstatic int
183799497Salfrednge_ifmedia_upd(ifp)
183876479Swpaul	struct ifnet		*ifp;
183976479Swpaul{
184076479Swpaul	struct nge_softc	*sc;
1841151296Sjhb
1842151296Sjhb	sc = ifp->if_softc;
1843151296Sjhb	NGE_LOCK(sc);
1844151296Sjhb	nge_ifmedia_upd_locked(ifp);
1845151296Sjhb	NGE_UNLOCK(sc);
1846151296Sjhb	return (0);
1847151296Sjhb}
1848151296Sjhb
1849151296Sjhbstatic void
1850151296Sjhbnge_ifmedia_upd_locked(ifp)
1851151296Sjhb	struct ifnet		*ifp;
1852151296Sjhb{
1853151296Sjhb	struct nge_softc	*sc;
185476479Swpaul	struct mii_data		*mii;
185576479Swpaul
185676479Swpaul	sc = ifp->if_softc;
1857151296Sjhb	NGE_LOCK_ASSERT(sc);
185876479Swpaul
1859101540Sambrisko	if (sc->nge_tbi) {
1860101540Sambrisko		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
1861101540Sambrisko		     == IFM_AUTO) {
1862101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_ANAR,
1863101540Sambrisko				CSR_READ_4(sc, NGE_TBI_ANAR)
1864101540Sambrisko					| NGE_TBIANAR_HDX | NGE_TBIANAR_FDX
1865101540Sambrisko					| NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2);
1866101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG
1867101540Sambrisko				| NGE_TBIBMCR_RESTART_ANEG);
1868101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG);
1869101540Sambrisko		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media
1870101540Sambrisko			    & IFM_GMASK) == IFM_FDX) {
1871101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1872101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1873101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1874101540Sambrisko
1875101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
1876101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
1877101540Sambrisko		} else {
1878101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1879101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1880101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1881101540Sambrisko
1882101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
1883101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
1884101540Sambrisko		}
1885101540Sambrisko
1886101540Sambrisko		CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1887101540Sambrisko			    & ~NGE_GPIO_GP3_OUT);
1888101540Sambrisko	} else {
1889101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1890101540Sambrisko		sc->nge_link = 0;
1891101540Sambrisko		if (mii->mii_instance) {
1892101540Sambrisko			struct mii_softc	*miisc;
1893151296Sjhb
1894151296Sjhb			LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1895101540Sambrisko				mii_phy_reset(miisc);
1896101540Sambrisko		}
1897101540Sambrisko		mii_mediachg(mii);
189876479Swpaul	}
189976479Swpaul}
190076479Swpaul
190176479Swpaul/*
190276479Swpaul * Report current media status.
190376479Swpaul */
190499497Salfredstatic void
190599497Salfrednge_ifmedia_sts(ifp, ifmr)
190676479Swpaul	struct ifnet		*ifp;
190776479Swpaul	struct ifmediareq	*ifmr;
190876479Swpaul{
190976479Swpaul	struct nge_softc	*sc;
191076479Swpaul	struct mii_data		*mii;
191176479Swpaul
191276479Swpaul	sc = ifp->if_softc;
191376479Swpaul
1914151296Sjhb	NGE_LOCK(sc);
1915101540Sambrisko	if (sc->nge_tbi) {
1916101540Sambrisko		ifmr->ifm_status = IFM_AVALID;
1917101540Sambrisko		ifmr->ifm_active = IFM_ETHER;
191876479Swpaul
1919101540Sambrisko		if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
1920101540Sambrisko			ifmr->ifm_status |= IFM_ACTIVE;
1921101540Sambrisko		}
1922101540Sambrisko		if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK)
1923101540Sambrisko			ifmr->ifm_active |= IFM_LOOP;
1924101540Sambrisko		if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
1925101540Sambrisko			ifmr->ifm_active |= IFM_NONE;
1926101540Sambrisko			ifmr->ifm_status = 0;
1927151296Sjhb			NGE_UNLOCK(sc);
1928101540Sambrisko			return;
1929101540Sambrisko		}
1930101540Sambrisko		ifmr->ifm_active |= IFM_1000_SX;
1931101540Sambrisko		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
1932101540Sambrisko		    == IFM_AUTO) {
1933101540Sambrisko			ifmr->ifm_active |= IFM_AUTO;
1934101540Sambrisko			if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
1935101540Sambrisko			    & NGE_TBIANAR_FDX) {
1936101540Sambrisko				ifmr->ifm_active |= IFM_FDX;
1937101540Sambrisko			}else if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
1938101540Sambrisko				  & NGE_TBIANAR_HDX) {
1939101540Sambrisko				ifmr->ifm_active |= IFM_HDX;
1940101540Sambrisko			}
1941101540Sambrisko		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
1942101540Sambrisko			== IFM_FDX)
1943101540Sambrisko			ifmr->ifm_active |= IFM_FDX;
1944101540Sambrisko		else
1945101540Sambrisko			ifmr->ifm_active |= IFM_HDX;
1946101540Sambrisko
1947101540Sambrisko	} else {
1948101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1949101540Sambrisko		mii_pollstat(mii);
1950101540Sambrisko		ifmr->ifm_active = mii->mii_media_active;
1951101540Sambrisko		ifmr->ifm_status = mii->mii_media_status;
1952101540Sambrisko	}
1953151296Sjhb	NGE_UNLOCK(sc);
1954101540Sambrisko
195576479Swpaul	return;
195676479Swpaul}
195776479Swpaul
195899497Salfredstatic int
195999497Salfrednge_ioctl(ifp, command, data)
196076479Swpaul	struct ifnet		*ifp;
196176479Swpaul	u_long			command;
196276479Swpaul	caddr_t			data;
196376479Swpaul{
196476479Swpaul	struct nge_softc	*sc = ifp->if_softc;
196576479Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
196676479Swpaul	struct mii_data		*mii;
1967135250Swpaul	int			error = 0;
196876479Swpaul
196976479Swpaul	switch(command) {
197076479Swpaul	case SIOCSIFMTU:
197176479Swpaul		if (ifr->ifr_mtu > NGE_JUMBO_MTU)
197276479Swpaul			error = EINVAL;
197378323Swpaul		else {
1974151296Sjhb			NGE_LOCK(sc);
197576479Swpaul			ifp->if_mtu = ifr->ifr_mtu;
197678323Swpaul			/*
197778323Swpaul			 * Workaround: if the MTU is larger than
197878323Swpaul			 * 8152 (TX FIFO size minus 64 minus 18), turn off
197978323Swpaul			 * TX checksum offloading.
198078323Swpaul			 */
1981129632Syar			if (ifr->ifr_mtu >= 8152) {
1982129632Syar				ifp->if_capenable &= ~IFCAP_TXCSUM;
198378323Swpaul				ifp->if_hwassist = 0;
1984129632Syar			} else {
1985129632Syar				ifp->if_capenable |= IFCAP_TXCSUM;
198678323Swpaul				ifp->if_hwassist = NGE_CSUM_FEATURES;
1987129632Syar			}
1988151296Sjhb			NGE_UNLOCK(sc);
198978323Swpaul		}
199076479Swpaul		break;
199176479Swpaul	case SIOCSIFFLAGS:
1992135250Swpaul		NGE_LOCK(sc);
199376479Swpaul		if (ifp->if_flags & IFF_UP) {
1994148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
199576479Swpaul			    ifp->if_flags & IFF_PROMISC &&
199676479Swpaul			    !(sc->nge_if_flags & IFF_PROMISC)) {
199776479Swpaul				NGE_SETBIT(sc, NGE_RXFILT_CTL,
199876479Swpaul				    NGE_RXFILTCTL_ALLPHYS|
199976479Swpaul				    NGE_RXFILTCTL_ALLMULTI);
2000148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
200176479Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
200276479Swpaul			    sc->nge_if_flags & IFF_PROMISC) {
200376479Swpaul				NGE_CLRBIT(sc, NGE_RXFILT_CTL,
200476479Swpaul				    NGE_RXFILTCTL_ALLPHYS);
200576479Swpaul				if (!(ifp->if_flags & IFF_ALLMULTI))
200676479Swpaul					NGE_CLRBIT(sc, NGE_RXFILT_CTL,
200776479Swpaul					    NGE_RXFILTCTL_ALLMULTI);
200876479Swpaul			} else {
2009148887Srwatson				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2010135250Swpaul				nge_init_locked(sc);
201176479Swpaul			}
201276479Swpaul		} else {
2013148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
201476479Swpaul				nge_stop(sc);
201576479Swpaul		}
201676479Swpaul		sc->nge_if_flags = ifp->if_flags;
2017135250Swpaul		NGE_UNLOCK(sc);
201876479Swpaul		error = 0;
201976479Swpaul		break;
202076479Swpaul	case SIOCADDMULTI:
202176479Swpaul	case SIOCDELMULTI:
2022135250Swpaul		NGE_LOCK(sc);
202376479Swpaul		nge_setmulti(sc);
2024135250Swpaul		NGE_UNLOCK(sc);
202576479Swpaul		error = 0;
202676479Swpaul		break;
202776479Swpaul	case SIOCGIFMEDIA:
202876479Swpaul	case SIOCSIFMEDIA:
2029101540Sambrisko		if (sc->nge_tbi) {
2030101540Sambrisko			error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia,
2031101540Sambrisko					      command);
2032101540Sambrisko		} else {
2033101540Sambrisko			mii = device_get_softc(sc->nge_miibus);
2034101540Sambrisko			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
2035101540Sambrisko					      command);
2036101540Sambrisko		}
203776479Swpaul		break;
2038128132Sru	case SIOCSIFCAP:
2039150789Sglebius#ifdef DEVICE_POLLING
2040150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
2041150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
2042150789Sglebius			error = ether_poll_register(nge_poll, ifp);
2043150789Sglebius			if (error)
2044150789Sglebius				return(error);
2045150789Sglebius			NGE_LOCK(sc);
2046150789Sglebius			/* Disable interrupts */
2047150789Sglebius			CSR_WRITE_4(sc, NGE_IER, 0);
2048150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
2049150789Sglebius			NGE_UNLOCK(sc);
2050150789Sglebius			return (error);
2051150789Sglebius
2052150789Sglebius		}
2053150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
2054150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
2055150789Sglebius			error = ether_poll_deregister(ifp);
2056150789Sglebius			/* Enable interrupts. */
2057150789Sglebius			NGE_LOCK(sc);
2058150789Sglebius			CSR_WRITE_4(sc, NGE_IER, 1);
2059150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
2060150789Sglebius			NGE_UNLOCK(sc);
2061150789Sglebius			return (error);
2062150789Sglebius		}
2063150789Sglebius#endif /* DEVICE_POLLING */
2064128132Sru		break;
206576479Swpaul	default:
2066106937Ssam		error = ether_ioctl(ifp, command, data);
206776479Swpaul		break;
206876479Swpaul	}
206976479Swpaul
207076479Swpaul	return(error);
207176479Swpaul}
207276479Swpaul
207399497Salfredstatic void
207499497Salfrednge_watchdog(ifp)
207576479Swpaul	struct ifnet		*ifp;
207676479Swpaul{
207776479Swpaul	struct nge_softc	*sc;
207876479Swpaul
207976479Swpaul	sc = ifp->if_softc;
208076479Swpaul
208176479Swpaul	ifp->if_oerrors++;
2082151296Sjhb	if_printf(sc->nge_ifp, "watchdog timeout\n");
208376479Swpaul
2084135250Swpaul	NGE_LOCK(sc);
208576479Swpaul	nge_stop(sc);
208676479Swpaul	nge_reset(sc);
2087148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2088135250Swpaul	nge_init_locked(sc);
208976479Swpaul
209076479Swpaul	if (ifp->if_snd.ifq_head != NULL)
2091135250Swpaul		nge_start_locked(ifp);
209276479Swpaul
2093135250Swpaul	NGE_UNLOCK(sc);
2094135250Swpaul
209576479Swpaul	return;
209676479Swpaul}
209776479Swpaul
209876479Swpaul/*
209976479Swpaul * Stop the adapter and free any mbufs allocated to the
210076479Swpaul * RX and TX lists.
210176479Swpaul */
210299497Salfredstatic void
210399497Salfrednge_stop(sc)
210476479Swpaul	struct nge_softc	*sc;
210576479Swpaul{
210676479Swpaul	register int		i;
210776479Swpaul	struct ifnet		*ifp;
210876479Swpaul	struct mii_data		*mii;
210976479Swpaul
2110135250Swpaul	NGE_LOCK_ASSERT(sc);
2111147256Sbrooks	ifp = sc->nge_ifp;
211276479Swpaul	ifp->if_timer = 0;
2113101540Sambrisko	if (sc->nge_tbi) {
2114101540Sambrisko		mii = NULL;
2115101540Sambrisko	} else {
2116101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
2117101540Sambrisko	}
211876479Swpaul
2119135250Swpaul	callout_stop(&sc->nge_stat_ch);
212076479Swpaul	CSR_WRITE_4(sc, NGE_IER, 0);
212176479Swpaul	CSR_WRITE_4(sc, NGE_IMR, 0);
212276479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
212376479Swpaul	DELAY(1000);
212476479Swpaul	CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0);
212576479Swpaul	CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0);
212676479Swpaul
2127101540Sambrisko	if (!sc->nge_tbi)
2128101540Sambrisko		mii_down(mii);
212976479Swpaul
213076479Swpaul	sc->nge_link = 0;
213176479Swpaul
213276479Swpaul	/*
213376479Swpaul	 * Free data in the RX lists.
213476479Swpaul	 */
213576479Swpaul	for (i = 0; i < NGE_RX_LIST_CNT; i++) {
213676479Swpaul		if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) {
213776479Swpaul			m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf);
213876479Swpaul			sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL;
213976479Swpaul		}
214076479Swpaul	}
214176479Swpaul	bzero((char *)&sc->nge_ldata->nge_rx_list,
214276479Swpaul		sizeof(sc->nge_ldata->nge_rx_list));
214376479Swpaul
214476479Swpaul	/*
214576479Swpaul	 * Free the TX list buffers.
214676479Swpaul	 */
214776479Swpaul	for (i = 0; i < NGE_TX_LIST_CNT; i++) {
214876479Swpaul		if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) {
214976479Swpaul			m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf);
215076479Swpaul			sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL;
215176479Swpaul		}
215276479Swpaul	}
215376479Swpaul
215476479Swpaul	bzero((char *)&sc->nge_ldata->nge_tx_list,
215576479Swpaul		sizeof(sc->nge_ldata->nge_tx_list));
215676479Swpaul
2157148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
215876479Swpaul
215976479Swpaul	return;
216076479Swpaul}
216176479Swpaul
216276479Swpaul/*
216376479Swpaul * Stop all chip I/O so that the kernel's probe routines don't
216476479Swpaul * get confused by errant DMAs when rebooting.
216576479Swpaul */
216699497Salfredstatic void
216799497Salfrednge_shutdown(dev)
216876479Swpaul	device_t		dev;
216976479Swpaul{
217076479Swpaul	struct nge_softc	*sc;
217176479Swpaul
217276479Swpaul	sc = device_get_softc(dev);
217376479Swpaul
2174135250Swpaul	NGE_LOCK(sc);
217576479Swpaul	nge_reset(sc);
217676479Swpaul	nge_stop(sc);
2177135250Swpaul	NGE_UNLOCK(sc);
217876479Swpaul
217976479Swpaul	return;
218076479Swpaul}
2181