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 */
113242625Sdimstatic 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 *);
125254842Sandrestatic int lge_jfree(struct mbuf *, 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
178227843Smarius	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{
441226270Smarius	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));
539152727Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
54077542Swpaul	ifp->if_ioctl = lge_ioctl;
54177542Swpaul	ifp->if_start = lge_start;
54277542Swpaul	ifp->if_init = lge_init;
54377542Swpaul	ifp->if_snd.ifq_maxlen = LGE_TX_LIST_CNT - 1;
54483638Sjlemon	ifp->if_capabilities = IFCAP_RXCSUM;
54583638Sjlemon	ifp->if_capenable = ifp->if_capabilities;
54677542Swpaul
54777542Swpaul	if (CSR_READ_4(sc, LGE_GMIIMODE) & LGE_GMIIMODE_PCSENH)
54877542Swpaul		sc->lge_pcs = 1;
54977542Swpaul	else
55077542Swpaul		sc->lge_pcs = 0;
55177542Swpaul
55277542Swpaul	/*
55377542Swpaul	 * Do MII setup.
55477542Swpaul	 */
555213894Smarius	error = mii_attach(dev, &sc->lge_miibus, ifp, lge_ifmedia_upd,
556213894Smarius	    lge_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
557213894Smarius	if (error != 0) {
558213894Smarius		device_printf(dev, "attaching PHYs failed\n");
55977542Swpaul		goto fail;
56077542Swpaul	}
56177542Swpaul
56277542Swpaul	/*
56377542Swpaul	 * Call MI attach routine.
56477542Swpaul	 */
565106937Ssam	ether_ifattach(ifp, eaddr);
566152727Sjhb
567152727Sjhb	error = bus_setup_intr(dev, sc->lge_irq, INTR_TYPE_NET | INTR_MPSAFE,
568166901Spiso	    NULL, lge_intr, sc, &sc->lge_intrhand);
569152727Sjhb
570152727Sjhb	if (error) {
571152727Sjhb		ether_ifdetach(ifp);
572152727Sjhb		device_printf(dev, "couldn't set up irq\n");
573152727Sjhb		goto fail;
574152727Sjhb	}
575150879Sjhb	return (0);
57677542Swpaul
57777542Swpaulfail:
578176813Syongari	lge_free_jumbo_mem(sc);
579150879Sjhb	if (sc->lge_ldata)
580150879Sjhb		contigfree(sc->lge_ldata,
581150879Sjhb		    sizeof(struct lge_list_data), M_DEVBUF);
582150879Sjhb	if (ifp)
583150879Sjhb		if_free(ifp);
584150879Sjhb	if (sc->lge_irq)
585150879Sjhb		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
586150879Sjhb	if (sc->lge_res)
587150879Sjhb		bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
588152727Sjhb	mtx_destroy(&sc->lge_mtx);
58977542Swpaul	return(error);
59077542Swpaul}
59177542Swpaul
59299498Salfredstatic int
59399498Salfredlge_detach(dev)
59477542Swpaul	device_t		dev;
59577542Swpaul{
59677542Swpaul	struct lge_softc	*sc;
59777542Swpaul	struct ifnet		*ifp;
59877542Swpaul
59977542Swpaul	sc = device_get_softc(dev);
600147256Sbrooks	ifp = sc->lge_ifp;
60177542Swpaul
602152727Sjhb	LGE_LOCK(sc);
60377542Swpaul	lge_reset(sc);
60477542Swpaul	lge_stop(sc);
605152727Sjhb	LGE_UNLOCK(sc);
606152727Sjhb	callout_drain(&sc->lge_stat_callout);
607106937Ssam	ether_ifdetach(ifp);
60877542Swpaul
60977542Swpaul	bus_generic_detach(dev);
61077542Swpaul	device_delete_child(dev, sc->lge_miibus);
61177542Swpaul
61277542Swpaul	bus_teardown_intr(dev, sc->lge_irq, sc->lge_intrhand);
61377542Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
61477542Swpaul	bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
61577542Swpaul
61677542Swpaul	contigfree(sc->lge_ldata, sizeof(struct lge_list_data), M_DEVBUF);
617150306Simp	if_free(ifp);
61877542Swpaul	lge_free_jumbo_mem(sc);
619152727Sjhb	mtx_destroy(&sc->lge_mtx);
62077542Swpaul
62177542Swpaul	return(0);
62277542Swpaul}
62377542Swpaul
62477542Swpaul/*
62577542Swpaul * Initialize the transmit descriptors.
62677542Swpaul */
62799498Salfredstatic int
62899498Salfredlge_list_tx_init(sc)
62977542Swpaul	struct lge_softc	*sc;
63077542Swpaul{
63177542Swpaul	struct lge_list_data	*ld;
63277542Swpaul	struct lge_ring_data	*cd;
63377542Swpaul	int			i;
63477542Swpaul
63577542Swpaul	cd = &sc->lge_cdata;
63677542Swpaul	ld = sc->lge_ldata;
63777542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
63877542Swpaul		ld->lge_tx_list[i].lge_mbuf = NULL;
63977542Swpaul		ld->lge_tx_list[i].lge_ctl = 0;
64077542Swpaul	}
64177542Swpaul
64277542Swpaul	cd->lge_tx_prod = cd->lge_tx_cons = 0;
64377542Swpaul
64477542Swpaul	return(0);
64577542Swpaul}
64677542Swpaul
64777542Swpaul
64877542Swpaul/*
64977542Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
65077542Swpaul * we arralge the descriptors in a closed ring, so that the last descriptor
65177542Swpaul * points back to the first.
65277542Swpaul */
65399498Salfredstatic int
65499498Salfredlge_list_rx_init(sc)
65577542Swpaul	struct lge_softc	*sc;
65677542Swpaul{
65777542Swpaul	struct lge_list_data	*ld;
65877542Swpaul	struct lge_ring_data	*cd;
65977542Swpaul	int			i;
66077542Swpaul
66177542Swpaul	ld = sc->lge_ldata;
66277542Swpaul	cd = &sc->lge_cdata;
66377542Swpaul
66477542Swpaul	cd->lge_rx_prod = cd->lge_rx_cons = 0;
66577542Swpaul
66677542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
66777542Swpaul
66877542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
66977542Swpaul		if (CSR_READ_1(sc, LGE_RXCMDFREE_8BIT) == 0)
67077542Swpaul			break;
67177542Swpaul		if (lge_newbuf(sc, &ld->lge_rx_list[i], NULL) == ENOBUFS)
67277542Swpaul			return(ENOBUFS);
67377542Swpaul	}
67477542Swpaul
67577542Swpaul	/* Clear possible 'rx command queue empty' interrupt. */
67677542Swpaul	CSR_READ_4(sc, LGE_ISR);
67777542Swpaul
67877542Swpaul	return(0);
67977542Swpaul}
68077542Swpaul
68177542Swpaul/*
68277542Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
68377542Swpaul */
68499498Salfredstatic int
68599498Salfredlge_newbuf(sc, c, m)
68677542Swpaul	struct lge_softc	*sc;
68777542Swpaul	struct lge_rx_desc	*c;
68877542Swpaul	struct mbuf		*m;
68977542Swpaul{
69077542Swpaul	struct mbuf		*m_new = NULL;
69177542Swpaul	caddr_t			*buf = NULL;
69277542Swpaul
69377542Swpaul	if (m == NULL) {
694243857Sglebius		MGETHDR(m_new, M_NOWAIT, MT_DATA);
69577542Swpaul		if (m_new == NULL) {
696162321Sglebius			device_printf(sc->lge_dev, "no memory for rx list "
697150879Sjhb			    "-- packet dropped!\n");
69877542Swpaul			return(ENOBUFS);
69977542Swpaul		}
70077542Swpaul
70177542Swpaul		/* Allocate the jumbo buffer */
70277542Swpaul		buf = lge_jalloc(sc);
70377542Swpaul		if (buf == NULL) {
70477542Swpaul#ifdef LGE_VERBOSE
705162321Sglebius			device_printf(sc->lge_dev, "jumbo allocation failed "
706150879Sjhb			    "-- packet dropped!\n");
70777542Swpaul#endif
70877542Swpaul			m_freem(m_new);
70977542Swpaul			return(ENOBUFS);
71077542Swpaul		}
71177542Swpaul		/* Attach the buffer to the mbuf */
71277542Swpaul		m_new->m_data = (void *)buf;
71378440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
71478440Swpaul		MEXTADD(m_new, buf, LGE_JUMBO_FRAMELEN, lge_jfree,
715175872Sphk		    buf, (struct lge_softc *)sc, 0, EXT_NET_DRV);
71677542Swpaul	} else {
71777542Swpaul		m_new = m;
71878440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
71977542Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
72077542Swpaul	}
72177542Swpaul
72277542Swpaul	/*
72377542Swpaul	 * Adjust alignment so packet payload begins on a
72477542Swpaul	 * longword boundary. Mandatory for Alpha, useful on
72577542Swpaul	 * x86 too.
72677542Swpaul	*/
72777542Swpaul	m_adj(m_new, ETHER_ALIGN);
72877542Swpaul
72977542Swpaul	c->lge_mbuf = m_new;
73077542Swpaul	c->lge_fragptr_hi = 0;
73177542Swpaul	c->lge_fragptr_lo = vtophys(mtod(m_new, caddr_t));
73277542Swpaul	c->lge_fraglen = m_new->m_len;
73377542Swpaul	c->lge_ctl = m_new->m_len | LGE_RXCTL_WANTINTR | LGE_FRAGCNT(1);
73477542Swpaul	c->lge_sts = 0;
73577542Swpaul
73677542Swpaul	/*
73777542Swpaul	 * Put this buffer in the RX command FIFO. To do this,
73877542Swpaul	 * we just write the physical address of the descriptor
73977542Swpaul	 * into the RX descriptor address registers. Note that
74077542Swpaul	 * there are two registers, one high DWORD and one low
74177542Swpaul	 * DWORD, which lets us specify a 64-bit address if
74277542Swpaul	 * desired. We only use a 32-bit address for now.
74377542Swpaul	 * Writing to the low DWORD register is what actually
74477542Swpaul	 * causes the command to be issued, so we do that
74577542Swpaul	 * last.
74677542Swpaul	 */
74777542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_LO, vtophys(c));
74877542Swpaul	LGE_INC(sc->lge_cdata.lge_rx_prod, LGE_RX_LIST_CNT);
74977542Swpaul
75077542Swpaul	return(0);
75177542Swpaul}
75277542Swpaul
75399498Salfredstatic int
75499498Salfredlge_alloc_jumbo_mem(sc)
75577542Swpaul	struct lge_softc	*sc;
75677542Swpaul{
75777542Swpaul	caddr_t			ptr;
75877542Swpaul	register int		i;
75977542Swpaul	struct lge_jpool_entry   *entry;
76077542Swpaul
76177542Swpaul	/* Grab a big chunk o' storage. */
76277542Swpaul	sc->lge_cdata.lge_jumbo_buf = contigmalloc(LGE_JMEM, M_DEVBUF,
76377542Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
76477542Swpaul
76577542Swpaul	if (sc->lge_cdata.lge_jumbo_buf == NULL) {
766162321Sglebius		device_printf(sc->lge_dev, "no memory for jumbo buffers!\n");
76777542Swpaul		return(ENOBUFS);
76877542Swpaul	}
76977542Swpaul
77077542Swpaul	SLIST_INIT(&sc->lge_jfree_listhead);
77177542Swpaul	SLIST_INIT(&sc->lge_jinuse_listhead);
77277542Swpaul
77377542Swpaul	/*
77477542Swpaul	 * Now divide it up into 9K pieces and save the addresses
77577542Swpaul	 * in an array.
77677542Swpaul	 */
77777542Swpaul	ptr = sc->lge_cdata.lge_jumbo_buf;
77877542Swpaul	for (i = 0; i < LGE_JSLOTS; i++) {
77977542Swpaul		sc->lge_cdata.lge_jslots[i] = ptr;
78078440Swpaul		ptr += LGE_JLEN;
781150879Sjhb		entry = malloc(sizeof(struct lge_jpool_entry),
78277542Swpaul		    M_DEVBUF, M_NOWAIT);
78377542Swpaul		if (entry == NULL) {
784162321Sglebius			device_printf(sc->lge_dev, "no memory for jumbo "
785150879Sjhb			    "buffer queue!\n");
78677542Swpaul			return(ENOBUFS);
78777542Swpaul		}
78877542Swpaul		entry->slot = i;
78977542Swpaul		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead,
79077542Swpaul		    entry, jpool_entries);
79177542Swpaul	}
79277542Swpaul
79377542Swpaul	return(0);
79477542Swpaul}
79577542Swpaul
79699498Salfredstatic void
79799498Salfredlge_free_jumbo_mem(sc)
79877542Swpaul	struct lge_softc	*sc;
79977542Swpaul{
80077542Swpaul	struct lge_jpool_entry	*entry;
80177542Swpaul
802176813Syongari	if (sc->lge_cdata.lge_jumbo_buf == NULL)
803176813Syongari		return;
804176813Syongari
805176813Syongari	while ((entry = SLIST_FIRST(&sc->lge_jinuse_listhead))) {
806176813Syongari		device_printf(sc->lge_dev,
807176813Syongari		    "asked to free buffer that is in use!\n");
808176813Syongari		SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
809176813Syongari		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry,
810176813Syongari		    jpool_entries);
811176813Syongari	}
812176813Syongari	while (!SLIST_EMPTY(&sc->lge_jfree_listhead)) {
81377542Swpaul		entry = SLIST_FIRST(&sc->lge_jfree_listhead);
81478440Swpaul		SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
81577542Swpaul		free(entry, M_DEVBUF);
81677542Swpaul	}
81777542Swpaul
81877542Swpaul	contigfree(sc->lge_cdata.lge_jumbo_buf, LGE_JMEM, M_DEVBUF);
81977542Swpaul
82077542Swpaul	return;
82177542Swpaul}
82277542Swpaul
82377542Swpaul/*
82477542Swpaul * Allocate a jumbo buffer.
82577542Swpaul */
82699498Salfredstatic void *
82799498Salfredlge_jalloc(sc)
82877542Swpaul	struct lge_softc	*sc;
82977542Swpaul{
83077542Swpaul	struct lge_jpool_entry   *entry;
83177542Swpaul
83277542Swpaul	entry = SLIST_FIRST(&sc->lge_jfree_listhead);
83377542Swpaul
83477542Swpaul	if (entry == NULL) {
83577542Swpaul#ifdef LGE_VERBOSE
836162321Sglebius		device_printf(sc->lge_dev, "no free jumbo buffers\n");
83777542Swpaul#endif
83877542Swpaul		return(NULL);
83977542Swpaul	}
84077542Swpaul
84177542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
84277542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jinuse_listhead, entry, jpool_entries);
84377542Swpaul	return(sc->lge_cdata.lge_jslots[entry->slot]);
84477542Swpaul}
84577542Swpaul
84677542Swpaul/*
84777542Swpaul * Release a jumbo buffer.
84877542Swpaul */
849254842Sandrestatic int
850254799Sandrelge_jfree(struct mbuf *m, void *buf, void *args)
85177542Swpaul{
85277542Swpaul	struct lge_softc	*sc;
85377542Swpaul	int		        i;
85477542Swpaul	struct lge_jpool_entry   *entry;
85577542Swpaul
85677542Swpaul	/* Extract the softc struct pointer. */
85777542Swpaul	sc = args;
85877542Swpaul
85977542Swpaul	if (sc == NULL)
86077542Swpaul		panic("lge_jfree: can't find softc pointer!");
86177542Swpaul
86277542Swpaul	/* calculate the slot this buffer belongs to */
86377542Swpaul	i = ((vm_offset_t)buf
86477542Swpaul	     - (vm_offset_t)sc->lge_cdata.lge_jumbo_buf) / LGE_JLEN;
86577542Swpaul
86677542Swpaul	if ((i < 0) || (i >= LGE_JSLOTS))
86777542Swpaul		panic("lge_jfree: asked to free buffer that we don't manage!");
86877542Swpaul
86977542Swpaul	entry = SLIST_FIRST(&sc->lge_jinuse_listhead);
87077542Swpaul	if (entry == NULL)
87177542Swpaul		panic("lge_jfree: buffer not in use!");
87277542Swpaul	entry->slot = i;
87377542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
87477542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry, jpool_entries);
87577542Swpaul
876254842Sandre	return (EXT_FREE_OK);
87777542Swpaul}
87877542Swpaul
87977542Swpaul/*
88077542Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
88177542Swpaul * the higher level protocols.
88277542Swpaul */
88399498Salfredstatic void
88499498Salfredlge_rxeof(sc, cnt)
88577542Swpaul	struct lge_softc	*sc;
88677542Swpaul	int			cnt;
88777542Swpaul{
88877542Swpaul        struct mbuf		*m;
88977542Swpaul        struct ifnet		*ifp;
89077542Swpaul	struct lge_rx_desc	*cur_rx;
89177542Swpaul	int			c, i, total_len = 0;
89277542Swpaul	u_int32_t		rxsts, rxctl;
89377542Swpaul
894147256Sbrooks	ifp = sc->lge_ifp;
89577542Swpaul
89677542Swpaul	/* Find out how many frames were processed. */
89777542Swpaul	c = cnt;
89877542Swpaul	i = sc->lge_cdata.lge_rx_cons;
89977542Swpaul
90077542Swpaul	/* Suck them in. */
90177542Swpaul	while(c) {
90277542Swpaul		struct mbuf		*m0 = NULL;
90377542Swpaul
90477542Swpaul		cur_rx = &sc->lge_ldata->lge_rx_list[i];
90577542Swpaul		rxctl = cur_rx->lge_ctl;
90677542Swpaul		rxsts = cur_rx->lge_sts;
90777542Swpaul		m = cur_rx->lge_mbuf;
90877542Swpaul		cur_rx->lge_mbuf = NULL;
90977542Swpaul		total_len = LGE_RXBYTES(cur_rx);
91077542Swpaul		LGE_INC(i, LGE_RX_LIST_CNT);
91177542Swpaul		c--;
91277542Swpaul
91377542Swpaul		/*
91477542Swpaul		 * If an error occurs, update stats, clear the
91577542Swpaul		 * status word and leave the mbuf cluster in place:
91677542Swpaul		 * it should simply get re-used next time this descriptor
91777542Swpaul	 	 * comes up in the ring.
91877542Swpaul		 */
91977542Swpaul		if (rxctl & LGE_RXCTL_ERRMASK) {
92077542Swpaul			ifp->if_ierrors++;
92177542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
92277542Swpaul			continue;
92377542Swpaul		}
92477542Swpaul
92577542Swpaul		if (lge_newbuf(sc, &LGE_RXTAIL(sc), NULL) == ENOBUFS) {
92678508Sbmilekic			m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
92778508Sbmilekic			    ifp, NULL);
92877542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
92977542Swpaul			if (m0 == NULL) {
930162321Sglebius				device_printf(sc->lge_dev, "no receive buffers "
931150879Sjhb				    "available -- packet dropped!\n");
93277542Swpaul				ifp->if_ierrors++;
93377542Swpaul				continue;
93477542Swpaul			}
93577542Swpaul			m = m0;
93677542Swpaul		} else {
93777542Swpaul			m->m_pkthdr.rcvif = ifp;
93877542Swpaul			m->m_pkthdr.len = m->m_len = total_len;
93977542Swpaul		}
94077542Swpaul
94177542Swpaul		ifp->if_ipackets++;
94277542Swpaul
94377542Swpaul		/* Do IP checksum checking. */
94477542Swpaul		if (rxsts & LGE_RXSTS_ISIP)
94577542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
94677542Swpaul		if (!(rxsts & LGE_RXSTS_IPCSUMERR))
94777542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
94877542Swpaul		if ((rxsts & LGE_RXSTS_ISTCP &&
94977542Swpaul		    !(rxsts & LGE_RXSTS_TCPCSUMERR)) ||
95077542Swpaul		    (rxsts & LGE_RXSTS_ISUDP &&
95177542Swpaul		    !(rxsts & LGE_RXSTS_UDPCSUMERR))) {
95277542Swpaul			m->m_pkthdr.csum_flags |=
95377542Swpaul			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
95478287Swpaul			m->m_pkthdr.csum_data = 0xffff;
95577542Swpaul		}
95678287Swpaul
957152727Sjhb		LGE_UNLOCK(sc);
958106937Ssam		(*ifp->if_input)(ifp, m);
959152727Sjhb		LGE_LOCK(sc);
96077542Swpaul	}
96177542Swpaul
96277542Swpaul	sc->lge_cdata.lge_rx_cons = i;
96377542Swpaul
96477542Swpaul	return;
96577542Swpaul}
96677542Swpaul
967104094Sphkstatic void
96899498Salfredlge_rxeoc(sc)
96977542Swpaul	struct lge_softc	*sc;
97077542Swpaul{
97177542Swpaul	struct ifnet		*ifp;
97277542Swpaul
973147256Sbrooks	ifp = sc->lge_ifp;
974148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
975152727Sjhb	lge_init_locked(sc);
97677542Swpaul	return;
97777542Swpaul}
97877542Swpaul
97977542Swpaul/*
98077542Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
98177542Swpaul * the list buffers.
98277542Swpaul */
98377542Swpaul
98499498Salfredstatic void
98599498Salfredlge_txeof(sc)
98677542Swpaul	struct lge_softc	*sc;
98777542Swpaul{
98877542Swpaul	struct lge_tx_desc	*cur_tx = NULL;
98977542Swpaul	struct ifnet		*ifp;
99077542Swpaul	u_int32_t		idx, txdone;
99177542Swpaul
992147256Sbrooks	ifp = sc->lge_ifp;
99377542Swpaul
99477542Swpaul	/* Clear the timeout timer. */
995199560Sjhb	sc->lge_timer = 0;
99677542Swpaul
99777542Swpaul	/*
99877542Swpaul	 * Go through our tx list and free mbufs for those
99977542Swpaul	 * frames that have been transmitted.
100077542Swpaul	 */
100177542Swpaul	idx = sc->lge_cdata.lge_tx_cons;
100277542Swpaul	txdone = CSR_READ_1(sc, LGE_TXDMADONE_8BIT);
100377542Swpaul
100477542Swpaul	while (idx != sc->lge_cdata.lge_tx_prod && txdone) {
100577542Swpaul		cur_tx = &sc->lge_ldata->lge_tx_list[idx];
100677542Swpaul
100777542Swpaul		ifp->if_opackets++;
100877542Swpaul		if (cur_tx->lge_mbuf != NULL) {
100977542Swpaul			m_freem(cur_tx->lge_mbuf);
101077542Swpaul			cur_tx->lge_mbuf = NULL;
101177542Swpaul		}
101277542Swpaul		cur_tx->lge_ctl = 0;
101377542Swpaul
101477542Swpaul		txdone--;
101577542Swpaul		LGE_INC(idx, LGE_TX_LIST_CNT);
1016199560Sjhb		sc->lge_timer = 0;
101777542Swpaul	}
101877542Swpaul
101977542Swpaul	sc->lge_cdata.lge_tx_cons = idx;
102077542Swpaul
102177542Swpaul	if (cur_tx != NULL)
1022148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
102377542Swpaul
102477542Swpaul	return;
102577542Swpaul}
102677542Swpaul
102799498Salfredstatic void
102899498Salfredlge_tick(xsc)
102977542Swpaul	void			*xsc;
103077542Swpaul{
103177542Swpaul	struct lge_softc	*sc;
103277542Swpaul	struct mii_data		*mii;
103377542Swpaul	struct ifnet		*ifp;
103477542Swpaul
103577542Swpaul	sc = xsc;
1036147256Sbrooks	ifp = sc->lge_ifp;
1037152727Sjhb	LGE_LOCK_ASSERT(sc);
103877542Swpaul
103977542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_SINGLE_COLL_PKTS);
104077542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
104177542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_MULTI_COLL_PKTS);
104277542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
104377542Swpaul
104477542Swpaul	if (!sc->lge_link) {
104577542Swpaul		mii = device_get_softc(sc->lge_miibus);
104677542Swpaul		mii_tick(mii);
104777542Swpaul		if (mii->mii_media_status & IFM_ACTIVE &&
104877542Swpaul		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
104977542Swpaul			sc->lge_link++;
1050137402Sphk			if (bootverbose &&
1051137402Sphk		  	    (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX||
1052137402Sphk			    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T))
1053162321Sglebius				device_printf(sc->lge_dev, "gigabit link up\n");
105477542Swpaul			if (ifp->if_snd.ifq_head != NULL)
1055152727Sjhb				lge_start_locked(ifp);
105677542Swpaul		}
105777542Swpaul	}
105877542Swpaul
1059199560Sjhb	if (sc->lge_timer != 0 && --sc->lge_timer == 0)
1060199560Sjhb		lge_watchdog(sc);
1061152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
106277542Swpaul
106377542Swpaul	return;
106477542Swpaul}
106577542Swpaul
106699498Salfredstatic void
106799498Salfredlge_intr(arg)
106877542Swpaul	void			*arg;
106977542Swpaul{
107077542Swpaul	struct lge_softc	*sc;
107177542Swpaul	struct ifnet		*ifp;
107277542Swpaul	u_int32_t		status;
107377542Swpaul
107477542Swpaul	sc = arg;
1075147256Sbrooks	ifp = sc->lge_ifp;
1076152727Sjhb	LGE_LOCK(sc);
107777542Swpaul
107877542Swpaul	/* Supress unwanted interrupts */
107977542Swpaul	if (!(ifp->if_flags & IFF_UP)) {
108077542Swpaul		lge_stop(sc);
1081152727Sjhb		LGE_UNLOCK(sc);
108277542Swpaul		return;
108377542Swpaul	}
108477542Swpaul
108577542Swpaul	for (;;) {
108677542Swpaul		/*
108777542Swpaul		 * Reading the ISR register clears all interrupts, and
108877542Swpaul		 * clears the 'interrupts enabled' bit in the IMR
108977542Swpaul		 * register.
109077542Swpaul		 */
109177542Swpaul		status = CSR_READ_4(sc, LGE_ISR);
109277542Swpaul
109377542Swpaul		if ((status & LGE_INTRS) == 0)
109477542Swpaul			break;
109577542Swpaul
109677542Swpaul		if ((status & (LGE_ISR_TXCMDFIFO_EMPTY|LGE_ISR_TXDMA_DONE)))
109777542Swpaul			lge_txeof(sc);
109877542Swpaul
109977542Swpaul		if (status & LGE_ISR_RXDMA_DONE)
110077542Swpaul			lge_rxeof(sc, LGE_RX_DMACNT(status));
110177542Swpaul
110277542Swpaul		if (status & LGE_ISR_RXCMDFIFO_EMPTY)
110377542Swpaul			lge_rxeoc(sc);
110477542Swpaul
110577542Swpaul		if (status & LGE_ISR_PHY_INTR) {
110677542Swpaul			sc->lge_link = 0;
1107152727Sjhb			callout_stop(&sc->lge_stat_callout);
110877542Swpaul			lge_tick(sc);
110977542Swpaul		}
111077542Swpaul	}
111177542Swpaul
111277542Swpaul	/* Re-enable interrupts. */
111377542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|LGE_IMR_INTR_ENB);
111477542Swpaul
111577542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1116152727Sjhb		lge_start_locked(ifp);
111777542Swpaul
1118152727Sjhb	LGE_UNLOCK(sc);
111977542Swpaul	return;
112077542Swpaul}
112177542Swpaul
112277542Swpaul/*
112377542Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
112477542Swpaul * pointers to the fragment pointers.
112577542Swpaul */
112699498Salfredstatic int
112799498Salfredlge_encap(sc, m_head, txidx)
112877542Swpaul	struct lge_softc	*sc;
112977542Swpaul	struct mbuf		*m_head;
113077542Swpaul	u_int32_t		*txidx;
113177542Swpaul{
113277542Swpaul	struct lge_frag		*f = NULL;
113377542Swpaul	struct lge_tx_desc	*cur_tx;
113477542Swpaul	struct mbuf		*m;
113577542Swpaul	int			frag = 0, tot_len = 0;
113677542Swpaul
113777542Swpaul	/*
113877542Swpaul 	 * Start packing the mbufs in this chain into
113977542Swpaul	 * the fragment pointers. Stop when we run out
114077542Swpaul 	 * of fragments or hit the end of the mbuf chain.
114177542Swpaul	 */
114277542Swpaul	m = m_head;
114377542Swpaul	cur_tx = &sc->lge_ldata->lge_tx_list[*txidx];
114477542Swpaul	frag = 0;
114577542Swpaul
114677542Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
114777542Swpaul		if (m->m_len != 0) {
114877542Swpaul			tot_len += m->m_len;
114977542Swpaul			f = &cur_tx->lge_frags[frag];
115077542Swpaul			f->lge_fraglen = m->m_len;
115177542Swpaul			f->lge_fragptr_lo = vtophys(mtod(m, vm_offset_t));
115277542Swpaul			f->lge_fragptr_hi = 0;
115377542Swpaul			frag++;
115477542Swpaul		}
115577542Swpaul	}
115677542Swpaul
115777542Swpaul	if (m != NULL)
115877542Swpaul		return(ENOBUFS);
115977542Swpaul
116077542Swpaul	cur_tx->lge_mbuf = m_head;
116177542Swpaul	cur_tx->lge_ctl = LGE_TXCTL_WANTINTR|LGE_FRAGCNT(frag)|tot_len;
116277827Swpaul	LGE_INC((*txidx), LGE_TX_LIST_CNT);
116377542Swpaul
116477542Swpaul	/* Queue for transmit */
116577542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_LO, vtophys(cur_tx));
116677542Swpaul
116777542Swpaul	return(0);
116877542Swpaul}
116977542Swpaul
117077542Swpaul/*
117177542Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
117277542Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
117377542Swpaul * copy of the pointers since the transmit list fragment pointers are
117477542Swpaul * physical addresses.
117577542Swpaul */
117677542Swpaul
117799498Salfredstatic void
117899498Salfredlge_start(ifp)
117977542Swpaul	struct ifnet		*ifp;
118077542Swpaul{
118177542Swpaul	struct lge_softc	*sc;
1182152727Sjhb
1183152727Sjhb	sc = ifp->if_softc;
1184152727Sjhb	LGE_LOCK(sc);
1185152727Sjhb	lge_start_locked(ifp);
1186152727Sjhb	LGE_UNLOCK(sc);
1187152727Sjhb}
1188152727Sjhb
1189152727Sjhbstatic void
1190152727Sjhblge_start_locked(ifp)
1191152727Sjhb	struct ifnet		*ifp;
1192152727Sjhb{
1193152727Sjhb	struct lge_softc	*sc;
119477542Swpaul	struct mbuf		*m_head = NULL;
119577542Swpaul	u_int32_t		idx;
119677542Swpaul
119777542Swpaul	sc = ifp->if_softc;
119877542Swpaul
119977542Swpaul	if (!sc->lge_link)
120077542Swpaul		return;
120177542Swpaul
120277542Swpaul	idx = sc->lge_cdata.lge_tx_prod;
120377542Swpaul
1204148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
120577542Swpaul		return;
120677542Swpaul
120777542Swpaul	while(sc->lge_ldata->lge_tx_list[idx].lge_mbuf == NULL) {
120877542Swpaul		if (CSR_READ_1(sc, LGE_TXCMDFREE_8BIT) == 0)
120977542Swpaul			break;
121077542Swpaul
121177542Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
121277542Swpaul		if (m_head == NULL)
121377542Swpaul			break;
121477542Swpaul
121577542Swpaul		if (lge_encap(sc, m_head, &idx)) {
121677542Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1217148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
121877542Swpaul			break;
121977542Swpaul		}
122077542Swpaul
122177542Swpaul		/*
122277542Swpaul		 * If there's a BPF listener, bounce a copy of this frame
122377542Swpaul		 * to him.
122477542Swpaul		 */
1225106937Ssam		BPF_MTAP(ifp, m_head);
122677542Swpaul	}
122777542Swpaul
122877542Swpaul	sc->lge_cdata.lge_tx_prod = idx;
122977542Swpaul
123077542Swpaul	/*
123177542Swpaul	 * Set a timeout in case the chip goes out to lunch.
123277542Swpaul	 */
1233199560Sjhb	sc->lge_timer = 5;
123477542Swpaul
123577542Swpaul	return;
123677542Swpaul}
123777542Swpaul
123899498Salfredstatic void
123999498Salfredlge_init(xsc)
124077542Swpaul	void			*xsc;
124177542Swpaul{
124277542Swpaul	struct lge_softc	*sc = xsc;
1243152727Sjhb
1244152727Sjhb	LGE_LOCK(sc);
1245152727Sjhb	lge_init_locked(sc);
1246152727Sjhb	LGE_UNLOCK(sc);
1247152727Sjhb}
1248152727Sjhb
1249152727Sjhbstatic void
1250152727Sjhblge_init_locked(sc)
1251152727Sjhb	struct lge_softc	*sc;
1252152727Sjhb{
1253147256Sbrooks	struct ifnet		*ifp = sc->lge_ifp;
125477542Swpaul
1255152727Sjhb	LGE_LOCK_ASSERT(sc);
1256148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
125777542Swpaul		return;
125877542Swpaul
125977542Swpaul	/*
126077542Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
126177542Swpaul	 */
126277542Swpaul	lge_stop(sc);
126377542Swpaul	lge_reset(sc);
126477542Swpaul
126577542Swpaul	/* Set MAC address */
1266152315Sru	CSR_WRITE_4(sc, LGE_PAR0, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[0]));
1267152315Sru	CSR_WRITE_4(sc, LGE_PAR1, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[4]));
126877542Swpaul
126977542Swpaul	/* Init circular RX list. */
127077542Swpaul	if (lge_list_rx_init(sc) == ENOBUFS) {
1271162321Sglebius		device_printf(sc->lge_dev, "initialization failed: no "
1272150879Sjhb		    "memory for rx buffers\n");
127377542Swpaul		lge_stop(sc);
127477542Swpaul		return;
127577542Swpaul	}
127677542Swpaul
127777542Swpaul	/*
127877542Swpaul	 * Init tx descriptors.
127977542Swpaul	 */
128077542Swpaul	lge_list_tx_init(sc);
128177542Swpaul
128277542Swpaul	/* Set initial value for MODE1 register. */
128377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_UCAST|
128477542Swpaul	    LGE_MODE1_TX_CRC|LGE_MODE1_TXPAD|
128577542Swpaul	    LGE_MODE1_RX_FLOWCTL|LGE_MODE1_SETRST_CTL0|
128677542Swpaul	    LGE_MODE1_SETRST_CTL1|LGE_MODE1_SETRST_CTL2);
128777542Swpaul
128877542Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
128977542Swpaul	if (ifp->if_flags & IFF_PROMISC) {
129077542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
129177542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_PROMISC);
129277542Swpaul	} else {
129377542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_PROMISC);
129477542Swpaul	}
129577542Swpaul
129677542Swpaul	/*
129777542Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
129877542Swpaul	 */
129977542Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
130077542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
130177542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_BCAST);
130277542Swpaul	} else {
130377542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_BCAST);
130477542Swpaul	}
130577542Swpaul
130677542Swpaul	/* Packet padding workaround? */
130777542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RMVPAD);
130877542Swpaul
130977542Swpaul	/* No error frames */
131077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ERRPKTS);
131177542Swpaul
131277542Swpaul	/* Receive large frames */
131377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_GIANTS);
131477542Swpaul
131577542Swpaul	/* Workaround: disable RX/TX flow control */
131677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_TX_FLOWCTL);
131777542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_FLOWCTL);
131877542Swpaul
131977542Swpaul	/* Make sure to strip CRC from received frames */
132077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_CRC);
132177542Swpaul
132277542Swpaul	/* Turn off magic packet mode */
132377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_MPACK_ENB);
132477542Swpaul
132577542Swpaul	/* Turn off all VLAN stuff */
132677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_VLAN_RX|LGE_MODE1_VLAN_TX|
132777542Swpaul	    LGE_MODE1_VLAN_STRIP|LGE_MODE1_VLAN_INSERT);
132877542Swpaul
132977542Swpaul	/* Workarond: FIFO overflow */
133077542Swpaul	CSR_WRITE_2(sc, LGE_RXFIFO_HIWAT, 0x3FFF);
133177542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL1|LGE_IMR_RXFIFO_WAT);
133277542Swpaul
133377542Swpaul	/*
133477542Swpaul	 * Load the multicast filter.
133577542Swpaul	 */
133677542Swpaul	lge_setmulti(sc);
133777542Swpaul
133877542Swpaul	/*
133977542Swpaul	 * Enable hardware checksum validation for all received IPv4
134077542Swpaul	 * packets, do not reject packets with bad checksums.
134177542Swpaul	 */
134277542Swpaul	CSR_WRITE_4(sc, LGE_MODE2, LGE_MODE2_RX_IPCSUM|
134377542Swpaul	    LGE_MODE2_RX_TCPCSUM|LGE_MODE2_RX_UDPCSUM|
134477542Swpaul	    LGE_MODE2_RX_ERRCSUM);
134577542Swpaul
134677542Swpaul	/*
134777542Swpaul	 * Enable the delivery of PHY interrupts based on
134877542Swpaul	 * link/speed/duplex status chalges.
134977542Swpaul	 */
135077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL0|LGE_MODE1_GMIIPOLL);
135177542Swpaul
135277542Swpaul	/* Enable receiver and transmitter. */
135377542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
135477542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_ENB);
135577542Swpaul
135677542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_HI, 0);
135777542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_TX_ENB);
135877542Swpaul
135977542Swpaul	/*
136077542Swpaul	 * Enable interrupts.
136177542Swpaul	 */
136277542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|
136377542Swpaul	    LGE_IMR_SETRST_CTL1|LGE_IMR_INTR_ENB|LGE_INTRS);
136477542Swpaul
1365152727Sjhb	lge_ifmedia_upd_locked(ifp);
136677542Swpaul
1367148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1368148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
136977542Swpaul
1370152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
137177542Swpaul
137277542Swpaul	return;
137377542Swpaul}
137477542Swpaul
137577542Swpaul/*
137677542Swpaul * Set media options.
137777542Swpaul */
137899498Salfredstatic int
137999498Salfredlge_ifmedia_upd(ifp)
138077542Swpaul	struct ifnet		*ifp;
138177542Swpaul{
138277542Swpaul	struct lge_softc	*sc;
1383152727Sjhb
1384152727Sjhb	sc = ifp->if_softc;
1385152727Sjhb	LGE_LOCK(sc);
1386152727Sjhb	lge_ifmedia_upd_locked(ifp);
1387152727Sjhb	LGE_UNLOCK(sc);
1388152727Sjhb
1389152727Sjhb	return(0);
1390152727Sjhb}
1391152727Sjhb
1392152727Sjhbstatic void
1393152727Sjhblge_ifmedia_upd_locked(ifp)
1394152727Sjhb	struct ifnet		*ifp;
1395152727Sjhb{
1396152727Sjhb	struct lge_softc	*sc;
139777542Swpaul	struct mii_data		*mii;
1398221407Smarius	struct mii_softc	*miisc;
139977542Swpaul
140077542Swpaul	sc = ifp->if_softc;
140177542Swpaul
1402152727Sjhb	LGE_LOCK_ASSERT(sc);
140377542Swpaul	mii = device_get_softc(sc->lge_miibus);
140477542Swpaul	sc->lge_link = 0;
1405221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1406221407Smarius		PHY_RESET(miisc);
140777542Swpaul	mii_mediachg(mii);
140877542Swpaul}
140977542Swpaul
141077542Swpaul/*
141177542Swpaul * Report current media status.
141277542Swpaul */
141399498Salfredstatic void
141499498Salfredlge_ifmedia_sts(ifp, ifmr)
141577542Swpaul	struct ifnet		*ifp;
141677542Swpaul	struct ifmediareq	*ifmr;
141777542Swpaul{
141877542Swpaul	struct lge_softc	*sc;
141977542Swpaul	struct mii_data		*mii;
142077542Swpaul
142177542Swpaul	sc = ifp->if_softc;
142277542Swpaul
1423152727Sjhb	LGE_LOCK(sc);
142477542Swpaul	mii = device_get_softc(sc->lge_miibus);
142577542Swpaul	mii_pollstat(mii);
142677542Swpaul	ifmr->ifm_active = mii->mii_media_active;
142777542Swpaul	ifmr->ifm_status = mii->mii_media_status;
1428226478Syongari	LGE_UNLOCK(sc);
142977542Swpaul
143077542Swpaul	return;
143177542Swpaul}
143277542Swpaul
143399498Salfredstatic int
143499498Salfredlge_ioctl(ifp, command, data)
143577542Swpaul	struct ifnet		*ifp;
143677542Swpaul	u_long			command;
143777542Swpaul	caddr_t			data;
143877542Swpaul{
143977542Swpaul	struct lge_softc	*sc = ifp->if_softc;
144077542Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
144177542Swpaul	struct mii_data		*mii;
1442152727Sjhb	int			error = 0;
144377542Swpaul
144477542Swpaul	switch(command) {
144577542Swpaul	case SIOCSIFMTU:
1446152727Sjhb		LGE_LOCK(sc);
144777542Swpaul		if (ifr->ifr_mtu > LGE_JUMBO_MTU)
144877542Swpaul			error = EINVAL;
144977542Swpaul		else
145077542Swpaul			ifp->if_mtu = ifr->ifr_mtu;
1451152727Sjhb		LGE_UNLOCK(sc);
145277542Swpaul		break;
145377542Swpaul	case SIOCSIFFLAGS:
1454152727Sjhb		LGE_LOCK(sc);
145577542Swpaul		if (ifp->if_flags & IFF_UP) {
1456148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
145777542Swpaul			    ifp->if_flags & IFF_PROMISC &&
145877542Swpaul			    !(sc->lge_if_flags & IFF_PROMISC)) {
145977542Swpaul				CSR_WRITE_4(sc, LGE_MODE1,
146077542Swpaul				    LGE_MODE1_SETRST_CTL1|
146177542Swpaul				    LGE_MODE1_RX_PROMISC);
1462148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
146377542Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
146477542Swpaul			    sc->lge_if_flags & IFF_PROMISC) {
146577542Swpaul				CSR_WRITE_4(sc, LGE_MODE1,
146677542Swpaul				    LGE_MODE1_RX_PROMISC);
146777542Swpaul			} else {
1468148887Srwatson				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1469152727Sjhb				lge_init_locked(sc);
147077542Swpaul			}
147177542Swpaul		} else {
1472148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
147377542Swpaul				lge_stop(sc);
147477542Swpaul		}
147577542Swpaul		sc->lge_if_flags = ifp->if_flags;
1476152727Sjhb		LGE_UNLOCK(sc);
147777542Swpaul		error = 0;
147877542Swpaul		break;
147977542Swpaul	case SIOCADDMULTI:
148077542Swpaul	case SIOCDELMULTI:
1481152727Sjhb		LGE_LOCK(sc);
148277542Swpaul		lge_setmulti(sc);
1483152727Sjhb		LGE_UNLOCK(sc);
148477542Swpaul		error = 0;
148577542Swpaul		break;
148677542Swpaul	case SIOCGIFMEDIA:
148777542Swpaul	case SIOCSIFMEDIA:
148877542Swpaul		mii = device_get_softc(sc->lge_miibus);
148977542Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
149077542Swpaul		break;
149177542Swpaul	default:
1492106937Ssam		error = ether_ioctl(ifp, command, data);
149377542Swpaul		break;
149477542Swpaul	}
149577542Swpaul
149677542Swpaul	return(error);
149777542Swpaul}
149877542Swpaul
149999498Salfredstatic void
1500199560Sjhblge_watchdog(sc)
1501199560Sjhb	struct lge_softc	*sc;
1502199560Sjhb{
150377542Swpaul	struct ifnet		*ifp;
150477542Swpaul
1505199560Sjhb	LGE_LOCK_ASSERT(sc);
1506199560Sjhb	ifp = sc->lge_ifp;
150777542Swpaul
150877542Swpaul	ifp->if_oerrors++;
1509150879Sjhb	if_printf(ifp, "watchdog timeout\n");
151077542Swpaul
151177542Swpaul	lge_stop(sc);
151277542Swpaul	lge_reset(sc);
1513148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1514152727Sjhb	lge_init_locked(sc);
151577542Swpaul
151677542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1517152727Sjhb		lge_start_locked(ifp);
151877542Swpaul}
151977542Swpaul
152077542Swpaul/*
152177542Swpaul * Stop the adapter and free any mbufs allocated to the
152277542Swpaul * RX and TX lists.
152377542Swpaul */
152499498Salfredstatic void
152599498Salfredlge_stop(sc)
152677542Swpaul	struct lge_softc	*sc;
152777542Swpaul{
152877542Swpaul	register int		i;
152977542Swpaul	struct ifnet		*ifp;
153077542Swpaul
1531152727Sjhb	LGE_LOCK_ASSERT(sc);
1532147256Sbrooks	ifp = sc->lge_ifp;
1533199560Sjhb	sc->lge_timer = 0;
1534152727Sjhb	callout_stop(&sc->lge_stat_callout);
153577542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_INTR_ENB);
153677542Swpaul
153777542Swpaul	/* Disable receiver and transmitter. */
153877542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ENB|LGE_MODE1_TX_ENB);
153977542Swpaul	sc->lge_link = 0;
154077542Swpaul
154177542Swpaul	/*
154277542Swpaul	 * Free data in the RX lists.
154377542Swpaul	 */
154477542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
154577542Swpaul		if (sc->lge_ldata->lge_rx_list[i].lge_mbuf != NULL) {
154677542Swpaul			m_freem(sc->lge_ldata->lge_rx_list[i].lge_mbuf);
154777542Swpaul			sc->lge_ldata->lge_rx_list[i].lge_mbuf = NULL;
154877542Swpaul		}
154977542Swpaul	}
155077542Swpaul	bzero((char *)&sc->lge_ldata->lge_rx_list,
155177542Swpaul		sizeof(sc->lge_ldata->lge_rx_list));
155277542Swpaul
155377542Swpaul	/*
155477542Swpaul	 * Free the TX list buffers.
155577542Swpaul	 */
155677542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
155777542Swpaul		if (sc->lge_ldata->lge_tx_list[i].lge_mbuf != NULL) {
155877542Swpaul			m_freem(sc->lge_ldata->lge_tx_list[i].lge_mbuf);
155977542Swpaul			sc->lge_ldata->lge_tx_list[i].lge_mbuf = NULL;
156077542Swpaul		}
156177542Swpaul	}
156277542Swpaul
156377542Swpaul	bzero((char *)&sc->lge_ldata->lge_tx_list,
156477542Swpaul		sizeof(sc->lge_ldata->lge_tx_list));
156577542Swpaul
1566148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
156777542Swpaul
156877542Swpaul	return;
156977542Swpaul}
157077542Swpaul
157177542Swpaul/*
157277542Swpaul * Stop all chip I/O so that the kernel's probe routines don't
157377542Swpaul * get confused by errant DMAs when rebooting.
157477542Swpaul */
1575173839Syongaristatic int
157699498Salfredlge_shutdown(dev)
157777542Swpaul	device_t		dev;
157877542Swpaul{
157977542Swpaul	struct lge_softc	*sc;
158077542Swpaul
158177542Swpaul	sc = device_get_softc(dev);
158277542Swpaul
1583152727Sjhb	LGE_LOCK(sc);
158477542Swpaul	lge_reset(sc);
158577542Swpaul	lge_stop(sc);
1586152727Sjhb	LGE_UNLOCK(sc);
158777542Swpaul
1588173839Syongari	return (0);
158977542Swpaul}
1590