[Midnightbsd-cvs] src: dev/le: sync with freebsd

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Dec 2 18:54:10 EST 2008


Log Message:
-----------
sync with freebsd

Modified Files:
--------------
    src/sys/dev/le:
        am7990.c (r1.2 -> r1.3)
        am79900.c (r1.2 -> r1.3)
        am79900reg.h (r1.1.1.1 -> r1.2)
        am79900var.h (r1.1.1.1 -> r1.2)
        am7990reg.h (r1.1.1.1 -> r1.2)
        am7990var.h (r1.1.1.1 -> r1.2)
        if_le_ledma.c (r1.1.1.1 -> r1.2)
        if_le_pci.c (r1.1.1.1 -> r1.2)
        lance.c (r1.1.1.1 -> r1.2)
        lancereg.h (r1.1.1.1 -> r1.2)
        lancevar.h (r1.1.1.1 -> r1.2)

Added Files:
-----------
    src/sys/dev/le:
        if_le_cbus.c (r1.1)
        if_le_isa.c (r1.1)
        if_le_lebuffer.c (r1.1)
        lebuffer_sbus.c (r1.1)

-------------- next part --------------
Index: if_le_ledma.c
===================================================================
RCS file: /home/cvs/src/sys/dev/le/if_le_ledma.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/if_le_ledma.c -L sys/dev/le/if_le_ledma.c -u -r1.1.1.1 -r1.2
--- sys/dev/le/if_le_ledma.c
+++ sys/dev/le/if_le_ledma.c
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/le/if_le_ledma.c,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/le/if_le_ledma.c,v 1.4 2007/02/23 12:18:45 piso Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -69,6 +69,7 @@
 #include <dev/le/lancevar.h>
 #include <dev/le/am7990var.h>
 
+#define	LEDMA_ALIGNMENT	8		/* ring desc. alignmet for NCR92C990 */
 #define	LEDMA_BOUNDARY	(16*1024*1024)	/* must not cross 16MB boundary */
 #define	LEDMA_MEMSIZE	(16*1024)	/* LANCE memory size */
 #define	LEREG1_RDP	0		/* Register Data Port */
@@ -91,7 +92,6 @@
 	bus_addr_t		sc_laddr;	/* LANCE DMA address */
 
 	struct lsi64854_softc	*sc_dma;	/* pointer to DMA engine */
-	int			sc_dodrain;
 };
 
 static device_probe_t le_dma_probe;
@@ -259,46 +259,7 @@
 	struct le_dma_softc *lesc = (struct le_dma_softc *)sc;
 	struct lsi64854_softc *dma = lesc->sc_dma;
 
-#if 0
 	return (DMA_INTR(dma));
-#else
-	/*
-	 * Inlined version of lsi64854_enet_intr() from rev. 1.8 of
-	 * sys/sparc64/sbus/lsi64854.c in order to not break the API
-	 * of the LSI64854 driver in RELENG_6.
-	 */
-	uint32_t csr;
-	int i, rv;
-
-	csr = L64854_GCSR(dma);
-
-	/* If the DMA logic shows an interrupt, claim it */
-	rv = ((csr & E_INT_PEND) != 0) ? 1 : 0;
-
-	if (csr & (E_ERR_PEND|E_SLAVE_ERR)) {
-		device_printf(dma->sc_dev, "error: csr=%b\n", csr,
-		    EDMACSR_BITS);
-		csr &= ~L64854_EN_DMA;	/* Stop DMA */
-		/* Invalidate the queue; SLAVE_ERR bit is write-to-clear */
-		csr |= E_INVALIDATE|E_SLAVE_ERR;
-		L64854_SCSR(dma, csr);
-		/* Will be drained with the LE_C0_IDON interrupt. */
-		lesc->sc_dodrain = 1;
-		return (-1);
-	}
-
-	/* XXX - is this necessary with E_DSBL_WR_INVAL on? */
-	if (lesc->sc_dodrain) {
-		i = 10;
-		csr |= E_DRAIN;
-		L64854_SCSR(dma, csr);
-		while (i-- > 0 && (L64854_GCSR(dma) & E_DRAINING))
-			DELAY(1);
-		lesc->sc_dodrain = 0;
-	}
-
-	return (rv);
-#endif
 }
 
 static void
@@ -395,14 +356,15 @@
 	sc->sc_memsize = LEDMA_MEMSIZE;
 	error = bus_dma_tag_create(
 	    dma->sc_parent_dmat,	/* parent */
-	    1, LEDMA_BOUNDARY,		/* alignment, boundary */
+	    LEDMA_ALIGNMENT,		/* alignment */
+	    LEDMA_BOUNDARY,		/* boundary */
 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
 	    BUS_SPACE_MAXADDR,		/* highaddr */
 	    NULL, NULL,			/* filter, filterarg */
 	    sc->sc_memsize,		/* maxsize */
 	    1,				/* nsegments */
 	    sc->sc_memsize,		/* maxsegsize */
-	    BUS_DMA_WAITOK,		/* flags */
+	    0,				/* flags */
 	    NULL, NULL,			/* lockfunc, lockarg */
 	    &lesc->sc_dmat);
 	if (error != 0) {
@@ -445,19 +407,19 @@
 
 	sc->sc_rdcsr = le_dma_rdcsr;
 	sc->sc_wrcsr = le_dma_wrcsr;
-	sc->sc_nocarrier = le_dma_nocarrier;
 	sc->sc_hwreset = le_dma_hwreset;
 	sc->sc_hwintr = le_dma_hwintr;
+	sc->sc_nocarrier = le_dma_nocarrier;
 
 	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
 	    device_get_unit(dev));
 	if (error != 0) {
-		device_printf(dev, "cannot attach AM7990\n");
+		device_printf(dev, "cannot attach Am7990\n");
 		goto fail_dmap;
 	}
 
 	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
-	    am7990_intr, sc, &lesc->sc_ih);
+	    NULL, am7990_intr, sc, &lesc->sc_ih);
 	if (error != 0) {
 		device_printf(dev, "cannot set up interrupt\n");
 		goto fail_am7990;
Index: am79900reg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am79900reg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/am79900reg.h -L sys/dev/le/am79900reg.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/am79900reg.h
+++ sys/dev/le/am79900reg.h
@@ -70,7 +70,7 @@
  *	@(#)if_lereg.h	8.1 (Berkeley) 6/10/93
  */
 
-/* $FreeBSD: src/sys/dev/le/am79900reg.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/am79900reg.h,v 1.1 2006/01/31 14:48:58 marius Exp $ */
 
 #ifndef _DEV_LE_AM79900REG_H_
 #define	_DEV_LE_AM79900REG_H_
Index: am7990.c
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am7990.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/le/am7990.c -L sys/dev/le/am7990.c -u -r1.2 -r1.3
--- sys/dev/le/am7990.c
+++ sys/dev/le/am7990.c
@@ -72,7 +72,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/le/am7990.c,v 1.1.2.2 2006/03/25 12:13:21 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/le/am7990.c,v 1.4 2006/12/06 02:14:31 marius Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -90,6 +90,8 @@
 #include <net/if_media.h>
 #include <net/if_var.h>
 
+#include <machine/bus.h>
+
 #include <dev/le/lancereg.h>
 #include <dev/le/lancevar.h>
 #include <dev/le/am7990reg.h>
@@ -215,8 +217,14 @@
 am7990_rint(struct lance_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
 	struct lermd rmd;
 	int bix, rp;
+#if defined(LANCE_REVC_BUG)
+	struct ether_header *eh;
+	/* Make sure this is short-aligned, for ether_cmp(). */
+	static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
+#endif
 
 	bix = sc->sc_last_rd;
 
@@ -228,35 +236,37 @@
 		if (rmd.rmd1_bits & LE_R1_OWN)
 			break;
 
-		if (rmd.rmd1_bits & LE_R1_ERR) {
-			if (rmd.rmd1_bits & LE_R1_ENP) {
-#ifdef LEDEBUG
-				if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
-					if (rmd.rmd1_bits & LE_R1_FRAM)
-						if_printf(ifp,
-						    "framing error\n");
-					if (rmd.rmd1_bits & LE_R1_CRC)
-						if_printf(ifp,
-						    "crc mismatch\n");
-				}
-#endif
-			} else {
-				if (rmd.rmd1_bits & LE_R1_OFLO)
-					if_printf(ifp, "overflow\n");
-			}
-			if (rmd.rmd1_bits & LE_R1_BUFF)
-				if_printf(ifp, "receive buffer error\n");
-			ifp->if_ierrors++;
-		} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
+		m = NULL;
+		if ((rmd.rmd1_bits & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
 		    (LE_R1_STP | LE_R1_ENP)) {
-			if_printf(ifp, "dropping chained buffer\n");
-			ifp->if_ierrors++;
+			if (rmd.rmd1_bits & LE_R1_ERR) {
+#ifdef LEDEBUG
+				if (rmd.rmd1_bits & LE_R1_ENP) {
+					if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
+						if (rmd.rmd1_bits & LE_R1_FRAM)
+							if_printf(ifp,
+							    "framing error\n");
+						if (rmd.rmd1_bits & LE_R1_CRC)
+							if_printf(ifp,
+							    "crc mismatch\n");
+					}
+				} else
+					if (rmd.rmd1_bits & LE_R1_OFLO)
+						if_printf(ifp, "overflow\n");
+#endif
+				if (rmd.rmd1_bits & LE_R1_BUFF)
+					if_printf(ifp,
+					    "receive buffer error\n");
+			} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
+			    (LE_R1_STP | LE_R1_ENP))
+				if_printf(ifp, "dropping chained buffer\n");
 		} else {
 #ifdef LEDEBUG
 			if (sc->sc_flags & LE_DEBUG)
-				am7990_recv_print(sc, sc->sc_last_rd);
+				am7990_recv_print(sc, bix);
 #endif
-			lance_read(sc, LE_RBUFADDR(sc, bix),
+			/* Pull the packet off the interface. */
+			m = lance_get(sc, LE_RBUFADDR(sc, bix),
 			    (int)rmd.rmd3 - ETHER_CRC_LEN);
 		}
 
@@ -265,17 +275,35 @@
 		rmd.rmd3 = 0;
 		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
 
-#ifdef LEDEBUG
-		if (sc->sc_flags & LE_DEBUG)
-			if_printf(ifp, "sc->sc_last_rd = %x, rmd: "
-			    "ladr %04x, hadr %02x, flags %02x, "
-			    "bcnt %04x, mcnt %04x\n",
-			    sc->sc_last_rd, rmd.rmd0, rmd.rmd1_hadr,
-			    rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
-#endif
-
 		if (++bix == sc->sc_nrbuf)
 			bix = 0;
+
+		if (m != NULL) {
+			ifp->if_ipackets++;
+
+#ifdef LANCE_REVC_BUG
+			/*
+			 * The old LANCE (Rev. C) chips have a bug which
+			 * causes garbage to be inserted in front of the
+			 * received packet. The workaround is to ignore
+			 * packets with an invalid destination address
+			 * (garbage will usually not match).
+			 * Of course, this precludes multicast support...
+			 */
+			eh = mtod(m, struct ether_header *);
+			if (ether_cmp(eh->ether_dhost, sc->sc_enaddr) &&
+			    ether_cmp(eh->ether_dhost, bcast_enaddr)) {
+				m_freem(m);
+				continue;
+			}
+#endif
+
+			/* Pass the packet up. */
+			LE_UNLOCK(sc);
+			(*ifp->if_input)(ifp, m);
+			LE_LOCK(sc);
+		} else
+			ifp->if_ierrors++;
 	}
 
 	sc->sc_last_rd = bix;
@@ -357,7 +385,7 @@
 
 	sc->sc_first_td = bix;
 
-	ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0;
+	sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
 }
 
 /*
@@ -392,11 +420,11 @@
 	/*
 	 * Clear interrupt source flags and turn off interrupts. If we
 	 * don't clear these flags before processing their sources we
-	 * could completely miss some interrupt events as the the NIC
-	 * can change these flags while we're in this handler. We turn
-	 * of interrupts while processing them so we don't get another
-	 * one while we still process the previous one in ifp->if_input()
-	 * with the driver lock dropped.
+	 * could completely miss some interrupt events as the NIC can
+	 * change these flags while we're in this handler. We turn off
+	 * interrupts so we don't get another RX interrupt while still
+	 * processing the previous one in ifp->if_input() with the
+	 * driver lock dropped.
 	 */
 	(*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD |
 	    LE_C0_STOP | LE_C0_STRT | LE_C0_INIT));
@@ -529,7 +557,7 @@
 
 #ifdef LEDEBUG
 		if (sc->sc_flags & LE_DEBUG)
-			am7990_xmit_print(sc, sc->sc_last_td);
+			am7990_xmit_print(sc, bix);
 #endif
 
 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
@@ -547,7 +575,7 @@
 	sc->sc_last_td = bix;
 
 	if (enq > 0)
-		ifp->if_timer = 5;
+		sc->sc_wdog_timer = 5;
 }
 
 #ifdef LEDEBUG
--- /dev/null
+++ sys/dev/le/if_le_lebuffer.c
@@ -0,0 +1,408 @@
+/*-
+ * Copyright (c) 2006 Marius Strobl <marius at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/le/if_le_lebuffer.c,v 1.2 2007/02/23 12:18:45 piso Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <dev/ofw/ofw_bus.h>
+
+#include <machine/bus.h>
+#include <machine/ofw_machdep.h>
+#include <machine/resource.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/le/lancereg.h>
+#include <dev/le/lancevar.h>
+#include <dev/le/am7990reg.h>
+#include <dev/le/am7990var.h>
+
+/*
+ * LANCE registers
+ */
+#define	LEREG1_RDP	0	/* Register Data port */
+#define	LEREG1_RAP	2	/* Register Address port */
+
+struct le_lebuffer_softc {
+	struct am7990_softc	sc_am7990;	/* glue to MI code */
+
+	int			sc_brid;
+	struct resource		*sc_bres;
+	bus_space_tag_t		sc_buft;
+	bus_space_handle_t	sc_bufh;
+
+	int			sc_rrid;
+	struct resource		*sc_rres;
+	bus_space_tag_t		sc_regt;
+	bus_space_handle_t	sc_regh;
+
+	int			sc_irid;
+	struct resource		*sc_ires;
+	void			*sc_ih;
+};
+
+static devclass_t le_lebuffer_devclass;
+
+static device_probe_t le_lebuffer_probe;
+static device_attach_t le_lebuffer_attach;
+static device_detach_t le_lebuffer_detach;
+static device_resume_t le_buffer_resume;
+static device_suspend_t le_buffer_suspend;
+
+static device_method_t le_lebuffer_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		le_lebuffer_probe),
+	DEVMETHOD(device_attach,	le_lebuffer_attach),
+	DEVMETHOD(device_detach,	le_lebuffer_detach),
+	/* We can just use the suspend method here. */
+	DEVMETHOD(device_shutdown,	le_buffer_suspend),
+	DEVMETHOD(device_suspend,	le_buffer_suspend),
+	DEVMETHOD(device_resume,	le_buffer_resume),
+
+	{ 0, 0 }
+};
+
+DEFINE_CLASS_0(le, le_lebuffer_driver, le_lebuffer_methods,
+    sizeof(struct le_lebuffer_softc));
+DRIVER_MODULE(le, lebuffer, le_lebuffer_driver, le_lebuffer_devclass, 0, 0);
+MODULE_DEPEND(le, ether, 1, 1, 1);
+
+/*
+ * Media types supported
+ */
+static const int le_lebuffer_media[] = {
+	IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0)
+};
+#define	NLEMEDIA							\
+    (sizeof(le_lebuffer_media) / sizeof(le_lebuffer_media[0]))
+
+static void le_lebuffer_wrcsr(struct lance_softc *, uint16_t, uint16_t);
+static uint16_t le_lebuffer_rdcsr(struct lance_softc *, uint16_t);
+static void le_lebuffer_copytodesc(struct lance_softc *, void *, int, int);
+static void le_lebuffer_copyfromdesc(struct lance_softc *, void *, int, int);
+static void le_lebuffer_copytobuf(struct lance_softc *, void *, int, int);
+static void le_lebuffer_copyfrombuf(struct lance_softc *, void *, int, int);
+static void le_lebuffer_zerobuf(struct lance_softc *, int, int);
+
+static void
+le_lebuffer_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP, val);
+}
+
+static uint16_t
+le_lebuffer_rdcsr(struct lance_softc *sc, uint16_t port)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, LEREG1_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, LEREG1_RDP));
+}
+
+/*
+ * It turns out that using bus_space(9) to access the buffers and the
+ * descriptors yields way more throughput than accessing them via the
+ * KVA returned by rman_get_virtual(9). The descriptor rings can be
+ * accessed using 8-bit up to 64-bit operations while the buffers can
+ * be only accessed using 8-bit and 16-bit operations.
+ * NB:	For whatever reason setting LE_C3_BSWP has no effect with at
+ *	least the 501-2981 (although their 'busmaster-regval' property
+ *	indicates to set LE_C3_BSWP also for these cards), so we need
+ *	to manually byte swap access to the buffers, i.e. the accesses
+ *	going through the RX/TX FIFOs.
+ */
+
+static void
+le_lebuffer_copytodesc(struct lance_softc *sc, void *fromv, int off, int len)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+	caddr_t from = fromv;
+
+	for (; len >= 8; len -= 8, off += 8, from += 8)
+		bus_space_write_8(lesc->sc_buft, lesc->sc_bufh, off,
+		    be64dec(from));
+	for (; len >= 4; len -= 4, off += 4, from += 4)
+		bus_space_write_4(lesc->sc_buft, lesc->sc_bufh, off,
+		    be32dec(from));
+	for (; len >= 2; len -= 2, off += 2, from += 2)
+		bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off,
+		    be16dec(from));
+	if (len == 1)
+		bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off,
+		    *from);
+}
+
+static void
+le_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+	caddr_t to = tov;
+
+	for (; len >= 8; len -= 8, off += 8, to += 8)
+		be64enc(to,
+		    bus_space_read_8(lesc->sc_buft, lesc->sc_bufh, off));
+	for (; len >= 4; len -= 4, off += 4, to += 4)
+		be32enc(to,
+		    bus_space_read_4(lesc->sc_buft, lesc->sc_bufh, off));
+	for (; len >= 2; len -= 2, off += 2, to += 2)
+		be16enc(to,
+		    bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off));
+	if (len == 1)
+		*to =
+		    bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off);
+}
+
+static void
+le_lebuffer_copytobuf(struct lance_softc *sc, void *fromv, int off, int len)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+	caddr_t from = fromv;
+
+	for (; len >= 2; len -= 2, off += 2, from += 2)
+		bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off,
+		    le16dec(from));
+	if (len == 1)
+		bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1,
+		    *from);
+}
+
+static void
+le_lebuffer_copyfrombuf(struct lance_softc *sc, void *tov, int off, int len)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+	caddr_t to = tov;
+
+	for (; len >= 2; len -= 2, off += 2, to += 2)
+		le16enc(to,
+		    bus_space_read_2(lesc->sc_buft, lesc->sc_bufh, off));
+	if (len == 1)
+		*to =
+		    bus_space_read_1(lesc->sc_buft, lesc->sc_bufh, off + 1);
+}
+
+static void
+le_lebuffer_zerobuf(struct lance_softc *sc, int off, int len)
+{
+	struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc;
+
+	for (; len >= 2; len -= 2, off += 2)
+		bus_space_write_2(lesc->sc_buft, lesc->sc_bufh, off, 0);
+	if (len == 1)
+		bus_space_write_1(lesc->sc_buft, lesc->sc_bufh, off + 1, 0);
+}
+
+static int
+le_lebuffer_probe(device_t dev)
+{
+
+	if (strcmp(ofw_bus_get_name(dev), "le") == 0) {
+		device_set_desc(dev, "LANCE Ethernet");
+		return (BUS_PROBE_DEFAULT);
+	}
+	return (ENXIO);
+}
+
+static int
+le_lebuffer_attach(device_t dev)
+{
+	struct le_lebuffer_softc *lesc;
+	struct lance_softc *sc;
+	int error;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	LE_LOCK_INIT(sc, device_get_nameunit(dev));
+
+	/*
+	 * The "register space" of the parent is just a buffer where the
+	 * the LANCE descriptor rings and the RX/TX buffers can be stored.
+	 */
+	lesc->sc_brid = 0;
+	lesc->sc_bres = bus_alloc_resource_any(device_get_parent(dev),
+	    SYS_RES_MEMORY, &lesc->sc_brid, RF_ACTIVE);
+	if (lesc->sc_bres == NULL) {
+		device_printf(dev, "cannot allocate LANCE buffer\n");
+		error = ENXIO;
+		goto fail_mtx;
+	}
+	lesc->sc_buft = rman_get_bustag(lesc->sc_bres);
+	lesc->sc_bufh = rman_get_bushandle(lesc->sc_bres);
+
+	/* Allocate LANCE registers. */
+	lesc->sc_rrid = 0;
+	lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+	    &lesc->sc_rrid, RF_ACTIVE);
+	if (lesc->sc_rres == NULL) {
+		device_printf(dev, "cannot allocate LANCE registers\n");
+		error = ENXIO;
+		goto fail_bres;
+	}
+	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
+	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
+
+	/* Allocate LANCE interrupt. */
+	lesc->sc_irid = 0;
+	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		error = ENXIO;
+		goto fail_rres;
+	}
+
+	/*
+	 * LANCE view is offset by buffer location.
+	 * Note that we don't use sc->sc_mem.
+	 */
+	sc->sc_addr = 0;
+	sc->sc_memsize = rman_get_size(lesc->sc_bres);
+	sc->sc_flags = 0;
+
+	/* That old black magic... */
+	if (OF_getprop(ofw_bus_get_node(dev), "busmaster-regval",
+	    &sc->sc_conf3, sizeof(sc->sc_conf3)) == -1)
+		sc->sc_conf3 = LE_C3_ACON | LE_C3_BCON;
+	/*
+	 * Make sure LE_C3_BSWP is cleared so that for cards where
+	 * that flag actually works le_lebuffer_copy{from,to}buf()
+	 * don't fail...
+	 */
+	sc->sc_conf3 &= ~LE_C3_BSWP;
+
+	OF_getetheraddr(dev, sc->sc_enaddr);
+
+	sc->sc_copytodesc = le_lebuffer_copytodesc;
+	sc->sc_copyfromdesc = le_lebuffer_copyfromdesc;
+	sc->sc_copytobuf = le_lebuffer_copytobuf;
+	sc->sc_copyfrombuf = le_lebuffer_copyfrombuf;
+	sc->sc_zerobuf = le_lebuffer_zerobuf;
+
+	sc->sc_rdcsr = le_lebuffer_rdcsr;
+	sc->sc_wrcsr = le_lebuffer_wrcsr;
+	sc->sc_hwreset = NULL;
+	sc->sc_hwinit = NULL;
+	sc->sc_hwintr = NULL;
+	sc->sc_nocarrier = NULL;
+	sc->sc_mediachange = NULL;
+	sc->sc_mediastatus = NULL;
+	sc->sc_supmedia = le_lebuffer_media;
+	sc->sc_nsupmedia = NLEMEDIA;
+	sc->sc_defaultmedia = le_lebuffer_media[0];
+
+	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
+	    device_get_unit(dev));
+	if (error != 0) {
+		device_printf(dev, "cannot attach Am7990\n");
+		goto fail_ires;
+	}
+
+	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, am7990_intr, sc, &lesc->sc_ih);
+	if (error != 0) {
+		device_printf(dev, "cannot set up interrupt\n");
+		goto fail_am7990;
+	}
+
+	return (0);
+
+ fail_am7990:
+	am7990_detach(&lesc->sc_am7990);
+ fail_ires:
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+ fail_rres:
+	bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres);
+ fail_bres:
+	bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY,
+	    lesc->sc_brid, lesc->sc_bres);
+ fail_mtx:
+	LE_LOCK_DESTROY(sc);
+	return (error);
+}
+
+static int
+le_lebuffer_detach(device_t dev)
+{
+	struct le_lebuffer_softc *lesc;
+	struct lance_softc *sc;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
+	am7990_detach(&lesc->sc_am7990);
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+	bus_release_resource(dev, SYS_RES_MEMORY, lesc->sc_rrid, lesc->sc_rres);
+	bus_release_resource(device_get_parent(dev), SYS_RES_MEMORY,
+	    lesc->sc_brid, lesc->sc_bres);
+	LE_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static int
+le_buffer_suspend(device_t dev)
+{
+	struct le_lebuffer_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_suspend(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
+
+static int
+le_buffer_resume(device_t dev)
+{
+	struct le_lebuffer_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_resume(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
Index: am7990reg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am7990reg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/am7990reg.h -L sys/dev/le/am7990reg.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/am7990reg.h
+++ sys/dev/le/am7990reg.h
@@ -70,7 +70,7 @@
  *	@(#)if_lereg.h	8.1 (Berkeley) 6/10/93
  */
 
-/* $FreeBSD: src/sys/dev/le/am7990reg.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/am7990reg.h,v 1.1 2006/01/31 14:48:58 marius Exp $ */
 
 #ifndef _DEV_LE_AM7990REG_H_
 #define	_DEV_LE_AM7990REG_H_
Index: am79900var.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am79900var.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/am79900var.h -L sys/dev/le/am79900var.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/am79900var.h
+++ sys/dev/le/am79900var.h
@@ -37,7 +37,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $FreeBSD: src/sys/dev/le/am79900var.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/am79900var.h,v 1.1 2006/01/31 14:48:58 marius Exp $ */
 
 #ifndef _DEV_LE_AM79900VAR_H_
 #define	_DEV_LE_AM79900VAR_H_
Index: lancereg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/lancereg.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/lancereg.h -L sys/dev/le/lancereg.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/lancereg.h
+++ sys/dev/le/lancereg.h
@@ -120,7 +120,7 @@
  * valid on the LANCE.
  */
 
-/* $FreeBSD: src/sys/dev/le/lancereg.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/lancereg.h,v 1.2 2006/05/16 21:04:01 marius Exp $ */
 
 #ifndef _DEV_LE_LANCEREG_H_
 #define	_DEV_LE_LANCEREG_H_
@@ -497,7 +497,7 @@
 #define	LE_B20_SSIZE32	0x0100		/* Software Size 32-bit */
 #define	LE_B20_SSTYLE	0x0007		/* Software Style */
 #define	LE_B20_SSTYLE_LANCE	0	/* LANCE/PCnet-ISA (16-bit) */
-#define	LE_B20_SSTYPE_ILACC	1	/* ILACC (32-bit) */
+#define	LE_B20_SSTYLE_ILACC	1	/* ILACC (32-bit) */
 #define	LE_B20_SSTYLE_PCNETPCI2	2	/* PCnet-PCI (32-bit) */
 #define	LE_B20_SSTYLE_PCNETPCI3	3	/* PCnet-PCI II (32-bit) */
 
Index: am79900.c
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am79900.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L sys/dev/le/am79900.c -L sys/dev/le/am79900.c -u -r1.2 -r1.3
--- sys/dev/le/am79900.c
+++ sys/dev/le/am79900.c
@@ -110,7 +110,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/le/am79900.c,v 1.1.2.2 2006/03/25 12:13:21 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/le/am79900.c,v 1.4 2006/12/06 02:14:31 marius Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -128,6 +128,8 @@
 #include <net/if_media.h>
 #include <net/if_var.h>
 
+#include <machine/bus.h>
+
 #include <dev/le/lancereg.h>
 #include <dev/le/lancevar.h>
 #include <dev/le/am79900reg.h>
@@ -255,9 +257,13 @@
 am79900_rint(struct lance_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
+	struct mbuf *m;
 	struct lermd rmd;
 	uint32_t rmd1;
 	int bix, rp;
+#if defined(__i386__) && !defined(PC98)
+	struct ether_header *eh;
+#endif
 
 	bix = sc->sc_last_rd;
 
@@ -270,35 +276,37 @@
 		if (rmd1 & LE_R1_OWN)
 			break;
 
-		if (rmd1 & LE_R1_ERR) {
-			if (rmd1 & LE_R1_ENP) {
-#ifdef LEDEBUG
-				if ((rmd1 & LE_R1_OFLO) == 0) {
-					if (rmd1 & LE_R1_FRAM)
-						if_printf(ifp,
-						    "framing error\n");
-					if (rmd1 & LE_R1_CRC)
-						if_printf(ifp,
-						    "crc mismatch\n");
-				}
-#endif
-			} else {
-				if (rmd1 & LE_R1_OFLO)
-					if_printf(ifp, "overflow\n");
-			}
-			if (rmd1 & LE_R1_BUFF)
-				if_printf(ifp, "receive buffer error\n");
-			ifp->if_ierrors++;
-		} else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
-		    (LE_R1_STP | LE_R1_ENP)) {
-			if_printf(ifp, "dropping chained buffer\n");
-			ifp->if_ierrors++;
+		m = NULL;
+		if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
+		    (LE_R1_STP | LE_R1_ENP)){
+			if (rmd1 & LE_R1_ERR) {
+#ifdef LEDEBUG
+				if (rmd1 & LE_R1_ENP) {
+					if ((rmd1 & LE_R1_OFLO) == 0) {
+						if (rmd1 & LE_R1_FRAM)
+							if_printf(ifp,
+							    "framing error\n");
+						if (rmd1 & LE_R1_CRC)
+							if_printf(ifp,
+							    "crc mismatch\n");
+					}
+				} else
+					if (rmd1 & LE_R1_OFLO)
+						if_printf(ifp, "overflow\n");
+#endif
+				if (rmd1 & LE_R1_BUFF)
+					if_printf(ifp,
+					    "receive buffer error\n");
+			} else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
+			    (LE_R1_STP | LE_R1_ENP))
+				if_printf(ifp, "dropping chained buffer\n");
 		} else {
 #ifdef LEDEBUG
 			if (sc->sc_flags & LE_DEBUG)
-				am79900_recv_print(sc, sc->sc_last_rd);
+				am79900_recv_print(sc, bix);
 #endif
-			lance_read(sc, LE_RBUFADDR(sc, bix),
+			/* Pull the packet off the interface. */
+			m = lance_get(sc, LE_RBUFADDR(sc, bix),
 			    (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN);
 		}
 
@@ -308,16 +316,31 @@
 		rmd.rmd3 = 0;
 		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
 
-#ifdef LEDEBUG
-		if (sc->sc_flags & LE_DEBUG)
-			if_printf(ifp, "sc->sc_last_rd = %x, rmd: "
-			    "adr %08x, flags/blen %08x\n",
-			    sc->sc_last_rd, LE_LE32TOH(rmd.rmd0),
-			    LE_LE32TOH(rmd.rmd1));
-#endif
-
 		if (++bix == sc->sc_nrbuf)
 			bix = 0;
+
+		if (m != NULL) {
+			ifp->if_ipackets++;
+
+#if defined(__i386__) && !defined(PC98)
+			/*
+			 * The VMware LANCE does not present IFF_SIMPLEX
+			 * behavior on multicast packets. Thus drop the
+			 * packet if it is from ourselves.
+			 */
+			eh = mtod(m, struct ether_header *);
+			if (!ether_cmp(eh->ether_shost, sc->sc_enaddr)) {
+				m_freem(m);
+				continue;
+			}
+#endif
+
+			/* Pass the packet up. */
+			LE_UNLOCK(sc);
+			(*ifp->if_input)(ifp, m);
+			LE_LOCK(sc);
+		} else
+			ifp->if_ierrors++;
 	}
 
 	sc->sc_last_rd = bix;
@@ -340,21 +363,22 @@
 		(*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
 		    sizeof(tmd));
 
+		tmd1 = LE_LE32TOH(tmd.tmd1);
+
 #ifdef LEDEBUG
 		if (sc->sc_flags & LE_DEBUG)
 			if_printf(ifp, "trans tmd: "
 			    "adr %08x, flags/blen %08x\n",
-			    LE_LE32TOH(tmd.tmd0), LE_LE32TOH(tmd.tmd1));
+			    LE_LE32TOH(tmd.tmd0), tmd1);
 #endif
 
-		tmd1 = LE_LE32TOH(tmd.tmd1);
 		if (tmd1 & LE_T1_OWN)
 			break;
 
 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
-		tmd2 = LE_LE32TOH(tmd.tmd2);
 		if (tmd1 & LE_T1_ERR) {
+			tmd2 = LE_LE32TOH(tmd.tmd2);
 			if (tmd2 & LE_T2_BUFF)
 				if_printf(ifp, "transmit buffer error\n");
 			else if (tmd2 & LE_T2_UFLO)
@@ -399,7 +423,7 @@
 
 	sc->sc_first_td = bix;
 
-	ifp->if_timer = sc->sc_no_td > 0 ? 5 : 0;
+	sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
 }
 
 /*
@@ -434,11 +458,11 @@
 	/*
 	 * Clear interrupt source flags and turn off interrupts. If we
 	 * don't clear these flags before processing their sources we
-	 * could completely miss some interrupt events as the the NIC
-	 * can change these flags while we're in this handler. We turn
-	 * of interrupts while processing them so we don't get another
-	 * one while we still process the previous one in ifp->if_input()
-	 * with the driver lock dropped.
+	 * could completely miss some interrupt events as the NIC can
+	 * change these flags while we're in this handler. We turn off
+	 * interrupts so we don't get another RX interrupt while still
+	 * processing the previous one in ifp->if_input() with the
+	 * driver lock dropped.
 	 */
 	(*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD |
 	    LE_C0_STOP | LE_C0_STRT | LE_C0_INIT));
@@ -572,7 +596,7 @@
 
 #ifdef LEDEBUG
 		if (sc->sc_flags & LE_DEBUG)
-			am79900_xmit_print(sc, sc->sc_last_td);
+			am79900_xmit_print(sc, bix);
 #endif
 
 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
@@ -590,7 +614,7 @@
 	sc->sc_last_td = bix;
 
 	if (enq > 0)
-		ifp->if_timer = 5;
+		sc->sc_wdog_timer = 5;
 }
 
 #ifdef LEDEBUG
--- /dev/null
+++ sys/dev/le/if_le_cbus.c
@@ -0,0 +1,451 @@
+/*-
+ * Copyright (c) 1994-2000
+ *	Paul Richards. All rights reserved.
+ *
+ * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    verbatim and that no modifications are made prior to this
+ *    point in the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name Paul Richards may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/le/if_le_cbus.c,v 1.5 2007/02/23 12:18:45 piso Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <isa/isavar.h>
+
+#include <dev/le/lancereg.h>
+#include <dev/le/lancevar.h>
+#include <dev/le/am7990var.h>
+
+#define	LE_CBUS_MEMSIZE	(16*1024)
+#define	CNET98S_IOSIZE	32
+#define	CNET98S_RDP	0x10
+#define	CNET98S_RAP	0x12
+#define	CNET98S_RESET	0x14
+#define	CNET98S_BDP	0x16
+
+struct le_cbus_softc {
+	struct am7990_softc	sc_am7990;	/* glue to MI code */
+
+	int			sc_rrid;
+	struct resource		*sc_rres;
+	bus_space_tag_t		sc_regt;
+	bus_space_handle_t	sc_regh;
+
+	int			sc_irid;
+	struct resource		*sc_ires;
+	void			*sc_ih;
+
+	bus_dma_tag_t		sc_pdmat;
+	bus_dma_tag_t		sc_dmat;
+	bus_dmamap_t		sc_dmam;
+};
+
+static device_probe_t le_cbus_probe;
+static device_attach_t le_cbus_attach;
+static device_detach_t le_cbus_detach;
+static device_resume_t le_cbus_resume;
+static device_suspend_t le_cbus_suspend;
+
+static device_method_t le_cbus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		le_cbus_probe),
+	DEVMETHOD(device_attach,	le_cbus_attach),
+	DEVMETHOD(device_detach,	le_cbus_detach),
+	/* We can just use the suspend method here. */
+	DEVMETHOD(device_shutdown,	le_cbus_suspend),
+	DEVMETHOD(device_suspend,	le_cbus_suspend),
+	DEVMETHOD(device_resume,	le_cbus_resume),
+
+	{ 0, 0 }
+};
+
+DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
+DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
+MODULE_DEPEND(le, ether, 1, 1, 1);
+
+static bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = {
+	0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
+	0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
+	0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
+	0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
+};
+
+static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
+#ifdef LEDEBUG
+static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
+#endif
+static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
+static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
+static void le_cbus_hwreset(struct lance_softc *);
+static bus_dmamap_callback_t le_cbus_dma_callback;
+
+static void
+le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
+{
+	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP, val);
+}
+
+#ifdef LEDEBUG
+static uint16_t
+le_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
+{
+	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP));
+}
+#endif
+
+static void
+le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
+{
+	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP, val);
+}
+
+static uint16_t
+le_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
+{
+	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP));
+}
+
+static void
+le_cbus_hwreset(struct lance_softc *sc)
+{
+	struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
+
+	/*
+	 * NB: These are Contec C-NET(98)S only.
+	 */
+
+	/* Reset the chip. */
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
+	    bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
+	DELAY(500);
+
+	/* ISA bus configuration */
+	/* ISACSR0 - set Master Mode Read Active time to 300ns. */
+    	le_cbus_wrbcr(sc, LE_BCR0, 0x0006);
+	/* ISACSR1 - set Master Mode Write Active time to 300ns. */
+    	le_cbus_wrbcr(sc, LE_BCR1, 0x0006);
+#ifdef LEDEBUG	
+	device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2));
+#endif
+	/* ISACSR5 - LED1 */
+	le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE);
+	/* ISACSR6 - LED2 */
+	le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE);
+	/* ISACSR7 - LED3 */
+	le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE);
+}
+
+static void
+le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct lance_softc *sc = (struct lance_softc *)xsc;
+
+	if (error != 0)
+		return;
+	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
+	sc->sc_addr = segs[0].ds_addr;
+}
+
+static int
+le_cbus_probe(device_t dev)
+{
+	struct le_cbus_softc *lesc;
+	struct lance_softc *sc;
+	int error;
+
+	/*
+	 * Skip PnP devices as some wedge when trying to probe them as
+	 * C-NET(98)S.
+	 */
+	if (isa_get_vendorid(dev))
+		return (ENXIO);
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	lesc->sc_rrid = 0;
+	lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
+	    le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
+	if (lesc->sc_rres == NULL)
+		return (ENXIO);
+	isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
+	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
+	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
+
+	/* Reset the chip. */
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
+	    bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
+	DELAY(500);
+
+	/* Stop the chip and put it in a known state. */
+	le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP);
+	DELAY(100);
+	if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
+		error = ENXIO;
+		goto fail;
+	}
+	le_cbus_wrcsr(sc, LE_CSR3, 0);
+	device_set_desc(dev, "C-NET(98)S");
+	error = BUS_PROBE_DEFAULT;
+
+ fail:
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+	return (error);
+}
+
+static int
+le_cbus_attach(device_t dev)
+{
+	struct le_cbus_softc *lesc;
+	struct lance_softc *sc;
+	int error, i;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	LE_LOCK_INIT(sc, device_get_nameunit(dev));
+
+	lesc->sc_rrid = 0;
+	lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
+	    le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
+	if (lesc->sc_rres == NULL) {
+		device_printf(dev, "cannot allocate registers\n");
+		error = ENXIO;
+		goto fail_mtx;
+	}
+	isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
+	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
+	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
+
+	lesc->sc_irid = 0;
+	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		error = ENXIO;
+		goto fail_rres;
+	}
+
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* parent */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
+	    0,				/* nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &lesc->sc_pdmat);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate parent DMA tag\n");
+		goto fail_ires;
+	}
+
+	sc->sc_memsize = LE_CBUS_MEMSIZE;
+	/*
+	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
+	 * aligned and the ring descriptors must be 8-byte aligned.
+	 */
+	error = bus_dma_tag_create(
+	    lesc->sc_pdmat,		/* parent */
+	    8, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    sc->sc_memsize,		/* maxsize */
+	    1,				/* nsegments */
+	    sc->sc_memsize,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &lesc->sc_dmat);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate buffer DMA tag\n");
+		goto fail_pdtag;
+	}
+
+	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate DMA buffer memory\n");
+		goto fail_dtag;
+	}
+
+	sc->sc_addr = 0;
+	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
+	    sc->sc_memsize, le_cbus_dma_callback, sc, 0);
+	if (error != 0 || sc->sc_addr == 0) {
+                device_printf(dev, "cannot load DMA buffer map\n");
+		goto fail_dmem;
+	}
+
+	sc->sc_flags = 0;
+	sc->sc_conf3 = 0;
+
+	/*
+	 * Extract the physical MAC address from the ROM.
+	 */
+	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
+		sc->sc_enaddr[i] =  bus_space_read_1(lesc->sc_regt,
+		    lesc->sc_regh, i * 2);
+
+	sc->sc_copytodesc = lance_copytobuf_contig;
+	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
+	sc->sc_copytobuf = lance_copytobuf_contig;
+	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
+	sc->sc_zerobuf = lance_zerobuf_contig;
+
+	sc->sc_rdcsr = le_cbus_rdcsr;
+	sc->sc_wrcsr = le_cbus_wrcsr;
+	sc->sc_hwreset = le_cbus_hwreset;
+	sc->sc_hwinit = NULL;
+	sc->sc_hwintr = NULL;
+	sc->sc_nocarrier = NULL;
+	sc->sc_mediachange = NULL;
+	sc->sc_mediastatus = NULL;
+	sc->sc_supmedia = NULL;
+
+	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
+	    device_get_unit(dev));
+	if (error != 0) {
+		device_printf(dev, "cannot attach Am7990\n");
+		goto fail_dmap;
+	}
+
+	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, am7990_intr, sc, &lesc->sc_ih);
+	if (error != 0) {
+		device_printf(dev, "cannot set up interrupt\n");
+		goto fail_am7990;
+	}
+
+	return (0);
+
+ fail_am7990:
+	am7990_detach(&lesc->sc_am7990);
+ fail_dmap:
+	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
+ fail_dmem:
+	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
+ fail_dtag:
+	bus_dma_tag_destroy(lesc->sc_dmat);
+ fail_pdtag:
+	bus_dma_tag_destroy(lesc->sc_pdmat);
+ fail_ires:
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+ fail_rres:
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+ fail_mtx:
+	LE_LOCK_DESTROY(sc);
+	return (error);
+}
+
+static int
+le_cbus_detach(device_t dev)
+{
+	struct le_cbus_softc *lesc;
+	struct lance_softc *sc;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
+	am7990_detach(&lesc->sc_am7990);
+	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
+	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
+	bus_dma_tag_destroy(lesc->sc_dmat);
+	bus_dma_tag_destroy(lesc->sc_pdmat);
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+	LE_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static int
+le_cbus_suspend(device_t dev)
+{
+	struct le_cbus_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_suspend(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
+
+static int
+le_cbus_resume(device_t dev)
+{
+	struct le_cbus_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_resume(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
--- /dev/null
+++ sys/dev/le/lebuffer_sbus.c
@@ -0,0 +1,300 @@
+/*-
+ * Copyright (c) 2006 Marius Strobl <marius at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/le/lebuffer_sbus.c,v 1.1 2007/01/20 12:53:30 marius Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/bus_common.h>
+#include <machine/resource.h>
+
+#include <sparc64/sbus/ofw_sbus.h>
+#include <sparc64/sbus/sbusreg.h>
+#include <sparc64/sbus/sbusvar.h>
+
+struct lebuffer_devinfo {
+	struct ofw_bus_devinfo	ldi_obdinfo;
+	struct resource_list	ldi_rl;
+};
+
+static devclass_t lebuffer_devclass;
+
+static device_probe_t lebuffer_probe;
+static device_attach_t lebuffer_attach;
+static device_detach_t lebuffer_detach;
+static bus_print_child_t lebuffer_print_child;
+static bus_probe_nomatch_t lebuffer_probe_nomatch;
+static bus_get_resource_list_t lebuffer_get_resource_list;
+static ofw_bus_get_devinfo_t lebuffer_get_devinfo;
+
+static struct lebuffer_devinfo *lebuffer_setup_dinfo(device_t, phandle_t);
+static void lebuffer_destroy_dinfo(struct lebuffer_devinfo *);
+static int lebuffer_print_res(struct lebuffer_devinfo *);
+
+static device_method_t lebuffer_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lebuffer_probe),
+	DEVMETHOD(device_attach,	lebuffer_attach),
+	DEVMETHOD(device_detach,	lebuffer_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+	DEVMETHOD(device_suspend,	bus_generic_suspend),
+	DEVMETHOD(device_resume,	bus_generic_resume),
+
+	/* Bus interface */
+	DEVMETHOD(bus_print_child,	lebuffer_print_child),
+	DEVMETHOD(bus_probe_nomatch,	lebuffer_probe_nomatch),
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+	DEVMETHOD(bus_alloc_resource,	bus_generic_rl_alloc_resource),
+	DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
+	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_get_resource_list, lebuffer_get_resource_list),
+	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
+
+	/* ofw_bus interface */
+	DEVMETHOD(ofw_bus_get_devinfo,	lebuffer_get_devinfo),
+	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
+	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
+	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
+	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
+	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
+
+	{ 0, 0 }
+};
+
+DEFINE_CLASS_0(lebuffer, lebuffer_driver, lebuffer_methods, 1);
+DRIVER_MODULE(lebuffer, sbus, lebuffer_driver, lebuffer_devclass, 0, 0);
+
+static int
+lebuffer_probe(device_t dev)
+{
+	const char *name;
+
+	name = ofw_bus_get_name(dev);
+	if (strcmp(name, "lebuffer") == 0) {
+		device_set_desc_copy(dev, name);
+		return (0);
+	}
+	return (ENXIO);
+}
+
+static int
+lebuffer_attach(device_t dev)
+{
+	struct lebuffer_devinfo *ldi;
+	device_t cdev;
+	phandle_t child;
+	int children;
+
+	children = 0;
+	for (child = OF_child(ofw_bus_get_node(dev)); child != 0;
+	    child = OF_peer(child)) {
+		if ((ldi = lebuffer_setup_dinfo(dev, child)) == NULL)
+			continue;
+		if (children != 0) {
+			device_printf(dev,
+			    "<%s>: only one child per buffer supported\n",
+			    ldi->ldi_obdinfo.obd_name);
+			lebuffer_destroy_dinfo(ldi);
+			continue;
+		}
+		if ((cdev = device_add_child(dev, NULL, -1)) == NULL) {
+			device_printf(dev, "<%s>: device_add_child failed\n",
+			    ldi->ldi_obdinfo.obd_name);
+			lebuffer_destroy_dinfo(ldi);
+			continue;
+		}
+		device_set_ivars(cdev, ldi);
+		children++;
+	}
+	return (bus_generic_attach(dev));
+}
+
+static int
+lebuffer_detach(device_t dev)
+{
+	device_t *children;
+	int i, nchildren;
+
+	bus_generic_detach(dev);
+	if (device_get_children(dev, &children, &nchildren) == 0) {
+		for (i = 0; i < nchildren; i++) {
+			lebuffer_destroy_dinfo(device_get_ivars(children[i]));
+			device_delete_child(dev, children[i]);
+		}
+		free(children, M_TEMP);
+	}
+	return (0);
+}
+
+static struct lebuffer_devinfo *
+lebuffer_setup_dinfo(device_t dev, phandle_t node)
+{
+	struct lebuffer_devinfo *ldi;
+	struct sbus_regs *reg;
+	uint32_t base, iv, *intr;
+	int i, nreg, nintr, slot, rslot;
+
+	ldi = malloc(sizeof(*ldi), M_DEVBUF, M_WAITOK | M_ZERO);
+	if (ofw_bus_gen_setup_devinfo(&ldi->ldi_obdinfo, node) != 0) {
+		free(ldi, M_DEVBUF);
+		return (NULL);
+	}
+	resource_list_init(&ldi->ldi_rl);
+	slot = -1;
+	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
+	if (nreg == -1) {
+		device_printf(dev, "<%s>: incomplete\n",
+		    ldi->ldi_obdinfo.obd_name);
+		goto fail;
+	}
+	for (i = 0; i < nreg; i++) {
+		base = reg[i].sbr_offset;
+		if (SBUS_ABS(base)) {
+			rslot = SBUS_ABS_TO_SLOT(base);
+			base = SBUS_ABS_TO_OFFSET(base);
+		} else
+			rslot = reg[i].sbr_slot;
+		if (slot != -1 && slot != rslot) {
+			device_printf(dev, "<%s>: multiple slots\n",
+			    ldi->ldi_obdinfo.obd_name);
+			free(reg, M_OFWPROP);
+			goto fail;
+		}
+		slot = rslot;
+
+		resource_list_add(&ldi->ldi_rl, SYS_RES_MEMORY, i, base,
+		    base + reg[i].sbr_size, reg[i].sbr_size);
+	}
+	free(reg, M_OFWPROP);
+	if (slot != sbus_get_slot(dev)) {
+		device_printf(dev, "<%s>: parent and child slot do not match\n",
+		    ldi->ldi_obdinfo.obd_name);
+		goto fail;
+	}
+
+	/*
+	 * The `interrupts' property contains the SBus interrupt level.
+	 */
+	nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr),
+	    (void **)&intr);
+	if (nintr != -1) {
+		for (i = 0; i < nintr; i++) {
+			iv = intr[i];
+			/*
+			 * SBus card devices need the slot number encoded into
+			 * the vector as this is generally not done.
+			 */
+			if ((iv & INTMAP_OBIO_MASK) == 0)
+				iv |= slot << 3;
+			/* Set the IGN as appropriate. */
+			iv |= sbus_get_ign(dev) << INTMAP_IGN_SHIFT;
+			resource_list_add(&ldi->ldi_rl, SYS_RES_IRQ, i,
+			    iv, iv, 1);
+		}
+		free(intr, M_OFWPROP);
+	}
+	return (ldi);
+
+ fail:
+	lebuffer_destroy_dinfo(ldi);
+	return (NULL);
+}
+
+static void
+lebuffer_destroy_dinfo(struct lebuffer_devinfo *dinfo)
+{
+
+	resource_list_free(&dinfo->ldi_rl);
+	ofw_bus_gen_destroy_devinfo(&dinfo->ldi_obdinfo);
+	free(dinfo, M_DEVBUF);
+}
+
+static int
+lebuffer_print_child(device_t dev, device_t child)
+{
+	int rv;
+
+	rv = bus_print_child_header(dev, child);
+	rv += lebuffer_print_res(device_get_ivars(child));
+	rv += bus_print_child_footer(dev, child);
+	return (rv);
+}
+
+static void
+lebuffer_probe_nomatch(device_t dev, device_t child)
+{
+	const char *type;
+
+	device_printf(dev, "<%s>", ofw_bus_get_name(child));
+	lebuffer_print_res(device_get_ivars(child));
+	type = ofw_bus_get_type(child);
+	printf(" type %s (no driver attached)\n",
+	    type != NULL ? type : "unknown");
+}
+
+static struct resource_list *
+lebuffer_get_resource_list(device_t dev, device_t child)
+{
+	struct lebuffer_devinfo *ldi;
+
+	ldi = device_get_ivars(child);
+	return (&ldi->ldi_rl);
+}
+
+static const struct ofw_bus_devinfo *
+lebuffer_get_devinfo(device_t bus, device_t child)
+{
+	struct lebuffer_devinfo *ldi;
+
+	ldi = device_get_ivars(child);
+	return (&ldi->ldi_obdinfo);
+}
+
+static int
+lebuffer_print_res(struct lebuffer_devinfo *ldi)
+{
+	int rv;
+
+	rv = 0;
+	rv += resource_list_print_type(&ldi->ldi_rl, "mem", SYS_RES_MEMORY,
+	    "%#lx");
+	rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%ld");
+	return (rv);
+}
Index: lancevar.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/lancevar.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/lancevar.h -L sys/dev/le/lancevar.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/lancevar.h
+++ sys/dev/le/lancevar.h
@@ -37,19 +37,19 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $FreeBSD: src/sys/dev/le/lancevar.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/lancevar.h,v 1.3 2006/12/06 02:14:31 marius Exp $ */
 
 #ifndef _DEV_LE_LANCEVAR_H_
 #define	_DEV_LE_LANCEVAR_H_
 
-#define	LE_DRIVER_NAME	"le"
-
 extern devclass_t le_devclass;
 
 struct lance_softc {
 	struct ifnet	*sc_ifp;
 	struct ifmedia	sc_media;
 	struct mtx	sc_mtx;
+	struct callout	sc_wdog_ch;
+	int		sc_wdog_timer;
 
 	/*
 	 * Memory functions:
@@ -92,10 +92,10 @@
 
 	uint16_t	sc_conf3;	/* CSR3 value */
 
-	void	*sc_mem;	/* base address of RAM -- CPU's view */
-	u_long	sc_addr;	/* base address of RAM -- LANCE's view */
+	void	*sc_mem;		/* base address of RAM - CPU's view */
+	bus_addr_t	sc_addr;	/* base address of RAM - LANCE's view */
 
-	u_long	sc_memsize;	/* size of RAM */
+	bus_size_t	sc_memsize;	/* size of RAM */
 
 	int	sc_nrbuf;	/* number of receive buffers */
 	int	sc_ntbuf;	/* number of transmit buffers */
@@ -131,6 +131,11 @@
 #define	LE_LOCK_ASSERT(_sc, _what)	mtx_assert(&(_sc)->sc_mtx, (_what))
 #define	LE_LOCK_DESTROY(_sc)		mtx_destroy(&(_sc)->sc_mtx)
 
+/*
+ * Unfortunately, manual byte swapping is only necessary for the PCnet-PCI
+ * variants but not for the original LANCE or ILACC so we cannot do this
+ * with #ifdefs resolved at compile time.
+ */
 #define	LE_HTOLE16(v)	(((sc)->sc_flags & LE_BSWAP) ? htole16(v) : (v))
 #define	LE_HTOLE32(v)	(((sc)->sc_flags & LE_BSWAP) ? htole32(v) : (v))
 #define	LE_LE16TOH(v)	(((sc)->sc_flags & LE_BSWAP) ? le16toh(v) : (v))
@@ -143,7 +148,7 @@
 void lance_resume(struct lance_softc *);
 void lance_init_locked(struct lance_softc *);
 int lance_put(struct lance_softc *, int, struct mbuf *);
-void lance_read(struct lance_softc *, int, int);
+struct mbuf *lance_get(struct lance_softc *, int, int);
 void lance_setladrf(struct lance_softc *, u_int16_t *);
 
 /*
@@ -166,4 +171,46 @@
 void lance_zerobuf_gap16(struct lance_softc *, int, int);
 #endif /* Example only */
 
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed.  Use this like memcmp().
+ *
+ * XXX: Add <machine/inlines.h> for stuff like this?
+ * XXX: or maybe add it to libkern.h instead?
+ *
+ * "I'd love to have an inline assembler version of this."
+ * XXX: Who wanted that? mycroft?  I wrote one, but this
+ * version in C is as good as hand-coded assembly. -gwr
+ *
+ * Please do NOT tweak this without looking at the actual
+ * assembly code generated before and after your tweaks!
+ */
+static inline uint16_t
+ether_cmp(void *one, void *two)
+{
+	uint16_t *a = (u_short *)one;
+	uint16_t *b = (u_short *)two;
+	uint16_t diff;
+
+#ifdef	m68k
+	/*
+	 * The post-increment-pointer form produces the best
+	 * machine code for m68k.  This was carefully tuned
+	 * so it compiles to just 8 short (2-byte) op-codes!
+	 */
+	diff  = *a++ - *b++;
+	diff |= *a++ - *b++;
+	diff |= *a++ - *b++;
+#else
+	/*
+	 * Most modern CPUs do better with a single expresion.
+	 * Note that short-cut evaluation is NOT helpful here,
+	 * because it just makes the code longer, not faster!
+	 */
+	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
+#endif
+
+	return (diff);
+}
+
 #endif /* _DEV_LE_LANCEVAR_H_ */
Index: am7990var.h
===================================================================
RCS file: /home/cvs/src/sys/dev/le/am7990var.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/am7990var.h -L sys/dev/le/am7990var.h -u -r1.1.1.1 -r1.2
--- sys/dev/le/am7990var.h
+++ sys/dev/le/am7990var.h
@@ -37,7 +37,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* $FreeBSD: src/sys/dev/le/am7990var.h,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $ */
+/* $FreeBSD: src/sys/dev/le/am7990var.h,v 1.1 2006/01/31 14:48:58 marius Exp $ */
 
 #ifndef _DEV_LE_AM7990VAR_H_
 #define	_DEV_LE_AM7990VAR_H_
--- /dev/null
+++ sys/dev/le/if_le_isa.c
@@ -0,0 +1,509 @@
+/*	$NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $	*/
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
+ * Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ralph Campbell and Rick Macklem.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/dev/le/if_le_isa.c,v 1.4 2007/02/23 12:18:45 piso Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <isa/isavar.h>
+
+#include <dev/le/lancereg.h>
+#include <dev/le/lancevar.h>
+#include <dev/le/am7990var.h>
+
+#define	LE_ISA_MEMSIZE	(16*1024)
+#define	PCNET_RDP	0x10
+#define	PCNET_RAP	0x12
+
+struct le_isa_softc {
+	struct am7990_softc	sc_am7990;	/* glue to MI code */
+
+	bus_size_t		sc_rap;		/* offsets to LANCE... */
+	bus_size_t		sc_rdp;		/* ...registers */
+
+	int			sc_rrid;
+	struct resource		*sc_rres;
+	bus_space_tag_t		sc_regt;
+	bus_space_handle_t	sc_regh;
+
+	int			sc_drid;
+	struct resource		*sc_dres;
+
+	int			sc_irid;
+	struct resource		*sc_ires;
+	void			*sc_ih;
+
+	bus_dma_tag_t		sc_pdmat;
+	bus_dma_tag_t		sc_dmat;
+	bus_dmamap_t		sc_dmam;
+};
+
+static device_probe_t le_isa_probe;
+static device_attach_t le_isa_attach;
+static device_detach_t le_isa_detach;
+static device_resume_t le_isa_resume;
+static device_suspend_t le_isa_suspend;
+
+static device_method_t le_isa_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		le_isa_probe),
+	DEVMETHOD(device_attach,	le_isa_attach),
+	DEVMETHOD(device_detach,	le_isa_detach),
+	/* We can just use the suspend method here. */
+	DEVMETHOD(device_shutdown,	le_isa_suspend),
+	DEVMETHOD(device_suspend,	le_isa_suspend),
+	DEVMETHOD(device_resume,	le_isa_resume),
+
+	{ 0, 0 }
+};
+
+DEFINE_CLASS_0(le, le_isa_driver, le_isa_methods, sizeof(struct le_isa_softc));
+DRIVER_MODULE(le, isa, le_isa_driver, le_devclass, 0, 0);
+MODULE_DEPEND(le, ether, 1, 1, 1);
+
+struct le_isa_param {
+	const char	*name;
+	u_long		iosize;
+	bus_size_t	rap;
+	bus_size_t	rdp;
+	bus_size_t	macstart;
+	int		macstride;
+} static const le_isa_params[] = {
+	{ "BICC Isolan", 24, 0xe, 0xc, 0, 2 },
+	{ "Novell NE2100", 16, 0x12, 0x10, 0, 1 }
+};
+
+static struct isa_pnp_id le_isa_ids[] = {
+	{ 0x0322690e, "Cabletron E2200 Single Chip" },	/* CSI2203 */
+	{ 0x0110490a, "Boca LANCard Combo" },		/* BRI1001 */
+	{ 0x0100a60a, "Melco Inc. LGY-IV" },		/* BUF0001 */
+	{ 0xd880d041, "Novell NE2100" },		/* PNP80D8 */
+	{ 0x0082d041, "Cabletron E2100 Series DNI" },	/* PNP8200 */
+	{ 0x3182d041, "AMD AM1500T/AM2100" },		/* PNP8231 */
+	{ 0x8c82d041, "AMD PCnet-ISA" },		/* PNP828C */
+	{ 0x8d82d041, "AMD PCnet-32" },			/* PNP828D */
+	{ 0xcefaedfe, "Racal InterLan EtherBlaster" },	/* _WMFACE */
+	{ 0, NULL }
+};
+
+static void le_isa_wrcsr(struct lance_softc *, uint16_t, uint16_t);
+static uint16_t le_isa_rdcsr(struct lance_softc *, uint16_t);
+static bus_dmamap_callback_t le_isa_dma_callback;
+static int le_isa_probe_legacy(device_t, const struct le_isa_param *);
+
+static void
+le_isa_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
+{
+	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rdp, val);
+}
+
+static uint16_t
+le_isa_rdcsr(struct lance_softc *sc, uint16_t port)
+{
+	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
+
+	bus_space_write_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, port);
+	bus_space_barrier(lesc->sc_regt, lesc->sc_regh, lesc->sc_rap, 2,
+	    BUS_SPACE_BARRIER_WRITE);
+	return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, lesc->sc_rdp));
+}
+
+static void
+le_isa_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct lance_softc *sc = (struct lance_softc *)xsc;
+
+	if (error != 0)
+		return;
+	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
+	sc->sc_addr = segs[0].ds_addr;
+}
+
+static int
+le_isa_probe_legacy(device_t dev, const struct le_isa_param *leip)
+{
+	struct le_isa_softc *lesc;
+	struct lance_softc *sc;
+	int error;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	lesc->sc_rrid = 0;
+	lesc->sc_rres = bus_alloc_resource(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
+	    0, ~0, leip->iosize, RF_ACTIVE);
+	if (lesc->sc_rres == NULL)
+		return (ENXIO);
+	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
+	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
+	lesc->sc_rap = leip->rap;
+	lesc->sc_rdp = leip->rdp;
+
+	/* Stop the chip and put it in a known state. */
+	le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
+	DELAY(100);
+	if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
+		error = ENXIO;
+		goto fail;
+	}
+	le_isa_wrcsr(sc, LE_CSR3, 0);
+	error = 0;
+
+ fail:
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+	return (error);
+}
+
+static int
+le_isa_probe(device_t dev)
+{
+	int i;
+
+	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
+	case 0:
+		return (BUS_PROBE_DEFAULT);
+	case ENOENT:
+		for (i = 0; i < sizeof(le_isa_params) /
+		    sizeof(le_isa_params[0]); i++) {
+			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
+				device_set_desc(dev, le_isa_params[i].name);
+				return (BUS_PROBE_DEFAULT);
+			}
+		}
+		/* FALLTHROUGH */
+	case ENXIO:
+	default:
+		return (ENXIO);
+	}
+}
+
+static int
+le_isa_attach(device_t dev)
+{
+	struct le_isa_softc *lesc;
+	struct lance_softc *sc;
+	bus_size_t macstart, rap, rdp;
+	int error, i, macstride;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	LE_LOCK_INIT(sc, device_get_nameunit(dev));
+
+	lesc->sc_rrid = 0;
+	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
+	case 0:
+		lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
+		    &lesc->sc_rrid, RF_ACTIVE);
+		rap = PCNET_RAP;
+		rdp = PCNET_RDP;
+		macstart = 0;
+		macstride = 1;
+		break;
+	case ENOENT:
+		for (i = 0; i < sizeof(le_isa_params) /
+		    sizeof(le_isa_params[0]); i++) {
+			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
+				lesc->sc_rres = bus_alloc_resource(dev,
+				    SYS_RES_IOPORT, &lesc->sc_rrid, 0, ~0,
+				    le_isa_params[i].iosize, RF_ACTIVE);
+				rap = le_isa_params[i].rap;
+				rdp = le_isa_params[i].rdp;
+				macstart = le_isa_params[i].macstart;
+				macstride = le_isa_params[i].macstride;
+				goto found;
+			}
+		}
+		/* FALLTHROUGH */
+	case ENXIO:
+	default:
+		device_printf(dev, "cannot determine chip\n");
+		error = ENXIO;
+		goto fail_mtx;
+	}
+
+ found:
+	if (lesc->sc_rres == NULL) {
+		device_printf(dev, "cannot allocate registers\n");
+		error = ENXIO;
+		goto fail_mtx;
+	}
+	lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
+	lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
+	lesc->sc_rap = rap;
+	lesc->sc_rdp = rdp;
+
+	lesc->sc_drid = 0;
+	if ((lesc->sc_dres = bus_alloc_resource_any(dev, SYS_RES_DRQ,
+	    &lesc->sc_drid, RF_ACTIVE)) == NULL) {
+		device_printf(dev, "cannot allocate DMA channel\n");
+		error = ENXIO;
+		goto fail_rres;
+	}
+
+	lesc->sc_irid = 0;
+	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+	    &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		error = ENXIO;
+		goto fail_dres;
+	}
+
+	error = bus_dma_tag_create(
+	    bus_get_dma_tag(dev),	/* parent */
+	    1, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
+	    0,				/* nsegments */
+	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &lesc->sc_pdmat);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate parent DMA tag\n");
+		goto fail_ires;
+	}
+
+	sc->sc_memsize = LE_ISA_MEMSIZE;
+	/*
+	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
+	 * aligned and the ring descriptors must be 8-byte aligned.
+	 */
+	error = bus_dma_tag_create(
+	    lesc->sc_pdmat,		/* parent */
+	    8, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    sc->sc_memsize,		/* maxsize */
+	    1,				/* nsegments */
+	    sc->sc_memsize,		/* maxsegsize */
+	    0,				/* flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &lesc->sc_dmat);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate buffer DMA tag\n");
+		goto fail_pdtag;
+	}
+
+	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
+	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
+	if (error != 0) {
+		device_printf(dev, "cannot allocate DMA buffer memory\n");
+		goto fail_dtag;
+	}
+
+	sc->sc_addr = 0;
+	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
+	    sc->sc_memsize, le_isa_dma_callback, sc, 0);
+	if (error != 0 || sc->sc_addr == 0) {
+                device_printf(dev, "cannot load DMA buffer map\n");
+		goto fail_dmem;
+	}
+
+	isa_dmacascade(rman_get_start(lesc->sc_dres));
+
+	sc->sc_flags = 0;
+	sc->sc_conf3 = 0;
+
+	/*
+	 * Extract the physical MAC address from the ROM.
+	 */
+	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
+		sc->sc_enaddr[i] =  bus_space_read_1(lesc->sc_regt,
+		    lesc->sc_regh, macstart + i * macstride);
+
+	sc->sc_copytodesc = lance_copytobuf_contig;
+	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
+	sc->sc_copytobuf = lance_copytobuf_contig;
+	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
+	sc->sc_zerobuf = lance_zerobuf_contig;
+
+	sc->sc_rdcsr = le_isa_rdcsr;
+	sc->sc_wrcsr = le_isa_wrcsr;
+	sc->sc_hwreset = NULL;
+	sc->sc_hwinit = NULL;
+	sc->sc_hwintr = NULL;
+	sc->sc_nocarrier = NULL;
+	sc->sc_mediachange = NULL;
+	sc->sc_mediastatus = NULL;
+	sc->sc_supmedia = NULL;
+
+	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
+	    device_get_unit(dev));
+	if (error != 0) {
+		device_printf(dev, "cannot attach Am7990\n");
+		goto fail_dmap;
+	}
+
+	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
+	    NULL, am7990_intr, sc, &lesc->sc_ih);
+	if (error != 0) {
+		device_printf(dev, "cannot set up interrupt\n");
+		goto fail_am7990;
+	}
+
+	return (0);
+
+ fail_am7990:
+	am7990_detach(&lesc->sc_am7990);
+ fail_dmap:
+	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
+ fail_dmem:
+	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
+ fail_dtag:
+	bus_dma_tag_destroy(lesc->sc_dmat);
+ fail_pdtag:
+	bus_dma_tag_destroy(lesc->sc_pdmat);
+ fail_ires:
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+ fail_dres:
+	bus_release_resource(dev, SYS_RES_DRQ, lesc->sc_drid, lesc->sc_dres);
+ fail_rres:
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+ fail_mtx:
+	LE_LOCK_DESTROY(sc);
+	return (error);
+}
+
+static int
+le_isa_detach(device_t dev)
+{
+	struct le_isa_softc *lesc;
+	struct lance_softc *sc;
+
+	lesc = device_get_softc(dev);
+	sc = &lesc->sc_am7990.lsc;
+
+	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
+	am7990_detach(&lesc->sc_am7990);
+	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
+	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
+	bus_dma_tag_destroy(lesc->sc_dmat);
+	bus_dma_tag_destroy(lesc->sc_pdmat);
+	bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
+	bus_release_resource(dev, SYS_RES_DRQ, lesc->sc_drid, lesc->sc_dres);
+	bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
+	LE_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static int
+le_isa_suspend(device_t dev)
+{
+	struct le_isa_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_suspend(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
+
+static int
+le_isa_resume(device_t dev)
+{
+	struct le_isa_softc *lesc;
+
+	lesc = device_get_softc(dev);
+
+	lance_resume(&lesc->sc_am7990.lsc);
+
+	return (0);
+}
Index: if_le_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/le/if_le_pci.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/if_le_pci.c -L sys/dev/le/if_le_pci.c -u -r1.1.1.1 -r1.2
--- sys/dev/le/if_le_pci.c
+++ sys/dev/le/if_le_pci.c
@@ -72,7 +72,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/le/if_le_pci.c,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/le/if_le_pci.c,v 1.7 2007/02/23 12:18:45 piso Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -103,7 +103,7 @@
 #define	AMD_VENDOR	0x1022
 #define	AMD_PCNET_PCI	0x2000
 #define	AMD_PCNET_HOME	0x2001
-#define	PCNET_MEMSIZE	16384
+#define	PCNET_MEMSIZE	(32*1024)
 #define	PCNET_PCI_RDP	0x10
 #define	PCNET_PCI_RAP	0x12
 #define	PCNET_PCI_BDP	0x16
@@ -146,7 +146,7 @@
 
 DEFINE_CLASS_0(le, le_pci_driver, le_pci_methods, sizeof(struct le_pci_softc));
 DRIVER_MODULE(le, pci, le_pci_driver, le_devclass, 0, 0);
-MODULE_DEPEND(le_DRIVER_NAME, ether, 1, 1, 1);
+MODULE_DEPEND(le, ether, 1, 1, 1);
 
 static const int le_home_supmedia[] = {
 	IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 0)
@@ -263,7 +263,15 @@
 le_pci_hwreset(struct lance_softc *sc)
 {
 
-	/* Chip is stopped. Set "software style" to 32-bit. */
+	/*
+	 * Chip is stopped. Set software style to PCnet-PCI (32-bit).
+	 * Actually, am79900.c implements ILACC support (hence its
+	 * name) but unfortunately VMware does not. As far as this
+	 * driver is concerned that should not make a difference
+	 * though, as the settings used have the same meaning for
+	 * both, ILACC and PCnet-PCI (note that there would be a
+	 * difference for the ADD_FCS/NO_FCS bit if used).
+	 */
 	le_pci_wrbcr(sc, LE_BCR20, LE_B20_SSTYLE_PCNETPCI2);
 }
 
@@ -287,9 +295,12 @@
 
 	switch (pci_get_device(dev)) {
 	case AMD_PCNET_PCI:
+		device_set_desc(dev, "AMD PCnet-PCI");
+		/* Let pcn(4) win. */
+		return (BUS_PROBE_LOW_PRIORITY);
 	case AMD_PCNET_HOME:
-		device_set_desc(dev, "AMD PCnet Ethernet");
-		/* Let lnc(4) win for now. */
+		device_set_desc(dev, "AMD PCnet-Home");
+		/* Let pcn(4) win. */
 		return (BUS_PROBE_LOW_PRIORITY);
 	default:
 		return (ENXIO);
@@ -331,15 +342,15 @@
 	}
 
 	error = bus_dma_tag_create(
-	    NULL,			/* parent */
-	    PAGE_SIZE, 0,		/* alignment, boundary */
+	    bus_get_dma_tag(dev),	/* parent */
+	    1, 0,			/* alignment, boundary */
 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
 	    BUS_SPACE_MAXADDR,		/* highaddr */
 	    NULL, NULL,			/* filter, filterarg */
 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
 	    0,				/* nsegments */
 	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
-	    BUS_DMA_WAITOK,		/* flags */
+	    0,				/* flags */
 	    NULL, NULL,			/* lockfunc, lockarg */
 	    &lesc->sc_pdmat);
 	if (error != 0) {
@@ -348,16 +359,21 @@
 	}
 
 	sc->sc_memsize = PCNET_MEMSIZE;
+	/*
+	 * For Am79C970A, Am79C971 and Am79C978 the init block must be 2-byte
+	 * aligned and the ring descriptors must be 16-byte aligned when using
+	 * a 32-bit software style.
+	 */
 	error = bus_dma_tag_create(
 	    lesc->sc_pdmat,		/* parent */
-	    1, 0,			/* alignment, boundary */
+	    16, 0,			/* alignment, boundary */
 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
 	    BUS_SPACE_MAXADDR,		/* highaddr */
 	    NULL, NULL,			/* filter, filterarg */
 	    sc->sc_memsize,		/* maxsize */
 	    1,				/* nsegments */
 	    sc->sc_memsize,		/* maxsegsize */
-	    BUS_DMA_WAITOK,		/* flags */
+	    0,				/* flags */
 	    NULL, NULL,			/* lockfunc, lockarg */
 	    &lesc->sc_dmat);
 	if (error != 0) {
@@ -383,6 +399,7 @@
 	sc->sc_flags = LE_BSWAP;
 	sc->sc_conf3 = 0;
 
+	sc->sc_mediastatus = NULL;
 	switch (pci_get_device(dev)) {
 	case AMD_PCNET_HOME:
 		sc->sc_mediachange = le_pci_mediachange;
@@ -413,16 +430,19 @@
 	sc->sc_rdcsr = le_pci_rdcsr;
 	sc->sc_wrcsr = le_pci_wrcsr;
 	sc->sc_hwreset = le_pci_hwreset;
+	sc->sc_hwinit = NULL;
+	sc->sc_hwintr = NULL;
+	sc->sc_nocarrier = NULL;
 
 	error = am79900_config(&lesc->sc_am79900, device_get_name(dev),
 	    device_get_unit(dev));
 	if (error != 0) {
-		device_printf(dev, "cannot attach AM79900\n");
+		device_printf(dev, "cannot attach Am79900\n");
 		goto fail_dmap;
 	}
 
 	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
-	    am79900_intr, sc, &lesc->sc_ih);
+	    NULL, am79900_intr, sc, &lesc->sc_ih);
 	if (error != 0) {
 		device_printf(dev, "cannot set up interrupt\n");
 		goto fail_am79900;
Index: lance.c
===================================================================
RCS file: /home/cvs/src/sys/dev/le/lance.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L sys/dev/le/lance.c -L sys/dev/le/lance.c -u -r1.1.1.1 -r1.2
--- sys/dev/le/lance.c
+++ sys/dev/le/lance.c
@@ -72,12 +72,13 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/dev/le/lance.c,v 1.1.2.1 2006/02/13 11:30:40 marius Exp $");
+__FBSDID("$FreeBSD: src/sys/dev/le/lance.c,v 1.4 2007/01/20 10:47:16 marius Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/endian.h>
 #include <sys/lock.h>
+#include <sys/kernel.h>
 #include <sys/mbuf.h>
 #include <sys/mutex.h>
 #include <sys/socket.h>
@@ -91,71 +92,21 @@
 #include <net/if_types.h>
 #include <net/if_vlan_var.h>
 
+#include <machine/bus.h>
+
 #include <dev/le/lancereg.h>
 #include <dev/le/lancevar.h>
 
 devclass_t le_devclass;
 
-static inline uint16_t ether_cmp(void *, void *);
-
 static void lance_start(struct ifnet *);
 static void lance_stop(struct lance_softc *);
 static void lance_init(void *);
-static struct mbuf *lance_get(struct lance_softc *, int, int);
-static void lance_watchdog(struct ifnet *);
+static void lance_watchdog(void *s);
 static int lance_mediachange(struct ifnet *);
 static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
 static int lance_ioctl(struct ifnet *, u_long, caddr_t);
 
-/*
- * Compare two Ether/802 addresses for equality, inlined and
- * unrolled for speed.  Use this like memcmp().
- *
- * XXX: Add <machine/inlines.h> for stuff like this?
- * XXX: or maybe add it to libkern.h instead?
- *
- * "I'd love to have an inline assembler version of this."
- * XXX: Who wanted that? mycroft?  I wrote one, but this
- * version in C is as good as hand-coded assembly. -gwr
- *
- * Please do NOT tweak this without looking at the actual
- * assembly code generated before and after your tweaks!
- */
-static inline uint16_t
-ether_cmp(void *one, void *two)
-{
-	uint16_t *a = (u_short *)one;
-	uint16_t *b = (u_short *)two;
-	uint16_t diff;
-
-#ifdef	m68k
-	/*
-	 * The post-increment-pointer form produces the best
-	 * machine code for m68k.  This was carefully tuned
-	 * so it compiles to just 8 short (2-byte) op-codes!
-	 */
-	diff  = *a++ - *b++;
-	diff |= *a++ - *b++;
-	diff |= *a++ - *b++;
-#else
-	/*
-	 * Most modern CPUs do better with a single expresion.
-	 * Note that short-cut evaluation is NOT helpful here,
-	 * because it just makes the code longer, not faster!
-	 */
-	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
-#endif
-
-	return (diff);
-}
-
-#define ETHER_CMP	ether_cmp
-
-#ifdef LANCE_REVC_BUG
-/* Make sure this is short-aligned, for ether_cmp(). */
-static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
-#endif
-
 int
 lance_config(struct lance_softc *sc, const char* name, int unit)
 {
@@ -169,12 +120,13 @@
 	if (ifp == NULL)
 		return (ENOSPC);
 
+	callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
+
 	/* Initialize ifnet structure. */
 	ifp->if_softc = sc;
 	if_initname(ifp, name, unit);
 	ifp->if_start = lance_start;
 	ifp->if_ioctl = lance_ioctl;
-	ifp->if_watchdog = lance_watchdog;
 	ifp->if_init = lance_init;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 #ifdef LANCE_REVC_BUG
@@ -263,6 +215,7 @@
 	LE_LOCK(sc);
 	lance_stop(sc);
 	LE_UNLOCK(sc);
+	callout_drain(&sc->sc_wdog_ch);
 	ether_ifdetach(ifp);
 	if_free(ifp);
 }
@@ -307,7 +260,8 @@
 	 * Mark the interface down and cancel the watchdog timer.
 	 */
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-	ifp->if_timer = 0;
+	callout_stop(&sc->sc_wdog_ch);
+	sc->sc_wdog_timer = 0;
 
 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
 }
@@ -345,6 +299,10 @@
 	/* Set the correct byte swapping mode, etc. */
 	(*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
 
+	/* Set the current media. This may require the chip to be stopped. */
+	if (sc->sc_mediachange)
+		(void)(*sc->sc_mediachange)(sc);
+
 	/*
 	 * Update our private copy of the Ethernet address.
 	 * We NEED the copy so we can ensure its alignment!
@@ -368,16 +326,13 @@
 		if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
 			break;
 
-	/* Set the current media. */
-	if (sc->sc_mediachange)
-		(void)(*sc->sc_mediachange)(sc);
-
 	if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
 		/* Start the LANCE. */
 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
 		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-		ifp->if_timer = 0;
+		sc->sc_wdog_timer = 0;
+		callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
 		(*sc->sc_start_locked)(sc);
 	} else
 		if_printf(ifp, "controller failed to initialize\n");
@@ -424,7 +379,7 @@
  * We copy the data into mbufs.  When full cluster sized units are present
  * we copy into clusters.
  */
-static struct mbuf *
+struct mbuf *
 lance_get(struct lance_softc *sc, int boff, int totlen)
 {
 	struct ifnet *ifp = sc->sc_ifp;
@@ -432,9 +387,16 @@
 	caddr_t newdata;
 	int len;
 
+	if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
+#ifdef LEDEBUG
+		if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
+#endif
+		return (NULL);
+	}
+
 	MGETHDR(m0, M_DONTWAIT, MT_DATA);
-	if (m0 == 0)
-		return (0);
+	if (m0 == NULL)
+		return (NULL);
 	m0->m_pkthdr.rcvif = ifp;
 	m0->m_pkthdr.len = totlen;
 	len = MHLEN;
@@ -473,93 +435,46 @@
 
  bad:
 	m_freem(m0);
-	return (0);
+	return (NULL);
 }
 
-/*
- * Pass a packet to the higher levels.
- */
-void
-lance_read(struct lance_softc *sc, int boff, int len)
+static void
+lance_watchdog(void *xsc)
 {
+	struct lance_softc *sc = (struct lance_softc *)xsc;
 	struct ifnet *ifp = sc->sc_ifp;
-	struct ether_header *eh;
-	struct mbuf *m;
 
 	LE_LOCK_ASSERT(sc, MA_OWNED);
 
-	if (len <= ETHER_HDR_LEN || len > LEBLEN - ETHER_CRC_LEN) {
-#ifdef LEDEBUG
-		if_printf(ifp, "invalid packet size %d; dropping\n", len);
-#endif
-		ifp->if_ierrors++;
-		return;
-	}
-
-	/* Pull packet off interface. */
-	m = lance_get(sc, boff, len);
-	if (m == 0) {
-		ifp->if_ierrors++;
-		return;
-	}
-
-	ifp->if_ipackets++;
-
-	eh = mtod(m, struct ether_header *);
-
-#ifdef LANCE_REVC_BUG
-	/*
-	 * The old LANCE (Rev. C) chips have a bug which causes
-	 * garbage to be inserted in front of the received packet.
-	 * The work-around is to ignore packets with an invalid
-	 * destination address (garbage will usually not match).
-	 * Of course, this precludes multicast support...
-	 */
-	if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
-	    ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
-		m_freem(m);
+	if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
+		callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
 		return;
 	}
-#endif
 
-	/*
-	 * Some lance device does not present IFF_SIMPLEX behavior on multicast
-	 * packets.  Make sure to drop it if it is from ourselves.
-	 */
-	if (!ETHER_CMP(eh->ether_shost, sc->sc_enaddr)) {
-		m_freem(m);
-		return;
-	}
-
-	/* Pass the packet up. */
-	LE_UNLOCK(sc);
-	(*ifp->if_input)(ifp, m);
-	LE_LOCK(sc);
-}
-
-static void
-lance_watchdog(struct ifnet *ifp)
-{
-	struct lance_softc *sc = ifp->if_softc;
-
-	LE_LOCK(sc);
 	if_printf(ifp, "device timeout\n");
 	++ifp->if_oerrors;
 	lance_init_locked(sc);
-	LE_UNLOCK(sc);
 }
 
 static int
 lance_mediachange(struct ifnet *ifp)
 {
 	struct lance_softc *sc = ifp->if_softc;
-	int error;
 
 	if (sc->sc_mediachange) {
+		/*
+		 * For setting the port in LE_CSR15 the PCnet chips must
+		 * be powered down or stopped and unlike documented may
+		 * not take effect without an initialization. So don't
+		 * invoke (*sc_mediachange) directly here but go through
+		 * lance_init_locked().
+		 */
 		LE_LOCK(sc);
-		error = (*sc->sc_mediachange)(sc);
+		lance_stop(sc);
+		lance_init_locked(sc);
+		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+			(*sc->sc_start_locked)(sc);
 		LE_UNLOCK(sc);
-		return (error);
 	}
 	return (0);
 }
@@ -702,7 +617,7 @@
 		crc >>= 26;
 
 		/* Set the corresponding bit in the filter. */
-		af[crc >> 4] |= LE_HTOLE16(1U << (crc & 0xf));
+		af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
 	}
 	IF_ADDR_UNLOCK(ifp);
 }


More information about the Midnightbsd-cvs mailing list