if_lge.c revision 195049
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: head/sys/dev/lge/if_lge.c 195049 2009-06-26 11:45:06Z rwatson $");
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 */
11377542Swpaulstatic 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 *);
14099498Salfredstatic void lge_watchdog(struct ifnet *);
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	/* bus interface */
17477542Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
17577542Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
17677542Swpaul
17777542Swpaul	/* MII interface */
17877542Swpaul	DEVMETHOD(miibus_readreg,	lge_miibus_readreg),
17977542Swpaul	DEVMETHOD(miibus_writereg,	lge_miibus_writereg),
18077542Swpaul	DEVMETHOD(miibus_statchg,	lge_miibus_statchg),
18177542Swpaul
18277542Swpaul	{ 0, 0 }
18377542Swpaul};
18477542Swpaul
18577542Swpaulstatic driver_t lge_driver = {
18677542Swpaul	"lge",
18777542Swpaul	lge_methods,
18877542Swpaul	sizeof(struct lge_softc)
18977542Swpaul};
19077542Swpaul
19177542Swpaulstatic devclass_t lge_devclass;
19277542Swpaul
193113506SmdoddDRIVER_MODULE(lge, pci, lge_driver, lge_devclass, 0, 0);
19477542SwpaulDRIVER_MODULE(miibus, lge, miibus_driver, miibus_devclass, 0, 0);
195113506SmdoddMODULE_DEPEND(lge, pci, 1, 1, 1);
196113506SmdoddMODULE_DEPEND(lge, ether, 1, 1, 1);
197113506SmdoddMODULE_DEPEND(lge, miibus, 1, 1, 1);
19877542Swpaul
19977542Swpaul#define LGE_SETBIT(sc, reg, x)				\
20077542Swpaul	CSR_WRITE_4(sc, reg,				\
20177542Swpaul		CSR_READ_4(sc, reg) | (x))
20277542Swpaul
20377542Swpaul#define LGE_CLRBIT(sc, reg, x)				\
20477542Swpaul	CSR_WRITE_4(sc, reg,				\
20577542Swpaul		CSR_READ_4(sc, reg) & ~(x))
20677542Swpaul
20777542Swpaul#define SIO_SET(x)					\
20877542Swpaul	CSR_WRITE_4(sc, LGE_MEAR, CSR_READ_4(sc, LGE_MEAR) | x)
20977542Swpaul
21077542Swpaul#define SIO_CLR(x)					\
21177542Swpaul	CSR_WRITE_4(sc, LGE_MEAR, CSR_READ_4(sc, LGE_MEAR) & ~x)
21277542Swpaul
21377542Swpaul/*
21477542Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
21577542Swpaul */
21699498Salfredstatic void
21799498Salfredlge_eeprom_getword(sc, addr, dest)
21877542Swpaul	struct lge_softc	*sc;
21977542Swpaul	int			addr;
22077542Swpaul	u_int16_t		*dest;
22177542Swpaul{
22277542Swpaul	register int		i;
22377542Swpaul	u_int32_t		val;
22477542Swpaul
22577542Swpaul	CSR_WRITE_4(sc, LGE_EECTL, LGE_EECTL_CMD_READ|
22677542Swpaul	    LGE_EECTL_SINGLEACCESS|((addr >> 1) << 8));
22777542Swpaul
22877542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
22977542Swpaul		if (!(CSR_READ_4(sc, LGE_EECTL) & LGE_EECTL_CMD_READ))
23077542Swpaul			break;
23177542Swpaul
23277542Swpaul	if (i == LGE_TIMEOUT) {
233162321Sglebius		device_printf(sc->lge_dev, "EEPROM read timed out\n");
23477542Swpaul		return;
23577542Swpaul	}
23677542Swpaul
23777542Swpaul	val = CSR_READ_4(sc, LGE_EEDATA);
23877542Swpaul
23977542Swpaul	if (addr & 1)
24077542Swpaul		*dest = (val >> 16) & 0xFFFF;
24177542Swpaul	else
24277542Swpaul		*dest = val & 0xFFFF;
24377542Swpaul
24477542Swpaul	return;
24577542Swpaul}
24677542Swpaul
24777542Swpaul/*
24877542Swpaul * Read a sequence of words from the EEPROM.
24977542Swpaul */
25099498Salfredstatic void
25199498Salfredlge_read_eeprom(sc, dest, off, cnt, swap)
25277542Swpaul	struct lge_softc	*sc;
25377542Swpaul	caddr_t			dest;
25477542Swpaul	int			off;
25577542Swpaul	int			cnt;
25677542Swpaul	int			swap;
25777542Swpaul{
25877542Swpaul	int			i;
25977542Swpaul	u_int16_t		word = 0, *ptr;
26077542Swpaul
26177542Swpaul	for (i = 0; i < cnt; i++) {
26277542Swpaul		lge_eeprom_getword(sc, off + i, &word);
26377542Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
26477542Swpaul		if (swap)
26577542Swpaul			*ptr = ntohs(word);
26677542Swpaul		else
26777542Swpaul			*ptr = word;
26877542Swpaul	}
26977542Swpaul
27077542Swpaul	return;
27177542Swpaul}
27277542Swpaul
27399498Salfredstatic int
27499498Salfredlge_miibus_readreg(dev, phy, reg)
27577542Swpaul	device_t		dev;
27677542Swpaul	int			phy, reg;
27777542Swpaul{
27877542Swpaul	struct lge_softc	*sc;
27977542Swpaul	int			i;
28077542Swpaul
28177542Swpaul	sc = device_get_softc(dev);
28277542Swpaul
28377542Swpaul	/*
28477542Swpaul	 * If we have a non-PCS PHY, pretend that the internal
28577542Swpaul	 * autoneg stuff at PHY address 0 isn't there so that
28677542Swpaul	 * the miibus code will find only the GMII PHY.
28777542Swpaul	 */
28877542Swpaul	if (sc->lge_pcs == 0 && phy == 0)
28977542Swpaul		return(0);
29077542Swpaul
29177542Swpaul	CSR_WRITE_4(sc, LGE_GMIICTL, (phy << 8) | reg | LGE_GMIICMD_READ);
29277542Swpaul
29377542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
29477542Swpaul		if (!(CSR_READ_4(sc, LGE_GMIICTL) & LGE_GMIICTL_CMDBUSY))
29577542Swpaul			break;
29677542Swpaul
29777542Swpaul	if (i == LGE_TIMEOUT) {
298162321Sglebius		device_printf(sc->lge_dev, "PHY read timed out\n");
29977542Swpaul		return(0);
30077542Swpaul	}
30177542Swpaul
30277542Swpaul	return(CSR_READ_4(sc, LGE_GMIICTL) >> 16);
30377542Swpaul}
30477542Swpaul
30599498Salfredstatic int
30699498Salfredlge_miibus_writereg(dev, phy, reg, data)
30777542Swpaul	device_t		dev;
30877542Swpaul	int			phy, reg, data;
30977542Swpaul{
31077542Swpaul	struct lge_softc	*sc;
31177542Swpaul	int			i;
31277542Swpaul
31377542Swpaul	sc = device_get_softc(dev);
31477542Swpaul
31577542Swpaul	CSR_WRITE_4(sc, LGE_GMIICTL,
31677542Swpaul	    (data << 16) | (phy << 8) | reg | LGE_GMIICMD_WRITE);
31777542Swpaul
31877542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++)
31977542Swpaul		if (!(CSR_READ_4(sc, LGE_GMIICTL) & LGE_GMIICTL_CMDBUSY))
32077542Swpaul			break;
32177542Swpaul
32277542Swpaul	if (i == LGE_TIMEOUT) {
323162321Sglebius		device_printf(sc->lge_dev, "PHY write timed out\n");
32477542Swpaul		return(0);
32577542Swpaul	}
32677542Swpaul
32777542Swpaul	return(0);
32877542Swpaul}
32977542Swpaul
33099498Salfredstatic void
33199498Salfredlge_miibus_statchg(dev)
33277542Swpaul	device_t		dev;
33377542Swpaul{
33477542Swpaul	struct lge_softc	*sc;
33577542Swpaul	struct mii_data		*mii;
33677542Swpaul
33777542Swpaul	sc = device_get_softc(dev);
33877542Swpaul	mii = device_get_softc(sc->lge_miibus);
33977542Swpaul
34077542Swpaul	LGE_CLRBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_SPEED);
34177542Swpaul	switch (IFM_SUBTYPE(mii->mii_media_active)) {
34295673Sphk	case IFM_1000_T:
34377542Swpaul	case IFM_1000_SX:
34477542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_1000);
34577542Swpaul		break;
34677542Swpaul	case IFM_100_TX:
34777542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_100);
34877542Swpaul		break;
34977542Swpaul	case IFM_10_T:
35077542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_10);
35177542Swpaul		break;
35277542Swpaul	default:
35377542Swpaul		/*
35477542Swpaul		 * Choose something, even if it's wrong. Clearing
35577542Swpaul		 * all the bits will hose autoneg on the internal
35677542Swpaul		 * PHY.
35777542Swpaul		 */
35877542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_SPEED_1000);
35977542Swpaul		break;
36077542Swpaul	}
36177542Swpaul
36277542Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
36377542Swpaul		LGE_SETBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_FDX);
36477542Swpaul	} else {
36577542Swpaul		LGE_CLRBIT(sc, LGE_GMIIMODE, LGE_GMIIMODE_FDX);
36677542Swpaul	}
36777542Swpaul
36877542Swpaul	return;
36977542Swpaul}
37077542Swpaul
37199498Salfredstatic void
37299498Salfredlge_setmulti(sc)
37377542Swpaul	struct lge_softc	*sc;
37477542Swpaul{
37577542Swpaul	struct ifnet		*ifp;
37677542Swpaul	struct ifmultiaddr	*ifma;
37777542Swpaul	u_int32_t		h = 0, hashes[2] = { 0, 0 };
37877542Swpaul
379147256Sbrooks	ifp = sc->lge_ifp;
380152727Sjhb	LGE_LOCK_ASSERT(sc);
38177542Swpaul
38277542Swpaul	/* Make sure multicast hash table is enabled. */
38377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_MCAST);
38477542Swpaul
38577542Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
38677542Swpaul		CSR_WRITE_4(sc, LGE_MAR0, 0xFFFFFFFF);
38777542Swpaul		CSR_WRITE_4(sc, LGE_MAR1, 0xFFFFFFFF);
38877542Swpaul		return;
38977542Swpaul	}
39077542Swpaul
39177542Swpaul	/* first, zot all the existing hash bits */
39277542Swpaul	CSR_WRITE_4(sc, LGE_MAR0, 0);
39377542Swpaul	CSR_WRITE_4(sc, LGE_MAR1, 0);
39477542Swpaul
39577542Swpaul	/* now program new ones */
396195049Srwatson	if_maddr_rlock(ifp);
39777542Swpaul	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
39877542Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
39977542Swpaul			continue;
400130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
401130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
40277542Swpaul		if (h < 32)
40377542Swpaul			hashes[0] |= (1 << h);
40477542Swpaul		else
40577542Swpaul			hashes[1] |= (1 << (h - 32));
40677542Swpaul	}
407195049Srwatson	if_maddr_runlock(ifp);
40877542Swpaul
40977542Swpaul	CSR_WRITE_4(sc, LGE_MAR0, hashes[0]);
41077542Swpaul	CSR_WRITE_4(sc, LGE_MAR1, hashes[1]);
41177542Swpaul
41277542Swpaul	return;
41377542Swpaul}
41477542Swpaul
41599498Salfredstatic void
41699498Salfredlge_reset(sc)
41777542Swpaul	struct lge_softc	*sc;
41877542Swpaul{
41977542Swpaul	register int		i;
42077542Swpaul
42177542Swpaul	LGE_SETBIT(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL0|LGE_MODE1_SOFTRST);
42277542Swpaul
42377542Swpaul	for (i = 0; i < LGE_TIMEOUT; i++) {
42477542Swpaul		if (!(CSR_READ_4(sc, LGE_MODE1) & LGE_MODE1_SOFTRST))
42577542Swpaul			break;
42677542Swpaul	}
42777542Swpaul
42877542Swpaul	if (i == LGE_TIMEOUT)
429162321Sglebius		device_printf(sc->lge_dev, "reset never completed\n");
43077542Swpaul
43177542Swpaul	/* Wait a little while for the chip to get its brains in order. */
43277542Swpaul	DELAY(1000);
43377542Swpaul
43477542Swpaul        return;
43577542Swpaul}
43677542Swpaul
43777542Swpaul/*
43877542Swpaul * Probe for a Level 1 chip. Check the PCI vendor and device
43977542Swpaul * IDs against our list and return a device name if we find a match.
44077542Swpaul */
44199498Salfredstatic int
44299498Salfredlge_probe(dev)
44377542Swpaul	device_t		dev;
44477542Swpaul{
44577542Swpaul	struct lge_type		*t;
44677542Swpaul
44777542Swpaul	t = lge_devs;
44877542Swpaul
44977542Swpaul	while(t->lge_name != NULL) {
45077542Swpaul		if ((pci_get_vendor(dev) == t->lge_vid) &&
45177542Swpaul		    (pci_get_device(dev) == t->lge_did)) {
45277542Swpaul			device_set_desc(dev, t->lge_name);
453143160Simp			return(BUS_PROBE_DEFAULT);
45477542Swpaul		}
45577542Swpaul		t++;
45677542Swpaul	}
45777542Swpaul
45877542Swpaul	return(ENXIO);
45977542Swpaul}
46077542Swpaul
46177542Swpaul/*
46277542Swpaul * Attach the interface. Allocate softc structures, do ifmedia
46377542Swpaul * setup and ethernet/BPF attach.
46477542Swpaul */
46599498Salfredstatic int
46699498Salfredlge_attach(dev)
46777542Swpaul	device_t		dev;
46877542Swpaul{
46977542Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
47077542Swpaul	struct lge_softc	*sc;
471150879Sjhb	struct ifnet		*ifp = NULL;
472150879Sjhb	int			error = 0, rid;
47377542Swpaul
47477542Swpaul	sc = device_get_softc(dev);
475162321Sglebius	sc->lge_dev = dev;
476162321Sglebius
477152727Sjhb	mtx_init(&sc->lge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
478152727Sjhb	    MTX_DEF);
479152727Sjhb	callout_init_mtx(&sc->lge_stat_callout, &sc->lge_mtx, 0);
480150879Sjhb
48177542Swpaul	/*
48277542Swpaul	 * Map control/status registers.
48377542Swpaul	 */
48477542Swpaul	pci_enable_busmaster(dev);
48577542Swpaul
48677542Swpaul	rid = LGE_RID;
487127135Snjl	sc->lge_res = bus_alloc_resource_any(dev, LGE_RES, &rid, RF_ACTIVE);
48877542Swpaul
48977542Swpaul	if (sc->lge_res == NULL) {
490150879Sjhb		device_printf(dev, "couldn't map ports/memory\n");
49177542Swpaul		error = ENXIO;
49277542Swpaul		goto fail;
49377542Swpaul	}
49477542Swpaul
49577542Swpaul	sc->lge_btag = rman_get_bustag(sc->lge_res);
49677542Swpaul	sc->lge_bhandle = rman_get_bushandle(sc->lge_res);
49777542Swpaul
49877542Swpaul	/* Allocate interrupt */
49977542Swpaul	rid = 0;
500127135Snjl	sc->lge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
50177542Swpaul	    RF_SHAREABLE | RF_ACTIVE);
50277542Swpaul
50377542Swpaul	if (sc->lge_irq == NULL) {
504150879Sjhb		device_printf(dev, "couldn't map interrupt\n");
50577542Swpaul		error = ENXIO;
50677542Swpaul		goto fail;
50777542Swpaul	}
50877542Swpaul
50977542Swpaul	/* Reset the adapter. */
51077542Swpaul	lge_reset(sc);
51177542Swpaul
51277542Swpaul	/*
51377542Swpaul	 * Get station address from the EEPROM.
51477542Swpaul	 */
51577542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[0], LGE_EE_NODEADDR_0, 1, 0);
51677542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[2], LGE_EE_NODEADDR_1, 1, 0);
51777542Swpaul	lge_read_eeprom(sc, (caddr_t)&eaddr[4], LGE_EE_NODEADDR_2, 1, 0);
51877542Swpaul
51977542Swpaul	sc->lge_ldata = contigmalloc(sizeof(struct lge_list_data), M_DEVBUF,
520152727Sjhb	    M_NOWAIT | M_ZERO, 0, 0xffffffff, PAGE_SIZE, 0);
52177542Swpaul
52277542Swpaul	if (sc->lge_ldata == NULL) {
523150879Sjhb		device_printf(dev, "no memory for list buffers!\n");
52477542Swpaul		error = ENXIO;
52577542Swpaul		goto fail;
52677542Swpaul	}
52777542Swpaul
52877542Swpaul	/* Try to allocate memory for jumbo buffers. */
52977542Swpaul	if (lge_alloc_jumbo_mem(sc)) {
530150879Sjhb		device_printf(dev, "jumbo buffer allocation failed\n");
53177542Swpaul		error = ENXIO;
53277542Swpaul		goto fail;
53377542Swpaul	}
53477542Swpaul
535147256Sbrooks	ifp = sc->lge_ifp = if_alloc(IFT_ETHER);
536147256Sbrooks	if (ifp == NULL) {
537150879Sjhb		device_printf(dev, "can not if_alloc()\n");
538147256Sbrooks		error = ENOSPC;
539147256Sbrooks		goto fail;
540147256Sbrooks	}
54177542Swpaul	ifp->if_softc = sc;
542121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
54377542Swpaul	ifp->if_mtu = ETHERMTU;
544152727Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
54577542Swpaul	ifp->if_ioctl = lge_ioctl;
54677542Swpaul	ifp->if_start = lge_start;
54777542Swpaul	ifp->if_watchdog = lge_watchdog;
54877542Swpaul	ifp->if_init = lge_init;
54977542Swpaul	ifp->if_snd.ifq_maxlen = LGE_TX_LIST_CNT - 1;
55083638Sjlemon	ifp->if_capabilities = IFCAP_RXCSUM;
55183638Sjlemon	ifp->if_capenable = ifp->if_capabilities;
55277542Swpaul
55377542Swpaul	if (CSR_READ_4(sc, LGE_GMIIMODE) & LGE_GMIIMODE_PCSENH)
55477542Swpaul		sc->lge_pcs = 1;
55577542Swpaul	else
55677542Swpaul		sc->lge_pcs = 0;
55777542Swpaul
55877542Swpaul	/*
55977542Swpaul	 * Do MII setup.
56077542Swpaul	 */
56177542Swpaul	if (mii_phy_probe(dev, &sc->lge_miibus,
56277542Swpaul	    lge_ifmedia_upd, lge_ifmedia_sts)) {
563150879Sjhb		device_printf(dev, "MII without any PHY!\n");
56477542Swpaul		error = ENXIO;
56577542Swpaul		goto fail;
56677542Swpaul	}
56777542Swpaul
56877542Swpaul	/*
56977542Swpaul	 * Call MI attach routine.
57077542Swpaul	 */
571106937Ssam	ether_ifattach(ifp, eaddr);
572152727Sjhb
573152727Sjhb	error = bus_setup_intr(dev, sc->lge_irq, INTR_TYPE_NET | INTR_MPSAFE,
574166901Spiso	    NULL, lge_intr, sc, &sc->lge_intrhand);
575152727Sjhb
576152727Sjhb	if (error) {
577152727Sjhb		ether_ifdetach(ifp);
578152727Sjhb		device_printf(dev, "couldn't set up irq\n");
579152727Sjhb		goto fail;
580152727Sjhb	}
581150879Sjhb	return (0);
58277542Swpaul
58377542Swpaulfail:
584176813Syongari	lge_free_jumbo_mem(sc);
585150879Sjhb	if (sc->lge_ldata)
586150879Sjhb		contigfree(sc->lge_ldata,
587150879Sjhb		    sizeof(struct lge_list_data), M_DEVBUF);
588150879Sjhb	if (ifp)
589150879Sjhb		if_free(ifp);
590150879Sjhb	if (sc->lge_irq)
591150879Sjhb		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
592150879Sjhb	if (sc->lge_res)
593150879Sjhb		bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
594152727Sjhb	mtx_destroy(&sc->lge_mtx);
59577542Swpaul	return(error);
59677542Swpaul}
59777542Swpaul
59899498Salfredstatic int
59999498Salfredlge_detach(dev)
60077542Swpaul	device_t		dev;
60177542Swpaul{
60277542Swpaul	struct lge_softc	*sc;
60377542Swpaul	struct ifnet		*ifp;
60477542Swpaul
60577542Swpaul	sc = device_get_softc(dev);
606147256Sbrooks	ifp = sc->lge_ifp;
60777542Swpaul
608152727Sjhb	LGE_LOCK(sc);
60977542Swpaul	lge_reset(sc);
61077542Swpaul	lge_stop(sc);
611152727Sjhb	LGE_UNLOCK(sc);
612152727Sjhb	callout_drain(&sc->lge_stat_callout);
613106937Ssam	ether_ifdetach(ifp);
61477542Swpaul
61577542Swpaul	bus_generic_detach(dev);
61677542Swpaul	device_delete_child(dev, sc->lge_miibus);
61777542Swpaul
61877542Swpaul	bus_teardown_intr(dev, sc->lge_irq, sc->lge_intrhand);
61977542Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lge_irq);
62077542Swpaul	bus_release_resource(dev, LGE_RES, LGE_RID, sc->lge_res);
62177542Swpaul
62277542Swpaul	contigfree(sc->lge_ldata, sizeof(struct lge_list_data), M_DEVBUF);
623150306Simp	if_free(ifp);
62477542Swpaul	lge_free_jumbo_mem(sc);
625152727Sjhb	mtx_destroy(&sc->lge_mtx);
62677542Swpaul
62777542Swpaul	return(0);
62877542Swpaul}
62977542Swpaul
63077542Swpaul/*
63177542Swpaul * Initialize the transmit descriptors.
63277542Swpaul */
63399498Salfredstatic int
63499498Salfredlge_list_tx_init(sc)
63577542Swpaul	struct lge_softc	*sc;
63677542Swpaul{
63777542Swpaul	struct lge_list_data	*ld;
63877542Swpaul	struct lge_ring_data	*cd;
63977542Swpaul	int			i;
64077542Swpaul
64177542Swpaul	cd = &sc->lge_cdata;
64277542Swpaul	ld = sc->lge_ldata;
64377542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
64477542Swpaul		ld->lge_tx_list[i].lge_mbuf = NULL;
64577542Swpaul		ld->lge_tx_list[i].lge_ctl = 0;
64677542Swpaul	}
64777542Swpaul
64877542Swpaul	cd->lge_tx_prod = cd->lge_tx_cons = 0;
64977542Swpaul
65077542Swpaul	return(0);
65177542Swpaul}
65277542Swpaul
65377542Swpaul
65477542Swpaul/*
65577542Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
65677542Swpaul * we arralge the descriptors in a closed ring, so that the last descriptor
65777542Swpaul * points back to the first.
65877542Swpaul */
65999498Salfredstatic int
66099498Salfredlge_list_rx_init(sc)
66177542Swpaul	struct lge_softc	*sc;
66277542Swpaul{
66377542Swpaul	struct lge_list_data	*ld;
66477542Swpaul	struct lge_ring_data	*cd;
66577542Swpaul	int			i;
66677542Swpaul
66777542Swpaul	ld = sc->lge_ldata;
66877542Swpaul	cd = &sc->lge_cdata;
66977542Swpaul
67077542Swpaul	cd->lge_rx_prod = cd->lge_rx_cons = 0;
67177542Swpaul
67277542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
67377542Swpaul
67477542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
67577542Swpaul		if (CSR_READ_1(sc, LGE_RXCMDFREE_8BIT) == 0)
67677542Swpaul			break;
67777542Swpaul		if (lge_newbuf(sc, &ld->lge_rx_list[i], NULL) == ENOBUFS)
67877542Swpaul			return(ENOBUFS);
67977542Swpaul	}
68077542Swpaul
68177542Swpaul	/* Clear possible 'rx command queue empty' interrupt. */
68277542Swpaul	CSR_READ_4(sc, LGE_ISR);
68377542Swpaul
68477542Swpaul	return(0);
68577542Swpaul}
68677542Swpaul
68777542Swpaul/*
68877542Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
68977542Swpaul */
69099498Salfredstatic int
69199498Salfredlge_newbuf(sc, c, m)
69277542Swpaul	struct lge_softc	*sc;
69377542Swpaul	struct lge_rx_desc	*c;
69477542Swpaul	struct mbuf		*m;
69577542Swpaul{
69677542Swpaul	struct mbuf		*m_new = NULL;
69777542Swpaul	caddr_t			*buf = NULL;
69877542Swpaul
69977542Swpaul	if (m == NULL) {
700111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
70177542Swpaul		if (m_new == NULL) {
702162321Sglebius			device_printf(sc->lge_dev, "no memory for rx list "
703150879Sjhb			    "-- packet dropped!\n");
70477542Swpaul			return(ENOBUFS);
70577542Swpaul		}
70677542Swpaul
70777542Swpaul		/* Allocate the jumbo buffer */
70877542Swpaul		buf = lge_jalloc(sc);
70977542Swpaul		if (buf == NULL) {
71077542Swpaul#ifdef LGE_VERBOSE
711162321Sglebius			device_printf(sc->lge_dev, "jumbo allocation failed "
712150879Sjhb			    "-- packet dropped!\n");
71377542Swpaul#endif
71477542Swpaul			m_freem(m_new);
71577542Swpaul			return(ENOBUFS);
71677542Swpaul		}
71777542Swpaul		/* Attach the buffer to the mbuf */
71877542Swpaul		m_new->m_data = (void *)buf;
71978440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
72078440Swpaul		MEXTADD(m_new, buf, LGE_JUMBO_FRAMELEN, lge_jfree,
721175872Sphk		    buf, (struct lge_softc *)sc, 0, EXT_NET_DRV);
72277542Swpaul	} else {
72377542Swpaul		m_new = m;
72478440Swpaul		m_new->m_len = m_new->m_pkthdr.len = LGE_JUMBO_FRAMELEN;
72577542Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
72677542Swpaul	}
72777542Swpaul
72877542Swpaul	/*
72977542Swpaul	 * Adjust alignment so packet payload begins on a
73077542Swpaul	 * longword boundary. Mandatory for Alpha, useful on
73177542Swpaul	 * x86 too.
73277542Swpaul	*/
73377542Swpaul	m_adj(m_new, ETHER_ALIGN);
73477542Swpaul
73577542Swpaul	c->lge_mbuf = m_new;
73677542Swpaul	c->lge_fragptr_hi = 0;
73777542Swpaul	c->lge_fragptr_lo = vtophys(mtod(m_new, caddr_t));
73877542Swpaul	c->lge_fraglen = m_new->m_len;
73977542Swpaul	c->lge_ctl = m_new->m_len | LGE_RXCTL_WANTINTR | LGE_FRAGCNT(1);
74077542Swpaul	c->lge_sts = 0;
74177542Swpaul
74277542Swpaul	/*
74377542Swpaul	 * Put this buffer in the RX command FIFO. To do this,
74477542Swpaul	 * we just write the physical address of the descriptor
74577542Swpaul	 * into the RX descriptor address registers. Note that
74677542Swpaul	 * there are two registers, one high DWORD and one low
74777542Swpaul	 * DWORD, which lets us specify a 64-bit address if
74877542Swpaul	 * desired. We only use a 32-bit address for now.
74977542Swpaul	 * Writing to the low DWORD register is what actually
75077542Swpaul	 * causes the command to be issued, so we do that
75177542Swpaul	 * last.
75277542Swpaul	 */
75377542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_LO, vtophys(c));
75477542Swpaul	LGE_INC(sc->lge_cdata.lge_rx_prod, LGE_RX_LIST_CNT);
75577542Swpaul
75677542Swpaul	return(0);
75777542Swpaul}
75877542Swpaul
75999498Salfredstatic int
76099498Salfredlge_alloc_jumbo_mem(sc)
76177542Swpaul	struct lge_softc	*sc;
76277542Swpaul{
76377542Swpaul	caddr_t			ptr;
76477542Swpaul	register int		i;
76577542Swpaul	struct lge_jpool_entry   *entry;
76677542Swpaul
76777542Swpaul	/* Grab a big chunk o' storage. */
76877542Swpaul	sc->lge_cdata.lge_jumbo_buf = contigmalloc(LGE_JMEM, M_DEVBUF,
76977542Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
77077542Swpaul
77177542Swpaul	if (sc->lge_cdata.lge_jumbo_buf == NULL) {
772162321Sglebius		device_printf(sc->lge_dev, "no memory for jumbo buffers!\n");
77377542Swpaul		return(ENOBUFS);
77477542Swpaul	}
77577542Swpaul
77677542Swpaul	SLIST_INIT(&sc->lge_jfree_listhead);
77777542Swpaul	SLIST_INIT(&sc->lge_jinuse_listhead);
77877542Swpaul
77977542Swpaul	/*
78077542Swpaul	 * Now divide it up into 9K pieces and save the addresses
78177542Swpaul	 * in an array.
78277542Swpaul	 */
78377542Swpaul	ptr = sc->lge_cdata.lge_jumbo_buf;
78477542Swpaul	for (i = 0; i < LGE_JSLOTS; i++) {
78577542Swpaul		sc->lge_cdata.lge_jslots[i] = ptr;
78678440Swpaul		ptr += LGE_JLEN;
787150879Sjhb		entry = malloc(sizeof(struct lge_jpool_entry),
78877542Swpaul		    M_DEVBUF, M_NOWAIT);
78977542Swpaul		if (entry == NULL) {
790162321Sglebius			device_printf(sc->lge_dev, "no memory for jumbo "
791150879Sjhb			    "buffer queue!\n");
79277542Swpaul			return(ENOBUFS);
79377542Swpaul		}
79477542Swpaul		entry->slot = i;
79577542Swpaul		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead,
79677542Swpaul		    entry, jpool_entries);
79777542Swpaul	}
79877542Swpaul
79977542Swpaul	return(0);
80077542Swpaul}
80177542Swpaul
80299498Salfredstatic void
80399498Salfredlge_free_jumbo_mem(sc)
80477542Swpaul	struct lge_softc	*sc;
80577542Swpaul{
80677542Swpaul	struct lge_jpool_entry	*entry;
80777542Swpaul
808176813Syongari	if (sc->lge_cdata.lge_jumbo_buf == NULL)
809176813Syongari		return;
810176813Syongari
811176813Syongari	while ((entry = SLIST_FIRST(&sc->lge_jinuse_listhead))) {
812176813Syongari		device_printf(sc->lge_dev,
813176813Syongari		    "asked to free buffer that is in use!\n");
814176813Syongari		SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
815176813Syongari		SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry,
816176813Syongari		    jpool_entries);
817176813Syongari	}
818176813Syongari	while (!SLIST_EMPTY(&sc->lge_jfree_listhead)) {
81977542Swpaul		entry = SLIST_FIRST(&sc->lge_jfree_listhead);
82078440Swpaul		SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
82177542Swpaul		free(entry, M_DEVBUF);
82277542Swpaul	}
82377542Swpaul
82477542Swpaul	contigfree(sc->lge_cdata.lge_jumbo_buf, LGE_JMEM, M_DEVBUF);
82577542Swpaul
82677542Swpaul	return;
82777542Swpaul}
82877542Swpaul
82977542Swpaul/*
83077542Swpaul * Allocate a jumbo buffer.
83177542Swpaul */
83299498Salfredstatic void *
83399498Salfredlge_jalloc(sc)
83477542Swpaul	struct lge_softc	*sc;
83577542Swpaul{
83677542Swpaul	struct lge_jpool_entry   *entry;
83777542Swpaul
83877542Swpaul	entry = SLIST_FIRST(&sc->lge_jfree_listhead);
83977542Swpaul
84077542Swpaul	if (entry == NULL) {
84177542Swpaul#ifdef LGE_VERBOSE
842162321Sglebius		device_printf(sc->lge_dev, "no free jumbo buffers\n");
84377542Swpaul#endif
84477542Swpaul		return(NULL);
84577542Swpaul	}
84677542Swpaul
84777542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jfree_listhead, jpool_entries);
84877542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jinuse_listhead, entry, jpool_entries);
84977542Swpaul	return(sc->lge_cdata.lge_jslots[entry->slot]);
85077542Swpaul}
85177542Swpaul
85277542Swpaul/*
85377542Swpaul * Release a jumbo buffer.
85477542Swpaul */
85599498Salfredstatic void
85699498Salfredlge_jfree(buf, args)
85799004Salfred	void			*buf;
85877542Swpaul	void			*args;
85977542Swpaul{
86077542Swpaul	struct lge_softc	*sc;
86177542Swpaul	int		        i;
86277542Swpaul	struct lge_jpool_entry   *entry;
86377542Swpaul
86477542Swpaul	/* Extract the softc struct pointer. */
86577542Swpaul	sc = args;
86677542Swpaul
86777542Swpaul	if (sc == NULL)
86877542Swpaul		panic("lge_jfree: can't find softc pointer!");
86977542Swpaul
87077542Swpaul	/* calculate the slot this buffer belongs to */
87177542Swpaul	i = ((vm_offset_t)buf
87277542Swpaul	     - (vm_offset_t)sc->lge_cdata.lge_jumbo_buf) / LGE_JLEN;
87377542Swpaul
87477542Swpaul	if ((i < 0) || (i >= LGE_JSLOTS))
87577542Swpaul		panic("lge_jfree: asked to free buffer that we don't manage!");
87677542Swpaul
87777542Swpaul	entry = SLIST_FIRST(&sc->lge_jinuse_listhead);
87877542Swpaul	if (entry == NULL)
87977542Swpaul		panic("lge_jfree: buffer not in use!");
88077542Swpaul	entry->slot = i;
88177542Swpaul	SLIST_REMOVE_HEAD(&sc->lge_jinuse_listhead, jpool_entries);
88277542Swpaul	SLIST_INSERT_HEAD(&sc->lge_jfree_listhead, entry, jpool_entries);
88377542Swpaul
88477542Swpaul	return;
88577542Swpaul}
88677542Swpaul
88777542Swpaul/*
88877542Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
88977542Swpaul * the higher level protocols.
89077542Swpaul */
89199498Salfredstatic void
89299498Salfredlge_rxeof(sc, cnt)
89377542Swpaul	struct lge_softc	*sc;
89477542Swpaul	int			cnt;
89577542Swpaul{
89677542Swpaul        struct mbuf		*m;
89777542Swpaul        struct ifnet		*ifp;
89877542Swpaul	struct lge_rx_desc	*cur_rx;
89977542Swpaul	int			c, i, total_len = 0;
90077542Swpaul	u_int32_t		rxsts, rxctl;
90177542Swpaul
902147256Sbrooks	ifp = sc->lge_ifp;
90377542Swpaul
90477542Swpaul	/* Find out how many frames were processed. */
90577542Swpaul	c = cnt;
90677542Swpaul	i = sc->lge_cdata.lge_rx_cons;
90777542Swpaul
90877542Swpaul	/* Suck them in. */
90977542Swpaul	while(c) {
91077542Swpaul		struct mbuf		*m0 = NULL;
91177542Swpaul
91277542Swpaul		cur_rx = &sc->lge_ldata->lge_rx_list[i];
91377542Swpaul		rxctl = cur_rx->lge_ctl;
91477542Swpaul		rxsts = cur_rx->lge_sts;
91577542Swpaul		m = cur_rx->lge_mbuf;
91677542Swpaul		cur_rx->lge_mbuf = NULL;
91777542Swpaul		total_len = LGE_RXBYTES(cur_rx);
91877542Swpaul		LGE_INC(i, LGE_RX_LIST_CNT);
91977542Swpaul		c--;
92077542Swpaul
92177542Swpaul		/*
92277542Swpaul		 * If an error occurs, update stats, clear the
92377542Swpaul		 * status word and leave the mbuf cluster in place:
92477542Swpaul		 * it should simply get re-used next time this descriptor
92577542Swpaul	 	 * comes up in the ring.
92677542Swpaul		 */
92777542Swpaul		if (rxctl & LGE_RXCTL_ERRMASK) {
92877542Swpaul			ifp->if_ierrors++;
92977542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
93077542Swpaul			continue;
93177542Swpaul		}
93277542Swpaul
93377542Swpaul		if (lge_newbuf(sc, &LGE_RXTAIL(sc), NULL) == ENOBUFS) {
93478508Sbmilekic			m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN,
93578508Sbmilekic			    ifp, NULL);
93677542Swpaul			lge_newbuf(sc, &LGE_RXTAIL(sc), m);
93777542Swpaul			if (m0 == NULL) {
938162321Sglebius				device_printf(sc->lge_dev, "no receive buffers "
939150879Sjhb				    "available -- packet dropped!\n");
94077542Swpaul				ifp->if_ierrors++;
94177542Swpaul				continue;
94277542Swpaul			}
94377542Swpaul			m = m0;
94477542Swpaul		} else {
94577542Swpaul			m->m_pkthdr.rcvif = ifp;
94677542Swpaul			m->m_pkthdr.len = m->m_len = total_len;
94777542Swpaul		}
94877542Swpaul
94977542Swpaul		ifp->if_ipackets++;
95077542Swpaul
95177542Swpaul		/* Do IP checksum checking. */
95277542Swpaul		if (rxsts & LGE_RXSTS_ISIP)
95377542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
95477542Swpaul		if (!(rxsts & LGE_RXSTS_IPCSUMERR))
95577542Swpaul			m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
95677542Swpaul		if ((rxsts & LGE_RXSTS_ISTCP &&
95777542Swpaul		    !(rxsts & LGE_RXSTS_TCPCSUMERR)) ||
95877542Swpaul		    (rxsts & LGE_RXSTS_ISUDP &&
95977542Swpaul		    !(rxsts & LGE_RXSTS_UDPCSUMERR))) {
96077542Swpaul			m->m_pkthdr.csum_flags |=
96177542Swpaul			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
96278287Swpaul			m->m_pkthdr.csum_data = 0xffff;
96377542Swpaul		}
96478287Swpaul
965152727Sjhb		LGE_UNLOCK(sc);
966106937Ssam		(*ifp->if_input)(ifp, m);
967152727Sjhb		LGE_LOCK(sc);
96877542Swpaul	}
96977542Swpaul
97077542Swpaul	sc->lge_cdata.lge_rx_cons = i;
97177542Swpaul
97277542Swpaul	return;
97377542Swpaul}
97477542Swpaul
975104094Sphkstatic void
97699498Salfredlge_rxeoc(sc)
97777542Swpaul	struct lge_softc	*sc;
97877542Swpaul{
97977542Swpaul	struct ifnet		*ifp;
98077542Swpaul
981147256Sbrooks	ifp = sc->lge_ifp;
982148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
983152727Sjhb	lge_init_locked(sc);
98477542Swpaul	return;
98577542Swpaul}
98677542Swpaul
98777542Swpaul/*
98877542Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
98977542Swpaul * the list buffers.
99077542Swpaul */
99177542Swpaul
99299498Salfredstatic void
99399498Salfredlge_txeof(sc)
99477542Swpaul	struct lge_softc	*sc;
99577542Swpaul{
99677542Swpaul	struct lge_tx_desc	*cur_tx = NULL;
99777542Swpaul	struct ifnet		*ifp;
99877542Swpaul	u_int32_t		idx, txdone;
99977542Swpaul
1000147256Sbrooks	ifp = sc->lge_ifp;
100177542Swpaul
100277542Swpaul	/* Clear the timeout timer. */
100377542Swpaul	ifp->if_timer = 0;
100477542Swpaul
100577542Swpaul	/*
100677542Swpaul	 * Go through our tx list and free mbufs for those
100777542Swpaul	 * frames that have been transmitted.
100877542Swpaul	 */
100977542Swpaul	idx = sc->lge_cdata.lge_tx_cons;
101077542Swpaul	txdone = CSR_READ_1(sc, LGE_TXDMADONE_8BIT);
101177542Swpaul
101277542Swpaul	while (idx != sc->lge_cdata.lge_tx_prod && txdone) {
101377542Swpaul		cur_tx = &sc->lge_ldata->lge_tx_list[idx];
101477542Swpaul
101577542Swpaul		ifp->if_opackets++;
101677542Swpaul		if (cur_tx->lge_mbuf != NULL) {
101777542Swpaul			m_freem(cur_tx->lge_mbuf);
101877542Swpaul			cur_tx->lge_mbuf = NULL;
101977542Swpaul		}
102077542Swpaul		cur_tx->lge_ctl = 0;
102177542Swpaul
102277542Swpaul		txdone--;
102377542Swpaul		LGE_INC(idx, LGE_TX_LIST_CNT);
102477542Swpaul		ifp->if_timer = 0;
102577542Swpaul	}
102677542Swpaul
102777542Swpaul	sc->lge_cdata.lge_tx_cons = idx;
102877542Swpaul
102977542Swpaul	if (cur_tx != NULL)
1030148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
103177542Swpaul
103277542Swpaul	return;
103377542Swpaul}
103477542Swpaul
103599498Salfredstatic void
103699498Salfredlge_tick(xsc)
103777542Swpaul	void			*xsc;
103877542Swpaul{
103977542Swpaul	struct lge_softc	*sc;
104077542Swpaul	struct mii_data		*mii;
104177542Swpaul	struct ifnet		*ifp;
104277542Swpaul
104377542Swpaul	sc = xsc;
1044147256Sbrooks	ifp = sc->lge_ifp;
1045152727Sjhb	LGE_LOCK_ASSERT(sc);
104677542Swpaul
104777542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_SINGLE_COLL_PKTS);
104877542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
104977542Swpaul	CSR_WRITE_4(sc, LGE_STATSIDX, LGE_STATS_MULTI_COLL_PKTS);
105077542Swpaul	ifp->if_collisions += CSR_READ_4(sc, LGE_STATSVAL);
105177542Swpaul
105277542Swpaul	if (!sc->lge_link) {
105377542Swpaul		mii = device_get_softc(sc->lge_miibus);
105477542Swpaul		mii_tick(mii);
105577542Swpaul		if (mii->mii_media_status & IFM_ACTIVE &&
105677542Swpaul		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
105777542Swpaul			sc->lge_link++;
1058137402Sphk			if (bootverbose &&
1059137402Sphk		  	    (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX||
1060137402Sphk			    IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T))
1061162321Sglebius				device_printf(sc->lge_dev, "gigabit link up\n");
106277542Swpaul			if (ifp->if_snd.ifq_head != NULL)
1063152727Sjhb				lge_start_locked(ifp);
106477542Swpaul		}
106577542Swpaul	}
106677542Swpaul
1067152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
106877542Swpaul
106977542Swpaul	return;
107077542Swpaul}
107177542Swpaul
107299498Salfredstatic void
107399498Salfredlge_intr(arg)
107477542Swpaul	void			*arg;
107577542Swpaul{
107677542Swpaul	struct lge_softc	*sc;
107777542Swpaul	struct ifnet		*ifp;
107877542Swpaul	u_int32_t		status;
107977542Swpaul
108077542Swpaul	sc = arg;
1081147256Sbrooks	ifp = sc->lge_ifp;
1082152727Sjhb	LGE_LOCK(sc);
108377542Swpaul
108477542Swpaul	/* Supress unwanted interrupts */
108577542Swpaul	if (!(ifp->if_flags & IFF_UP)) {
108677542Swpaul		lge_stop(sc);
1087152727Sjhb		LGE_UNLOCK(sc);
108877542Swpaul		return;
108977542Swpaul	}
109077542Swpaul
109177542Swpaul	for (;;) {
109277542Swpaul		/*
109377542Swpaul		 * Reading the ISR register clears all interrupts, and
109477542Swpaul		 * clears the 'interrupts enabled' bit in the IMR
109577542Swpaul		 * register.
109677542Swpaul		 */
109777542Swpaul		status = CSR_READ_4(sc, LGE_ISR);
109877542Swpaul
109977542Swpaul		if ((status & LGE_INTRS) == 0)
110077542Swpaul			break;
110177542Swpaul
110277542Swpaul		if ((status & (LGE_ISR_TXCMDFIFO_EMPTY|LGE_ISR_TXDMA_DONE)))
110377542Swpaul			lge_txeof(sc);
110477542Swpaul
110577542Swpaul		if (status & LGE_ISR_RXDMA_DONE)
110677542Swpaul			lge_rxeof(sc, LGE_RX_DMACNT(status));
110777542Swpaul
110877542Swpaul		if (status & LGE_ISR_RXCMDFIFO_EMPTY)
110977542Swpaul			lge_rxeoc(sc);
111077542Swpaul
111177542Swpaul		if (status & LGE_ISR_PHY_INTR) {
111277542Swpaul			sc->lge_link = 0;
1113152727Sjhb			callout_stop(&sc->lge_stat_callout);
111477542Swpaul			lge_tick(sc);
111577542Swpaul		}
111677542Swpaul	}
111777542Swpaul
111877542Swpaul	/* Re-enable interrupts. */
111977542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|LGE_IMR_INTR_ENB);
112077542Swpaul
112177542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1122152727Sjhb		lge_start_locked(ifp);
112377542Swpaul
1124152727Sjhb	LGE_UNLOCK(sc);
112577542Swpaul	return;
112677542Swpaul}
112777542Swpaul
112877542Swpaul/*
112977542Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
113077542Swpaul * pointers to the fragment pointers.
113177542Swpaul */
113299498Salfredstatic int
113399498Salfredlge_encap(sc, m_head, txidx)
113477542Swpaul	struct lge_softc	*sc;
113577542Swpaul	struct mbuf		*m_head;
113677542Swpaul	u_int32_t		*txidx;
113777542Swpaul{
113877542Swpaul	struct lge_frag		*f = NULL;
113977542Swpaul	struct lge_tx_desc	*cur_tx;
114077542Swpaul	struct mbuf		*m;
114177542Swpaul	int			frag = 0, tot_len = 0;
114277542Swpaul
114377542Swpaul	/*
114477542Swpaul 	 * Start packing the mbufs in this chain into
114577542Swpaul	 * the fragment pointers. Stop when we run out
114677542Swpaul 	 * of fragments or hit the end of the mbuf chain.
114777542Swpaul	 */
114877542Swpaul	m = m_head;
114977542Swpaul	cur_tx = &sc->lge_ldata->lge_tx_list[*txidx];
115077542Swpaul	frag = 0;
115177542Swpaul
115277542Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
115377542Swpaul		if (m->m_len != 0) {
115477542Swpaul			tot_len += m->m_len;
115577542Swpaul			f = &cur_tx->lge_frags[frag];
115677542Swpaul			f->lge_fraglen = m->m_len;
115777542Swpaul			f->lge_fragptr_lo = vtophys(mtod(m, vm_offset_t));
115877542Swpaul			f->lge_fragptr_hi = 0;
115977542Swpaul			frag++;
116077542Swpaul		}
116177542Swpaul	}
116277542Swpaul
116377542Swpaul	if (m != NULL)
116477542Swpaul		return(ENOBUFS);
116577542Swpaul
116677542Swpaul	cur_tx->lge_mbuf = m_head;
116777542Swpaul	cur_tx->lge_ctl = LGE_TXCTL_WANTINTR|LGE_FRAGCNT(frag)|tot_len;
116877827Swpaul	LGE_INC((*txidx), LGE_TX_LIST_CNT);
116977542Swpaul
117077542Swpaul	/* Queue for transmit */
117177542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_LO, vtophys(cur_tx));
117277542Swpaul
117377542Swpaul	return(0);
117477542Swpaul}
117577542Swpaul
117677542Swpaul/*
117777542Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
117877542Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
117977542Swpaul * copy of the pointers since the transmit list fragment pointers are
118077542Swpaul * physical addresses.
118177542Swpaul */
118277542Swpaul
118399498Salfredstatic void
118499498Salfredlge_start(ifp)
118577542Swpaul	struct ifnet		*ifp;
118677542Swpaul{
118777542Swpaul	struct lge_softc	*sc;
1188152727Sjhb
1189152727Sjhb	sc = ifp->if_softc;
1190152727Sjhb	LGE_LOCK(sc);
1191152727Sjhb	lge_start_locked(ifp);
1192152727Sjhb	LGE_UNLOCK(sc);
1193152727Sjhb}
1194152727Sjhb
1195152727Sjhbstatic void
1196152727Sjhblge_start_locked(ifp)
1197152727Sjhb	struct ifnet		*ifp;
1198152727Sjhb{
1199152727Sjhb	struct lge_softc	*sc;
120077542Swpaul	struct mbuf		*m_head = NULL;
120177542Swpaul	u_int32_t		idx;
120277542Swpaul
120377542Swpaul	sc = ifp->if_softc;
120477542Swpaul
120577542Swpaul	if (!sc->lge_link)
120677542Swpaul		return;
120777542Swpaul
120877542Swpaul	idx = sc->lge_cdata.lge_tx_prod;
120977542Swpaul
1210148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
121177542Swpaul		return;
121277542Swpaul
121377542Swpaul	while(sc->lge_ldata->lge_tx_list[idx].lge_mbuf == NULL) {
121477542Swpaul		if (CSR_READ_1(sc, LGE_TXCMDFREE_8BIT) == 0)
121577542Swpaul			break;
121677542Swpaul
121777542Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
121877542Swpaul		if (m_head == NULL)
121977542Swpaul			break;
122077542Swpaul
122177542Swpaul		if (lge_encap(sc, m_head, &idx)) {
122277542Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
1223148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
122477542Swpaul			break;
122577542Swpaul		}
122677542Swpaul
122777542Swpaul		/*
122877542Swpaul		 * If there's a BPF listener, bounce a copy of this frame
122977542Swpaul		 * to him.
123077542Swpaul		 */
1231106937Ssam		BPF_MTAP(ifp, m_head);
123277542Swpaul	}
123377542Swpaul
123477542Swpaul	sc->lge_cdata.lge_tx_prod = idx;
123577542Swpaul
123677542Swpaul	/*
123777542Swpaul	 * Set a timeout in case the chip goes out to lunch.
123877542Swpaul	 */
123977542Swpaul	ifp->if_timer = 5;
124077542Swpaul
124177542Swpaul	return;
124277542Swpaul}
124377542Swpaul
124499498Salfredstatic void
124599498Salfredlge_init(xsc)
124677542Swpaul	void			*xsc;
124777542Swpaul{
124877542Swpaul	struct lge_softc	*sc = xsc;
1249152727Sjhb
1250152727Sjhb	LGE_LOCK(sc);
1251152727Sjhb	lge_init_locked(sc);
1252152727Sjhb	LGE_UNLOCK(sc);
1253152727Sjhb}
1254152727Sjhb
1255152727Sjhbstatic void
1256152727Sjhblge_init_locked(sc)
1257152727Sjhb	struct lge_softc	*sc;
1258152727Sjhb{
1259147256Sbrooks	struct ifnet		*ifp = sc->lge_ifp;
126077542Swpaul
1261152727Sjhb	LGE_LOCK_ASSERT(sc);
1262148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
126377542Swpaul		return;
126477542Swpaul
126577542Swpaul	/*
126677542Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
126777542Swpaul	 */
126877542Swpaul	lge_stop(sc);
126977542Swpaul	lge_reset(sc);
127077542Swpaul
127177542Swpaul	/* Set MAC address */
1272152315Sru	CSR_WRITE_4(sc, LGE_PAR0, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[0]));
1273152315Sru	CSR_WRITE_4(sc, LGE_PAR1, *(u_int32_t *)(&IF_LLADDR(sc->lge_ifp)[4]));
127477542Swpaul
127577542Swpaul	/* Init circular RX list. */
127677542Swpaul	if (lge_list_rx_init(sc) == ENOBUFS) {
1277162321Sglebius		device_printf(sc->lge_dev, "initialization failed: no "
1278150879Sjhb		    "memory for rx buffers\n");
127977542Swpaul		lge_stop(sc);
128077542Swpaul		return;
128177542Swpaul	}
128277542Swpaul
128377542Swpaul	/*
128477542Swpaul	 * Init tx descriptors.
128577542Swpaul	 */
128677542Swpaul	lge_list_tx_init(sc);
128777542Swpaul
128877542Swpaul	/* Set initial value for MODE1 register. */
128977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_UCAST|
129077542Swpaul	    LGE_MODE1_TX_CRC|LGE_MODE1_TXPAD|
129177542Swpaul	    LGE_MODE1_RX_FLOWCTL|LGE_MODE1_SETRST_CTL0|
129277542Swpaul	    LGE_MODE1_SETRST_CTL1|LGE_MODE1_SETRST_CTL2);
129377542Swpaul
129477542Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
129577542Swpaul	if (ifp->if_flags & IFF_PROMISC) {
129677542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
129777542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_PROMISC);
129877542Swpaul	} else {
129977542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_PROMISC);
130077542Swpaul	}
130177542Swpaul
130277542Swpaul	/*
130377542Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
130477542Swpaul	 */
130577542Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
130677542Swpaul		CSR_WRITE_4(sc, LGE_MODE1,
130777542Swpaul		    LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_BCAST);
130877542Swpaul	} else {
130977542Swpaul		CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_BCAST);
131077542Swpaul	}
131177542Swpaul
131277542Swpaul	/* Packet padding workaround? */
131377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RMVPAD);
131477542Swpaul
131577542Swpaul	/* No error frames */
131677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ERRPKTS);
131777542Swpaul
131877542Swpaul	/* Receive large frames */
131977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_GIANTS);
132077542Swpaul
132177542Swpaul	/* Workaround: disable RX/TX flow control */
132277542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_TX_FLOWCTL);
132377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_FLOWCTL);
132477542Swpaul
132577542Swpaul	/* Make sure to strip CRC from received frames */
132677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_CRC);
132777542Swpaul
132877542Swpaul	/* Turn off magic packet mode */
132977542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_MPACK_ENB);
133077542Swpaul
133177542Swpaul	/* Turn off all VLAN stuff */
133277542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_VLAN_RX|LGE_MODE1_VLAN_TX|
133377542Swpaul	    LGE_MODE1_VLAN_STRIP|LGE_MODE1_VLAN_INSERT);
133477542Swpaul
133577542Swpaul	/* Workarond: FIFO overflow */
133677542Swpaul	CSR_WRITE_2(sc, LGE_RXFIFO_HIWAT, 0x3FFF);
133777542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL1|LGE_IMR_RXFIFO_WAT);
133877542Swpaul
133977542Swpaul	/*
134077542Swpaul	 * Load the multicast filter.
134177542Swpaul	 */
134277542Swpaul	lge_setmulti(sc);
134377542Swpaul
134477542Swpaul	/*
134577542Swpaul	 * Enable hardware checksum validation for all received IPv4
134677542Swpaul	 * packets, do not reject packets with bad checksums.
134777542Swpaul	 */
134877542Swpaul	CSR_WRITE_4(sc, LGE_MODE2, LGE_MODE2_RX_IPCSUM|
134977542Swpaul	    LGE_MODE2_RX_TCPCSUM|LGE_MODE2_RX_UDPCSUM|
135077542Swpaul	    LGE_MODE2_RX_ERRCSUM);
135177542Swpaul
135277542Swpaul	/*
135377542Swpaul	 * Enable the delivery of PHY interrupts based on
135477542Swpaul	 * link/speed/duplex status chalges.
135577542Swpaul	 */
135677542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL0|LGE_MODE1_GMIIPOLL);
135777542Swpaul
135877542Swpaul	/* Enable receiver and transmitter. */
135977542Swpaul	CSR_WRITE_4(sc, LGE_RXDESC_ADDR_HI, 0);
136077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_RX_ENB);
136177542Swpaul
136277542Swpaul	CSR_WRITE_4(sc, LGE_TXDESC_ADDR_HI, 0);
136377542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_SETRST_CTL1|LGE_MODE1_TX_ENB);
136477542Swpaul
136577542Swpaul	/*
136677542Swpaul	 * Enable interrupts.
136777542Swpaul	 */
136877542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_SETRST_CTL0|
136977542Swpaul	    LGE_IMR_SETRST_CTL1|LGE_IMR_INTR_ENB|LGE_INTRS);
137077542Swpaul
1371152727Sjhb	lge_ifmedia_upd_locked(ifp);
137277542Swpaul
1373148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1374148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
137577542Swpaul
1376152727Sjhb	callout_reset(&sc->lge_stat_callout, hz, lge_tick, sc);
137777542Swpaul
137877542Swpaul	return;
137977542Swpaul}
138077542Swpaul
138177542Swpaul/*
138277542Swpaul * Set media options.
138377542Swpaul */
138499498Salfredstatic int
138599498Salfredlge_ifmedia_upd(ifp)
138677542Swpaul	struct ifnet		*ifp;
138777542Swpaul{
138877542Swpaul	struct lge_softc	*sc;
1389152727Sjhb
1390152727Sjhb	sc = ifp->if_softc;
1391152727Sjhb	LGE_LOCK(sc);
1392152727Sjhb	lge_ifmedia_upd_locked(ifp);
1393152727Sjhb	LGE_UNLOCK(sc);
1394152727Sjhb
1395152727Sjhb	return(0);
1396152727Sjhb}
1397152727Sjhb
1398152727Sjhbstatic void
1399152727Sjhblge_ifmedia_upd_locked(ifp)
1400152727Sjhb	struct ifnet		*ifp;
1401152727Sjhb{
1402152727Sjhb	struct lge_softc	*sc;
140377542Swpaul	struct mii_data		*mii;
140477542Swpaul
140577542Swpaul	sc = ifp->if_softc;
140677542Swpaul
1407152727Sjhb	LGE_LOCK_ASSERT(sc);
140877542Swpaul	mii = device_get_softc(sc->lge_miibus);
140977542Swpaul	sc->lge_link = 0;
141077542Swpaul	if (mii->mii_instance) {
141177542Swpaul		struct mii_softc	*miisc;
141277542Swpaul		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
141377542Swpaul		    miisc = LIST_NEXT(miisc, mii_list))
141477542Swpaul			mii_phy_reset(miisc);
141577542Swpaul	}
141677542Swpaul	mii_mediachg(mii);
141777542Swpaul}
141877542Swpaul
141977542Swpaul/*
142077542Swpaul * Report current media status.
142177542Swpaul */
142299498Salfredstatic void
142399498Salfredlge_ifmedia_sts(ifp, ifmr)
142477542Swpaul	struct ifnet		*ifp;
142577542Swpaul	struct ifmediareq	*ifmr;
142677542Swpaul{
142777542Swpaul	struct lge_softc	*sc;
142877542Swpaul	struct mii_data		*mii;
142977542Swpaul
143077542Swpaul	sc = ifp->if_softc;
143177542Swpaul
1432152727Sjhb	LGE_LOCK(sc);
143377542Swpaul	mii = device_get_softc(sc->lge_miibus);
143477542Swpaul	mii_pollstat(mii);
1435152727Sjhb	LGE_UNLOCK(sc);
143677542Swpaul	ifmr->ifm_active = mii->mii_media_active;
143777542Swpaul	ifmr->ifm_status = mii->mii_media_status;
143877542Swpaul
143977542Swpaul	return;
144077542Swpaul}
144177542Swpaul
144299498Salfredstatic int
144399498Salfredlge_ioctl(ifp, command, data)
144477542Swpaul	struct ifnet		*ifp;
144577542Swpaul	u_long			command;
144677542Swpaul	caddr_t			data;
144777542Swpaul{
144877542Swpaul	struct lge_softc	*sc = ifp->if_softc;
144977542Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
145077542Swpaul	struct mii_data		*mii;
1451152727Sjhb	int			error = 0;
145277542Swpaul
145377542Swpaul	switch(command) {
145477542Swpaul	case SIOCSIFMTU:
1455152727Sjhb		LGE_LOCK(sc);
145677542Swpaul		if (ifr->ifr_mtu > LGE_JUMBO_MTU)
145777542Swpaul			error = EINVAL;
145877542Swpaul		else
145977542Swpaul			ifp->if_mtu = ifr->ifr_mtu;
1460152727Sjhb		LGE_UNLOCK(sc);
146177542Swpaul		break;
146277542Swpaul	case SIOCSIFFLAGS:
1463152727Sjhb		LGE_LOCK(sc);
146477542Swpaul		if (ifp->if_flags & IFF_UP) {
1465148887Srwatson			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_SETRST_CTL1|
147077542Swpaul				    LGE_MODE1_RX_PROMISC);
1471148887Srwatson			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
147277542Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
147377542Swpaul			    sc->lge_if_flags & IFF_PROMISC) {
147477542Swpaul				CSR_WRITE_4(sc, LGE_MODE1,
147577542Swpaul				    LGE_MODE1_RX_PROMISC);
147677542Swpaul			} else {
1477148887Srwatson				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1478152727Sjhb				lge_init_locked(sc);
147977542Swpaul			}
148077542Swpaul		} else {
1481148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
148277542Swpaul				lge_stop(sc);
148377542Swpaul		}
148477542Swpaul		sc->lge_if_flags = ifp->if_flags;
1485152727Sjhb		LGE_UNLOCK(sc);
148677542Swpaul		error = 0;
148777542Swpaul		break;
148877542Swpaul	case SIOCADDMULTI:
148977542Swpaul	case SIOCDELMULTI:
1490152727Sjhb		LGE_LOCK(sc);
149177542Swpaul		lge_setmulti(sc);
1492152727Sjhb		LGE_UNLOCK(sc);
149377542Swpaul		error = 0;
149477542Swpaul		break;
149577542Swpaul	case SIOCGIFMEDIA:
149677542Swpaul	case SIOCSIFMEDIA:
149777542Swpaul		mii = device_get_softc(sc->lge_miibus);
149877542Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
149977542Swpaul		break;
150077542Swpaul	default:
1501106937Ssam		error = ether_ioctl(ifp, command, data);
150277542Swpaul		break;
150377542Swpaul	}
150477542Swpaul
150577542Swpaul	return(error);
150677542Swpaul}
150777542Swpaul
150899498Salfredstatic void
150999498Salfredlge_watchdog(ifp)
151077542Swpaul	struct ifnet		*ifp;
151177542Swpaul{
151277542Swpaul	struct lge_softc	*sc;
151377542Swpaul
151477542Swpaul	sc = ifp->if_softc;
151577542Swpaul
1516152727Sjhb	LGE_LOCK(sc);
151777542Swpaul	ifp->if_oerrors++;
1518150879Sjhb	if_printf(ifp, "watchdog timeout\n");
151977542Swpaul
152077542Swpaul	lge_stop(sc);
152177542Swpaul	lge_reset(sc);
1522148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1523152727Sjhb	lge_init_locked(sc);
152477542Swpaul
152577542Swpaul	if (ifp->if_snd.ifq_head != NULL)
1526152727Sjhb		lge_start_locked(ifp);
1527152727Sjhb	LGE_UNLOCK(sc);
152877542Swpaul
152977542Swpaul	return;
153077542Swpaul}
153177542Swpaul
153277542Swpaul/*
153377542Swpaul * Stop the adapter and free any mbufs allocated to the
153477542Swpaul * RX and TX lists.
153577542Swpaul */
153699498Salfredstatic void
153799498Salfredlge_stop(sc)
153877542Swpaul	struct lge_softc	*sc;
153977542Swpaul{
154077542Swpaul	register int		i;
154177542Swpaul	struct ifnet		*ifp;
154277542Swpaul
1543152727Sjhb	LGE_LOCK_ASSERT(sc);
1544147256Sbrooks	ifp = sc->lge_ifp;
154577542Swpaul	ifp->if_timer = 0;
1546152727Sjhb	callout_stop(&sc->lge_stat_callout);
154777542Swpaul	CSR_WRITE_4(sc, LGE_IMR, LGE_IMR_INTR_ENB);
154877542Swpaul
154977542Swpaul	/* Disable receiver and transmitter. */
155077542Swpaul	CSR_WRITE_4(sc, LGE_MODE1, LGE_MODE1_RX_ENB|LGE_MODE1_TX_ENB);
155177542Swpaul	sc->lge_link = 0;
155277542Swpaul
155377542Swpaul	/*
155477542Swpaul	 * Free data in the RX lists.
155577542Swpaul	 */
155677542Swpaul	for (i = 0; i < LGE_RX_LIST_CNT; i++) {
155777542Swpaul		if (sc->lge_ldata->lge_rx_list[i].lge_mbuf != NULL) {
155877542Swpaul			m_freem(sc->lge_ldata->lge_rx_list[i].lge_mbuf);
155977542Swpaul			sc->lge_ldata->lge_rx_list[i].lge_mbuf = NULL;
156077542Swpaul		}
156177542Swpaul	}
156277542Swpaul	bzero((char *)&sc->lge_ldata->lge_rx_list,
156377542Swpaul		sizeof(sc->lge_ldata->lge_rx_list));
156477542Swpaul
156577542Swpaul	/*
156677542Swpaul	 * Free the TX list buffers.
156777542Swpaul	 */
156877542Swpaul	for (i = 0; i < LGE_TX_LIST_CNT; i++) {
156977542Swpaul		if (sc->lge_ldata->lge_tx_list[i].lge_mbuf != NULL) {
157077542Swpaul			m_freem(sc->lge_ldata->lge_tx_list[i].lge_mbuf);
157177542Swpaul			sc->lge_ldata->lge_tx_list[i].lge_mbuf = NULL;
157277542Swpaul		}
157377542Swpaul	}
157477542Swpaul
157577542Swpaul	bzero((char *)&sc->lge_ldata->lge_tx_list,
157677542Swpaul		sizeof(sc->lge_ldata->lge_tx_list));
157777542Swpaul
1578148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
157977542Swpaul
158077542Swpaul	return;
158177542Swpaul}
158277542Swpaul
158377542Swpaul/*
158477542Swpaul * Stop all chip I/O so that the kernel's probe routines don't
158577542Swpaul * get confused by errant DMAs when rebooting.
158677542Swpaul */
1587173839Syongaristatic int
158899498Salfredlge_shutdown(dev)
158977542Swpaul	device_t		dev;
159077542Swpaul{
159177542Swpaul	struct lge_softc	*sc;
159277542Swpaul
159377542Swpaul	sc = device_get_softc(dev);
159477542Swpaul
1595152727Sjhb	LGE_LOCK(sc);
159677542Swpaul	lge_reset(sc);
159777542Swpaul	lge_stop(sc);
1598152727Sjhb	LGE_UNLOCK(sc);
159977542Swpaul
1600173839Syongari	return (0);
160177542Swpaul}
1602