1139749Simp/*-
277542Swpaul * Copyright (c) 2001 Wind River Systems
377542Swpaul * Copyright (c) 1997, 1998, 1999, 2000, 2001
477542Swpaul *	Bill Paul <william.paul@windriver.com>.  All rights reserved.
577542Swpaul *
677542Swpaul * Redistribution and use in source and binary forms, with or without
777542Swpaul * modification, are permitted provided that the following conditions
877542Swpaul * are met:
977542Swpaul * 1. Redistributions of source code must retain the above copyright
1077542Swpaul *    notice, this list of conditions and the following disclaimer.
1177542Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1277542Swpaul *    notice, this list of conditions and the following disclaimer in the
1377542Swpaul *    documentation and/or other materials provided with the distribution.
1477542Swpaul * 3. All advertising materials mentioning features or use of this software
1577542Swpaul *    must display the following acknowledgement:
1677542Swpaul *	This product includes software developed by Bill Paul.
1777542Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1877542Swpaul *    may be used to endorse or promote products derived from this software
1977542Swpaul *    without specific prior written permission.
2077542Swpaul *
2177542Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2277542Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2377542Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2477542Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2577542Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2677542Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2777542Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2877542Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2977542Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3077542Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3177542Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3277542Swpaul */
3377542Swpaul
34119418Sobrien#include <sys/cdefs.h>
35119418Sobrien__FBSDID("$FreeBSD$");
36119418Sobrien
3777542Swpaul/*
3877542Swpaul * Level 1 LXT1001 gigabit ethernet driver for FreeBSD. Public
3977542Swpaul * documentation not available, but ask me nicely.
4077542Swpaul *
4177542Swpaul * The Level 1 chip is used on some D-Link, SMC and Addtron NICs.
4277542Swpaul * It's a 64-bit PCI part that supports TCP/IP checksum offload,
4377542Swpaul * VLAN tagging/insertion, GMII and TBI (1000baseX) ports. There
4477542Swpaul * are three supported methods for data transfer between host and
4577542Swpaul * NIC: programmed I/O, traditional scatter/gather DMA and Packet
4677542Swpaul * Propulsion Technology (tm) DMA. The latter mechanism is a form
4777542Swpaul * of double buffer DMA where the packet data is copied to a
4877542Swpaul * pre-allocated DMA buffer who's physical address has been loaded
4977542Swpaul * into a table at device initialization time. The rationale is that
5077542Swpaul * the virtual to physical address translation needed for normal
5177542Swpaul * scatter/gather DMA is more expensive than the data copy needed
5277542Swpaul * for double buffering. This may be true in Windows NT and the like,
5377542Swpaul * but it isn't true for us, at least on the x86 arch. This driver
5477542Swpaul * uses the scatter/gather I/O method for both TX and RX.
5577542Swpaul *
5677542Swpaul * The LXT1001 only supports TCP/IP checksum offload on receive.
5777542Swpaul * Also, the VLAN tagging is done using a 16-entry table which allows
5877542Swpaul * the chip to perform hardware filtering based on VLAN tags. Sadly,
5977542Swpaul * our vlan support doesn't currently play well with this kind of
6077542Swpaul * hardware support.
6177542Swpaul *
6277542Swpaul * Special thanks to:
6377542Swpaul * - Jeff James at Intel, for arranging to have the LXT1001 manual
6477542Swpaul *   released (at long last)
6577542Swpaul * - Beny Chen at D-Link, for actually sending it to me
6677542Swpaul * - Brad Short and Keith Alexis at SMC, for sending me sample
6777542Swpaul *   SMC9462SX and SMC9462TX adapters for testing
6877542Swpaul * - Paul Saab at Y!, for not killing me (though it remains to be seen
6977542Swpaul *   if in fact he did me much of a favor)
7077542Swpaul */
7177542Swpaul
7277542Swpaul#include <sys/param.h>
7377542Swpaul#include <sys/systm.h>
7477542Swpaul#include <sys/sockio.h>
7577542Swpaul#include <sys/mbuf.h>
7677542Swpaul#include <sys/malloc.h>
7777542Swpaul#include <sys/kernel.h>
78129879Sphk#include <sys/module.h>
7977542Swpaul#include <sys/socket.h>
8077542Swpaul
8177542Swpaul#include <net/if.h>
8277542Swpaul#include <net/if_arp.h>
8377542Swpaul#include <net/ethernet.h>
8477542Swpaul#include <net/if_dl.h>
8577542Swpaul#include <net/if_media.h>
86147256Sbrooks#include <net/if_types.h>
8777542Swpaul
8877542Swpaul#include <net/bpf.h>
8977542Swpaul
9077542Swpaul#include <vm/vm.h>              /* for vtophys */
9177542Swpaul#include <vm/pmap.h>            /* for vtophys */
9277542Swpaul#include <machine/bus.h>
9377542Swpaul#include <machine/resource.h>
9477542Swpaul#include <sys/bus.h>
9577542Swpaul#include <sys/rman.h>
9677542Swpaul
9777542Swpaul#include <dev/mii/mii.h>
9877542Swpaul#include <dev/mii/miivar.h>
9977542Swpaul
100119291Simp#include <dev/pci/pcireg.h>
101119291Simp#include <dev/pci/pcivar.h>
10277542Swpaul
10377542Swpaul#define LGE_USEIOSPACE
10477542Swpaul
10577542Swpaul#include <dev/lge/if_lgereg.h>
10677542Swpaul
107151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
10877542Swpaul#include "miibus_if.h"
10977542Swpaul
11077542Swpaul/*
11177542Swpaul * Various supported device vendors/types and their names.
11277542Swpaul */
113242908Sdimstatic const struct lge_type lge_devs[] = {
11477542Swpaul	{ LGE_VENDORID, LGE_DEVICEID, "Level 1 Gigabit Ethernet" },
11577542Swpaul	{ 0, 0, NULL }
11677542Swpaul};
11777542Swpaul
11899498Salfredstatic int lge_probe(device_t);
11999498Salfredstatic int lge_attach(device_t);
12099498Salfredstatic int lge_detach(device_t);
12177542Swpaul
12299498Salfredstatic int lge_alloc_jumbo_mem(struct lge_softc *);
12399498Salfredstatic void lge_free_jumbo_mem(struct lge_softc *);
12499498Salfredstatic void *lge_jalloc(struct lge_softc *);
12599498Salfredstatic void lge_jfree(void *, void *);
12677542Swpaul
12799498Salfredstatic int lge_newbuf(struct lge_softc *, struct lge_rx_desc *, struct mbuf *);
12899498Salfredstatic int lge_encap(struct lge_softc *, struct mbuf *, u_int32_t *);
12999498Salfredstatic void lge_rxeof(struct lge_softc *, int);
13099498Salfredstatic void lge_rxeoc(struct lge_softc *);
13199498Salfredstatic void lge_txeof(struct lge_softc *);
13299498Salfredstatic void lge_intr(void *);
13399498Salfredstatic void lge_tick(void *);
13499498Salfredstatic void lge_start(struct ifnet *);
135152727Sjhbstatic void lge_start_locked(struct ifnet *);
13699498Salfredstatic int lge_ioctl(struct ifnet *, u_long, caddr_t);
13799498Salfredstatic void lge_init(void *);
138152727Sjhbstatic void lge_init_locked(struct lge_softc *);
13999498Salfredstatic void lge_stop(struct lge_softc *);
140199560Sjhbstatic void lge_watchdog(struct lge_softc *);
141173839Syongaristatic int lge_shutdown(device_t);
14299498Salfredstatic int lge_ifmedia_upd(struct ifnet *);
143152727Sjhbstatic void lge_ifmedia_upd_locked(struct ifnet *);
14499498Salfredstatic void lge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
14577542Swpaul
14699498Salfredstatic void lge_eeprom_getword(struct lge_softc *, int, u_int16_t *);
14799498Salfredstatic void lge_read_eeprom(struct lge_softc *, caddr_t, int, int, int);
14877542Swpaul
14999498Salfredstatic int lge_miibus_readreg(device_t, int, int);
15099498Salfredstatic int lge_miibus_writereg(device_t, int, int, int);
15199498Salfredstatic void lge_miibus_statchg(device_t);
15277542Swpaul
15399498Salfredstatic void lge_setmulti(struct lge_softc *);
15499498Salfredstatic void lge_reset(struct lge_softc *);
15599498Salfredstatic int lge_list_rx_init(struct lge_softc *);
15699498Salfredstatic int lge_list_tx_init(struct lge_softc *);
15777542Swpaul
15877542Swpaul#ifdef LGE_USEIOSPACE
15977542Swpaul#define LGE_RES			SYS_RES_IOPORT
16077542Swpaul#define LGE_RID			LGE_PCI_LOIO
16177542Swpaul#else
16277542Swpaul#define LGE_RES			SYS_RES_MEMORY
16377542Swpaul#define LGE_RID			LGE_PCI_LOMEM
16477542Swpaul#endif
16577542Swpaul
16677542Swpaulstatic device_method_t lge_methods[] = {
16777542Swpaul	/* Device interface */
16877542Swpaul	DEVMETHOD(device_probe,		lge_probe),
16977542Swpaul	DEVMETHOD(device_attach,	lge_attach),
17077542Swpaul	DEVMETHOD(device_detach,	lge_detach),
17177542Swpaul	DEVMETHOD(device_shutdown,	lge_shutdown),
17277542Swpaul
17377542Swpaul	/* MII interface */
17477542Swpaul	DEVMETHOD(miibus_readreg,	lge_miibus_readreg),
17577542Swpaul	DEVMETHOD(miibus_writereg,	lge_miibus_writereg),
17677542Swpaul	DEVMETHOD(miibus_statchg,	lge_miibus_statchg),
17777542Swpaul
178229093Shselasky	DEVMETHOD_END
17977542Swpaul};
18077542Swpaul
18177542Swpaulstatic driver_t lge_driver = {
18277542Swpaul	"lge",
18377542Swpaul	lge_methods,
18477542Swpaul	sizeof(struct lge_softc)
18577542Swpaul};
18677542Swpaul
18777542Swpaulstatic devclass_t lge_devclass;
18877542Swpaul
189113506SmdoddDRIVER_MODULE(lge, pci, lge_driver, lge_devclass, 0, 0);
19077542SwpaulDRIVER_MODULE(miibus, lge, miibus_driver, miibus_devclass, 0, 0);
191113506SmdoddMODULE_DEPEND(lge, pci, 1, 1, 1);
192113506SmdoddMODULE_DEPEND(lge, ether, 1, 1, 1);
193113506SmdoddMODULE_DEPEND(lge, miibus, 1, 1, 1);
19477542Swpaul
19577542Swpaul#define LGE_SETBIT(sc, reg, x)				\
19677542Swpaul	CSR_WRITE_4(sc, reg,				\
19777542Swpaul		CSR_READ_4(sc, reg) | (x))
19877542Swpaul
19977542Swpaul#define LGE_CLRBIT(sc, reg, x)				\
20077542Swpaul	CSR_WRITE_4(sc, reg,				\
20177542Swpaul		CSR_READ_4(sc, reg) & ~(x))
20277542Swpaul
20377542Swpaul#define SIO_SET(x)					\
20477542Swpaul	CSR_WRITE_4(sc, LGE_MEAR, CSR_READ_4(sc, LGE_MEAR) | x)
20577542Swpaul
20677542Swpaul#define SIO_CLR(x)					\
20777542Swpaul	CSR_WRITE_4(sc, LGE_MEAR, CSR_READ_4(sc, LGE_MEAR) & ~x)
20877542Swpaul
20977542Swpaul/*
21077542Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
21177542Swpaul */
21299498Salfredstatic void
21399498Salfredlge_eeprom_getword(sc, addr, dest)
21477542Swpaul	struct lge_softc	*sc;
21577542Swpaul	int			addr;
21677542Swpaul	u_int16_t		*dest;
21777542Swpaul{
21877542Swpaul	register int		i;
21977542Swpaul	u_int32_t		val;
22077542Swpaul
22177542Swpaul	CSR_WRITE_4(sc, LGE_EECTL, LGE_EECTL_CMD_READ|
22277542Swpaul	    LGE_EECTL_SINGLEACCESS|((addr >> 1) << 8));
22377542Swpaul
22477542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
22577542Swpaul		if (!(CSR_READ_4(sc, LGE_EECTL) & LGE_EECTL_CMD_READ))
22677542Swpaul			break;
22777542Swpaul
22877542Swpaul	if (i == LGE_TIMEOUT) {
229162321Sglebius		device_printf(sc->lge_dev, "EEPROM read timed out\n");
23077542Swpaul		return;
23177542Swpaul	}
23277542Swpaul
23377542Swpaul	val = CSR_READ_4(sc, LGE_EEDATA);
23477542Swpaul
23577542Swpaul	if (addr & 1)
23677542Swpaul		*dest = (val >> 16) & 0xFFFF;
23777542Swpaul	else
23877542Swpaul		*dest = val & 0xFFFF;
23977542Swpaul
24077542Swpaul	return;
24177542Swpaul}
24277542Swpaul
24377542Swpaul/*
24477542Swpaul * Read a sequence of words from the EEPROM.
24577542Swpaul */
24699498Salfredstatic void
24799498Salfredlge_read_eeprom(sc, dest, off, cnt, swap)
24877542Swpaul	struct lge_softc	*sc;
24977542Swpaul	caddr_t			dest;
25077542Swpaul	int			off;
25177542Swpaul	int			cnt;
25277542Swpaul	int			swap;
25377542Swpaul{
25477542Swpaul	int			i;
25577542Swpaul	u_int16_t		word = 0, *ptr;
25677542Swpaul
25777542Swpaul	for (i = 0; i < cnt; i++) {
25877542Swpaul		lge_eeprom_getword(sc, off + i, &word);
25977542Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
26077542Swpaul		if (swap)
26177542Swpaul			*ptr = ntohs(word);
26277542Swpaul		else
26377542Swpaul			*ptr = word;
26477542Swpaul	}
26577542Swpaul
26677542Swpaul	return;
26777542Swpaul}
26877542Swpaul
26999498Salfredstatic int
27099498Salfredlge_miibus_readreg(dev, phy, reg)
27177542Swpaul	device_t		dev;
27277542Swpaul	int			phy, reg;
27377542Swpaul{
27477542Swpaul	struct lge_softc	*sc;
27577542Swpaul	int			i;
27677542Swpaul
27777542Swpaul	sc = device_get_softc(dev);
27877542Swpaul
27977542Swpaul	/*
28077542Swpaul	 * If we have a non-PCS PHY, pretend that the internal
28177542Swpaul	 * autoneg stuff at PHY address 0 isn't there so that
28277542Swpaul	 * the miibus code will find only the GMII PHY.
28377542Swpaul	 */
28477542Swpaul	if (sc->lge_pcs == 0 && phy == 0)
28577542Swpaul		return(0);
28677542Swpaul
28777542Swpaul	CSR_WRITE_4(sc, LGE_GMIICTL, (phy << 8) | reg | LGE_GMIICMD_READ);
28877542Swpaul
28977542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
29077542Swpaul		if (!(CSR_READ_4(sc, LGE_GMIICTL) & LGE_GMIICTL_CMDBUSY))
29177542Swpaul			break;
29277542Swpaul
29377542Swpaul	if (i == LGE_TIMEOUT) {
294162321Sglebius		device_printf(sc->lge_dev, "PHY read timed out\n");
29577542Swpaul		return(0);
29677542Swpaul	}
29777542Swpaul
29877542Swpaul	return(CSR_READ_4(sc, LGE_GMIICTL) >> 16);
29977542Swpaul}
30077542Swpaul
30199498Salfredstatic int
30299498Salfredlge_miibus_writereg(dev, phy, reg, data)
30377542Swpaul	device_t		dev;
30477542Swpaul	int			phy, reg, data;
30577542Swpaul{
30677542Swpaul	struct lge_softc	*sc;
30777542Swpaul	int			i;
30877542Swpaul
30977542Swpaul	sc = device_get_softc(dev);
31077542Swpaul
31177542Swpaul	CSR_WRITE_4(sc, LGE_GMIICTL,
31277542Swpaul	    (data << 16) | (phy << 8) | reg | LGE_GMIICMD_WRITE);
31377542Swpaul
31477542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
31577542Swpaul		if (!(CSR_READ_4(sc, LGE_GMIICTL) & LGE_GMIICTL_CMDBUSY))
31677542Swpaul			break;
31777542Swpaul
31877542Swpaul	if (i == LGE_TIMEOUT) {
319162321Sglebius		device_printf(sc->lge_dev, "PHY write timed out\n");
32077542Swpaul		return(0);
32177542Swpaul	}
32277542Swpaul
32377542Swpaul	return(0);
32477542Swpaul}
32577542Swpaul
32699498Salfredstatic void
32799498Salfredlge_miibus_statchg(dev)
32877542Swpaul	device_t		dev;
32977542Swpaul{
33077542Swpaul	struct lge_softc	*sc;
33177542Swpaul	struct mii_data		*mii;
33277542Swpaul
33377542Swpaul	sc = device_get_softc(dev);
33477542Swpaul	mii = device_get_softc(sc->lge_miibus);
33577542Swpaul
33677542Swpaul	LGE_CLRBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_SPEED);
33777542Swpaul	switch (IFM_SUBTYPE(mii->mii_media_active)) {
33895673Sphk	case IFM_1000_T:
33977542Swpaul	case IFM_1000_SX:
34077542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_1000);
34177542Swpaul		break;
34277542Swpaul	case IFM_100_TX:
34377542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_100);
34477542Swpaul		break;
34577542Swpaul	case IFM_10_T:
34677542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_10);
34777542Swpaul		break;
34877542Swpaul	default:
34977542Swpaul		/*
35077542Swpaul		 * Choose something, even if it's wrong. Clearing
35177542Swpaul		 * all the bits will hose autoneg on the internal
35277542Swpaul		 * PHY.
35377542Swpaul		 */
35477542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_1000);
35577542Swpaul		break;
35677542Swpaul	}
35777542Swpaul
35877542Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
35977542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_FDX);
36077542Swpaul	} else {
36177542Swpaul		LGE_CLRBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_FDX);
36277542Swpaul	}
36377542Swpaul
36477542Swpaul	return;
36577542Swpaul}
36677542Swpaul
36799498Salfredstatic void
36899498Salfredlge_setmulti(sc)
36977542Swpaul	struct lge_softc	*sc;
37077542Swpaul{
37177542Swpaul	struct ifnet		*ifp;
37277542Swpaul	struct ifmultiaddr	*ifma;
37377542Swpaul	u_int32_t		h = 0, hashes[2] = { 0, 0 };
37477542Swpaul
375147256Sbrooks	ifp = sc->lge_ifp;
376152727Sjhb	LGE_LOCK_ASSERT(sc);
37777542Swpaul
37877542Swpaul	/* Make sure multicast hash table is enabled. */
37977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_MCAST);
38077542Swpaul
38177542Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
38277542Swpaul		CSR_WRITE_4(sc, LGE_MAR0, 0xFFFFFFFF);
38377542Swpaul		CSR_WRITE_4(sc, LGE_MAR1, 0xFFFFFFFF);
38477542Swpaul		return;
38577542Swpaul	}
38677542Swpaul
38777542Swpaul	/* first, zot all the existing hash bits */
38877542Swpaul	CSR_WRITE_4(sc, LGE_MAR0, 0);
38977542Swpaul	CSR_WRITE_4(sc, LGE_MAR1, 0);
39077542Swpaul
39177542Swpaul	/* now program new ones */
392195049Srwatson	if_maddr_rlock(ifp);
39377542Swpaul	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
39477542Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
39577542Swpaul			continue;
396130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
397130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
39877542Swpaul		if (h < 32)
39977542Swpaul			hashes[0] |= (1 << h);
40077542Swpaul		else
40177542Swpaul			hashes[1] |= (1 << (h - 32));
40277542Swpaul	}
403195049Srwatson	if_maddr_runlock(ifp);
40477542Swpaul
40577542Swpaul	CSR_WRITE_4(sc, LGE_MAR0, hashes[0]);
40677542Swpaul	CSR_WRITE_4(sc, LGE_MAR1, hashes[1]);
40777542Swpaul
40877542Swpaul	return;
40977542Swpaul}
41077542Swpaul
41199498Salfredstatic void
41299498Salfredlge_reset(sc)
41377542Swpaul	struct lge_softc	*sc;
41477542Swpaul{
41577542Swpaul	register int		i;
41677542Swpaul
41777542Swpaul	LGE_SETBIT(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL0|LGE_MODE1_SOFTRST);
41877542Swpaul
41977542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++) {
42077542Swpaul		if (!(CSR_READ_4(sc, LGE_MODE1) & LGE_MODE1_SOFTRST))
42177542Swpaul			break;
42277542Swpaul	}
42377542Swpaul
42477542Swpaul	if (i == LGE_TIMEOUT)
425162321Sglebius		device_printf(sc->lge_dev, "reset never completed\n");
42677542Swpaul
42777542Swpaul	/* Wait a little while for the chip to get its brains in order. */
42877542Swpaul	DELAY(1000);
42977542Swpaul
43077542Swpaul        return;
43177542Swpaul}
43277542Swpaul
43377542Swpaul/*
43477542Swpaul * Probe for a Level 1 chip. Check the PCI vendor and device
43577542Swpaul * IDs against our list and return a device name if we find a match.
43677542Swpaul */
43799498Salfredstatic int
43899498Salfredlge_probe(dev)
43977542Swpaul	device_t		dev;
44077542Swpaul{
441230697Smarius	const struct lge_type	*t;
44277542Swpaul
44377542Swpaul	t = lge_devs;
44477542Swpaul
44577542Swpaul	while(t->lge_name != NULL) {
44677542Swpaul		if ((pci_get_vendor(dev) == t->lge_vid) &&
44777542Swpaul		    (pci_get_device(dev) == t->lge_did)) {
44877542Swpaul			device_set_desc(dev, t->lge_name);
449143160Simp			return(BUS_PROBE_DEFAULT);
45077542Swpaul		}
45177542Swpaul		t++;
45277542Swpaul	}
45377542Swpaul
45477542Swpaul	return(ENXIO);
45577542Swpaul}
45677542Swpaul
45777542Swpaul/*
45877542Swpaul * Attach the interface. Allocate softc structures, do ifmedia
45977542Swpaul * setup and ethernet/BPF attach.
46077542Swpaul */
46199498Salfredstatic int
46299498Salfredlge_attach(dev)
46377542Swpaul	device_t		dev;
46477542Swpaul{
46577542Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
46677542Swpaul	struct lge_softc	*sc;
467150879Sjhb	struct ifnet		*ifp = NULL;
468150879Sjhb	int			error = 0, rid;
46977542Swpaul
47077542Swpaul	sc = device_get_softc(dev);
471162321Sglebius	sc->lge_dev = dev;
472162321Sglebius
473152727Sjhb	mtx_init(&sc->lge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
474152727Sjhb	    MTX_DEF);
475152727Sjhb	callout_init_mtx(&sc->lge_stat_callout, &sc->lge_mtx, 0);
476150879Sjhb
47777542Swpaul	/*
47877542Swpaul	 * Map control/status registers.
47977542Swpaul	 */
48077542Swpaul	pci_enable_busmaster(dev);
48177542Swpaul
48277542Swpaul	rid = LGE_RID;
483127135Snjl	sc->lge_res = bus_alloc_resource_any(dev, LGE_RES, &rid, RF_ACTIVE);
48477542Swpaul
48577542Swpaul	if (sc->lge_res == NULL) {
486150879Sjhb		device_printf(dev, "couldn't map ports/memory\n");
48777542Swpaul		error = ENXIO;
48877542Swpaul		goto fail;
48977542Swpaul	}
49077542Swpaul
49177542Swpaul	sc->lge_btag = rman_get_bustag(sc->lge_res);
49277542Swpaul	sc->lge_bhandle = rman_get_bushandle(sc->lge_res);
49377542Swpaul
49477542Swpaul	/* Allocate interrupt */
49577542Swpaul	rid = 0;
496127135Snjl	sc->lge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
49777542Swpaul	    RF_SHAREABLE | RF_ACTIVE);
49877542Swpaul
49977542Swpaul	if (sc->lge_irq == NULL) {
500150879Sjhb		device_printf(dev, "couldn't map interrupt\n");
50177542Swpaul		error = ENXIO;
50277542Swpaul		goto fail;
50377542Swpaul	}
50477542Swpaul
50577542Swpaul	/* Reset the adapter. */
50677542Swpaul	lge_reset(sc);
50777542Swpaul
50877542Swpaul	/*
50977542Swpaul	 * Get station address from the EEPROM.
51077542Swpaul	 */
51177542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[0], LGE_EE_NODEADDR_0, 1, 0);
51277542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[2], LGE_EE_NODEADDR_1, 1, 0);
51377542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[4], LGE_EE_NODEADDR_2, 1, 0);
51477542Swpaul
51577542Swpaul	sc->lge_ldata = contigmalloc(sizeof(struct lge_list_data), M_DEVBUF,
516152727Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
51777542Swpaul
51877542Swpaul	if (sc->lge_ldata == NULL) {
519150879Sjhb		device_printf(dev, "no memory for list buffers!\n");
52077542Swpaul		error = ENXIO;
52177542Swpaul		goto fail;
52277542Swpaul	}
52377542Swpaul
52477542Swpaul	/* Try to allocate memory for jumbo buffers. */
52577542Swpaul	if (lge_alloc_jumbo_mem(sc)) {
526150879Sjhb		device_printf(dev, "jumbo buffer allocation failed\n");
52777542Swpaul		error = ENXIO;
52877542Swpaul		goto fail;
52977542Swpaul	}
53077542Swpaul
531147256Sbrooks	ifp = sc->lge_ifp = if_alloc(IFT_ETHER);
532147256Sbrooks	if (ifp == NULL) {
533150879Sjhb		device_printf(dev, "can not if_alloc()\n");
534147256Sbrooks		error = ENOSPC;
535147256Sbrooks		goto fail;
536147256Sbrooks	}
53777542Swpaul	ifp->if_softc = sc;
538121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
53977542Swpaul	ifp->if_mtu = ETHERMTU;
540152727Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
54177542Swpaul	ifp->if_ioctl = lge_ioctl;
54277542Swpaul	ifp->if_start = lge_start;
54377542Swpaul	ifp->if_init = lge_init;
54477542Swpaul	ifp->if_snd.ifq_maxlen = LGE_TX_LIST_CNT - 1;
54583638Sjlemon	ifp->if_capabilities = IFCAP_RXCSUM;
54683638Sjlemon	ifp->if_capenable = ifp->if_capabilities;
54777542Swpaul
54877542Swpaul	if (CSR_READ_4(sc, LGE_GMIIMODE) & LGE_GMIIMODE_PCSENH)
54977542Swpaul		sc->lge_pcs = 1;
55077542Swpaul	else
55177542Swpaul		sc->lge_pcs = 0;
55277542Swpaul
55377542Swpaul	/*
55477542Swpaul	 * Do MII setup.
55577542Swpaul	 */
556213894Smarius	error = mii_attach(dev, &sc->lge_miibus, ifp, lge_ifmedia_upd,
557213894Smarius	    lge_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
558213894Smarius	if (error != 0) {
559213894Smarius		device_printf(dev, "attaching PHYs failed\n");
56077542Swpaul		goto fail;
56177542Swpaul	}
56277542Swpaul
56377542Swpaul	/*
56477542Swpaul	 * Call MI attach routine.
56577542Swpaul	 */
566106937Ssam	ether_ifattach(ifp, eaddr);
567152727Sjhb
568152727Sjhb	error = bus_setup_intr(dev, sc->lge_irq, INTR_TYPE_NET | INTR_MPSAFE,
569166901Spiso	    NULL, lge_intr, sc, &sc->lge_intrhand);
570152727Sjhb
571152727Sjhb	if (error) {
572152727Sjhb		ether_ifdetach(ifp);
573152727Sjhb		device_printf(dev, "couldn't set up irq\n");
574152727Sjhb		goto fail;
575152727Sjhb	}
576150879Sjhb	return (0);
57777542Swpaul
57877542Swpaulfail:
579176813Syongari	lge_free_jumbo_mem(sc);
580150879Sjhb	if (sc->lge_ldata)
581150879Sjhb		contigfree(sc->lge_ldata,
582150879Sjhb		    sizeof(struct lge_list_data), M_DEVBUF);
583150879Sjhb	if (ifp)
584150879Sjhb		if_free(ifp);
585150879Sjhb	if (sc->lge_irq)
586150879Sjhb		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
587150879Sjhb	if (sc->lge_res)
588150879Sjhb		bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
589152727Sjhb	mtx_destroy(&sc->lge_mtx);
59077542Swpaul	return(error);
59177542Swpaul}
59277542Swpaul
59399498Salfredstatic int
59499498Salfredlge_detach(dev)
59577542Swpaul	device_t		dev;
59677542Swpaul{
59777542Swpaul	struct lge_softc	*sc;
59877542Swpaul	struct ifnet		*ifp;
59977542Swpaul
60077542Swpaul	sc = device_get_softc(dev);
601147256Sbrooks	ifp = sc->lge_ifp;
60277542Swpaul
603152727Sjhb	LGE_LOCK(sc);
60477542Swpaul	lge_reset(sc);
60577542Swpaul	lge_stop(sc);
606152727Sjhb	LGE_UNLOCK(sc);
607152727Sjhb	callout_drain(&sc->lge_stat_callout);
608106937Ssam	ether_ifdetach(ifp);
60977542Swpaul
61077542Swpaul	bus_generic_detach(dev);
61177542Swpaul	device_delete_child(dev, sc->lge_miibus);
61277542Swpaul
61377542Swpaul	bus_teardown_intr(dev, sc->lge_irq, sc->lge_intrhand);
61477542Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
61577542Swpaul	bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
61677542Swpaul
61777542Swpaul	contigfree(sc->lge_ldata, sizeof(struct lge_list_data), M_DEVBUF);
618150306Simp	if_free(ifp);
61977542Swpaul	lge_free_jumbo_mem(sc);
620152727Sjhb	mtx_destroy(&sc->lge_mtx);
62177542Swpaul
62277542Swpaul	return(0);
62377542Swpaul}
62477542Swpaul
62577542Swpaul/*
62677542Swpaul * Initialize the transmit descriptors.
62777542Swpaul */
62899498Salfredstatic int
62999498Salfredlge_list_tx_init(sc)
63077542Swpaul	struct lge_softc	*sc;
63177542Swpaul{
63277542Swpaul	struct lge_list_data	*ld;
63377542Swpaul	struct lge_ring_data	*cd;
63477542Swpaul	int			i;
63577542Swpaul
63677542Swpaul	cd = &sc->lge_cdata;
63777542Swpaul	ld = sc->lge_ldata;
63877542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
63977542Swpaul		ld->lge_tx_list[i].lge_mbuf = NULL;
64077542Swpaul		ld->lge_tx_list[i].lge_ctl = 0;
64177542Swpaul	}
64277542Swpaul
64377542Swpaul	cd->lge_tx_prod = cd->lge_tx_cons = 0;
64477542Swpaul
64577542Swpaul	return(0);
64677542Swpaul}
64777542Swpaul
64877542Swpaul
64977542Swpaul/*
65077542Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
65177542Swpaul * we arralge the descriptors in a closed ring, so that the last descriptor
65277542Swpaul * points back to the first.
65377542Swpaul */
65499498Salfredstatic int
65599498Salfredlge_list_rx_init(sc)
65677542Swpaul	struct lge_softc	*sc;
65777542Swpaul{
65877542Swpaul	struct lge_list_data	*ld;
65977542Swpaul	struct lge_ring_data	*cd;
66077542Swpaul	int			i;
66177542Swpaul
66277542Swpaul	ld = sc->lge_ldata;
66377542Swpaul	cd = &sc->lge_cdata;
66477542Swpaul
66577542Swpaul	cd->lge_rx_prod = cd->lge_rx_cons = 0;
66677542Swpaul
66777542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
66877542Swpaul
66977542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
67077542Swpaul		if (CSR_READ_1(sc, LGE_RXCMDFREE_8BIT) == 0)
67177542Swpaul			break;
67277542Swpaul		if (lge_newbuf(sc, &ld->lge_rx_list[i], NULL) == ENOBUFS)
67377542Swpaul			return(ENOBUFS);
67477542Swpaul	}
67577542Swpaul
67677542Swpaul	/* Clear possible 'rx command queue empty' interrupt. */
67777542Swpaul	CSR_READ_4(sc, LGE_ISR);
67877542Swpaul
67977542Swpaul	return(0);
68077542Swpaul}
68177542Swpaul
68277542Swpaul/*
68377542Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
68477542Swpaul */
68599498Salfredstatic int
68699498Salfredlge_newbuf(sc, c, m)
68777542Swpaul	struct lge_softc	*sc;
68877542Swpaul	struct lge_rx_desc	*c;
68977542Swpaul	struct mbuf		*m;
69077542Swpaul{
69177542Swpaul	struct mbuf		*m_new = NULL;
69277542Swpaul	caddr_t			*buf = NULL;
69377542Swpaul
69477542Swpaul	if (m == NULL) {
695248078Smarius		MGETHDR(m_new, M_NOWAIT, MT_DATA);
69677542Swpaul		if (m_new == NULL) {
697162321Sglebius			device_printf(sc->lge_dev, "no memory for rx list "
698150879Sjhb			    "-- packet dropped!\n");
69977542Swpaul			return(ENOBUFS);
70077542Swpaul		}
70177542Swpaul
70277542Swpaul		/* Allocate the jumbo buffer */
70377542Swpaul		buf = lge_jalloc(sc);
70477542Swpaul		if (buf == NULL) {
70577542Swpaul#ifdef LGE_VERBOSE
706162321Sglebius			device_printf(sc->lge_dev, "jumbo allocation failed "
707150879Sjhb			    "-- packet dropped!\n");
70877542Swpaul#endif
70977542Swpaul			m_freem(m_new);
71077542Swpaul			return(ENOBUFS);
71177542Swpaul		}
71277542Swpaul		/* Attach the buffer to the mbuf */
71377542Swpaul		m_new->m_data = (void *)buf;
71478440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
71578440Swpaul		MEXTADD(m_new, buf, LGE_JUMBO_FRAMELEN, lge_jfree,
716175872Sphk		    buf, (struct lge_softc *)sc, 0, EXT_NET_DRV);
71777542Swpaul	} else {
71877542Swpaul		m_new = m;
71978440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
72077542Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
72177542Swpaul	}
72277542Swpaul
72377542Swpaul	/*
72477542Swpaul	 * Adjust alignment so packet payload begins on a
72577542Swpaul	 * longword boundary. Mandatory for Alpha, useful on
72677542Swpaul	 * x86 too.
72777542Swpaul	*/
72877542Swpaul	m_adj(m_new, ETHER_ALIGN);
72977542Swpaul
73077542Swpaul	c->lge_mbuf = m_new;
73177542Swpaul	c->lge_fragptr_hi = 0;
73277542Swpaul	c->lge_fragptr_lo = vtophys(mtod(m_new, caddr_t));
73377542Swpaul	c->lge_fraglen = m_new->m_len;
73477542Swpaul	c->lge_ctl = m_new->m_len | LGE_RXCTL_WANTINTR | LGE_FRAGCNT(1);
73577542Swpaul	c->lge_sts = 0;
73677542Swpaul
73777542Swpaul	/*
73877542Swpaul	 * Put this buffer in the RX command FIFO. To do this,
73977542Swpaul	 * we just write the physical address of the descriptor
74077542Swpaul	 * into the RX descriptor address registers. Note that
74177542Swpaul	 * there are two registers, one high DWORD and one low
74277542Swpaul	 * DWORD, which lets us specify a 64-bit address if
74377542Swpaul	 * desired. We only use a 32-bit address for now.
74477542Swpaul	 * Writing to the low DWORD register is what actually
74577542Swpaul	 * causes the command to be issued, so we do that
74677542Swpaul	 * last.
74777542Swpaul	 */
74877542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_LO, vtophys(c));
74977542Swpaul	LGE_INC(sc->lge_cdata.lge_rx_prod, LGE_RX_LIST_CNT);
75077542Swpaul
75177542Swpaul	return(0);
75277542Swpaul}
75377542Swpaul
75499498Salfredstatic int
75599498Salfredlge_alloc_jumbo_mem(sc)
75677542Swpaul	struct lge_softc	*sc;
75777542Swpaul{
75877542Swpaul	caddr_t			ptr;
75977542Swpaul	register int		i;
76077542Swpaul	struct lge_jpool_entry   *entry;
76177542Swpaul
76277542Swpaul	/* Grab a big chunk o' storage. */
76377542Swpaul	sc->lge_cdata.lge_jumbo_buf = contigmalloc(LGE_JMEM, M_DEVBUF,
76477542Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
76577542Swpaul
76677542Swpaul	if (sc->lge_cdata.lge_jumbo_buf == NULL) {
767162321Sglebius		device_printf(sc->lge_dev, "no memory for jumbo buffers!\n");
76877542Swpaul		return(ENOBUFS);
76977542Swpaul	}
77077542Swpaul
77177542Swpaul	SLIST_INIT(&sc->lge_jfree_listhead);
77277542Swpaul	SLIST_INIT(&sc->lge_jinuse_listhead);
77377542Swpaul
77477542Swpaul	/*
77577542Swpaul	 * Now divide it up into 9K pieces and save the addresses
77677542Swpaul	 * in an array.
77777542Swpaul	 */
77877542Swpaul	ptr = sc->lge_cdata.lge_jumbo_buf;
77977542Swpaul	for (i = 0; i < LGE_JSLOTS; i++) {
78077542Swpaul		sc->lge_cdata.lge_jslots[i] = ptr;
78178440Swpaul		ptr += LGE_JLEN;
782150879Sjhb		entry = malloc(sizeof(struct lge_jpool_entry),
78377542Swpaul		    M_DEVBUF, M_NOWAIT);
78477542Swpaul		if (entry == NULL) {
785162321Sglebius			device_printf(sc->lge_dev, "no memory for jumbo "
786150879Sjhb			    "buffer queue!\n");
78777542Swpaul			return(ENOBUFS);
78877542Swpaul		}
78977542Swpaul		entry->slot = i;
79077542Swpaul		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead,
79177542Swpaul		    entry, jpool_entries);
79277542Swpaul	}
79377542Swpaul
79477542Swpaul	return(0);
79577542Swpaul}
79677542Swpaul
79799498Salfredstatic void
79899498Salfredlge_free_jumbo_mem(sc)
79977542Swpaul	struct lge_softc	*sc;
80077542Swpaul{
80177542Swpaul	struct lge_jpool_entry	*entry;
80277542Swpaul
803176813Syongari	if (sc->lge_cdata.lge_jumbo_buf == NULL)
804176813Syongari		return;
805176813Syongari
806176813Syongari	while ((entry = SLIST_FIRST(&sc->lge_jinuse_listhead))) {
807176813Syongari		device_printf(sc->lge_dev,
808176813Syongari		    "asked to free buffer that is in use!\n");
809176813Syongari		SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
810176813Syongari		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry,
811176813Syongari		    jpool_entries);
812176813Syongari	}
813176813Syongari	while (!SLIST_EMPTY(&sc->lge_jfree_listhead)) {
81477542Swpaul		entry = SLIST_FIRST(&sc->lge_jfree_listhead);
81578440Swpaul		SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
81677542Swpaul		free(entry, M_DEVBUF);
81777542Swpaul	}
81877542Swpaul
81977542Swpaul	contigfree(sc->lge_cdata.lge_jumbo_buf, LGE_JMEM, M_DEVBUF);
82077542Swpaul
82177542Swpaul	return;
82277542Swpaul}
82377542Swpaul
82477542Swpaul/*
82577542Swpaul * Allocate a jumbo buffer.
82677542Swpaul */
82799498Salfredstatic void *
82899498Salfredlge_jalloc(sc)
82977542Swpaul	struct lge_softc	*sc;
83077542Swpaul{
83177542Swpaul	struct lge_jpool_entry   *entry;
83277542Swpaul
83377542Swpaul	entry = SLIST_FIRST(&sc->lge_jfree_listhead);
83477542Swpaul
83577542Swpaul	if (entry == NULL) {
83677542Swpaul#ifdef LGE_VERBOSE
837162321Sglebius		device_printf(sc->lge_dev, "no free jumbo buffers\n");
83877542Swpaul#endif
83977542Swpaul		return(NULL);
84077542Swpaul	}
84177542Swpaul
84277542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
84377542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jinuse_listhead, entry, jpool_entries);
84477542Swpaul	return(sc->lge_cdata.lge_jslots[entry->slot]);
84577542Swpaul}
84677542Swpaul
84777542Swpaul/*
84877542Swpaul * Release a jumbo buffer.
84977542Swpaul */
85099498Salfredstatic void
85199498Salfredlge_jfree(buf, args)
85299004Salfred	void			*buf;
85377542Swpaul	void			*args;
85477542Swpaul{
85577542Swpaul	struct lge_softc	*sc;
85677542Swpaul	int		        i;
85777542Swpaul	struct lge_jpool_entry   *entry;
85877542Swpaul
85977542Swpaul	/* Extract the softc struct pointer. */
86077542Swpaul	sc = args;
86177542Swpaul
86277542Swpaul	if (sc == NULL)
86377542Swpaul		panic("lge_jfree: can't find softc pointer!");
86477542Swpaul
86577542Swpaul	/* calculate the slot this buffer belongs to */
86677542Swpaul	i = ((vm_offset_t)buf
86777542Swpaul	     - (vm_offset_t)sc->lge_cdata.lge_jumbo_buf) / LGE_JLEN;
86877542Swpaul
86977542Swpaul	if ((i < 0) || (i >= LGE_JSLOTS))
87077542Swpaul		panic("lge_jfree: asked to free buffer that we don't manage!");
87177542Swpaul
87277542Swpaul	entry = SLIST_FIRST(&sc->lge_jinuse_listhead);
87377542Swpaul	if (entry == NULL)
87477542Swpaul		panic("lge_jfree: buffer not in use!");
87577542Swpaul	entry->slot = i;
87677542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
87777542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry, jpool_entries);
87877542Swpaul
87977542Swpaul	return;
88077542Swpaul}
88177542Swpaul
88277542Swpaul/*
88377542Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
88477542Swpaul * the higher level protocols.
88577542Swpaul */
88699498Salfredstatic void
88799498Salfredlge_rxeof(sc, cnt)
88877542Swpaul	struct lge_softc	*sc;
88977542Swpaul	int			cnt;
89077542Swpaul{
89177542Swpaul        struct mbuf		*m;
89277542Swpaul        struct ifnet		*ifp;
89377542Swpaul	struct lge_rx_desc	*cur_rx;
89477542Swpaul	int			c, i, total_len = 0;
89577542Swpaul	u_int32_t		rxsts, rxctl;
89677542Swpaul
897147256Sbrooks	ifp = sc->lge_ifp;
89877542Swpaul
89977542Swpaul	/* Find out how many frames were processed. */
90077542Swpaul	c = cnt;
90177542Swpaul	i = sc->lge_cdata.lge_rx_cons;
90277542Swpaul
90377542Swpaul	/* Suck them in. */
90477542Swpaul	while(c) {
90577542Swpaul		struct mbuf		*m0 = NULL;
90677542Swpaul
90777542Swpaul		cur_rx = &sc->lge_ldata->lge_rx_list[i];
90877542Swpaul		rxctl = cur_rx->lge_ctl;
90977542Swpaul		rxsts = cur_rx->lge_sts;
91077542Swpaul		m = cur_rx->lge_mbuf;
91177542Swpaul		cur_rx->lge_mbuf = NULL;
91277542Swpaul		total_len = LGE_RXBYTES(cur_rx);
91377542Swpaul		LGE_INC(i, LGE_RX_LIST_CNT);
91477542Swpaul		c--;
91577542Swpaul
91677542Swpaul		/*
91777542Swpaul		 * If an error occurs, update stats, clear the
91877542Swpaul		 * status word and leave the mbuf cluster in place:
91977542Swpaul		 * it should simply get re-used next time this descriptor
92077542Swpaul	 	 * comes up in the ring.
92177542Swpaul		 */
92277542Swpaul		if (rxctl & LGE_RXCTL_ERRMASK) {
92377542Swpaul			ifp->if_ierrors++;
92477542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
92577542Swpaul			continue;
92677542Swpaul		}
92777542Swpaul
92877542Swpaul		if (lge_newbuf(sc, &LGE_RXTAIL(sc), NULL) == ENOBUFS) {
92978508Sbmilekic			m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
93078508Sbmilekic			    ifp, NULL);
93177542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
93277542Swpaul			if (m0 == NULL) {
933162321Sglebius				device_printf(sc->lge_dev, "no receive buffers "
934150879Sjhb				    "available -- packet dropped!\n");
93577542Swpaul				ifp->if_ierrors++;
93677542Swpaul				continue;
93777542Swpaul			}
93877542Swpaul			m = m0;
93977542Swpaul		} else {
94077542Swpaul			m->m_pkthdr.rcvif = ifp;
94177542Swpaul			m->m_pkthdr.len = m->m_len = total_len;
94277542Swpaul		}
94377542Swpaul
94477542Swpaul		ifp->if_ipackets++;
94577542Swpaul
94677542Swpaul		/* Do IP checksum checking. */
94777542Swpaul		if (rxsts & LGE_RXSTS_ISIP)
94877542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
94977542Swpaul		if (!(rxsts & LGE_RXSTS_IPCSUMERR))
95077542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
95177542Swpaul		if ((rxsts & LGE_RXSTS_ISTCP &&
95277542Swpaul		    !(rxsts & LGE_RXSTS_TCPCSUMERR)) ||
95377542Swpaul		    (rxsts & LGE_RXSTS_ISUDP &&
95477542Swpaul		    !(rxsts & LGE_RXSTS_UDPCSUMERR))) {
95577542Swpaul			m->m_pkthdr.csum_flags |=
95677542Swpaul			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
95778287Swpaul			m->m_pkthdr.csum_data = 0xffff;
95877542Swpaul		}
95978287Swpaul
960152727Sjhb		LGE_UNLOCK(sc);
961106937Ssam		(*ifp->if_input)(ifp, m);
962152727Sjhb		LGE_LOCK(sc);
96377542Swpaul	}
96477542Swpaul
96577542Swpaul	sc->lge_cdata.lge_rx_cons = i;
96677542Swpaul
96777542Swpaul	return;
96877542Swpaul}
96977542Swpaul
970104094Sphkstatic void
97199498Salfredlge_rxeoc(sc)
97277542Swpaul	struct lge_softc	*sc;
97377542Swpaul{
97477542Swpaul	struct ifnet		*ifp;
97577542Swpaul
976147256Sbrooks	ifp = sc->lge_ifp;
977148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
978152727Sjhb	lge_init_locked(sc);
97977542Swpaul	return;
98077542Swpaul}
98177542Swpaul
98277542Swpaul/*
98377542Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
98477542Swpaul * the list buffers.
98577542Swpaul */
98677542Swpaul
98799498Salfredstatic void
98899498Salfredlge_txeof(sc)
98977542Swpaul	struct lge_softc	*sc;
99077542Swpaul{
99177542Swpaul	struct lge_tx_desc	*cur_tx = NULL;
99277542Swpaul	struct ifnet		*ifp;
99377542Swpaul	u_int32_t		idx, txdone;
99477542Swpaul
995147256Sbrooks	ifp = sc->lge_ifp;
99677542Swpaul
99777542Swpaul	/* Clear the timeout timer. */
998199560Sjhb	sc->lge_timer = 0;
99977542Swpaul
100077542Swpaul	/*
100177542Swpaul	 * Go through our tx list and free mbufs for those
100277542Swpaul	 * frames that have been transmitted.
100377542Swpaul	 */
100477542Swpaul	idx = sc->lge_cdata.lge_tx_cons;
100577542Swpaul	txdone = CSR_READ_1(sc, LGE_TXDMADONE_8BIT);
100677542Swpaul
100777542Swpaul	while (idx != sc->lge_cdata.lge_tx_prod && txdone) {
100877542Swpaul		cur_tx = &sc->lge_ldata->lge_tx_list[idx];
100977542Swpaul
101077542Swpaul		ifp->if_opackets++;
101177542Swpaul		if (cur_tx->lge_mbuf != NULL) {
101277542Swpaul			m_freem(cur_tx->lge_mbuf);
101377542Swpaul			cur_tx->lge_mbuf = NULL;
101477542Swpaul		}
101577542Swpaul		cur_tx->lge_ctl = 0;
101677542Swpaul
101777542Swpaul		txdone--;
101877542Swpaul		LGE_INC(idx, LGE_TX_LIST_CNT);
1019199560Sjhb		sc->lge_timer = 0;
102077542Swpaul	}
102177542Swpaul
102277542Swpaul	sc->lge_cdata.lge_tx_cons = idx;
102377542Swpaul
102477542Swpaul	if (cur_tx != NULL)
1025148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
102677542Swpaul
102777542Swpaul	return;
102877542Swpaul}
102977542Swpaul
103099498Salfredstatic void
103199498Salfredlge_tick(xsc)
103277542Swpaul	void			*xsc;
103377542Swpaul{
103477542Swpaul	struct lge_softc	*sc;
103577542Swpaul	struct mii_data		*mii;
103677542Swpaul	struct ifnet		*ifp;
103777542Swpaul
103877542Swpaul	sc = xsc;
1039147256Sbrooks	ifp = sc->lge_ifp;
1040152727Sjhb	LGE_LOCK_ASSERT(sc);
104177542Swpaul
104277542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_SINGLE_COLL_PKTS);
104377542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
104477542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_MULTI_COLL_PKTS);
104577542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
104677542Swpaul
104777542Swpaul	if (!sc->lge_link) {
104877542Swpaul		mii = device_get_softc(sc->lge_miibus);
104977542Swpaul		mii_tick(mii);
105077542Swpaul		if (mii->mii_media_status & IFM_ACTIVE &&
105177542Swpaul		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
105277542Swpaul			sc->lge_link++;
1053137402Sphk			if (bootverbose &&
1054137402Sphk		  	    (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX||
1055137402Sphk			    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T))
1056162321Sglebius				device_printf(sc->lge_dev, "gigabit link up\n");
105777542Swpaul			if (ifp->if_snd.ifq_head != NULL)
1058152727Sjhb				lge_start_locked(ifp);
105977542Swpaul		}
106077542Swpaul	}
106177542Swpaul
1062199560Sjhb	if (sc->lge_timer != 0 && --sc->lge_timer == 0)
1063199560Sjhb		lge_watchdog(sc);
1064152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
106577542Swpaul
106677542Swpaul	return;
106777542Swpaul}
106877542Swpaul
106999498Salfredstatic void
107099498Salfredlge_intr(arg)
107177542Swpaul	void			*arg;
107277542Swpaul{
107377542Swpaul	struct lge_softc	*sc;
107477542Swpaul	struct ifnet		*ifp;
107577542Swpaul	u_int32_t		status;
107677542Swpaul
107777542Swpaul	sc = arg;
1078147256Sbrooks	ifp = sc->lge_ifp;
1079152727Sjhb	LGE_LOCK(sc);
108077542Swpaul
108177542Swpaul	/* Supress unwanted interrupts */
108277542Swpaul	if (!(ifp->if_flags & IFF_UP)) {
108377542Swpaul		lge_stop(sc);
1084152727Sjhb		LGE_UNLOCK(sc);
108577542Swpaul		return;
108677542Swpaul	}
108777542Swpaul
108877542Swpaul	for (;;) {
108977542Swpaul		/*
109077542Swpaul		 * Reading the ISR register clears all interrupts, and
109177542Swpaul		 * clears the 'interrupts enabled' bit in the IMR
109277542Swpaul		 * register.
109377542Swpaul		 */
109477542Swpaul		status = CSR_READ_4(sc, LGE_ISR);
109577542Swpaul
109677542Swpaul		if ((status & LGE_INTRS) == 0)
109777542Swpaul			break;
109877542Swpaul
109977542Swpaul		if ((status & (LGE_ISR_TXCMDFIFO_EMPTY|LGE_ISR_TXDMA_DONE)))
110077542Swpaul			lge_txeof(sc);
110177542Swpaul
110277542Swpaul		if (status & LGE_ISR_RXDMA_DONE)
110377542Swpaul			lge_rxeof(sc, LGE_RX_DMACNT(status));
110477542Swpaul
110577542Swpaul		if (status & LGE_ISR_RXCMDFIFO_EMPTY)
110677542Swpaul			lge_rxeoc(sc);
110777542Swpaul
110877542Swpaul		if (status & LGE_ISR_PHY_INTR) {
110977542Swpaul			sc->lge_link = 0;
1110152727Sjhb			callout_stop(&sc->lge_stat_callout);
111177542Swpaul			lge_tick(sc);
111277542Swpaul		}
111377542Swpaul	}
111477542Swpaul
111577542Swpaul	/* Re-enable interrupts. */
111677542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|LGE_IMR_INTR_ENB);
111777542Swpaul
111877542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1119152727Sjhb		lge_start_locked(ifp);
112077542Swpaul
1121152727Sjhb	LGE_UNLOCK(sc);
112277542Swpaul	return;
112377542Swpaul}
112477542Swpaul
112577542Swpaul/*
112677542Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
112777542Swpaul * pointers to the fragment pointers.
112877542Swpaul */
112999498Salfredstatic int
113099498Salfredlge_encap(sc, m_head, txidx)
113177542Swpaul	struct lge_softc	*sc;
113277542Swpaul	struct mbuf		*m_head;
113377542Swpaul	u_int32_t		*txidx;
113477542Swpaul{
113577542Swpaul	struct lge_frag		*f = NULL;
113677542Swpaul	struct lge_tx_desc	*cur_tx;
113777542Swpaul	struct mbuf		*m;
113877542Swpaul	int			frag = 0, tot_len = 0;
113977542Swpaul
114077542Swpaul	/*
114177542Swpaul 	 * Start packing the mbufs in this chain into
114277542Swpaul	 * the fragment pointers. Stop when we run out
114377542Swpaul 	 * of fragments or hit the end of the mbuf chain.
114477542Swpaul	 */
114577542Swpaul	m = m_head;
114677542Swpaul	cur_tx = &sc->lge_ldata->lge_tx_list[*txidx];
114777542Swpaul	frag = 0;
114877542Swpaul
114977542Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
115077542Swpaul		if (m->m_len != 0) {
115177542Swpaul			tot_len += m->m_len;
115277542Swpaul			f = &cur_tx->lge_frags[frag];
115377542Swpaul			f->lge_fraglen = m->m_len;
115477542Swpaul			f->lge_fragptr_lo = vtophys(mtod(m, vm_offset_t));
115577542Swpaul			f->lge_fragptr_hi = 0;
115677542Swpaul			frag++;
115777542Swpaul		}
115877542Swpaul	}
115977542Swpaul
116077542Swpaul	if (m != NULL)
116177542Swpaul		return(ENOBUFS);
116277542Swpaul
116377542Swpaul	cur_tx->lge_mbuf = m_head;
116477542Swpaul	cur_tx->lge_ctl = LGE_TXCTL_WANTINTR|LGE_FRAGCNT(frag)|tot_len;
116577827Swpaul	LGE_INC((*txidx), LGE_TX_LIST_CNT);
116677542Swpaul
116777542Swpaul	/* Queue for transmit */
116877542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_LO, vtophys(cur_tx));
116977542Swpaul
117077542Swpaul	return(0);
117177542Swpaul}
117277542Swpaul
117377542Swpaul/*
117477542Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
117577542Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
117677542Swpaul * copy of the pointers since the transmit list fragment pointers are
117777542Swpaul * physical addresses.
117877542Swpaul */
117977542Swpaul
118099498Salfredstatic void
118199498Salfredlge_start(ifp)
118277542Swpaul	struct ifnet		*ifp;
118377542Swpaul{
118477542Swpaul	struct lge_softc	*sc;
1185152727Sjhb
1186152727Sjhb	sc = ifp->if_softc;
1187152727Sjhb	LGE_LOCK(sc);
1188152727Sjhb	lge_start_locked(ifp);
1189152727Sjhb	LGE_UNLOCK(sc);
1190152727Sjhb}
1191152727Sjhb
1192152727Sjhbstatic void
1193152727Sjhblge_start_locked(ifp)
1194152727Sjhb	struct ifnet		*ifp;
1195152727Sjhb{
1196152727Sjhb	struct lge_softc	*sc;
119777542Swpaul	struct mbuf		*m_head = NULL;
119877542Swpaul	u_int32_t		idx;
119977542Swpaul
120077542Swpaul	sc = ifp->if_softc;
120177542Swpaul
120277542Swpaul	if (!sc->lge_link)
120377542Swpaul		return;
120477542Swpaul
120577542Swpaul	idx = sc->lge_cdata.lge_tx_prod;
120677542Swpaul
1207148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
120877542Swpaul		return;
120977542Swpaul
121077542Swpaul	while(sc->lge_ldata->lge_tx_list[idx].lge_mbuf == NULL) {
121177542Swpaul		if (CSR_READ_1(sc, LGE_TXCMDFREE_8BIT) == 0)
121277542Swpaul			break;
121377542Swpaul
121477542Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
121577542Swpaul		if (m_head == NULL)
121677542Swpaul			break;
121777542Swpaul
121877542Swpaul		if (lge_encap(sc, m_head, &idx)) {
121977542Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1220148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
122177542Swpaul			break;
122277542Swpaul		}
122377542Swpaul
122477542Swpaul		/*
122577542Swpaul		 * If there's a BPF listener, bounce a copy of this frame
122677542Swpaul		 * to him.
122777542Swpaul		 */
1228106937Ssam		BPF_MTAP(ifp, m_head);
122977542Swpaul	}
123077542Swpaul
123177542Swpaul	sc->lge_cdata.lge_tx_prod = idx;
123277542Swpaul
123377542Swpaul	/*
123477542Swpaul	 * Set a timeout in case the chip goes out to lunch.
123577542Swpaul	 */
1236199560Sjhb	sc->lge_timer = 5;
123777542Swpaul
123877542Swpaul	return;
123977542Swpaul}
124077542Swpaul
124199498Salfredstatic void
124299498Salfredlge_init(xsc)
124377542Swpaul	void			*xsc;
124477542Swpaul{
124577542Swpaul	struct lge_softc	*sc = xsc;
1246152727Sjhb
1247152727Sjhb	LGE_LOCK(sc);
1248152727Sjhb	lge_init_locked(sc);
1249152727Sjhb	LGE_UNLOCK(sc);
1250152727Sjhb}
1251152727Sjhb
1252152727Sjhbstatic void
1253152727Sjhblge_init_locked(sc)
1254152727Sjhb	struct lge_softc	*sc;
1255152727Sjhb{
1256147256Sbrooks	struct ifnet		*ifp = sc->lge_ifp;
125777542Swpaul
1258152727Sjhb	LGE_LOCK_ASSERT(sc);
1259148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
126077542Swpaul		return;
126177542Swpaul
126277542Swpaul	/*
126377542Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
126477542Swpaul	 */
126577542Swpaul	lge_stop(sc);
126677542Swpaul	lge_reset(sc);
126777542Swpaul
126877542Swpaul	/* Set MAC address */
1269152315Sru	CSR_WRITE_4(sc, LGE_PAR0, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[0]));
1270152315Sru	CSR_WRITE_4(sc, LGE_PAR1, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[4]));
127177542Swpaul
127277542Swpaul	/* Init circular RX list. */
127377542Swpaul	if (lge_list_rx_init(sc) == ENOBUFS) {
1274162321Sglebius		device_printf(sc->lge_dev, "initialization failed: no "
1275150879Sjhb		    "memory for rx buffers\n");
127677542Swpaul		lge_stop(sc);
127777542Swpaul		return;
127877542Swpaul	}
127977542Swpaul
128077542Swpaul	/*
128177542Swpaul	 * Init tx descriptors.
128277542Swpaul	 */
128377542Swpaul	lge_list_tx_init(sc);
128477542Swpaul
128577542Swpaul	/* Set initial value for MODE1 register. */
128677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_UCAST|
128777542Swpaul	    LGE_MODE1_TX_CRC|LGE_MODE1_TXPAD|
128877542Swpaul	    LGE_MODE1_RX_FLOWCTL|LGE_MODE1_SETRST_CTL0|
128977542Swpaul	    LGE_MODE1_SETRST_CTL1|LGE_MODE1_SETRST_CTL2);
129077542Swpaul
129177542Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
129277542Swpaul	if (ifp->if_flags & IFF_PROMISC) {
129377542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
129477542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_PROMISC);
129577542Swpaul	} else {
129677542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_PROMISC);
129777542Swpaul	}
129877542Swpaul
129977542Swpaul	/*
130077542Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
130177542Swpaul	 */
130277542Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
130377542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
130477542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_BCAST);
130577542Swpaul	} else {
130677542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_BCAST);
130777542Swpaul	}
130877542Swpaul
130977542Swpaul	/* Packet padding workaround? */
131077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RMVPAD);
131177542Swpaul
131277542Swpaul	/* No error frames */
131377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ERRPKTS);
131477542Swpaul
131577542Swpaul	/* Receive large frames */
131677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_GIANTS);
131777542Swpaul
131877542Swpaul	/* Workaround: disable RX/TX flow control */
131977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_TX_FLOWCTL);
132077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_FLOWCTL);
132177542Swpaul
132277542Swpaul	/* Make sure to strip CRC from received frames */
132377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_CRC);
132477542Swpaul
132577542Swpaul	/* Turn off magic packet mode */
132677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_MPACK_ENB);
132777542Swpaul
132877542Swpaul	/* Turn off all VLAN stuff */
132977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_VLAN_RX|LGE_MODE1_VLAN_TX|
133077542Swpaul	    LGE_MODE1_VLAN_STRIP|LGE_MODE1_VLAN_INSERT);
133177542Swpaul
133277542Swpaul	/* Workarond: FIFO overflow */
133377542Swpaul	CSR_WRITE_2(sc, LGE_RXFIFO_HIWAT, 0x3FFF);
133477542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL1|LGE_IMR_RXFIFO_WAT);
133577542Swpaul
133677542Swpaul	/*
133777542Swpaul	 * Load the multicast filter.
133877542Swpaul	 */
133977542Swpaul	lge_setmulti(sc);
134077542Swpaul
134177542Swpaul	/*
134277542Swpaul	 * Enable hardware checksum validation for all received IPv4
134377542Swpaul	 * packets, do not reject packets with bad checksums.
134477542Swpaul	 */
134577542Swpaul	CSR_WRITE_4(sc, LGE_MODE2, LGE_MODE2_RX_IPCSUM|
134677542Swpaul	    LGE_MODE2_RX_TCPCSUM|LGE_MODE2_RX_UDPCSUM|
134777542Swpaul	    LGE_MODE2_RX_ERRCSUM);
134877542Swpaul
134977542Swpaul	/*
135077542Swpaul	 * Enable the delivery of PHY interrupts based on
135177542Swpaul	 * link/speed/duplex status chalges.
135277542Swpaul	 */
135377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL0|LGE_MODE1_GMIIPOLL);
135477542Swpaul
135577542Swpaul	/* Enable receiver and transmitter. */
135677542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
135777542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_ENB);
135877542Swpaul
135977542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_HI, 0);
136077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_TX_ENB);
136177542Swpaul
136277542Swpaul	/*
136377542Swpaul	 * Enable interrupts.
136477542Swpaul	 */
136577542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|
136677542Swpaul	    LGE_IMR_SETRST_CTL1|LGE_IMR_INTR_ENB|LGE_INTRS);
136777542Swpaul
1368152727Sjhb	lge_ifmedia_upd_locked(ifp);
136977542Swpaul
1370148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1371148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
137277542Swpaul
1373152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
137477542Swpaul
137577542Swpaul	return;
137677542Swpaul}
137777542Swpaul
137877542Swpaul/*
137977542Swpaul * Set media options.
138077542Swpaul */
138199498Salfredstatic int
138299498Salfredlge_ifmedia_upd(ifp)
138377542Swpaul	struct ifnet		*ifp;
138477542Swpaul{
138577542Swpaul	struct lge_softc	*sc;
1386152727Sjhb
1387152727Sjhb	sc = ifp->if_softc;
1388152727Sjhb	LGE_LOCK(sc);
1389152727Sjhb	lge_ifmedia_upd_locked(ifp);
1390152727Sjhb	LGE_UNLOCK(sc);
1391152727Sjhb
1392152727Sjhb	return(0);
1393152727Sjhb}
1394152727Sjhb
1395152727Sjhbstatic void
1396152727Sjhblge_ifmedia_upd_locked(ifp)
1397152727Sjhb	struct ifnet		*ifp;
1398152727Sjhb{
1399152727Sjhb	struct lge_softc	*sc;
140077542Swpaul	struct mii_data		*mii;
1401221407Smarius	struct mii_softc	*miisc;
140277542Swpaul
140377542Swpaul	sc = ifp->if_softc;
140477542Swpaul
1405152727Sjhb	LGE_LOCK_ASSERT(sc);
140677542Swpaul	mii = device_get_softc(sc->lge_miibus);
140777542Swpaul	sc->lge_link = 0;
1408221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1409221407Smarius		PHY_RESET(miisc);
141077542Swpaul	mii_mediachg(mii);
141177542Swpaul}
141277542Swpaul
141377542Swpaul/*
141477542Swpaul * Report current media status.
141577542Swpaul */
141699498Salfredstatic void
141799498Salfredlge_ifmedia_sts(ifp, ifmr)
141877542Swpaul	struct ifnet		*ifp;
141977542Swpaul	struct ifmediareq	*ifmr;
142077542Swpaul{
142177542Swpaul	struct lge_softc	*sc;
142277542Swpaul	struct mii_data		*mii;
142377542Swpaul
142477542Swpaul	sc = ifp->if_softc;
142577542Swpaul
1426152727Sjhb	LGE_LOCK(sc);
142777542Swpaul	mii = device_get_softc(sc->lge_miibus);
142877542Swpaul	mii_pollstat(mii);
142977542Swpaul	ifmr->ifm_active = mii->mii_media_active;
143077542Swpaul	ifmr->ifm_status = mii->mii_media_status;
1431229057Syongari	LGE_UNLOCK(sc);
143277542Swpaul
143377542Swpaul	return;
143477542Swpaul}
143577542Swpaul
143699498Salfredstatic int
143799498Salfredlge_ioctl(ifp, command, data)
143877542Swpaul	struct ifnet		*ifp;
143977542Swpaul	u_long			command;
144077542Swpaul	caddr_t			data;
144177542Swpaul{
144277542Swpaul	struct lge_softc	*sc = ifp->if_softc;
144377542Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
144477542Swpaul	struct mii_data		*mii;
1445152727Sjhb	int			error = 0;
144677542Swpaul
144777542Swpaul	switch(command) {
144877542Swpaul	case SIOCSIFMTU:
1449152727Sjhb		LGE_LOCK(sc);
145077542Swpaul		if (ifr->ifr_mtu > LGE_JUMBO_MTU)
145177542Swpaul			error = EINVAL;
145277542Swpaul		else
145377542Swpaul			ifp->if_mtu = ifr->ifr_mtu;
1454152727Sjhb		LGE_UNLOCK(sc);
145577542Swpaul		break;
145677542Swpaul	case SIOCSIFFLAGS:
1457152727Sjhb		LGE_LOCK(sc);
145877542Swpaul		if (ifp->if_flags & IFF_UP) {
1459148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
146077542Swpaul			    ifp->if_flags & IFF_PROMISC &&
146177542Swpaul			    !(sc->lge_if_flags & IFF_PROMISC)) {
146277542Swpaul				CSR_WRITE_4(sc, LGE_MODE1,
146377542Swpaul				    LGE_MODE1_SETRST_CTL1|
146477542Swpaul				    LGE_MODE1_RX_PROMISC);
1465148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
146677542Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
146777542Swpaul			    sc->lge_if_flags & IFF_PROMISC) {
146877542Swpaul				CSR_WRITE_4(sc, LGE_MODE1,
146977542Swpaul				    LGE_MODE1_RX_PROMISC);
147077542Swpaul			} else {
1471148887Srwatson				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1472152727Sjhb				lge_init_locked(sc);
147377542Swpaul			}
147477542Swpaul		} else {
1475148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
147677542Swpaul				lge_stop(sc);
147777542Swpaul		}
147877542Swpaul		sc->lge_if_flags = ifp->if_flags;
1479152727Sjhb		LGE_UNLOCK(sc);
148077542Swpaul		error = 0;
148177542Swpaul		break;
148277542Swpaul	case SIOCADDMULTI:
148377542Swpaul	case SIOCDELMULTI:
1484152727Sjhb		LGE_LOCK(sc);
148577542Swpaul		lge_setmulti(sc);
1486152727Sjhb		LGE_UNLOCK(sc);
148777542Swpaul		error = 0;
148877542Swpaul		break;
148977542Swpaul	case SIOCGIFMEDIA:
149077542Swpaul	case SIOCSIFMEDIA:
149177542Swpaul		mii = device_get_softc(sc->lge_miibus);
149277542Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
149377542Swpaul		break;
149477542Swpaul	default:
1495106937Ssam		error = ether_ioctl(ifp, command, data);
149677542Swpaul		break;
149777542Swpaul	}
149877542Swpaul
149977542Swpaul	return(error);
150077542Swpaul}
150177542Swpaul
150299498Salfredstatic void
1503199560Sjhblge_watchdog(sc)
1504199560Sjhb	struct lge_softc	*sc;
1505199560Sjhb{
150677542Swpaul	struct ifnet		*ifp;
150777542Swpaul
1508199560Sjhb	LGE_LOCK_ASSERT(sc);
1509199560Sjhb	ifp = sc->lge_ifp;
151077542Swpaul
151177542Swpaul	ifp->if_oerrors++;
1512150879Sjhb	if_printf(ifp, "watchdog timeout\n");
151377542Swpaul
151477542Swpaul	lge_stop(sc);
151577542Swpaul	lge_reset(sc);
1516148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1517152727Sjhb	lge_init_locked(sc);
151877542Swpaul
151977542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1520152727Sjhb		lge_start_locked(ifp);
152177542Swpaul}
152277542Swpaul
152377542Swpaul/*
152477542Swpaul * Stop the adapter and free any mbufs allocated to the
152577542Swpaul * RX and TX lists.
152677542Swpaul */
152799498Salfredstatic void
152899498Salfredlge_stop(sc)
152977542Swpaul	struct lge_softc	*sc;
153077542Swpaul{
153177542Swpaul	register int		i;
153277542Swpaul	struct ifnet		*ifp;
153377542Swpaul
1534152727Sjhb	LGE_LOCK_ASSERT(sc);
1535147256Sbrooks	ifp = sc->lge_ifp;
1536199560Sjhb	sc->lge_timer = 0;
1537152727Sjhb	callout_stop(&sc->lge_stat_callout);
153877542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_INTR_ENB);
153977542Swpaul
154077542Swpaul	/* Disable receiver and transmitter. */
154177542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ENB|LGE_MODE1_TX_ENB);
154277542Swpaul	sc->lge_link = 0;
154377542Swpaul
154477542Swpaul	/*
154577542Swpaul	 * Free data in the RX lists.
154677542Swpaul	 */
154777542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
154877542Swpaul		if (sc->lge_ldata->lge_rx_list[i].lge_mbuf != NULL) {
154977542Swpaul			m_freem(sc->lge_ldata->lge_rx_list[i].lge_mbuf);
155077542Swpaul			sc->lge_ldata->lge_rx_list[i].lge_mbuf = NULL;
155177542Swpaul		}
155277542Swpaul	}
155377542Swpaul	bzero((char *)&sc->lge_ldata->lge_rx_list,
155477542Swpaul		sizeof(sc->lge_ldata->lge_rx_list));
155577542Swpaul
155677542Swpaul	/*
155777542Swpaul	 * Free the TX list buffers.
155877542Swpaul	 */
155977542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
156077542Swpaul		if (sc->lge_ldata->lge_tx_list[i].lge_mbuf != NULL) {
156177542Swpaul			m_freem(sc->lge_ldata->lge_tx_list[i].lge_mbuf);
156277542Swpaul			sc->lge_ldata->lge_tx_list[i].lge_mbuf = NULL;
156377542Swpaul		}
156477542Swpaul	}
156577542Swpaul
156677542Swpaul	bzero((char *)&sc->lge_ldata->lge_tx_list,
156777542Swpaul		sizeof(sc->lge_ldata->lge_tx_list));
156877542Swpaul
1569148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
157077542Swpaul
157177542Swpaul	return;
157277542Swpaul}
157377542Swpaul
157477542Swpaul/*
157577542Swpaul * Stop all chip I/O so that the kernel's probe routines don't
157677542Swpaul * get confused by errant DMAs when rebooting.
157777542Swpaul */
1578173839Syongaristatic int
157999498Salfredlge_shutdown(dev)
158077542Swpaul	device_t		dev;
158177542Swpaul{
158277542Swpaul	struct lge_softc	*sc;
158377542Swpaul
158477542Swpaul	sc = device_get_softc(dev);
158577542Swpaul
1586152727Sjhb	LGE_LOCK(sc);
158777542Swpaul	lge_reset(sc);
158877542Swpaul	lge_stop(sc);
1589152727Sjhb	LGE_UNLOCK(sc);
159077542Swpaul
1591173839Syongari	return (0);
159277542Swpaul}
1593