[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 **)®);
+ 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