if_nge.c revision 192290
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 192290 2009-05-18 06:09:10Z yongari $");
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/bus.h>
11776479Swpaul#include <machine/resource.h>
11876479Swpaul#include <sys/bus.h>
11976479Swpaul#include <sys/rman.h>
12076479Swpaul
12176479Swpaul#include <dev/mii/mii.h>
12276479Swpaul#include <dev/mii/miivar.h>
12376479Swpaul
124119285Simp#include <dev/pci/pcireg.h>
125119285Simp#include <dev/pci/pcivar.h>
12676479Swpaul
12776479Swpaul#define NGE_USEIOSPACE
12876479Swpaul
12976522Swpaul#include <dev/nge/if_ngereg.h>
13076479Swpaul
131113506SmdoddMODULE_DEPEND(nge, pci, 1, 1, 1);
132113506SmdoddMODULE_DEPEND(nge, ether, 1, 1, 1);
13376479SwpaulMODULE_DEPEND(nge, miibus, 1, 1, 1);
13476479Swpaul
135151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
13676479Swpaul#include "miibus_if.h"
13776479Swpaul
13876479Swpaul#define NGE_CSUM_FEATURES	(CSUM_IP | CSUM_TCP | CSUM_UDP)
13976479Swpaul
14076479Swpaul/*
14176479Swpaul * Various supported device vendors/types and their names.
14276479Swpaul */
14376479Swpaulstatic struct nge_type nge_devs[] = {
14476479Swpaul	{ NGE_VENDORID, NGE_DEVICEID,
14576479Swpaul	    "National Semiconductor Gigabit Ethernet" },
14676479Swpaul	{ 0, 0, NULL }
14776479Swpaul};
14876479Swpaul
14999497Salfredstatic int nge_probe(device_t);
15099497Salfredstatic int nge_attach(device_t);
15199497Salfredstatic int nge_detach(device_t);
15276479Swpaul
15399497Salfredstatic int nge_newbuf(struct nge_softc *, struct nge_desc *, struct mbuf *);
15499497Salfredstatic int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *);
155135254Salc#ifdef NGE_FIXUP_RX
156135250Swpaulstatic __inline void nge_fixup_rx (struct mbuf *);
157135250Swpaul#endif
15899497Salfredstatic void nge_rxeof(struct nge_softc *);
15999497Salfredstatic void nge_txeof(struct nge_softc *);
16099497Salfredstatic void nge_intr(void *);
16199497Salfredstatic void nge_tick(void *);
16299497Salfredstatic void nge_start(struct ifnet *);
163135250Swpaulstatic void nge_start_locked(struct ifnet *);
16499497Salfredstatic int nge_ioctl(struct ifnet *, u_long, caddr_t);
16599497Salfredstatic void nge_init(void *);
166135250Swpaulstatic void nge_init_locked(struct nge_softc *);
16799497Salfredstatic void nge_stop(struct nge_softc *);
16899497Salfredstatic void nge_watchdog(struct ifnet *);
169173839Syongaristatic int nge_shutdown(device_t);
17099497Salfredstatic int nge_ifmedia_upd(struct ifnet *);
171151296Sjhbstatic void nge_ifmedia_upd_locked(struct ifnet *);
17299497Salfredstatic void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
17376479Swpaul
17499497Salfredstatic void nge_delay(struct nge_softc *);
17599497Salfredstatic void nge_eeprom_idle(struct nge_softc *);
17699497Salfredstatic void nge_eeprom_putbyte(struct nge_softc *, int);
17799497Salfredstatic void nge_eeprom_getword(struct nge_softc *, int, u_int16_t *);
17899497Salfredstatic void nge_read_eeprom(struct nge_softc *, caddr_t, int, int, int);
17976479Swpaul
18099497Salfredstatic void nge_mii_sync(struct nge_softc *);
18199497Salfredstatic void nge_mii_send(struct nge_softc *, u_int32_t, int);
18299497Salfredstatic int nge_mii_readreg(struct nge_softc *, struct nge_mii_frame *);
18399497Salfredstatic int nge_mii_writereg(struct nge_softc *, struct nge_mii_frame *);
18476479Swpaul
18599497Salfredstatic int nge_miibus_readreg(device_t, int, int);
18699497Salfredstatic int nge_miibus_writereg(device_t, int, int, int);
18799497Salfredstatic void nge_miibus_statchg(device_t);
18876479Swpaul
18999497Salfredstatic void nge_setmulti(struct nge_softc *);
19099497Salfredstatic void nge_reset(struct nge_softc *);
19199497Salfredstatic int nge_list_rx_init(struct nge_softc *);
19299497Salfredstatic int nge_list_tx_init(struct nge_softc *);
19376479Swpaul
19476479Swpaul#ifdef NGE_USEIOSPACE
19576479Swpaul#define NGE_RES			SYS_RES_IOPORT
19676479Swpaul#define NGE_RID			NGE_PCI_LOIO
19776479Swpaul#else
19876479Swpaul#define NGE_RES			SYS_RES_MEMORY
19976479Swpaul#define NGE_RID			NGE_PCI_LOMEM
20076479Swpaul#endif
20176479Swpaul
20276479Swpaulstatic device_method_t nge_methods[] = {
20376479Swpaul	/* Device interface */
20476479Swpaul	DEVMETHOD(device_probe,		nge_probe),
20576479Swpaul	DEVMETHOD(device_attach,	nge_attach),
20676479Swpaul	DEVMETHOD(device_detach,	nge_detach),
20776479Swpaul	DEVMETHOD(device_shutdown,	nge_shutdown),
20876479Swpaul
20976479Swpaul	/* bus interface */
21076479Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
21176479Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
21276479Swpaul
21376479Swpaul	/* MII interface */
21476479Swpaul	DEVMETHOD(miibus_readreg,	nge_miibus_readreg),
21576479Swpaul	DEVMETHOD(miibus_writereg,	nge_miibus_writereg),
21676479Swpaul	DEVMETHOD(miibus_statchg,	nge_miibus_statchg),
21776479Swpaul
21876479Swpaul	{ 0, 0 }
21976479Swpaul};
22076479Swpaul
22176479Swpaulstatic driver_t nge_driver = {
22276479Swpaul	"nge",
22376479Swpaul	nge_methods,
22476479Swpaul	sizeof(struct nge_softc)
22576479Swpaul};
22676479Swpaul
22776479Swpaulstatic devclass_t nge_devclass;
22876479Swpaul
229113506SmdoddDRIVER_MODULE(nge, pci, nge_driver, nge_devclass, 0, 0);
23076479SwpaulDRIVER_MODULE(miibus, nge, miibus_driver, miibus_devclass, 0, 0);
23176479Swpaul
23276479Swpaul#define NGE_SETBIT(sc, reg, x)				\
23376479Swpaul	CSR_WRITE_4(sc, reg,				\
23476479Swpaul		CSR_READ_4(sc, reg) | (x))
23576479Swpaul
23676479Swpaul#define NGE_CLRBIT(sc, reg, x)				\
23776479Swpaul	CSR_WRITE_4(sc, reg,				\
23876479Swpaul		CSR_READ_4(sc, reg) & ~(x))
23976479Swpaul
24076479Swpaul#define SIO_SET(x)					\
241106696Salfred	CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) | (x))
24276479Swpaul
24376479Swpaul#define SIO_CLR(x)					\
244106696Salfred	CSR_WRITE_4(sc, NGE_MEAR, CSR_READ_4(sc, NGE_MEAR) & ~(x))
24576479Swpaul
24699497Salfredstatic void
247192288Syongaringe_delay(struct nge_softc *sc)
24876479Swpaul{
24976479Swpaul	int			idx;
25076479Swpaul
25176479Swpaul	for (idx = (300 / 33) + 1; idx > 0; idx--)
25276479Swpaul		CSR_READ_4(sc, NGE_CSR);
25376479Swpaul
25476479Swpaul	return;
25576479Swpaul}
25676479Swpaul
25799497Salfredstatic void
258192288Syongaringe_eeprom_idle(struct nge_softc *sc)
25976479Swpaul{
260192289Syongari	int			i;
26176479Swpaul
26276479Swpaul	SIO_SET(NGE_MEAR_EE_CSEL);
26376479Swpaul	nge_delay(sc);
26476479Swpaul	SIO_SET(NGE_MEAR_EE_CLK);
26576479Swpaul	nge_delay(sc);
26676479Swpaul
26776479Swpaul	for (i = 0; i < 25; i++) {
26876479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
26976479Swpaul		nge_delay(sc);
27076479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
27176479Swpaul		nge_delay(sc);
27276479Swpaul	}
27376479Swpaul
27476479Swpaul	SIO_CLR(NGE_MEAR_EE_CLK);
27576479Swpaul	nge_delay(sc);
27676479Swpaul	SIO_CLR(NGE_MEAR_EE_CSEL);
27776479Swpaul	nge_delay(sc);
27876479Swpaul	CSR_WRITE_4(sc, NGE_MEAR, 0x00000000);
27976479Swpaul
28076479Swpaul	return;
28176479Swpaul}
28276479Swpaul
28376479Swpaul/*
28476479Swpaul * Send a read command and address to the EEPROM, check for ACK.
28576479Swpaul */
28699497Salfredstatic void
287192288Syongaringe_eeprom_putbyte(struct nge_softc *sc, int addr)
28876479Swpaul{
289192289Syongari	int			d, i;
29076479Swpaul
29176479Swpaul	d = addr | NGE_EECMD_READ;
29276479Swpaul
29376479Swpaul	/*
29476479Swpaul	 * Feed in each bit and stobe the clock.
29576479Swpaul	 */
29676479Swpaul	for (i = 0x400; i; i >>= 1) {
29776479Swpaul		if (d & i) {
29876479Swpaul			SIO_SET(NGE_MEAR_EE_DIN);
29976479Swpaul		} else {
30076479Swpaul			SIO_CLR(NGE_MEAR_EE_DIN);
30176479Swpaul		}
30276479Swpaul		nge_delay(sc);
30376479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
30476479Swpaul		nge_delay(sc);
30576479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
30676479Swpaul		nge_delay(sc);
30776479Swpaul	}
30876479Swpaul
30976479Swpaul	return;
31076479Swpaul}
31176479Swpaul
31276479Swpaul/*
31376479Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
31476479Swpaul */
31599497Salfredstatic void
316192288Syongaringe_eeprom_getword(struct nge_softc *sc, int addr, u_int16_t *dest)
31776479Swpaul{
318192289Syongari	int			i;
31976479Swpaul	u_int16_t		word = 0;
32076479Swpaul
32176479Swpaul	/* Force EEPROM to idle state. */
32276479Swpaul	nge_eeprom_idle(sc);
32376479Swpaul
32476479Swpaul	/* Enter EEPROM access mode. */
32576479Swpaul	nge_delay(sc);
32676479Swpaul	SIO_CLR(NGE_MEAR_EE_CLK);
32776479Swpaul	nge_delay(sc);
32876479Swpaul	SIO_SET(NGE_MEAR_EE_CSEL);
32976479Swpaul	nge_delay(sc);
33076479Swpaul
33176479Swpaul	/*
33276479Swpaul	 * Send address of word we want to read.
33376479Swpaul	 */
33476479Swpaul	nge_eeprom_putbyte(sc, addr);
33576479Swpaul
33676479Swpaul	/*
33776479Swpaul	 * Start reading bits from EEPROM.
33876479Swpaul	 */
33976479Swpaul	for (i = 0x8000; i; i >>= 1) {
34076479Swpaul		SIO_SET(NGE_MEAR_EE_CLK);
34176479Swpaul		nge_delay(sc);
34276479Swpaul		if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_EE_DOUT)
34376479Swpaul			word |= i;
34476479Swpaul		nge_delay(sc);
34576479Swpaul		SIO_CLR(NGE_MEAR_EE_CLK);
34676479Swpaul		nge_delay(sc);
34776479Swpaul	}
34876479Swpaul
34976479Swpaul	/* Turn off EEPROM access mode. */
35076479Swpaul	nge_eeprom_idle(sc);
35176479Swpaul
35276479Swpaul	*dest = word;
35376479Swpaul
35476479Swpaul	return;
35576479Swpaul}
35676479Swpaul
35776479Swpaul/*
35876479Swpaul * Read a sequence of words from the EEPROM.
35976479Swpaul */
36099497Salfredstatic void
361192288Syongaringe_read_eeprom(struct nge_softc *sc, caddr_t dest, int off, int cnt, int swap)
36276479Swpaul{
36376479Swpaul	int			i;
36476479Swpaul	u_int16_t		word = 0, *ptr;
36576479Swpaul
36676479Swpaul	for (i = 0; i < cnt; i++) {
36776479Swpaul		nge_eeprom_getword(sc, off + i, &word);
36876479Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
36976479Swpaul		if (swap)
37076479Swpaul			*ptr = ntohs(word);
37176479Swpaul		else
37276479Swpaul			*ptr = word;
37376479Swpaul	}
37476479Swpaul
37576479Swpaul	return;
37676479Swpaul}
37776479Swpaul
37876479Swpaul/*
37976479Swpaul * Sync the PHYs by setting data bit and strobing the clock 32 times.
38076479Swpaul */
38199497Salfredstatic void
382192288Syongaringe_mii_sync(struct nge_softc *sc)
38376479Swpaul{
384192289Syongari	int			i;
38576479Swpaul
38676479Swpaul	SIO_SET(NGE_MEAR_MII_DIR|NGE_MEAR_MII_DATA);
38776479Swpaul
38876479Swpaul	for (i = 0; i < 32; i++) {
38976479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
39076479Swpaul		DELAY(1);
39176479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
39276479Swpaul		DELAY(1);
39376479Swpaul	}
39476479Swpaul
39576479Swpaul	return;
39676479Swpaul}
39776479Swpaul
39876479Swpaul/*
39976479Swpaul * Clock a series of bits through the MII.
40076479Swpaul */
40199497Salfredstatic void
402192288Syongaringe_mii_send(struct nge_softc *sc, u_int32_t bits, int cnt)
40376479Swpaul{
40476479Swpaul	int			i;
40576479Swpaul
40676479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
40776479Swpaul
40876479Swpaul	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
40976479Swpaul                if (bits & i) {
41076479Swpaul			SIO_SET(NGE_MEAR_MII_DATA);
41176479Swpaul                } else {
41276479Swpaul			SIO_CLR(NGE_MEAR_MII_DATA);
41376479Swpaul                }
41476479Swpaul		DELAY(1);
41576479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
41676479Swpaul		DELAY(1);
41776479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
41876479Swpaul	}
41976479Swpaul}
42076479Swpaul
42176479Swpaul/*
42276479Swpaul * Read an PHY register through the MII.
42376479Swpaul */
42499497Salfredstatic int
425192288Syongaringe_mii_readreg(struct nge_softc *sc, struct nge_mii_frame *frame)
42676479Swpaul{
427135250Swpaul	int			i, ack;
42876479Swpaul
42976479Swpaul	/*
43076479Swpaul	 * Set up frame for RX.
43176479Swpaul	 */
43276479Swpaul	frame->mii_stdelim = NGE_MII_STARTDELIM;
43376479Swpaul	frame->mii_opcode = NGE_MII_READOP;
43476479Swpaul	frame->mii_turnaround = 0;
43576479Swpaul	frame->mii_data = 0;
436192290Syongari
43776479Swpaul	CSR_WRITE_4(sc, NGE_MEAR, 0);
43876479Swpaul
43976479Swpaul	/*
44076479Swpaul 	 * Turn on data xmit.
44176479Swpaul	 */
44276479Swpaul	SIO_SET(NGE_MEAR_MII_DIR);
44376479Swpaul
44476479Swpaul	nge_mii_sync(sc);
44576479Swpaul
44676479Swpaul	/*
44776479Swpaul	 * Send command/address info.
44876479Swpaul	 */
44976479Swpaul	nge_mii_send(sc, frame->mii_stdelim, 2);
45076479Swpaul	nge_mii_send(sc, frame->mii_opcode, 2);
45176479Swpaul	nge_mii_send(sc, frame->mii_phyaddr, 5);
45276479Swpaul	nge_mii_send(sc, frame->mii_regaddr, 5);
45376479Swpaul
45476479Swpaul	/* Idle bit */
45576479Swpaul	SIO_CLR((NGE_MEAR_MII_CLK|NGE_MEAR_MII_DATA));
45676479Swpaul	DELAY(1);
45776479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
45876479Swpaul	DELAY(1);
45976479Swpaul
46076479Swpaul	/* Turn off xmit. */
46176479Swpaul	SIO_CLR(NGE_MEAR_MII_DIR);
46276479Swpaul	/* Check for ack */
46376479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
46476479Swpaul	DELAY(1);
465109058Smbr	ack = CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA;
46676479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
46776479Swpaul	DELAY(1);
46876479Swpaul
46976479Swpaul	/*
47076479Swpaul	 * Now try reading data bits. If the ack failed, we still
47176479Swpaul	 * need to clock through 16 cycles to keep the PHY(s) in sync.
47276479Swpaul	 */
47376479Swpaul	if (ack) {
47476479Swpaul		for(i = 0; i < 16; i++) {
47576479Swpaul			SIO_CLR(NGE_MEAR_MII_CLK);
47676479Swpaul			DELAY(1);
47776479Swpaul			SIO_SET(NGE_MEAR_MII_CLK);
47876479Swpaul			DELAY(1);
47976479Swpaul		}
48076479Swpaul		goto fail;
48176479Swpaul	}
48276479Swpaul
48376479Swpaul	for (i = 0x8000; i; i >>= 1) {
48476479Swpaul		SIO_CLR(NGE_MEAR_MII_CLK);
48576479Swpaul		DELAY(1);
48676479Swpaul		if (!ack) {
48776479Swpaul			if (CSR_READ_4(sc, NGE_MEAR) & NGE_MEAR_MII_DATA)
48876479Swpaul				frame->mii_data |= i;
48976479Swpaul			DELAY(1);
49076479Swpaul		}
49176479Swpaul		SIO_SET(NGE_MEAR_MII_CLK);
49276479Swpaul		DELAY(1);
49376479Swpaul	}
49476479Swpaul
49576479Swpaulfail:
49676479Swpaul
49776479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
49876479Swpaul	DELAY(1);
49976479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
50076479Swpaul	DELAY(1);
50176479Swpaul
50276479Swpaul	if (ack)
50376479Swpaul		return(1);
50476479Swpaul	return(0);
50576479Swpaul}
50676479Swpaul
50776479Swpaul/*
50876479Swpaul * Write to a PHY register through the MII.
50976479Swpaul */
51099497Salfredstatic int
511192288Syongaringe_mii_writereg(struct nge_softc *sc, struct nge_mii_frame *frame)
51276479Swpaul{
51376479Swpaul
51476479Swpaul	/*
51576479Swpaul	 * Set up frame for TX.
51676479Swpaul	 */
51776479Swpaul
51876479Swpaul	frame->mii_stdelim = NGE_MII_STARTDELIM;
51976479Swpaul	frame->mii_opcode = NGE_MII_WRITEOP;
52076479Swpaul	frame->mii_turnaround = NGE_MII_TURNAROUND;
521192290Syongari
52276479Swpaul	/*
52376479Swpaul 	 * Turn on data output.
52476479Swpaul	 */
52576479Swpaul	SIO_SET(NGE_MEAR_MII_DIR);
52676479Swpaul
52776479Swpaul	nge_mii_sync(sc);
52876479Swpaul
52976479Swpaul	nge_mii_send(sc, frame->mii_stdelim, 2);
53076479Swpaul	nge_mii_send(sc, frame->mii_opcode, 2);
53176479Swpaul	nge_mii_send(sc, frame->mii_phyaddr, 5);
53276479Swpaul	nge_mii_send(sc, frame->mii_regaddr, 5);
53376479Swpaul	nge_mii_send(sc, frame->mii_turnaround, 2);
53476479Swpaul	nge_mii_send(sc, frame->mii_data, 16);
53576479Swpaul
53676479Swpaul	/* Idle bit. */
53776479Swpaul	SIO_SET(NGE_MEAR_MII_CLK);
53876479Swpaul	DELAY(1);
53976479Swpaul	SIO_CLR(NGE_MEAR_MII_CLK);
54076479Swpaul	DELAY(1);
54176479Swpaul
54276479Swpaul	/*
54376479Swpaul	 * Turn off xmit.
54476479Swpaul	 */
54576479Swpaul	SIO_CLR(NGE_MEAR_MII_DIR);
54676479Swpaul
54776479Swpaul	return(0);
54876479Swpaul}
54976479Swpaul
55099497Salfredstatic int
551192288Syongaringe_miibus_readreg(device_t dev, int phy, int reg)
55276479Swpaul{
55376479Swpaul	struct nge_softc	*sc;
55476479Swpaul	struct nge_mii_frame	frame;
55576479Swpaul
55676479Swpaul	sc = device_get_softc(dev);
55776479Swpaul
55876479Swpaul	bzero((char *)&frame, sizeof(frame));
55976479Swpaul
56076479Swpaul	frame.mii_phyaddr = phy;
56176479Swpaul	frame.mii_regaddr = reg;
56276479Swpaul	nge_mii_readreg(sc, &frame);
56376479Swpaul
56476479Swpaul	return(frame.mii_data);
56576479Swpaul}
56676479Swpaul
56799497Salfredstatic int
568192288Syongaringe_miibus_writereg(device_t dev, int phy, int reg, int data)
56976479Swpaul{
57076479Swpaul	struct nge_softc	*sc;
57176479Swpaul	struct nge_mii_frame	frame;
57276479Swpaul
57376479Swpaul	sc = device_get_softc(dev);
57476479Swpaul
57576479Swpaul	bzero((char *)&frame, sizeof(frame));
57676479Swpaul
57776479Swpaul	frame.mii_phyaddr = phy;
57876479Swpaul	frame.mii_regaddr = reg;
57976479Swpaul	frame.mii_data = data;
58076479Swpaul	nge_mii_writereg(sc, &frame);
58176479Swpaul
58276479Swpaul	return(0);
58376479Swpaul}
58476479Swpaul
58599497Salfredstatic void
586192288Syongaringe_miibus_statchg(device_t dev)
58776479Swpaul{
588192290Syongari	int			status;
58976479Swpaul	struct nge_softc	*sc;
59076479Swpaul	struct mii_data		*mii;
59176479Swpaul
59276479Swpaul	sc = device_get_softc(dev);
593101540Sambrisko	if (sc->nge_tbi) {
594101540Sambrisko		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
595101540Sambrisko		    == IFM_AUTO) {
596101540Sambrisko			status = CSR_READ_4(sc, NGE_TBI_ANLPAR);
597101540Sambrisko			if (status == 0 || status & NGE_TBIANAR_FDX) {
598101540Sambrisko				NGE_SETBIT(sc, NGE_TX_CFG,
599101540Sambrisko				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
600101540Sambrisko				NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
601101540Sambrisko			} else {
602101540Sambrisko				NGE_CLRBIT(sc, NGE_TX_CFG,
603101540Sambrisko				    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
604101540Sambrisko				NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
605101540Sambrisko			}
60676479Swpaul
607192290Syongari		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
608101540Sambrisko			!= IFM_FDX) {
609101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
610101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
611101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
612101540Sambrisko		} else {
613101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
614101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
615101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
616101540Sambrisko		}
61776479Swpaul	} else {
618101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
61976479Swpaul
620101540Sambrisko		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
621101540Sambrisko		        NGE_SETBIT(sc, NGE_TX_CFG,
622101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
623101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
624101540Sambrisko		} else {
625101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
626101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
627101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
628101540Sambrisko		}
629101540Sambrisko
630101540Sambrisko		/* If we have a 1000Mbps link, set the mode_1000 bit. */
631101540Sambrisko		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
632101540Sambrisko		    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
633101540Sambrisko			NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
634101540Sambrisko		} else {
635101540Sambrisko			NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
636101540Sambrisko		}
63779424Swpaul	}
63876479Swpaul	return;
63976479Swpaul}
64076479Swpaul
64199497Salfredstatic void
642192288Syongaringe_setmulti(struct nge_softc *sc)
64376479Swpaul{
64476479Swpaul	struct ifnet		*ifp;
64576479Swpaul	struct ifmultiaddr	*ifma;
64676479Swpaul	u_int32_t		h = 0, i, filtsave;
64776479Swpaul	int			bit, index;
64876479Swpaul
649135250Swpaul	NGE_LOCK_ASSERT(sc);
650147256Sbrooks	ifp = sc->nge_ifp;
65176479Swpaul
65276479Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
65376479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL,
65476479Swpaul		    NGE_RXFILTCTL_MCHASH|NGE_RXFILTCTL_UCHASH);
65576479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLMULTI);
65676479Swpaul		return;
65776479Swpaul	}
65876479Swpaul
65976479Swpaul	/*
66076479Swpaul	 * We have to explicitly enable the multicast hash table
66176479Swpaul	 * on the NatSemi chip if we want to use it, which we do.
66276479Swpaul	 * We also have to tell it that we don't want to use the
66376479Swpaul	 * hash table for matching unicast addresses.
66476479Swpaul	 */
66576479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH);
66676479Swpaul	NGE_CLRBIT(sc, NGE_RXFILT_CTL,
66776479Swpaul	    NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH);
66876479Swpaul
66976479Swpaul	filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL);
67076479Swpaul
67176479Swpaul	/* first, zot all the existing hash bits */
67276479Swpaul	for (i = 0; i < NGE_MCAST_FILTER_LEN; i += 2) {
67376479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + i);
67476479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0);
67576479Swpaul	}
67676479Swpaul
67776479Swpaul	/*
67876479Swpaul	 * From the 11 bits returned by the crc routine, the top 7
67976479Swpaul	 * bits represent the 16-bit word in the mcast hash table
68076479Swpaul	 * that needs to be updated, and the lower 4 bits represent
68176479Swpaul	 * which bit within that byte needs to be set.
68276479Swpaul	 */
683148654Srwatson	IF_ADDR_LOCK(ifp);
68476479Swpaul	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
68576479Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
68676479Swpaul			continue;
687130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
688130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 21;
68976479Swpaul		index = (h >> 4) & 0x7F;
69076479Swpaul		bit = h & 0xF;
69176479Swpaul		CSR_WRITE_4(sc, NGE_RXFILT_CTL,
69276479Swpaul		    NGE_FILTADDR_MCAST_LO + (index * 2));
69376479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit));
69476479Swpaul	}
695148654Srwatson	IF_ADDR_UNLOCK(ifp);
69676479Swpaul
69776479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, filtsave);
69876479Swpaul
69976479Swpaul	return;
70076479Swpaul}
70176479Swpaul
70299497Salfredstatic void
703192288Syongaringe_reset(struct nge_softc *sc)
70476479Swpaul{
705192289Syongari	int			i;
70676479Swpaul
70776479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RESET);
70876479Swpaul
70976479Swpaul	for (i = 0; i < NGE_TIMEOUT; i++) {
71076479Swpaul		if (!(CSR_READ_4(sc, NGE_CSR) & NGE_CSR_RESET))
71176479Swpaul			break;
71276479Swpaul	}
71376479Swpaul
71476479Swpaul	if (i == NGE_TIMEOUT)
715162321Sglebius		device_printf(sc->nge_dev, "reset never completed\n");
71676479Swpaul
71776479Swpaul	/* Wait a little while for the chip to get its brains in order. */
71876479Swpaul	DELAY(1000);
71976479Swpaul
72076479Swpaul	/*
72176479Swpaul	 * If this is a NetSemi chip, make sure to clear
72276479Swpaul	 * PME mode.
72376479Swpaul	 */
72476479Swpaul	CSR_WRITE_4(sc, NGE_CLKRUN, NGE_CLKRUN_PMESTS);
72576479Swpaul	CSR_WRITE_4(sc, NGE_CLKRUN, 0);
72676479Swpaul
72776479Swpaul        return;
72876479Swpaul}
72976479Swpaul
73076479Swpaul/*
731108470Sschweikh * Probe for a NatSemi chip. Check the PCI vendor and device
73276479Swpaul * IDs against our list and return a device name if we find a match.
73376479Swpaul */
73499497Salfredstatic int
735192288Syongaringe_probe(device_t dev)
73676479Swpaul{
73776479Swpaul	struct nge_type		*t;
73876479Swpaul
73976479Swpaul	t = nge_devs;
74076479Swpaul
74176479Swpaul	while(t->nge_name != NULL) {
74276479Swpaul		if ((pci_get_vendor(dev) == t->nge_vid) &&
74376479Swpaul		    (pci_get_device(dev) == t->nge_did)) {
74476479Swpaul			device_set_desc(dev, t->nge_name);
745143158Simp			return(BUS_PROBE_DEFAULT);
74676479Swpaul		}
74776479Swpaul		t++;
74876479Swpaul	}
74976479Swpaul
75076479Swpaul	return(ENXIO);
75176479Swpaul}
75276479Swpaul
75376479Swpaul/*
75476479Swpaul * Attach the interface. Allocate softc structures, do ifmedia
75576479Swpaul * setup and ethernet/BPF attach.
75676479Swpaul */
75799497Salfredstatic int
758192288Syongaringe_attach(device_t dev)
75976479Swpaul{
76076479Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
76176479Swpaul	struct nge_softc	*sc;
762151296Sjhb	struct ifnet		*ifp = NULL;
763151296Sjhb	int			error = 0, rid;
76476479Swpaul
76576479Swpaul	sc = device_get_softc(dev);
766162321Sglebius	sc->nge_dev = dev;
76776479Swpaul
768135250Swpaul	NGE_LOCK_INIT(sc, device_get_nameunit(dev));
769151296Sjhb	callout_init_mtx(&sc->nge_stat_ch, &sc->nge_mtx, 0);
770151296Sjhb
77176479Swpaul	/*
77276479Swpaul	 * Map control/status registers.
77376479Swpaul	 */
77476479Swpaul	pci_enable_busmaster(dev);
77576479Swpaul
77676479Swpaul	rid = NGE_RID;
777127135Snjl	sc->nge_res = bus_alloc_resource_any(dev, NGE_RES, &rid, RF_ACTIVE);
77876479Swpaul
77976479Swpaul	if (sc->nge_res == NULL) {
780151296Sjhb		device_printf(dev, "couldn't map ports/memory\n");
78176479Swpaul		error = ENXIO;
78276479Swpaul		goto fail;
78376479Swpaul	}
78476479Swpaul
78576479Swpaul	sc->nge_btag = rman_get_bustag(sc->nge_res);
78676479Swpaul	sc->nge_bhandle = rman_get_bushandle(sc->nge_res);
78776479Swpaul
78876479Swpaul	/* Allocate interrupt */
78976479Swpaul	rid = 0;
790127135Snjl	sc->nge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
79176479Swpaul	    RF_SHAREABLE | RF_ACTIVE);
79276479Swpaul
79376479Swpaul	if (sc->nge_irq == NULL) {
794151296Sjhb		device_printf(dev, "couldn't map interrupt\n");
79576479Swpaul		error = ENXIO;
79676479Swpaul		goto fail;
79776479Swpaul	}
79876479Swpaul
79976479Swpaul	/* Reset the adapter. */
80076479Swpaul	nge_reset(sc);
80176479Swpaul
80276479Swpaul	/*
80376479Swpaul	 * Get station address from the EEPROM.
80476479Swpaul	 */
80576479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0);
80676479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0);
80776479Swpaul	nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0);
80876479Swpaul
80976479Swpaul	sc->nge_ldata = contigmalloc(sizeof(struct nge_list_data), M_DEVBUF,
810151296Sjhb	    M_NOWAIT|M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
81176479Swpaul
81276479Swpaul	if (sc->nge_ldata == NULL) {
813151296Sjhb		device_printf(dev, "no memory for list buffers!\n");
81476479Swpaul		error = ENXIO;
81576479Swpaul		goto fail;
81676479Swpaul	}
81776479Swpaul
818147256Sbrooks	ifp = sc->nge_ifp = if_alloc(IFT_ETHER);
819147256Sbrooks	if (ifp == NULL) {
820151296Sjhb		device_printf(dev, "can not if_alloc()\n");
821147256Sbrooks		error = ENOSPC;
822147256Sbrooks		goto fail;
823147256Sbrooks	}
82476479Swpaul	ifp->if_softc = sc;
825121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
82676479Swpaul	ifp->if_mtu = ETHERMTU;
827135250Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
82876479Swpaul	ifp->if_ioctl = nge_ioctl;
82976479Swpaul	ifp->if_start = nge_start;
83076479Swpaul	ifp->if_watchdog = nge_watchdog;
83176479Swpaul	ifp->if_init = nge_init;
83276479Swpaul	ifp->if_snd.ifq_maxlen = NGE_TX_LIST_CNT - 1;
83376479Swpaul	ifp->if_hwassist = NGE_CSUM_FEATURES;
834106937Ssam	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING;
835150789Sglebius	ifp->if_capenable = ifp->if_capabilities;
836128132Sru#ifdef DEVICE_POLLING
837128132Sru	ifp->if_capabilities |= IFCAP_POLLING;
838128132Sru#endif
83976479Swpaul
84076479Swpaul	/*
84176479Swpaul	 * Do MII setup.
84276479Swpaul	 */
843150185Sru	/* XXX: leaked on error */
84476479Swpaul	if (mii_phy_probe(dev, &sc->nge_miibus,
845101540Sambrisko			  nge_ifmedia_upd, nge_ifmedia_sts)) {
846101540Sambrisko		if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) {
847101540Sambrisko			sc->nge_tbi = 1;
848101540Sambrisko			device_printf(dev, "Using TBI\n");
849192290Syongari
850101540Sambrisko			sc->nge_miibus = dev;
851101540Sambrisko
852192290Syongari			ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd,
853101540Sambrisko				nge_ifmedia_sts);
854101540Sambrisko#define	ADD(m, c)	ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL)
855101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0);
856101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0);
857101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0);
858101540Sambrisko			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0);
859101540Sambrisko#undef ADD
860151296Sjhb			device_printf(dev, " 1000baseSX, 1000baseSX-FDX, auto\n");
861192290Syongari
862192290Syongari			ifmedia_set(&sc->nge_ifmedia,
863101540Sambrisko				IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0));
864192290Syongari
865101540Sambrisko			CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
866192290Syongari				| NGE_GPIO_GP4_OUT
867192290Syongari				| NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB
868101540Sambrisko				| NGE_GPIO_GP3_OUTENB
869101540Sambrisko				| NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
870192290Syongari
871101540Sambrisko		} else {
872151296Sjhb			device_printf(dev, "MII without any PHY!\n");
873101540Sambrisko			error = ENXIO;
874101540Sambrisko			goto fail;
875101540Sambrisko		}
87676479Swpaul	}
87776479Swpaul
87876479Swpaul	/*
87976479Swpaul	 * Call MI attach routine.
88076479Swpaul	 */
881106937Ssam	ether_ifattach(ifp, eaddr);
88276479Swpaul
883135250Swpaul	/*
884135250Swpaul	 * Hookup IRQ last.
885135250Swpaul	 */
886135250Swpaul	error = bus_setup_intr(dev, sc->nge_irq, INTR_TYPE_NET | INTR_MPSAFE,
887166901Spiso	    NULL, nge_intr, sc, &sc->nge_intrhand);
888135250Swpaul	if (error) {
889151296Sjhb		device_printf(dev, "couldn't set up irq\n");
890151296Sjhb		goto fail;
891151296Sjhb	}
892151296Sjhb
893151296Sjhb	return (0);
894151296Sjhb
895151296Sjhbfail:
896151296Sjhb	if (sc->nge_ldata)
897151296Sjhb		contigfree(sc->nge_ldata,
898151296Sjhb		  sizeof(struct nge_list_data), M_DEVBUF);
899151296Sjhb	if (ifp)
900150185Sru		if_free(ifp);
901151296Sjhb	if (sc->nge_irq)
902135250Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
903151296Sjhb	if (sc->nge_res)
904135250Swpaul		bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
905151296Sjhb	NGE_LOCK_DESTROY(sc);
90676479Swpaul	return(error);
90776479Swpaul}
90876479Swpaul
90999497Salfredstatic int
910192288Syongaringe_detach(device_t dev)
91176479Swpaul{
91276479Swpaul	struct nge_softc	*sc;
91376479Swpaul	struct ifnet		*ifp;
91476479Swpaul
91576479Swpaul	sc = device_get_softc(dev);
916147256Sbrooks	ifp = sc->nge_ifp;
91776479Swpaul
918150789Sglebius#ifdef DEVICE_POLLING
919150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
920150789Sglebius		ether_poll_deregister(ifp);
921150789Sglebius#endif
922135250Swpaul	NGE_LOCK(sc);
92376479Swpaul	nge_reset(sc);
92476479Swpaul	nge_stop(sc);
925135250Swpaul	NGE_UNLOCK(sc);
926151296Sjhb	callout_drain(&sc->nge_stat_ch);
927106937Ssam	ether_ifdetach(ifp);
92876479Swpaul
92976479Swpaul	bus_generic_detach(dev);
930101540Sambrisko	if (!sc->nge_tbi) {
931101540Sambrisko		device_delete_child(dev, sc->nge_miibus);
932101540Sambrisko	}
93376479Swpaul	bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
93476479Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
93576479Swpaul	bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
93676479Swpaul
93776479Swpaul	contigfree(sc->nge_ldata, sizeof(struct nge_list_data), M_DEVBUF);
938150306Simp	if_free(ifp);
93976479Swpaul
940135251Swpaul	NGE_LOCK_DESTROY(sc);
941135251Swpaul
94276479Swpaul	return(0);
94376479Swpaul}
94476479Swpaul
94576479Swpaul/*
94676479Swpaul * Initialize the transmit descriptors.
94776479Swpaul */
94899497Salfredstatic int
949192288Syongaringe_list_tx_init(struct nge_softc *sc)
95076479Swpaul{
95176479Swpaul	struct nge_list_data	*ld;
95276479Swpaul	struct nge_ring_data	*cd;
95376479Swpaul	int			i;
95476479Swpaul
95576479Swpaul	cd = &sc->nge_cdata;
95676479Swpaul	ld = sc->nge_ldata;
95776479Swpaul
95876479Swpaul	for (i = 0; i < NGE_TX_LIST_CNT; i++) {
95976479Swpaul		if (i == (NGE_TX_LIST_CNT - 1)) {
96076479Swpaul			ld->nge_tx_list[i].nge_nextdesc =
96176479Swpaul			    &ld->nge_tx_list[0];
96276479Swpaul			ld->nge_tx_list[i].nge_next =
96376479Swpaul			    vtophys(&ld->nge_tx_list[0]);
96476479Swpaul		} else {
96576479Swpaul			ld->nge_tx_list[i].nge_nextdesc =
96676479Swpaul			    &ld->nge_tx_list[i + 1];
96776479Swpaul			ld->nge_tx_list[i].nge_next =
96876479Swpaul			    vtophys(&ld->nge_tx_list[i + 1]);
96976479Swpaul		}
97076479Swpaul		ld->nge_tx_list[i].nge_mbuf = NULL;
97176479Swpaul		ld->nge_tx_list[i].nge_ptr = 0;
97276479Swpaul		ld->nge_tx_list[i].nge_ctl = 0;
97376479Swpaul	}
97476479Swpaul
97576479Swpaul	cd->nge_tx_prod = cd->nge_tx_cons = cd->nge_tx_cnt = 0;
97676479Swpaul
97776479Swpaul	return(0);
97876479Swpaul}
97976479Swpaul
98076479Swpaul
98176479Swpaul/*
98276479Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
98376479Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
98476479Swpaul * points back to the first.
98576479Swpaul */
98699497Salfredstatic int
987192288Syongaringe_list_rx_init(struct nge_softc *sc)
98876479Swpaul{
98976479Swpaul	struct nge_list_data	*ld;
99076479Swpaul	struct nge_ring_data	*cd;
99176479Swpaul	int			i;
99276479Swpaul
99376479Swpaul	ld = sc->nge_ldata;
99476479Swpaul	cd = &sc->nge_cdata;
99576479Swpaul
99676479Swpaul	for (i = 0; i < NGE_RX_LIST_CNT; i++) {
99776479Swpaul		if (nge_newbuf(sc, &ld->nge_rx_list[i], NULL) == ENOBUFS)
99876479Swpaul			return(ENOBUFS);
99976479Swpaul		if (i == (NGE_RX_LIST_CNT - 1)) {
100076479Swpaul			ld->nge_rx_list[i].nge_nextdesc =
100176479Swpaul			    &ld->nge_rx_list[0];
100276479Swpaul			ld->nge_rx_list[i].nge_next =
100376479Swpaul			    vtophys(&ld->nge_rx_list[0]);
100476479Swpaul		} else {
100576479Swpaul			ld->nge_rx_list[i].nge_nextdesc =
100676479Swpaul			    &ld->nge_rx_list[i + 1];
100776479Swpaul			ld->nge_rx_list[i].nge_next =
100876479Swpaul			    vtophys(&ld->nge_rx_list[i + 1]);
100976479Swpaul		}
101076479Swpaul	}
101176479Swpaul
101276479Swpaul	cd->nge_rx_prod = 0;
1013135250Swpaul	sc->nge_head = sc->nge_tail = NULL;
101476479Swpaul
101576479Swpaul	return(0);
101676479Swpaul}
101776479Swpaul
101876479Swpaul/*
101976479Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
102076479Swpaul */
102199497Salfredstatic int
1022192288Syongaringe_newbuf(struct nge_softc *sc, struct nge_desc *c, struct mbuf *m)
102376479Swpaul{
102476479Swpaul
102576479Swpaul	if (m == NULL) {
1026144241Ssam		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1027144241Ssam		if (m == NULL)
1028135250Swpaul			return (ENOBUFS);
1029135250Swpaul	} else
1030135250Swpaul		m->m_data = m->m_ext.ext_buf;
103176479Swpaul
1032135250Swpaul	m->m_len = m->m_pkthdr.len = MCLBYTES;
103376479Swpaul
1034144241Ssam	m_adj(m, sizeof(u_int64_t));
103576479Swpaul
1036144241Ssam	c->nge_mbuf = m;
1037144241Ssam	c->nge_ptr = vtophys(mtod(m, caddr_t));
1038144241Ssam	c->nge_ctl = m->m_len;
103976479Swpaul	c->nge_extsts = 0;
104076479Swpaul
104176479Swpaul	return(0);
104276479Swpaul}
104376479Swpaul
1044135250Swpaul#ifdef NGE_FIXUP_RX
1045135250Swpaulstatic __inline void
1046192288Syongaringe_fixup_rx(struct mbuf *m)
1047192290Syongari{
1048135250Swpaul        int			i;
1049135250Swpaul        uint16_t		*src, *dst;
1050192290Syongari
1051135250Swpaul	src = mtod(m, uint16_t *);
1052135250Swpaul	dst = src - 1;
1053192290Syongari
1054135250Swpaul	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1055135250Swpaul		*dst++ = *src++;
1056192290Syongari
1057135250Swpaul	m->m_data -= ETHER_ALIGN;
1058192290Syongari
105976479Swpaul	return;
1060192290Syongari}
106176479Swpaul#endif
106276479Swpaul
106376479Swpaul/*
106476479Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
106576479Swpaul * the higher level protocols.
106676479Swpaul */
106799497Salfredstatic void
1068192288Syongaringe_rxeof(struct nge_softc *sc)
106976479Swpaul{
107076479Swpaul        struct mbuf		*m;
107176479Swpaul        struct ifnet		*ifp;
107276479Swpaul	struct nge_desc		*cur_rx;
107376479Swpaul	int			i, total_len = 0;
107476479Swpaul	u_int32_t		rxstat;
107576479Swpaul
1076135250Swpaul	NGE_LOCK_ASSERT(sc);
1077147256Sbrooks	ifp = sc->nge_ifp;
107876479Swpaul	i = sc->nge_cdata.nge_rx_prod;
107976479Swpaul
108076479Swpaul	while(NGE_OWNDESC(&sc->nge_ldata->nge_rx_list[i])) {
108176479Swpaul		u_int32_t		extsts;
108276479Swpaul
1083106507Ssimokawa#ifdef DEVICE_POLLING
1084150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
1085106507Ssimokawa			if (sc->rxcycles <= 0)
1086106507Ssimokawa				break;
1087106507Ssimokawa			sc->rxcycles--;
1088106507Ssimokawa		}
1089150789Sglebius#endif
1090106507Ssimokawa
109176479Swpaul		cur_rx = &sc->nge_ldata->nge_rx_list[i];
109276479Swpaul		rxstat = cur_rx->nge_rxstat;
109376479Swpaul		extsts = cur_rx->nge_extsts;
109476479Swpaul		m = cur_rx->nge_mbuf;
109576479Swpaul		cur_rx->nge_mbuf = NULL;
109676479Swpaul		total_len = NGE_RXBYTES(cur_rx);
109776479Swpaul		NGE_INC(i, NGE_RX_LIST_CNT);
1098135250Swpaul
1099135250Swpaul		if (rxstat & NGE_CMDSTS_MORE) {
1100135250Swpaul			m->m_len = total_len;
1101135250Swpaul			if (sc->nge_head == NULL) {
1102135250Swpaul				m->m_pkthdr.len = total_len;
1103135250Swpaul				sc->nge_head = sc->nge_tail = m;
1104135250Swpaul			} else {
1105135250Swpaul				m->m_flags &= ~M_PKTHDR;
1106135250Swpaul				sc->nge_head->m_pkthdr.len += total_len;
1107135250Swpaul				sc->nge_tail->m_next = m;
1108135250Swpaul				sc->nge_tail = m;
1109135250Swpaul			}
1110135250Swpaul			nge_newbuf(sc, cur_rx, NULL);
1111135250Swpaul			continue;
1112135250Swpaul		}
1113135250Swpaul
111476479Swpaul		/*
111576479Swpaul		 * If an error occurs, update stats, clear the
111676479Swpaul		 * status word and leave the mbuf cluster in place:
111776479Swpaul		 * it should simply get re-used next time this descriptor
111876479Swpaul	 	 * comes up in the ring.
111976479Swpaul		 */
112076479Swpaul		if (!(rxstat & NGE_CMDSTS_PKT_OK)) {
112176479Swpaul			ifp->if_ierrors++;
1122135250Swpaul			if (sc->nge_head != NULL) {
1123135250Swpaul				m_freem(sc->nge_head);
1124135250Swpaul				sc->nge_head = sc->nge_tail = NULL;
1125135250Swpaul			}
112676479Swpaul			nge_newbuf(sc, cur_rx, m);
112776479Swpaul			continue;
112876479Swpaul		}
112976479Swpaul
1130135250Swpaul		/* Try conjure up a replacement mbuf. */
1131135250Swpaul
1132135250Swpaul		if (nge_newbuf(sc, cur_rx, NULL)) {
1133135250Swpaul			ifp->if_ierrors++;
1134135250Swpaul			if (sc->nge_head != NULL) {
1135135250Swpaul				m_freem(sc->nge_head);
1136135250Swpaul				sc->nge_head = sc->nge_tail = NULL;
1137135250Swpaul			}
1138135250Swpaul			nge_newbuf(sc, cur_rx, m);
1139135250Swpaul			continue;
1140135250Swpaul		}
1141135250Swpaul
1142135250Swpaul		if (sc->nge_head != NULL) {
1143135250Swpaul			m->m_len = total_len;
1144135250Swpaul			m->m_flags &= ~M_PKTHDR;
1145135250Swpaul			sc->nge_tail->m_next = m;
1146135250Swpaul			m = sc->nge_head;
1147135250Swpaul			m->m_pkthdr.len += total_len;
1148135250Swpaul			sc->nge_head = sc->nge_tail = NULL;
1149135250Swpaul		} else
1150135250Swpaul			m->m_pkthdr.len = m->m_len = total_len;
1151135250Swpaul
115276479Swpaul		/*
115376479Swpaul		 * Ok. NatSemi really screwed up here. This is the
115476479Swpaul		 * only gigE chip I know of with alignment constraints
115576479Swpaul		 * on receive buffers. RX buffers must be 64-bit aligned.
115676479Swpaul		 */
115779562Swpaul		/*
115879562Swpaul		 * By popular demand, ignore the alignment problems
115979562Swpaul		 * on the Intel x86 platform. The performance hit
116079562Swpaul		 * incurred due to unaligned accesses is much smaller
116179562Swpaul		 * than the hit produced by forcing buffer copies all
116279562Swpaul		 * the time, especially with jumbo frames. We still
116379562Swpaul		 * need to fix up the alignment everywhere else though.
116479562Swpaul		 */
1165135250Swpaul#ifdef NGE_FIXUP_RX
1166135250Swpaul		nge_fixup_rx(m);
116779562Swpaul#endif
116876479Swpaul
116976479Swpaul		ifp->if_ipackets++;
1170135250Swpaul		m->m_pkthdr.rcvif = ifp;
117176479Swpaul
117276479Swpaul		/* Do IP checksum checking. */
117378323Swpaul		if (extsts & NGE_RXEXTSTS_IPPKT)
117478323Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
117578323Swpaul		if (!(extsts & NGE_RXEXTSTS_IPCSUMERR))
117678323Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
117778323Swpaul		if ((extsts & NGE_RXEXTSTS_TCPPKT &&
117878323Swpaul		    !(extsts & NGE_RXEXTSTS_TCPCSUMERR)) ||
117978323Swpaul		    (extsts & NGE_RXEXTSTS_UDPPKT &&
118078323Swpaul		    !(extsts & NGE_RXEXTSTS_UDPCSUMERR))) {
118178323Swpaul			m->m_pkthdr.csum_flags |=
118278323Swpaul			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
118378323Swpaul			m->m_pkthdr.csum_data = 0xffff;
118478323Swpaul		}
118576479Swpaul
118676479Swpaul		/*
118776479Swpaul		 * If we received a packet with a vlan tag, pass it
118876479Swpaul		 * to vlan_input() instead of ether_input().
118976479Swpaul		 */
119076479Swpaul		if (extsts & NGE_RXEXTSTS_VLANPKT) {
1191162375Sandre			m->m_pkthdr.ether_vtag =
1192162375Sandre			    ntohs(extsts & NGE_RXEXTSTS_VTCI);
1193162375Sandre			m->m_flags |= M_VLANTAG;
1194106937Ssam		}
1195135250Swpaul		NGE_UNLOCK(sc);
1196106937Ssam		(*ifp->if_input)(ifp, m);
1197135250Swpaul		NGE_LOCK(sc);
119876479Swpaul	}
119976479Swpaul
120076479Swpaul	sc->nge_cdata.nge_rx_prod = i;
120176479Swpaul
120276479Swpaul	return;
120376479Swpaul}
120476479Swpaul
120576479Swpaul/*
120676479Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
120776479Swpaul * the list buffers.
120876479Swpaul */
120976479Swpaul
121099497Salfredstatic void
1211192288Syongaringe_txeof(struct nge_softc *sc)
121276479Swpaul{
1213128130Sru	struct nge_desc		*cur_tx;
121476479Swpaul	struct ifnet		*ifp;
121576479Swpaul	u_int32_t		idx;
121676479Swpaul
1217135250Swpaul	NGE_LOCK_ASSERT(sc);
1218147256Sbrooks	ifp = sc->nge_ifp;
121976479Swpaul
122076479Swpaul	/*
122176479Swpaul	 * Go through our tx list and free mbufs for those
122276479Swpaul	 * frames that have been transmitted.
122376479Swpaul	 */
122476479Swpaul	idx = sc->nge_cdata.nge_tx_cons;
122576479Swpaul	while (idx != sc->nge_cdata.nge_tx_prod) {
122676479Swpaul		cur_tx = &sc->nge_ldata->nge_tx_list[idx];
122776479Swpaul
122876479Swpaul		if (NGE_OWNDESC(cur_tx))
122976479Swpaul			break;
123076479Swpaul
123176479Swpaul		if (cur_tx->nge_ctl & NGE_CMDSTS_MORE) {
123276479Swpaul			sc->nge_cdata.nge_tx_cnt--;
123376479Swpaul			NGE_INC(idx, NGE_TX_LIST_CNT);
123476479Swpaul			continue;
123576479Swpaul		}
123676479Swpaul
123776479Swpaul		if (!(cur_tx->nge_ctl & NGE_CMDSTS_PKT_OK)) {
123876479Swpaul			ifp->if_oerrors++;
123976479Swpaul			if (cur_tx->nge_txstat & NGE_TXSTAT_EXCESSCOLLS)
124076479Swpaul				ifp->if_collisions++;
124176479Swpaul			if (cur_tx->nge_txstat & NGE_TXSTAT_OUTOFWINCOLL)
124276479Swpaul				ifp->if_collisions++;
124376479Swpaul		}
124476479Swpaul
124576479Swpaul		ifp->if_collisions +=
124676479Swpaul		    (cur_tx->nge_txstat & NGE_TXSTAT_COLLCNT) >> 16;
124776479Swpaul
124876479Swpaul		ifp->if_opackets++;
124976479Swpaul		if (cur_tx->nge_mbuf != NULL) {
125076479Swpaul			m_freem(cur_tx->nge_mbuf);
125176479Swpaul			cur_tx->nge_mbuf = NULL;
1252148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
125376479Swpaul		}
125476479Swpaul
125576479Swpaul		sc->nge_cdata.nge_tx_cnt--;
125676479Swpaul		NGE_INC(idx, NGE_TX_LIST_CNT);
125776479Swpaul	}
125876479Swpaul
125976479Swpaul	sc->nge_cdata.nge_tx_cons = idx;
126076479Swpaul
1261128130Sru	if (idx == sc->nge_cdata.nge_tx_prod)
1262128130Sru		ifp->if_timer = 0;
126376479Swpaul
126476479Swpaul	return;
126576479Swpaul}
126676479Swpaul
126799497Salfredstatic void
1268192288Syongaringe_tick(void *xsc)
126976479Swpaul{
127076479Swpaul	struct nge_softc	*sc;
127176479Swpaul	struct mii_data		*mii;
127276479Swpaul	struct ifnet		*ifp;
127376479Swpaul
1274151296Sjhb	sc = xsc;
1275135250Swpaul	NGE_LOCK_ASSERT(sc);
1276147256Sbrooks	ifp = sc->nge_ifp;
127776479Swpaul
1278101540Sambrisko	if (sc->nge_tbi) {
1279101540Sambrisko		if (!sc->nge_link) {
1280192290Syongari			if (CSR_READ_4(sc, NGE_TBI_BMSR)
1281101540Sambrisko			    & NGE_TBIBMSR_ANEG_DONE) {
1282137402Sphk				if (bootverbose)
1283192290Syongari					device_printf(sc->nge_dev,
1284151296Sjhb					    "gigabit link up\n");
1285101540Sambrisko				nge_miibus_statchg(sc->nge_miibus);
1286101540Sambrisko				sc->nge_link++;
1287101540Sambrisko				if (ifp->if_snd.ifq_head != NULL)
1288135250Swpaul					nge_start_locked(ifp);
1289101540Sambrisko			}
129096028Sphk		}
1291101540Sambrisko	} else {
1292101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1293101540Sambrisko		mii_tick(mii);
1294101540Sambrisko
1295101540Sambrisko		if (!sc->nge_link) {
1296101540Sambrisko			if (mii->mii_media_status & IFM_ACTIVE &&
1297101540Sambrisko			    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1298101540Sambrisko				sc->nge_link++;
1299192290Syongari				if (IFM_SUBTYPE(mii->mii_media_active)
1300137402Sphk				    == IFM_1000_T && bootverbose)
1301192290Syongari					device_printf(sc->nge_dev,
1302151296Sjhb					    "gigabit link up\n");
1303101540Sambrisko				if (ifp->if_snd.ifq_head != NULL)
1304135250Swpaul					nge_start_locked(ifp);
1305101540Sambrisko			}
1306101540Sambrisko		}
130776479Swpaul	}
1308135250Swpaul	callout_reset(&sc->nge_stat_ch, hz, nge_tick, sc);
130976479Swpaul
131076479Swpaul	return;
131176479Swpaul}
131276479Swpaul
1313106507Ssimokawa#ifdef DEVICE_POLLING
1314106507Ssimokawastatic poll_handler_t nge_poll;
1315106507Ssimokawa
131699497Salfredstatic void
1317106507Ssimokawange_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1318106507Ssimokawa{
1319106507Ssimokawa	struct  nge_softc *sc = ifp->if_softc;
1320106507Ssimokawa
1321135250Swpaul	NGE_LOCK(sc);
1322150789Sglebius	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1323135250Swpaul		NGE_UNLOCK(sc);
1324106507Ssimokawa		return;
1325106507Ssimokawa	}
1326106507Ssimokawa
1327106507Ssimokawa	/*
1328106507Ssimokawa	 * On the nge, reading the status register also clears it.
1329106507Ssimokawa	 * So before returning to intr mode we must make sure that all
1330106507Ssimokawa	 * possible pending sources of interrupts have been served.
1331106507Ssimokawa	 * In practice this means run to completion the *eof routines,
1332106507Ssimokawa	 * and then call the interrupt routine
1333106507Ssimokawa	 */
1334106507Ssimokawa	sc->rxcycles = count;
1335106507Ssimokawa	nge_rxeof(sc);
1336106507Ssimokawa	nge_txeof(sc);
1337106507Ssimokawa	if (ifp->if_snd.ifq_head != NULL)
1338135250Swpaul		nge_start_locked(ifp);
1339106507Ssimokawa
1340106507Ssimokawa	if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
1341106507Ssimokawa		u_int32_t	status;
1342106507Ssimokawa
1343106507Ssimokawa		/* Reading the ISR register clears all interrupts. */
1344106507Ssimokawa		status = CSR_READ_4(sc, NGE_ISR);
1345106507Ssimokawa
1346106507Ssimokawa		if (status & (NGE_ISR_RX_ERR|NGE_ISR_RX_OFLOW))
1347106507Ssimokawa			nge_rxeof(sc);
1348106507Ssimokawa
1349106507Ssimokawa		if (status & (NGE_ISR_RX_IDLE))
1350106507Ssimokawa			NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
1351106507Ssimokawa
1352106507Ssimokawa		if (status & NGE_ISR_SYSERR) {
1353106507Ssimokawa			nge_reset(sc);
1354135250Swpaul			nge_init_locked(sc);
1355106507Ssimokawa		}
1356106507Ssimokawa	}
1357135250Swpaul	NGE_UNLOCK(sc);
1358106507Ssimokawa}
1359106507Ssimokawa#endif /* DEVICE_POLLING */
1360106507Ssimokawa
1361106507Ssimokawastatic void
1362192288Syongaringe_intr(void *arg)
136376479Swpaul{
136476479Swpaul	struct nge_softc	*sc;
136576479Swpaul	struct ifnet		*ifp;
136676479Swpaul	u_int32_t		status;
136776479Swpaul
136876479Swpaul	sc = arg;
1369147256Sbrooks	ifp = sc->nge_ifp;
137076479Swpaul
1371135250Swpaul	NGE_LOCK(sc);
1372106507Ssimokawa#ifdef DEVICE_POLLING
1373150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING) {
1374135250Swpaul		NGE_UNLOCK(sc);
1375106507Ssimokawa		return;
1376135250Swpaul	}
1377150789Sglebius#endif
1378106507Ssimokawa
137976479Swpaul	/* Supress unwanted interrupts */
138076479Swpaul	if (!(ifp->if_flags & IFF_UP)) {
138176479Swpaul		nge_stop(sc);
1382135250Swpaul		NGE_UNLOCK(sc);
138376479Swpaul		return;
138476479Swpaul	}
138576479Swpaul
138676479Swpaul	/* Disable interrupts. */
138776479Swpaul	CSR_WRITE_4(sc, NGE_IER, 0);
138876479Swpaul
1389101540Sambrisko	/* Data LED on for TBI mode */
1390101540Sambrisko	if(sc->nge_tbi)
1391101540Sambrisko		 CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1392101540Sambrisko			     | NGE_GPIO_GP3_OUT);
1393101540Sambrisko
139476479Swpaul	for (;;) {
139576479Swpaul		/* Reading the ISR register clears all interrupts. */
139676479Swpaul		status = CSR_READ_4(sc, NGE_ISR);
139776479Swpaul
139876479Swpaul		if ((status & NGE_INTRS) == 0)
139976479Swpaul			break;
140076479Swpaul
140176479Swpaul		if ((status & NGE_ISR_TX_DESC_OK) ||
140276479Swpaul		    (status & NGE_ISR_TX_ERR) ||
140376479Swpaul		    (status & NGE_ISR_TX_OK) ||
140476479Swpaul		    (status & NGE_ISR_TX_IDLE))
140576479Swpaul			nge_txeof(sc);
140676479Swpaul
140776479Swpaul		if ((status & NGE_ISR_RX_DESC_OK) ||
140879798Swpaul		    (status & NGE_ISR_RX_ERR) ||
140983678Swpaul		    (status & NGE_ISR_RX_OFLOW) ||
141094612Sphk		    (status & NGE_ISR_RX_FIFO_OFLOW) ||
141194612Sphk		    (status & NGE_ISR_RX_IDLE) ||
141276479Swpaul		    (status & NGE_ISR_RX_OK))
141376479Swpaul			nge_rxeof(sc);
141494612Sphk
141594612Sphk		if ((status & NGE_ISR_RX_IDLE))
141694612Sphk			NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
141794612Sphk
141876479Swpaul		if (status & NGE_ISR_SYSERR) {
141976479Swpaul			nge_reset(sc);
1420148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1421135250Swpaul			nge_init_locked(sc);
142276479Swpaul		}
142376479Swpaul
142496028Sphk#if 0
1425192290Syongari		/*
142696028Sphk		 * XXX: nge_tick() is not ready to be called this way
142796028Sphk		 * it screws up the aneg timeout because mii_tick() is
142896028Sphk		 * only to be called once per second.
142996028Sphk		 */
143076479Swpaul		if (status & NGE_IMR_PHY_INTR) {
143176479Swpaul			sc->nge_link = 0;
1432151296Sjhb			nge_tick(sc);
143376479Swpaul		}
143496028Sphk#endif
143576479Swpaul	}
143676479Swpaul
143776479Swpaul	/* Re-enable interrupts. */
143876479Swpaul	CSR_WRITE_4(sc, NGE_IER, 1);
143976479Swpaul
144076479Swpaul	if (ifp->if_snd.ifq_head != NULL)
1441135250Swpaul		nge_start_locked(ifp);
144276479Swpaul
1443101540Sambrisko	/* Data LED off for TBI mode */
1444101540Sambrisko
1445101540Sambrisko	if(sc->nge_tbi)
1446101540Sambrisko		CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1447101540Sambrisko			    & ~NGE_GPIO_GP3_OUT);
1448101540Sambrisko
1449135250Swpaul	NGE_UNLOCK(sc);
1450135250Swpaul
145176479Swpaul	return;
145276479Swpaul}
145376479Swpaul
145476479Swpaul/*
145576479Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
145676479Swpaul * pointers to the fragment pointers.
145776479Swpaul */
145899497Salfredstatic int
1459192288Syongaringe_encap(struct nge_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
146076479Swpaul{
146176479Swpaul	struct nge_desc		*f = NULL;
146276479Swpaul	struct mbuf		*m;
146376479Swpaul	int			frag, cur, cnt = 0;
146476479Swpaul
146576479Swpaul	/*
146676479Swpaul 	 * Start packing the mbufs in this chain into
146776479Swpaul	 * the fragment pointers. Stop when we run out
146876479Swpaul 	 * of fragments or hit the end of the mbuf chain.
146976479Swpaul	 */
147076479Swpaul	m = m_head;
147176479Swpaul	cur = frag = *txidx;
147276479Swpaul
147376479Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
147476479Swpaul		if (m->m_len != 0) {
147576479Swpaul			if ((NGE_TX_LIST_CNT -
147676479Swpaul			    (sc->nge_cdata.nge_tx_cnt + cnt)) < 2)
147776479Swpaul				return(ENOBUFS);
147876479Swpaul			f = &sc->nge_ldata->nge_tx_list[frag];
147976479Swpaul			f->nge_ctl = NGE_CMDSTS_MORE | m->m_len;
148076479Swpaul			f->nge_ptr = vtophys(mtod(m, vm_offset_t));
148176479Swpaul			if (cnt != 0)
148276479Swpaul				f->nge_ctl |= NGE_CMDSTS_OWN;
148376479Swpaul			cur = frag;
148476479Swpaul			NGE_INC(frag, NGE_TX_LIST_CNT);
148576479Swpaul			cnt++;
148676479Swpaul		}
148776479Swpaul	}
148876479Swpaul
148976479Swpaul	if (m != NULL)
149076479Swpaul		return(ENOBUFS);
149176479Swpaul
149278286Swpaul	sc->nge_ldata->nge_tx_list[*txidx].nge_extsts = 0;
149376479Swpaul	if (m_head->m_pkthdr.csum_flags) {
149476479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_IP)
149578286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
149676479Swpaul			    NGE_TXEXTSTS_IPCSUM;
149776479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_TCP)
149878286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
149976479Swpaul			    NGE_TXEXTSTS_TCPCSUM;
150076479Swpaul		if (m_head->m_pkthdr.csum_flags & CSUM_UDP)
150178286Swpaul			sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
150276479Swpaul			    NGE_TXEXTSTS_UDPCSUM;
150376479Swpaul	}
150476479Swpaul
1505162375Sandre	if (m_head->m_flags & M_VLANTAG) {
150676479Swpaul		sc->nge_ldata->nge_tx_list[cur].nge_extsts |=
1507162375Sandre		    (NGE_TXEXTSTS_VLANPKT|htons(m_head->m_pkthdr.ether_vtag));
150876479Swpaul	}
150976479Swpaul
151076479Swpaul	sc->nge_ldata->nge_tx_list[cur].nge_mbuf = m_head;
151176479Swpaul	sc->nge_ldata->nge_tx_list[cur].nge_ctl &= ~NGE_CMDSTS_MORE;
151276479Swpaul	sc->nge_ldata->nge_tx_list[*txidx].nge_ctl |= NGE_CMDSTS_OWN;
151376479Swpaul	sc->nge_cdata.nge_tx_cnt += cnt;
151476479Swpaul	*txidx = frag;
151576479Swpaul
151676479Swpaul	return(0);
151776479Swpaul}
151876479Swpaul
151976479Swpaul/*
152076479Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
152176479Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
152276479Swpaul * copy of the pointers since the transmit list fragment pointers are
152376479Swpaul * physical addresses.
152476479Swpaul */
152576479Swpaul
152699497Salfredstatic void
1527192288Syongaringe_start(struct ifnet *ifp)
152876479Swpaul{
152976479Swpaul	struct nge_softc	*sc;
1530135250Swpaul
1531135250Swpaul	sc = ifp->if_softc;
1532135250Swpaul	NGE_LOCK(sc);
1533135250Swpaul	nge_start_locked(ifp);
1534135250Swpaul	NGE_UNLOCK(sc);
1535135250Swpaul}
1536135250Swpaul
1537135250Swpaulstatic void
1538192288Syongaringe_start_locked(struct ifnet *ifp)
1539135250Swpaul{
1540135250Swpaul	struct nge_softc	*sc;
154176479Swpaul	struct mbuf		*m_head = NULL;
154276479Swpaul	u_int32_t		idx;
154376479Swpaul
154476479Swpaul	sc = ifp->if_softc;
154576479Swpaul
154676479Swpaul	if (!sc->nge_link)
154776479Swpaul		return;
154876479Swpaul
154976479Swpaul	idx = sc->nge_cdata.nge_tx_prod;
155076479Swpaul
1551148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
155276479Swpaul		return;
155376479Swpaul
155476479Swpaul	while(sc->nge_ldata->nge_tx_list[idx].nge_mbuf == NULL) {
155576479Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
155676479Swpaul		if (m_head == NULL)
155776479Swpaul			break;
155876479Swpaul
155976479Swpaul		if (nge_encap(sc, m_head, &idx)) {
156076479Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1561148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
156276479Swpaul			break;
156376479Swpaul		}
156476479Swpaul
156576479Swpaul		/*
156676479Swpaul		 * If there's a BPF listener, bounce a copy of this frame
156776479Swpaul		 * to him.
156876479Swpaul		 */
1569167190Scsjp		ETHER_BPF_MTAP(ifp, m_head);
157076479Swpaul
157176479Swpaul	}
157276479Swpaul
157376479Swpaul	/* Transmit */
157476479Swpaul	sc->nge_cdata.nge_tx_prod = idx;
157576479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_ENABLE);
157676479Swpaul
157776479Swpaul	/*
157876479Swpaul	 * Set a timeout in case the chip goes out to lunch.
157976479Swpaul	 */
158076479Swpaul	ifp->if_timer = 5;
158176479Swpaul
158276479Swpaul	return;
158376479Swpaul}
158476479Swpaul
158599497Salfredstatic void
1586192288Syongaringe_init(void *xsc)
158776479Swpaul{
158876479Swpaul	struct nge_softc	*sc = xsc;
1589135250Swpaul
1590135250Swpaul	NGE_LOCK(sc);
1591135250Swpaul	nge_init_locked(sc);
1592135250Swpaul	NGE_UNLOCK(sc);
1593135250Swpaul}
1594135250Swpaul
1595135250Swpaulstatic void
1596192288Syongaringe_init_locked(struct nge_softc *sc)
1597135250Swpaul{
1598147256Sbrooks	struct ifnet		*ifp = sc->nge_ifp;
159976479Swpaul	struct mii_data		*mii;
160076479Swpaul
1601135250Swpaul	NGE_LOCK_ASSERT(sc);
1602135250Swpaul
1603148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
160476479Swpaul		return;
160576479Swpaul
160676479Swpaul	/*
160776479Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
160876479Swpaul	 */
160976479Swpaul	nge_stop(sc);
161076479Swpaul
1611101540Sambrisko	if (sc->nge_tbi) {
1612101540Sambrisko		mii = NULL;
1613101540Sambrisko	} else {
1614101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1615101540Sambrisko	}
161676479Swpaul
161776479Swpaul	/* Set MAC address */
161876479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0);
161976479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1620152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[0]);
162176479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR1);
162276479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1623152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[1]);
162476479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR2);
162576479Swpaul	CSR_WRITE_4(sc, NGE_RXFILT_DATA,
1626152315Sru	    ((u_int16_t *)IF_LLADDR(sc->nge_ifp))[2]);
162776479Swpaul
162876479Swpaul	/* Init circular RX list. */
162976479Swpaul	if (nge_list_rx_init(sc) == ENOBUFS) {
1630162321Sglebius		device_printf(sc->nge_dev, "initialization failed: no "
1631151296Sjhb			"memory for rx buffers\n");
163276479Swpaul		nge_stop(sc);
163376479Swpaul		return;
163476479Swpaul	}
163576479Swpaul
163676479Swpaul	/*
163776479Swpaul	 * Init tx descriptors.
163876479Swpaul	 */
163976479Swpaul	nge_list_tx_init(sc);
164076479Swpaul
164176479Swpaul	/*
164276479Swpaul	 * For the NatSemi chip, we have to explicitly enable the
164376479Swpaul	 * reception of ARP frames, as well as turn on the 'perfect
164476479Swpaul	 * match' filter where we store the station address, otherwise
164576479Swpaul	 * we won't receive unicasts meant for this host.
164676479Swpaul	 */
164776479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ARP);
164876479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_PERFECT);
164976479Swpaul
165076479Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
165176479Swpaul	if (ifp->if_flags & IFF_PROMISC) {
165276479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS);
165376479Swpaul	} else {
165476479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ALLPHYS);
165576479Swpaul	}
165676479Swpaul
165776479Swpaul	/*
165876479Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
165976479Swpaul	 */
166076479Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
166176479Swpaul		NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD);
166276479Swpaul	} else {
166376479Swpaul		NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_BROAD);
166476479Swpaul	}
166576479Swpaul
166676479Swpaul	/*
166776479Swpaul	 * Load the multicast filter.
166876479Swpaul	 */
166976479Swpaul	nge_setmulti(sc);
167076479Swpaul
167176479Swpaul	/* Turn the receive filter on */
167276479Swpaul	NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE);
167376479Swpaul
167476479Swpaul	/*
167576479Swpaul	 * Load the address of the RX and TX lists.
167676479Swpaul	 */
167776479Swpaul	CSR_WRITE_4(sc, NGE_RX_LISTPTR,
167876479Swpaul	    vtophys(&sc->nge_ldata->nge_rx_list[0]));
167976479Swpaul	CSR_WRITE_4(sc, NGE_TX_LISTPTR,
168076479Swpaul	    vtophys(&sc->nge_ldata->nge_tx_list[0]));
168176479Swpaul
168276479Swpaul	/* Set RX configuration */
168376479Swpaul	CSR_WRITE_4(sc, NGE_RX_CFG, NGE_RXCFG);
168476479Swpaul	/*
168576479Swpaul	 * Enable hardware checksum validation for all IPv4
168676479Swpaul	 * packets, do not reject packets with bad checksums.
168776479Swpaul	 */
168878323Swpaul	CSR_WRITE_4(sc, NGE_VLAN_IP_RXCTL, NGE_VIPRXCTL_IPCSUM_ENB);
168976479Swpaul
169076479Swpaul	/*
169183115Sbrooks	 * Tell the chip to detect and strip VLAN tag info from
169283115Sbrooks	 * received frames. The tag will be provided in the extsts
169383115Sbrooks	 * field in the RX descriptors.
169476479Swpaul	 */
169576479Swpaul	NGE_SETBIT(sc, NGE_VLAN_IP_RXCTL,
169676479Swpaul	    NGE_VIPRXCTL_TAG_DETECT_ENB|NGE_VIPRXCTL_TAG_STRIP_ENB);
169776479Swpaul
169876479Swpaul	/* Set TX configuration */
169976479Swpaul	CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG);
170076479Swpaul
170176479Swpaul	/*
170276479Swpaul	 * Enable TX IPv4 checksumming on a per-packet basis.
170376479Swpaul	 */
170478323Swpaul	CSR_WRITE_4(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_CSUM_PER_PKT);
170576479Swpaul
170676479Swpaul	/*
170783115Sbrooks	 * Tell the chip to insert VLAN tags on a per-packet basis as
170883115Sbrooks	 * dictated by the code in the frame encapsulation routine.
170976479Swpaul	 */
171076479Swpaul	NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT);
171176479Swpaul
171276479Swpaul	/* Set full/half duplex mode. */
1713101540Sambrisko	if (sc->nge_tbi) {
1714192290Syongari		if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
1715101540Sambrisko		    == IFM_FDX) {
1716101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1717101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1718101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1719101540Sambrisko		} else {
1720101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1721101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1722101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1723101540Sambrisko		}
172476479Swpaul	} else {
1725101540Sambrisko		if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
1726101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1727101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1728101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1729101540Sambrisko		} else {
1730101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1731101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1732101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1733101540Sambrisko		}
173476479Swpaul	}
173576479Swpaul
1736151296Sjhb	nge_tick(sc);
173796028Sphk
173876479Swpaul	/*
173976479Swpaul	 * Enable the delivery of PHY interrupts based on
174077842Swpaul	 * link/speed/duplex status changes. Also enable the
174177842Swpaul	 * extsts field in the DMA descriptors (needed for
174277842Swpaul	 * TCP/IP checksum offload on transmit).
174376479Swpaul	 */
174479424Swpaul	NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD|
174577842Swpaul	    NGE_CFG_PHYINTR_LNK|NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB);
174676479Swpaul
174776479Swpaul	/*
174879562Swpaul	 * Configure interrupt holdoff (moderation). We can
174979562Swpaul	 * have the chip delay interrupt delivery for a certain
175079562Swpaul	 * period. Units are in 100us, and the max setting
175179562Swpaul	 * is 25500us (0xFF x 100us). Default is a 100us holdoff.
175279562Swpaul	 */
175379562Swpaul	CSR_WRITE_4(sc, NGE_IHR, 0x01);
175479562Swpaul
175579562Swpaul	/*
175676479Swpaul	 * Enable interrupts.
175776479Swpaul	 */
175876479Swpaul	CSR_WRITE_4(sc, NGE_IMR, NGE_INTRS);
1759106507Ssimokawa#ifdef DEVICE_POLLING
1760106507Ssimokawa	/*
1761106507Ssimokawa	 * ... only enable interrupts if we are not polling, make sure
1762106507Ssimokawa	 * they are off otherwise.
1763106507Ssimokawa	 */
1764150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1765106507Ssimokawa		CSR_WRITE_4(sc, NGE_IER, 0);
1766106507Ssimokawa	else
1767150789Sglebius#endif
176876479Swpaul	CSR_WRITE_4(sc, NGE_IER, 1);
176976479Swpaul
177076479Swpaul	/* Enable receiver and transmitter. */
177176479Swpaul	NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
177276479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
177376479Swpaul
1774151296Sjhb	nge_ifmedia_upd_locked(ifp);
177576479Swpaul
1776148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1777148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
177876479Swpaul
177976479Swpaul	return;
178076479Swpaul}
178176479Swpaul
178276479Swpaul/*
178376479Swpaul * Set media options.
178476479Swpaul */
178599497Salfredstatic int
1786192288Syongaringe_ifmedia_upd(struct ifnet *ifp)
178776479Swpaul{
178876479Swpaul	struct nge_softc	*sc;
1789151296Sjhb
1790151296Sjhb	sc = ifp->if_softc;
1791151296Sjhb	NGE_LOCK(sc);
1792151296Sjhb	nge_ifmedia_upd_locked(ifp);
1793151296Sjhb	NGE_UNLOCK(sc);
1794151296Sjhb	return (0);
1795151296Sjhb}
1796151296Sjhb
1797151296Sjhbstatic void
1798192288Syongaringe_ifmedia_upd_locked(struct ifnet *ifp)
1799151296Sjhb{
1800151296Sjhb	struct nge_softc	*sc;
180176479Swpaul	struct mii_data		*mii;
180276479Swpaul
180376479Swpaul	sc = ifp->if_softc;
1804151296Sjhb	NGE_LOCK_ASSERT(sc);
180576479Swpaul
1806101540Sambrisko	if (sc->nge_tbi) {
1807192290Syongari		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
1808101540Sambrisko		     == IFM_AUTO) {
1809192290Syongari			CSR_WRITE_4(sc, NGE_TBI_ANAR,
1810101540Sambrisko				CSR_READ_4(sc, NGE_TBI_ANAR)
1811101540Sambrisko					| NGE_TBIANAR_HDX | NGE_TBIANAR_FDX
1812101540Sambrisko					| NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2);
1813101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG
1814101540Sambrisko				| NGE_TBIBMCR_RESTART_ANEG);
1815101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG);
1816192290Syongari		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media
1817101540Sambrisko			    & IFM_GMASK) == IFM_FDX) {
1818101540Sambrisko			NGE_SETBIT(sc, NGE_TX_CFG,
1819101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1820101540Sambrisko			NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1821101540Sambrisko
1822101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
1823101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
1824101540Sambrisko		} else {
1825101540Sambrisko			NGE_CLRBIT(sc, NGE_TX_CFG,
1826101540Sambrisko			    (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
1827101540Sambrisko			NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
1828101540Sambrisko
1829101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
1830101540Sambrisko			CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
1831101540Sambrisko		}
1832192290Syongari
1833101540Sambrisko		CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
1834101540Sambrisko			    & ~NGE_GPIO_GP3_OUT);
1835101540Sambrisko	} else {
1836101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1837101540Sambrisko		sc->nge_link = 0;
1838101540Sambrisko		if (mii->mii_instance) {
1839101540Sambrisko			struct mii_softc	*miisc;
1840151296Sjhb
1841151296Sjhb			LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1842101540Sambrisko				mii_phy_reset(miisc);
1843101540Sambrisko		}
1844101540Sambrisko		mii_mediachg(mii);
184576479Swpaul	}
184676479Swpaul}
184776479Swpaul
184876479Swpaul/*
184976479Swpaul * Report current media status.
185076479Swpaul */
185199497Salfredstatic void
1852192288Syongaringe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
185376479Swpaul{
185476479Swpaul	struct nge_softc	*sc;
185576479Swpaul	struct mii_data		*mii;
185676479Swpaul
185776479Swpaul	sc = ifp->if_softc;
185876479Swpaul
1859151296Sjhb	NGE_LOCK(sc);
1860101540Sambrisko	if (sc->nge_tbi) {
1861101540Sambrisko		ifmr->ifm_status = IFM_AVALID;
1862101540Sambrisko		ifmr->ifm_active = IFM_ETHER;
186376479Swpaul
1864101540Sambrisko		if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
1865101540Sambrisko			ifmr->ifm_status |= IFM_ACTIVE;
1866192290Syongari		}
1867101540Sambrisko		if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK)
1868101540Sambrisko			ifmr->ifm_active |= IFM_LOOP;
1869101540Sambrisko		if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
1870101540Sambrisko			ifmr->ifm_active |= IFM_NONE;
1871101540Sambrisko			ifmr->ifm_status = 0;
1872151296Sjhb			NGE_UNLOCK(sc);
1873101540Sambrisko			return;
1874192290Syongari		}
1875101540Sambrisko		ifmr->ifm_active |= IFM_1000_SX;
1876101540Sambrisko		if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
1877101540Sambrisko		    == IFM_AUTO) {
1878101540Sambrisko			ifmr->ifm_active |= IFM_AUTO;
1879101540Sambrisko			if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
1880101540Sambrisko			    & NGE_TBIANAR_FDX) {
1881101540Sambrisko				ifmr->ifm_active |= IFM_FDX;
1882101540Sambrisko			}else if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
1883101540Sambrisko				  & NGE_TBIANAR_HDX) {
1884101540Sambrisko				ifmr->ifm_active |= IFM_HDX;
1885101540Sambrisko			}
1886192290Syongari		} else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
1887101540Sambrisko			== IFM_FDX)
1888101540Sambrisko			ifmr->ifm_active |= IFM_FDX;
1889101540Sambrisko		else
1890101540Sambrisko			ifmr->ifm_active |= IFM_HDX;
1891192290Syongari
1892101540Sambrisko	} else {
1893101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
1894101540Sambrisko		mii_pollstat(mii);
1895101540Sambrisko		ifmr->ifm_active = mii->mii_media_active;
1896101540Sambrisko		ifmr->ifm_status = mii->mii_media_status;
1897101540Sambrisko	}
1898151296Sjhb	NGE_UNLOCK(sc);
1899101540Sambrisko
190076479Swpaul	return;
190176479Swpaul}
190276479Swpaul
190399497Salfredstatic int
1904192288Syongaringe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
190576479Swpaul{
190676479Swpaul	struct nge_softc	*sc = ifp->if_softc;
190776479Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
190876479Swpaul	struct mii_data		*mii;
1909135250Swpaul	int			error = 0;
191076479Swpaul
191176479Swpaul	switch(command) {
191276479Swpaul	case SIOCSIFMTU:
191376479Swpaul		if (ifr->ifr_mtu > NGE_JUMBO_MTU)
191476479Swpaul			error = EINVAL;
191578323Swpaul		else {
1916151296Sjhb			NGE_LOCK(sc);
191776479Swpaul			ifp->if_mtu = ifr->ifr_mtu;
191878323Swpaul			/*
191978323Swpaul			 * Workaround: if the MTU is larger than
192078323Swpaul			 * 8152 (TX FIFO size minus 64 minus 18), turn off
192178323Swpaul			 * TX checksum offloading.
192278323Swpaul			 */
1923129632Syar			if (ifr->ifr_mtu >= 8152) {
1924129632Syar				ifp->if_capenable &= ~IFCAP_TXCSUM;
192578323Swpaul				ifp->if_hwassist = 0;
1926129632Syar			} else {
1927129632Syar				ifp->if_capenable |= IFCAP_TXCSUM;
192878323Swpaul				ifp->if_hwassist = NGE_CSUM_FEATURES;
1929129632Syar			}
1930151296Sjhb			NGE_UNLOCK(sc);
193178323Swpaul		}
193276479Swpaul		break;
193376479Swpaul	case SIOCSIFFLAGS:
1934135250Swpaul		NGE_LOCK(sc);
193576479Swpaul		if (ifp->if_flags & IFF_UP) {
1936148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
193776479Swpaul			    ifp->if_flags & IFF_PROMISC &&
193876479Swpaul			    !(sc->nge_if_flags & IFF_PROMISC)) {
193976479Swpaul				NGE_SETBIT(sc, NGE_RXFILT_CTL,
194076479Swpaul				    NGE_RXFILTCTL_ALLPHYS|
194176479Swpaul				    NGE_RXFILTCTL_ALLMULTI);
1942148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
194376479Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
194476479Swpaul			    sc->nge_if_flags & IFF_PROMISC) {
194576479Swpaul				NGE_CLRBIT(sc, NGE_RXFILT_CTL,
194676479Swpaul				    NGE_RXFILTCTL_ALLPHYS);
194776479Swpaul				if (!(ifp->if_flags & IFF_ALLMULTI))
194876479Swpaul					NGE_CLRBIT(sc, NGE_RXFILT_CTL,
194976479Swpaul					    NGE_RXFILTCTL_ALLMULTI);
195076479Swpaul			} else {
1951148887Srwatson				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1952135250Swpaul				nge_init_locked(sc);
195376479Swpaul			}
195476479Swpaul		} else {
1955148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
195676479Swpaul				nge_stop(sc);
195776479Swpaul		}
195876479Swpaul		sc->nge_if_flags = ifp->if_flags;
1959135250Swpaul		NGE_UNLOCK(sc);
196076479Swpaul		error = 0;
196176479Swpaul		break;
196276479Swpaul	case SIOCADDMULTI:
196376479Swpaul	case SIOCDELMULTI:
1964135250Swpaul		NGE_LOCK(sc);
196576479Swpaul		nge_setmulti(sc);
1966135250Swpaul		NGE_UNLOCK(sc);
196776479Swpaul		error = 0;
196876479Swpaul		break;
196976479Swpaul	case SIOCGIFMEDIA:
197076479Swpaul	case SIOCSIFMEDIA:
1971101540Sambrisko		if (sc->nge_tbi) {
1972192290Syongari			error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia,
1973101540Sambrisko					      command);
1974101540Sambrisko		} else {
1975101540Sambrisko			mii = device_get_softc(sc->nge_miibus);
1976192290Syongari			error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
1977101540Sambrisko					      command);
1978101540Sambrisko		}
197976479Swpaul		break;
1980128132Sru	case SIOCSIFCAP:
1981150789Sglebius#ifdef DEVICE_POLLING
1982150789Sglebius		if (ifr->ifr_reqcap & IFCAP_POLLING &&
1983150789Sglebius		    !(ifp->if_capenable & IFCAP_POLLING)) {
1984150789Sglebius			error = ether_poll_register(nge_poll, ifp);
1985150789Sglebius			if (error)
1986150789Sglebius				return(error);
1987150789Sglebius			NGE_LOCK(sc);
1988150789Sglebius			/* Disable interrupts */
1989150789Sglebius			CSR_WRITE_4(sc, NGE_IER, 0);
1990150789Sglebius			ifp->if_capenable |= IFCAP_POLLING;
1991150789Sglebius			NGE_UNLOCK(sc);
1992150789Sglebius			return (error);
1993192290Syongari
1994150789Sglebius		}
1995150789Sglebius		if (!(ifr->ifr_reqcap & IFCAP_POLLING) &&
1996150789Sglebius		    ifp->if_capenable & IFCAP_POLLING) {
1997150789Sglebius			error = ether_poll_deregister(ifp);
1998150789Sglebius			/* Enable interrupts. */
1999150789Sglebius			NGE_LOCK(sc);
2000150789Sglebius			CSR_WRITE_4(sc, NGE_IER, 1);
2001150789Sglebius			ifp->if_capenable &= ~IFCAP_POLLING;
2002150789Sglebius			NGE_UNLOCK(sc);
2003150789Sglebius			return (error);
2004150789Sglebius		}
2005150789Sglebius#endif /* DEVICE_POLLING */
2006128132Sru		break;
200776479Swpaul	default:
2008106937Ssam		error = ether_ioctl(ifp, command, data);
200976479Swpaul		break;
201076479Swpaul	}
201176479Swpaul
201276479Swpaul	return(error);
201376479Swpaul}
201476479Swpaul
201599497Salfredstatic void
2016192288Syongaringe_watchdog(struct ifnet *ifp)
201776479Swpaul{
201876479Swpaul	struct nge_softc	*sc;
201976479Swpaul
202076479Swpaul	sc = ifp->if_softc;
202176479Swpaul
202276479Swpaul	ifp->if_oerrors++;
2023162321Sglebius	if_printf(ifp, "watchdog timeout\n");
202476479Swpaul
2025135250Swpaul	NGE_LOCK(sc);
202676479Swpaul	nge_stop(sc);
202776479Swpaul	nge_reset(sc);
2028148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2029135250Swpaul	nge_init_locked(sc);
203076479Swpaul
203176479Swpaul	if (ifp->if_snd.ifq_head != NULL)
2032135250Swpaul		nge_start_locked(ifp);
203376479Swpaul
2034135250Swpaul	NGE_UNLOCK(sc);
2035135250Swpaul
203676479Swpaul	return;
203776479Swpaul}
203876479Swpaul
203976479Swpaul/*
204076479Swpaul * Stop the adapter and free any mbufs allocated to the
204176479Swpaul * RX and TX lists.
204276479Swpaul */
204399497Salfredstatic void
2044192288Syongaringe_stop(struct nge_softc *sc)
204576479Swpaul{
2046192289Syongari	int			i;
204776479Swpaul	struct ifnet		*ifp;
204876479Swpaul	struct mii_data		*mii;
204976479Swpaul
2050135250Swpaul	NGE_LOCK_ASSERT(sc);
2051147256Sbrooks	ifp = sc->nge_ifp;
205276479Swpaul	ifp->if_timer = 0;
2053101540Sambrisko	if (sc->nge_tbi) {
2054101540Sambrisko		mii = NULL;
2055101540Sambrisko	} else {
2056101540Sambrisko		mii = device_get_softc(sc->nge_miibus);
2057101540Sambrisko	}
205876479Swpaul
2059135250Swpaul	callout_stop(&sc->nge_stat_ch);
206076479Swpaul	CSR_WRITE_4(sc, NGE_IER, 0);
206176479Swpaul	CSR_WRITE_4(sc, NGE_IMR, 0);
206276479Swpaul	NGE_SETBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
206376479Swpaul	DELAY(1000);
206476479Swpaul	CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0);
206576479Swpaul	CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0);
206676479Swpaul
2067101540Sambrisko	if (!sc->nge_tbi)
2068101540Sambrisko		mii_down(mii);
206976479Swpaul
207076479Swpaul	sc->nge_link = 0;
207176479Swpaul
207276479Swpaul	/*
207376479Swpaul	 * Free data in the RX lists.
207476479Swpaul	 */
207576479Swpaul	for (i = 0; i < NGE_RX_LIST_CNT; i++) {
207676479Swpaul		if (sc->nge_ldata->nge_rx_list[i].nge_mbuf != NULL) {
207776479Swpaul			m_freem(sc->nge_ldata->nge_rx_list[i].nge_mbuf);
207876479Swpaul			sc->nge_ldata->nge_rx_list[i].nge_mbuf = NULL;
207976479Swpaul		}
208076479Swpaul	}
208176479Swpaul	bzero((char *)&sc->nge_ldata->nge_rx_list,
208276479Swpaul		sizeof(sc->nge_ldata->nge_rx_list));
208376479Swpaul
208476479Swpaul	/*
208576479Swpaul	 * Free the TX list buffers.
208676479Swpaul	 */
208776479Swpaul	for (i = 0; i < NGE_TX_LIST_CNT; i++) {
208876479Swpaul		if (sc->nge_ldata->nge_tx_list[i].nge_mbuf != NULL) {
208976479Swpaul			m_freem(sc->nge_ldata->nge_tx_list[i].nge_mbuf);
209076479Swpaul			sc->nge_ldata->nge_tx_list[i].nge_mbuf = NULL;
209176479Swpaul		}
209276479Swpaul	}
209376479Swpaul
209476479Swpaul	bzero((char *)&sc->nge_ldata->nge_tx_list,
209576479Swpaul		sizeof(sc->nge_ldata->nge_tx_list));
209676479Swpaul
2097148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
209876479Swpaul
209976479Swpaul	return;
210076479Swpaul}
210176479Swpaul
210276479Swpaul/*
210376479Swpaul * Stop all chip I/O so that the kernel's probe routines don't
210476479Swpaul * get confused by errant DMAs when rebooting.
210576479Swpaul */
2106173839Syongaristatic int
2107192288Syongaringe_shutdown(device_t dev)
210876479Swpaul{
210976479Swpaul	struct nge_softc	*sc;
211076479Swpaul
211176479Swpaul	sc = device_get_softc(dev);
211276479Swpaul
2113135250Swpaul	NGE_LOCK(sc);
211476479Swpaul	nge_reset(sc);
211576479Swpaul	nge_stop(sc);
2116135250Swpaul	NGE_UNLOCK(sc);
211776479Swpaul
2118173839Syongari	return (0);
211976479Swpaul}
2120