summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorthorpej <thorpej@NetBSD.org>1998-06-02 01:29:41 +0000
committerthorpej <thorpej@NetBSD.org>1998-06-02 01:29:41 +0000
commit5852faaf84a0ef6ea5c065ff9e21dccb5e9e0bde (patch)
tree0e5dcf67741c505017b1969095677b530b515be0 /sys/dev
parentb8ce6ef7648b100e2792552d8afbb8b4348c2d70 (diff)
Device driver for the SMC 83c170 Ethernet PCI Integrated Controller (EPIC/100)
used in the SMC EtherPower II. Media control isn't yet supported, due to some MII infrastructure problems which I hope to address soon. This isn't a huge deal, since the PHY defaults to auto-negotiate mode. Also, the device just programs the multicast hash table to accept all multicast, to avoid a hardware bug that causes the multicast address filter to lose in 10Mb/s mode. This bug will be fixed in a more sane way once the media control issues are dealt with.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/smc83c170.c1293
-rw-r--r--sys/dev/ic/smc83c170reg.h492
-rw-r--r--sys/dev/ic/smc83c170var.h133
-rw-r--r--sys/dev/pci/files.pci6
-rw-r--r--sys/dev/pci/if_epic_pci.c193
5 files changed, 2116 insertions, 1 deletions
diff --git a/sys/dev/ic/smc83c170.c b/sys/dev/ic/smc83c170.c
new file mode 100644
index 00000000000..79c47df495c
--- /dev/null
+++ b/sys/dev/ic/smc83c170.c
@@ -0,0 +1,1293 @@
+/* $NetBSD: smc83c170.c,v 1.1 1998/06/02 01:29:42 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * 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.
+ */
+
+/*
+ * Device driver for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100).
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/smc83c170reg.h>
+#include <dev/ic/smc83c170var.h>
+
+void epic_start __P((struct ifnet *));
+void epic_watchdog __P((struct ifnet *));
+int epic_ioctl __P((struct ifnet *, u_long, caddr_t));
+
+void epic_shutdown __P((void *));
+
+void epic_reset __P((struct epic_softc *));
+void epic_init __P((struct epic_softc *));
+void epic_stop __P((struct epic_softc *));
+int epic_add_rxbuf __P((struct epic_softc *, int));
+void epic_read_eeprom __P((struct epic_softc *, int, int, u_int16_t *));
+void epic_set_mchash __P((struct epic_softc *));
+
+/*
+ * Fudge the incoming packets by this much, to ensure the data after
+ * the Ethernet header is aligned.
+ */
+#define RX_ALIGNMENT_FUDGE 2
+
+/* XXX Should be somewhere else. */
+#define ETHER_MIN_LEN 60
+
+#define INTMASK (INTSTAT_FATAL_INT | INTSTAT_TXU | \
+ INTSTAT_TXC | INTSTAT_RQE | INTSTAT_RCC)
+
+/*
+ * Attach an EPIC interface to the system.
+ */
+void
+epic_attach(sc)
+ struct epic_softc *sc;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ int i, rseg, error, attach_stage;
+ bus_dma_segment_t seg;
+ u_int8_t enaddr[ETHER_ADDR_LEN], devname[12 + 1];
+ u_int16_t myea[ETHER_ADDR_LEN / 2], mydevname[6];
+
+ attach_stage = 0;
+
+ /*
+ * Allocate the control data structures, and create and load the
+ * DMA map for it.
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_dmat,
+ sizeof(struct epic_control_data), NBPG, 0, &seg, 1, &rseg,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to allocate control data, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail;
+ }
+
+ attach_stage = 1;
+
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ sizeof(struct epic_control_data), (caddr_t *)&sc->sc_control_data,
+ BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
+ printf("%s: unable to map control data, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail;
+ }
+
+ attach_stage = 2;
+
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ sizeof(struct epic_control_data), 1,
+ sizeof(struct epic_control_data), 0, BUS_DMA_NOWAIT,
+ &sc->sc_cddmamap)) != 0) {
+ printf("%s: unable to create control data DMA map, "
+ "error = %d\n", sc->sc_dev.dv_xname, error);
+ goto fail;
+ }
+
+ attach_stage = 3;
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
+ sc->sc_control_data, sizeof(struct epic_control_data), NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load control data DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ goto fail;
+ }
+
+ attach_stage = 4;
+
+ /*
+ * Create the transmit buffer DMA maps.
+ */
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
+ EPIC_NFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
+ &sc->sc_txsoft[i].ds_dmamap)) != 0) {
+ printf("%s: unable to create tx DMA map %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail;
+ }
+ }
+
+ attach_stage = 5;
+
+ /*
+ * Create the recieve buffer DMA maps.
+ */
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
+ MCLBYTES, 0, BUS_DMA_NOWAIT,
+ &sc->sc_rxsoft[i].ds_dmamap)) != 0) {
+ printf("%s: unable to create rx DMA map %d, "
+ "error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail;
+ }
+ }
+
+ attach_stage = 6;
+
+ /*
+ * Pre-allocate the receive buffers.
+ */
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ if ((error = epic_add_rxbuf(sc, i)) != 0) {
+ printf("%s: unable to allocate or map rx buffer %d\n,"
+ " error = %d\n", sc->sc_dev.dv_xname, i, error);
+ goto fail;
+ }
+ }
+
+ attach_stage = 7;
+
+ /*
+ * Bring the chip out of low-power mode and reset it to a known state.
+ */
+ bus_space_write_4(st, sh, EPIC_GENCTL, 0);
+ epic_reset(sc);
+
+ /*
+ * Read the Ethernet address from the EEPROM.
+ */
+ epic_read_eeprom(sc, 0, (sizeof(myea) / sizeof(myea[0])), myea);
+ bcopy(myea, enaddr, sizeof(myea));
+
+ /*
+ * ...and the device name.
+ */
+ epic_read_eeprom(sc, 0x2c, (sizeof(mydevname) / sizeof(mydevname[0])),
+ mydevname);
+ bcopy(mydevname, devname, sizeof(mydevname));
+ devname[sizeof(mydevname)] = '\0';
+ for (i = sizeof(mydevname) - 1; i >= 0; i--) {
+ if (devname[i] == ' ')
+ devname[i] = '\0';
+ else
+ break;
+ }
+
+ printf("%s: %s, Ethernet address %s\n", sc->sc_dev.dv_xname,
+ devname, ether_sprintf(enaddr));
+
+ ifp = &sc->sc_ethercom.ec_if;
+ strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = epic_ioctl;
+ ifp->if_start = epic_start;
+ ifp->if_watchdog = epic_watchdog;
+
+ /*
+ * Attach the interface.
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp, enaddr);
+#if NBPFILTER > 0
+ bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ /*
+ * Make sure the interface is shutdown during reboot.
+ */
+ sc->sc_sdhook = shutdownhook_establish(epic_shutdown, sc);
+ if (sc->sc_sdhook == NULL)
+ printf("%s: WARNING: unable to establish shutdown hook\n",
+ sc->sc_dev.dv_xname);
+ return;
+
+ fail:
+ /*
+ * Free any resources we've allocated during the failed attach
+ * attempt. Do this in reverse order and fall through.
+ */
+ switch (attach_stage) {
+ case 7:
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ if (sc->sc_rxsoft[i].ds_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat,
+ sc->sc_rxsoft[i].ds_dmamap);
+ m_freem(sc->sc_rxsoft[i].ds_mbuf);
+ }
+ }
+ /* FALLTHROUGH */
+
+ case 6:
+ for (i = 0; i < EPIC_NRXDESC; i++)
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->sc_rxsoft[i].ds_dmamap);
+ /* FALLTHROUGH */
+
+ case 5:
+ for (i = 0; i < EPIC_NTXDESC; i++)
+ bus_dmamap_destroy(sc->sc_dmat,
+ sc->sc_txsoft[i].ds_dmamap);
+ /* FALLTHROUGH */
+
+ case 4:
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
+ /* FALLTHROUGH */
+
+ case 3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
+ /* FALLTHROUGH */
+
+ case 2:
+ bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_control_data,
+ sizeof(struct epic_control_data));
+ /* FALLTHROUGH */
+
+ case 1:
+ bus_dmamem_free(sc->sc_dmat, &seg, rseg);
+ break;
+ }
+}
+
+/*
+ * Shutdown hook. Make sure the interface is stopped at reboot.
+ */
+void
+epic_shutdown(arg)
+ void *arg;
+{
+ struct epic_softc *sc = arg;
+
+ epic_stop(sc);
+}
+
+/*
+ * Start packet transmission on the interface.
+ * [ifnet interface function]
+ */
+void
+epic_start(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ struct epic_txdesc *txd;
+ struct epic_descsoft *ds;
+ struct epic_fraglist *fr;
+ bus_dmamap_t dmamap;
+ struct mbuf *m0;
+ int nexttx, seg, error, txqueued;
+
+ txqueued = 0;
+
+ /*
+ * Loop through the send queue, setting up transmit descriptors
+ * until we drain the queue, or use up all available transmit
+ * descriptors.
+ */
+ while (ifp->if_snd.ifq_head != NULL &&
+ sc->sc_txpending < EPIC_NTXDESC) {
+ /*
+ * Grab a packet off the queue.
+ */
+ IF_DEQUEUE(&ifp->if_snd, m0);
+
+ /*
+ * Get the last and next available transmit descriptor.
+ */
+ nexttx = EPIC_NEXTTX(sc->sc_txlast);
+ txd = &sc->sc_control_data->ecd_txdescs[nexttx];
+ fr = &sc->sc_control_data->ecd_txfrags[nexttx];
+ ds = &sc->sc_txsoft[nexttx];
+ dmamap = ds->ds_dmamap;
+
+ loadmap:
+ /*
+ * Load the DMA map with the packet.
+ */
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
+ BUS_DMA_NOWAIT);
+ switch (error) {
+ case 0:
+ /* Success. */
+ break;
+
+ case EFBIG:
+ {
+ struct mbuf *mn;
+
+ /*
+ * We ran out of segments. We have to recopy this
+ * mbuf chain first. Bail out if we can't get the
+ * new buffers.
+ */
+ printf("%s: too many segments, ", sc->sc_dev.dv_xname);
+
+ MGETHDR(mn, M_DONTWAIT, MT_DATA);
+ if (mn == NULL) {
+ m_freem(m0);
+ printf("aborting\n");
+ goto out;
+ }
+ if (m0->m_pkthdr.len > MHLEN) {
+ MCLGET(mn, M_DONTWAIT);
+ if ((mn->m_flags & M_EXT) == 0) {
+ m_freem(mn);
+ m_freem(m0);
+ printf("aborting\n");
+ goto out;
+ }
+ }
+ m_copydata(m0, 0, m0->m_pkthdr.len, mtod(mn, caddr_t));
+ mn->m_pkthdr.len = mn->m_len = m0->m_pkthdr.len;
+ m_freem(m0);
+ m0 = mn;
+ printf("retrying\n");
+ goto loadmap;
+ }
+
+ default:
+ /*
+ * Some other problem; report it.
+ */
+ printf("%s: can't load mbuf chain, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ m_freem(m0);
+ goto out;
+ }
+
+ /*
+ * Initialize the fraglist.
+ */
+ fr->ef_nfrags = dmamap->dm_nsegs;
+ for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
+ fr->ef_frags[seg].ef_addr =
+ dmamap->dm_segs[seg].ds_addr;
+ fr->ef_frags[seg].ef_length =
+ dmamap->dm_segs[seg].ds_len;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Store a pointer to the packet so we can free it later.
+ */
+ ds->ds_mbuf = m0;
+
+ /*
+ * Finish setting up the new transmit descriptor: set the
+ * packet length and give it to the EPIC.
+ */
+ txd->et_txlength = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
+ txd->et_txstatus = ET_TXSTAT_OWNER;
+
+ /*
+ * Committed; advance the lasttx pointer. If nothing was
+ * previously queued, reset the dirty pointer.
+ */
+ sc->sc_txlast = nexttx;
+ if (sc->sc_txpending == 0)
+ sc->sc_txdirty = nexttx;
+
+ sc->sc_txpending++;
+
+ txqueued = 1;
+
+#if NBPFILTER > 0
+ /*
+ * Pass the packet to any BPF listeners.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif
+ }
+
+ out:
+ /*
+ * We're finished. If we added more packets, make sure the
+ * transmit DMA engine is running.
+ */
+ if (txqueued) {
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND,
+ COMMAND_TXQUEUED);
+
+ /*
+ * Set a 5 second watchdog timer.
+ */
+ ifp->if_timer = 5;
+ }
+}
+
+/*
+ * Watchdog timer handler.
+ * [ifnet interface function]
+ */
+void
+epic_watchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct epic_softc *sc = ifp->if_softc;
+
+ printf("%s: device timeout\n", sc->sc_dev.dv_xname);
+ ifp->if_oerrors++;
+
+ epic_init(sc);
+}
+
+/*
+ * Handle control requests from the operator.
+ * [ifnet interface function]
+ */
+int
+epic_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct epic_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ epic_init(sc);
+ arp_ifinit(ifp, ifa);
+ break;
+#endif /* INET */
+#ifdef NS
+ case AF_NS:
+ {
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host = *(union ns_host *)
+ LLADDR(ifp->if_sadl);
+ else
+ bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
+ ifp->if_addrlen);
+ /* Set new address. */
+ epic_init(sc);
+ break;
+ }
+#endif /* NS */
+ default:
+ epic_init(sc);
+ break;
+ }
+ break;
+
+ case SIOCSIFMTU:
+ if (ifr->ifr_mtu > ETHERMTU)
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING) != 0) {
+ /*
+ * If interface is marked down and it is running, then
+ * stop it.
+ */
+ epic_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else if ((ifp->if_flags & IFF_UP) != 0 &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ /*
+ * If interfase it marked up and it is stopped, then
+ * start it.
+ */
+ epic_init(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect the hardware state.
+ */
+ epic_init(sc);
+ }
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_ethercom) :
+ ether_delmulti(ifr, &sc->sc_ethercom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ epic_init(sc);
+ error = 0;
+ }
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ splx(s);
+ return (error);
+}
+
+/*
+ * Interrupt handler.
+ */
+int
+epic_intr(arg)
+ void *arg;
+{
+ struct epic_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct ether_header *eh;
+ struct epic_rxdesc *rxd;
+ struct epic_txdesc *txd;
+ struct epic_descsoft *ds;
+ struct mbuf *m;
+ u_int32_t intstat;
+ int i, len, claimed = 0, error;
+
+ top:
+ /*
+ * Get the interrupt status from the EPIC.
+ */
+ intstat = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT);
+ if ((intstat & INTSTAT_INT_ACTV) == 0)
+ return (claimed);
+
+ claimed = 1;
+
+ /*
+ * Acknowledge the interrupt.
+ */
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT,
+ intstat & INTMASK);
+
+ /*
+ * Check for receive interrupts.
+ */
+ if (intstat & (INTSTAT_RCC | INTSTAT_RQE)) {
+ for (i = sc->sc_rxptr;; i = EPIC_NEXTRX(i)) {
+ rxd = &sc->sc_control_data->ecd_rxdescs[i];
+ ds = &sc->sc_rxsoft[i];
+ m = ds->ds_mbuf;
+ error = 0;
+
+ if (rxd->er_rxstatus & ER_RXSTAT_OWNER) {
+ /*
+ * We have processed all of the
+ * receive buffers.
+ */
+ break;
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+ /*
+ * Make sure the packet arrived intact.
+ */
+ if ((rxd->er_rxstatus & ER_RXSTAT_PKTINTACT) == 0) {
+#if 1
+ if (rxd->er_rxstatus & ER_RXSTAT_CRCERROR)
+ printf("%s: CRC error\n",
+ sc->sc_dev.dv_xname);
+ if (rxd->er_rxstatus & ER_RXSTAT_ALIGNERROR)
+ printf("%s: alignment error\n",
+ sc->sc_dev.dv_xname);
+#endif
+ ifp->if_ierrors++;
+ error = 1;
+ }
+
+ /*
+ * Add a new buffer to the receive chain. If this
+ * fails, the old buffer is recycled.
+ */
+ if (epic_add_rxbuf(sc, i) == 0) {
+ /*
+ * We wanted to reset the buffer, but
+ * didn't want to pass it on up.
+ */
+ if (error) {
+ m_freem(m);
+ continue;
+ }
+
+ len = rxd->er_buflength;
+ if (len < sizeof(struct ether_header)) {
+ m_freem(m);
+ continue;
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+ eh = mtod(m, struct ether_header *);
+#if NBPFILTER > 0
+ /*
+ * Pass this up to any BPF listeners.
+ */
+ if (ifp->if_bpf) {
+ bpf_mtap(ifp->if_bpf, m);
+
+ /*
+ * Only pass this up the stack
+ * if it's for us.
+ */
+ if ((ifp->if_flags & IFF_PROMISC) &&
+ bcmp(LLADDR(ifp->if_sadl),
+ eh->ether_dhost,
+ ETHER_ADDR_LEN) != 0 &&
+ (rxd->er_rxstatus &
+ (ER_RXSTAT_BCAST|ER_RXSTAT_MCAST))
+ == 0) {
+ m_freem(m);
+ continue;
+ }
+ }
+#endif /* NPBFILTER > 0 */
+ m->m_data += sizeof(struct ether_header);
+ m->m_len -= sizeof(struct ether_header);
+ m->m_pkthdr.len = m->m_len;
+ ether_input(ifp, eh, m);
+ }
+ }
+
+ /*
+ * Update the recieve pointer.
+ */
+ sc->sc_rxptr = i;
+
+ /*
+ * Check for receive queue underflow.
+ */
+ if (intstat & INTSTAT_RQE) {
+ printf("%s: receiver queue empty\n",
+ sc->sc_dev.dv_xname);
+ /*
+ * Ring is already built; just restart the
+ * receiver.
+ */
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_PRCDAR,
+ sc->sc_cddma + EPIC_CDOFF(ecd_rxdescs[0]));
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND,
+ COMMAND_RXQUEUED | COMMAND_START_RX);
+ }
+ }
+
+ /*
+ * Check for transmission complete interrupts.
+ */
+ if (intstat & (INTSTAT_TXC | INTSTAT_TXU)) {
+ for (i = sc->sc_txdirty;; i = EPIC_NEXTTX(i)) {
+ txd = &sc->sc_control_data->ecd_txdescs[i];
+ ds = &sc->sc_txsoft[i];
+
+ if (sc->sc_txpending == 0 ||
+ (txd->et_txstatus & ET_TXSTAT_OWNER) != 0)
+ break;
+
+ if (ds->ds_mbuf != NULL) {
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap,
+ 0, ds->ds_dmamap->dm_mapsize,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+ }
+ sc->sc_txpending--;
+
+ /*
+ * Check for errors and collisions.
+ */
+ if ((txd->et_txstatus & ET_TXSTAT_PACKETTX) == 0)
+ ifp->if_oerrors++;
+ ifp->if_collisions +=
+ TXSTAT_COLLISIONS(txd->et_txstatus);
+ if (txd->et_txstatus & ET_TXSTAT_CARSENSELOST) {
+#if 1
+ printf("%s: lost carrier\n",
+ sc->sc_dev.dv_xname);
+#endif
+ /* XXX clear "active" but in media data */
+ }
+ }
+
+ /*
+ * Update the dirty transmit buffer pointer.
+ */
+ sc->sc_txdirty = i;
+
+ /*
+ * Cancel the watchdog timer if there are no pending
+ * transmissions.
+ */
+ if (sc->sc_txpending == 0)
+ ifp->if_timer = 0;
+
+ /*
+ * Kick the transmitter after a DMA underrun.
+ */
+ if (intstat & INTSTAT_TXU) {
+ printf("%s: transmit underrun\n", sc->sc_dev.dv_xname);
+ bus_space_write_4(sc->sc_st, sc->sc_sh,
+ EPIC_COMMAND, COMMAND_TXUGO);
+ if (sc->sc_txpending)
+ bus_space_write_4(sc->sc_st, sc->sc_sh,
+ EPIC_COMMAND, COMMAND_TXQUEUED);
+ }
+
+ /*
+ * Try to get more packets going.
+ */
+ epic_start(ifp);
+ }
+
+ /*
+ * Check for fatal interrupts.
+ */
+ if (intstat & INTSTAT_FATAL_INT) {
+ printf("%s: fatal error, resetting\n", sc->sc_dev.dv_xname);
+ epic_init(sc);
+ }
+
+ /*
+ * Check for more interrupts.
+ */
+ goto top;
+}
+
+/*
+ * Perform a soft reset on the EPIC.
+ */
+void
+epic_reset(sc)
+ struct epic_softc *sc;
+{
+
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_GENCTL, 0);
+ delay(100);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_GENCTL, GENCTL_SOFTRESET);
+ delay(100);
+}
+
+/*
+ * Initialize the interface. Must be called at splimp().
+ */
+void
+epic_init(sc)
+ struct epic_softc *sc;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ u_int8_t *enaddr = LLADDR(ifp->if_sadl);
+ struct epic_txdesc *txd;
+ struct epic_rxdesc *rxd;
+ u_int32_t genctl, reg0;
+ int i;
+
+ /*
+ * Cancel any pending I/O.
+ */
+ epic_stop(sc);
+
+ /*
+ * Reset the EPIC to a known state.
+ */
+ epic_reset(sc);
+
+ /*
+ * Magical mystery initialization.
+ */
+ bus_space_write_4(st, sh, EPIC_TEST, TEST_INIT);
+ bus_space_write_4(st, sh, EPIC_TXTEST, 0);
+
+ /*
+ * Initialize the EPIC genctl register:
+ *
+ * - 64 byte receive FIFO threshold
+ * - automatic advance to next receive frame
+ */
+ genctl = GENCTL_RX_FIFO_THRESH0 | GENCTL_ONECOPY;
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl);
+
+ /*
+ * Reset the MII bus and PHY.
+ */
+ reg0 = bus_space_read_4(st, sh, EPIC_NVCTL);
+ bus_space_write_4(st, sh, EPIC_NVCTL, reg0 | NVCTL_GPIO1 | NVCTL_GPOE1);
+ bus_space_write_4(st, sh, EPIC_MIICFG, MIICFG_ENASER);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl | GENCTL_RESET_PHY);
+ delay(100);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl);
+ delay(100);
+ bus_space_write_4(st, sh, EPIC_NVCTL, reg0);
+
+ /*
+ * Initialize Ethernet address.
+ */
+ reg0 = enaddr[1] << 8 | enaddr[0];
+ bus_space_write_4(st, sh, EPIC_LAN0, reg0);
+ reg0 = enaddr[3] << 8 | enaddr[2];
+ bus_space_write_4(st, sh, EPIC_LAN1, reg0);
+ reg0 = enaddr[5] << 8 | enaddr[4];
+ bus_space_write_4(st, sh, EPIC_LAN2, reg0);
+
+ /*
+ * Set up the multicast hash table.
+ */
+ epic_set_mchash(sc);
+
+ /*
+ * Initialize receive control. Remember the external buffer
+ * size setting.
+ */
+ reg0 = bus_space_read_4(st, sh, EPIC_RXCON) &
+ (RXCON_EXTBUFSIZESEL1 | RXCON_EXTBUFSIZESEL0);
+ reg0 |= (RXCON_RXMULTICAST | RXCON_RXBROADCAST);
+ if (ifp->if_flags & IFF_PROMISC)
+ reg0 |= RXCON_PROMISCMODE;
+ bus_space_write_4(st, sh, EPIC_RXCON, reg0);
+
+ /*
+ * XXX Media (full-duplex in TXCON).
+ */
+
+ /*
+ * Initialize the transmit descriptors.
+ */
+ txd = sc->sc_control_data->ecd_txdescs;
+ bzero(txd, sizeof(sc->sc_control_data->ecd_txdescs));
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ txd[i].et_control = ET_TXCTL_LASTDESC | ET_TXCTL_IAF |
+ ET_TXCTL_FRAGLIST;
+ txd[i].et_bufaddr = sc->sc_cddma + EPIC_CDOFF(ecd_txfrags[i]);
+ txd[i].et_nextdesc = sc->sc_cddma +
+ EPIC_CDOFF(ecd_txdescs[(i + 1) & EPIC_NTXDESC_MASK]);
+ }
+
+ /*
+ * Initialize the receive descriptors. Note the buffers
+ * and control word have already been initialized; we only
+ * need to initialize the ring.
+ */
+ rxd = sc->sc_control_data->ecd_rxdescs;
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ rxd[i].er_nextdesc = sc->sc_cddma +
+ EPIC_CDOFF(ecd_rxdescs[(i + 1) & EPIC_NRXDESC_MASK]);
+ }
+
+ /*
+ * Initialize the interrupt mask and enable interrupts.
+ */
+ bus_space_write_4(st, sh, EPIC_INTMASK, INTMASK);
+ bus_space_write_4(st, sh, EPIC_GENCTL, genctl | GENCTL_INTENA);
+
+ /*
+ * Give the transmit and receive rings to the EPIC.
+ */
+ bus_space_write_4(st, sh, EPIC_PTCDAR,
+ sc->sc_cddma + EPIC_CDOFF(ecd_txdescs[0]));
+ bus_space_write_4(st, sh, EPIC_PRCDAR,
+ sc->sc_cddma + EPIC_CDOFF(ecd_rxdescs[0]));
+
+ /*
+ * Initialize our ring pointers. txlast it initialized to
+ * the end of the list so that it will wrap around to the
+ * first descriptor when the first packet is transmitted.
+ */
+ sc->sc_txpending = 0;
+ sc->sc_txdirty = 0;
+ sc->sc_txlast = EPIC_NTXDESC - 1;
+
+ sc->sc_rxptr = 0;
+
+ /*
+ * Set the EPIC in motion.
+ */
+ bus_space_write_4(st, sh, EPIC_COMMAND,
+ COMMAND_RXQUEUED | COMMAND_START_RX);
+
+ /*
+ * ...all done!
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+}
+
+/*
+ * Stop transmission on the interface.
+ */
+void
+epic_stop(sc)
+ struct epic_softc *sc;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct epic_descsoft *ds;
+ u_int32_t reg;
+ int i;
+
+ /*
+ * Disable interrupts.
+ */
+ reg = bus_space_read_4(st, sh, EPIC_GENCTL);
+ bus_space_write_4(st, sh, EPIC_GENCTL, reg & ~GENCTL_INTENA);
+ bus_space_write_4(st, sh, EPIC_INTMASK, 0);
+
+ /*
+ * Stop the DMA engine and take the receiver off-line.
+ */
+ bus_space_write_4(st, sh, EPIC_COMMAND, COMMAND_STOP_RDMA |
+ COMMAND_STOP_TDMA | COMMAND_STOP_RX);
+
+ /*
+ * Release any queued transmit buffers.
+ */
+ for (i = 0; i < EPIC_NTXDESC; i++) {
+ ds = &sc->sc_txsoft[i];
+ if (ds->ds_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+ }
+ }
+ sc->sc_txpending = 0;
+
+ /*
+ * Release the receive buffers, then reallocate/reinitialize.
+ */
+ for (i = 0; i < EPIC_NRXDESC; i++) {
+ ds = &sc->sc_rxsoft[i];
+ if (ds->ds_mbuf != NULL) {
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+ }
+ if (epic_add_rxbuf(sc, i) != 0) {
+ /*
+ * This "can't happen" - we're at splimp()
+ * and we just freed the buffer we need
+ * above.
+ */
+ panic("epic_stop: no buffers!");
+ }
+ }
+
+ /*
+ * Mark the interface down and cancel the watchdog timer.
+ */
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ifp->if_timer = 0;
+}
+
+/*
+ * Read the EPIC Serial EEPROM.
+ */
+void
+epic_read_eeprom(sc, word, wordcnt, data)
+ struct epic_softc *sc;
+ int word, wordcnt;
+ u_int16_t *data;
+{
+ bus_space_tag_t st = sc->sc_st;
+ bus_space_handle_t sh = sc->sc_sh;
+ u_int16_t reg;
+ int i, x;
+
+#define EEPROM_WAIT_READY(st, sh) \
+ while ((bus_space_read_4((st), (sh), EPIC_EECTL) & EECTL_EERDY) == 0) \
+ /* nothing */
+
+ /*
+ * Enable the EEPROM.
+ */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE);
+ EEPROM_WAIT_READY(st, sh);
+
+ for (i = 0; i < wordcnt; i++) {
+ /* Send CHIP SELECT for one clock tick. */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE|EECTL_EECS);
+ EEPROM_WAIT_READY(st, sh);
+
+ /* Shift in the READ opcode. */
+ for (x = 3; x > 0; x--) {
+ reg = EECTL_ENABLE|EECTL_EECS;
+ if (EPIC_EEPROM_OPC_READ & (1 << (x - 1)))
+ reg |= EECTL_EEDI;
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Shift in address. */
+ for (x = 6; x > 0; x--) {
+ reg = EECTL_ENABLE|EECTL_EECS;
+ if ((word + i) & (1 << (x - 1)))
+ reg |= EECTL_EEDI;
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Shift out data. */
+ reg = EECTL_ENABLE|EECTL_EECS;
+ data[i] = 0;
+ for (x = 16; x > 0; x--) {
+ bus_space_write_4(st, sh, EPIC_EECTL, reg|EECTL_EESK);
+ EEPROM_WAIT_READY(st, sh);
+ if (bus_space_read_4(st, sh, EPIC_EECTL) & EECTL_EEDO)
+ data[i] |= (1 << (x - 1));
+ bus_space_write_4(st, sh, EPIC_EECTL, reg);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /* Clear CHIP SELECT. */
+ bus_space_write_4(st, sh, EPIC_EECTL, EECTL_ENABLE);
+ EEPROM_WAIT_READY(st, sh);
+ }
+
+ /*
+ * Disable the EEPROM.
+ */
+ bus_space_write_4(st, sh, EPIC_EECTL, 0);
+
+#undef EEPROM_WAIT_READY
+}
+
+/*
+ * Add a receive buffer to the indicated descriptor.
+ */
+int
+epic_add_rxbuf(sc, idx)
+ struct epic_softc *sc;
+ int idx;
+{
+ struct epic_rxdesc *rxd = &sc->sc_control_data->ecd_rxdescs[idx];
+ struct epic_descsoft *ds = &sc->sc_rxsoft[idx];
+ struct mbuf *m, *oldm;
+ int error = 0;
+
+ oldm = ds->ds_mbuf;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m != NULL) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ error = ENOMEM;
+ m_freem(m);
+ if (oldm == NULL)
+ return (error);
+ m = oldm;
+ m->m_data = m->m_ext.ext_buf;
+ }
+ } else {
+ error = ENOMEM;
+ if (oldm == NULL)
+ return (error);
+ m = oldm;
+ m->m_data = m->m_ext.ext_buf;
+ }
+
+ ds->ds_mbuf = m;
+
+ /*
+ * Set up the DMA map for this receive buffer.
+ */
+ if (m != oldm) {
+ if (oldm != NULL)
+ bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
+ error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap,
+ m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT);
+ if (error) {
+ printf("%s: can't load rx buffer, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ panic("epic_add_rxbuf"); /* XXX */
+ }
+ }
+
+ bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
+ ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
+
+ /*
+ * Move the data pointer up so that the incoming packet
+ * will be 32-bit aligned.
+ */
+ m->m_data += RX_ALIGNMENT_FUDGE;
+
+ /*
+ * Initialize the receive descriptor.
+ */
+ rxd->er_bufaddr = ds->ds_dmamap->dm_segs[0].ds_addr +
+ RX_ALIGNMENT_FUDGE;
+ rxd->er_buflength = m->m_ext.ext_size - RX_ALIGNMENT_FUDGE;
+ rxd->er_control = 0;
+ rxd->er_rxstatus = ER_RXSTAT_OWNER;
+
+ return (error);
+}
+
+/*
+ * Set the EPIC multicast hash table.
+ */
+void
+epic_set_mchash(sc)
+ struct epic_softc *sc;
+{
+ struct ethercom *ec = &sc->sc_ethercom;
+ struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ u_int8_t *cp;
+ u_int32_t crc, mchash[4];
+ int len;
+ static const u_int32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+
+ /*
+ * Set up the multicast address filter by passing all multicast
+ * addresses through a CRC generator, and then using the high-order
+ * 6 bits as an index into the 64 bit multicast hash table (only
+ * the lower 16 bits of each 32 bit multicast hash register are
+ * valid). The high order bit selects the register, while the
+ * rest of the bits select the bit within the register.
+ */
+
+ if (ifp->if_flags & IFF_PROMISC)
+ goto allmulti;
+
+#if 1 /* XXX thorpej - hardware bug in 10Mb mode */
+ goto allmulti;
+#endif
+
+ mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0;
+
+ ETHER_FIRST_MULTI(step, ec, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+ /*
+ * We must listen to a range of multicast addresses.
+ * For now, just accept all multicasts, rather than
+ * trying to set only those filter bits needed to match
+ * the range. (At this time, the only use of address
+ * ranges is for IP multicast routing, for which the
+ * range is big enough to require all bits set.)
+ */
+ goto allmulti;
+ }
+
+ cp = enm->enm_addrlo;
+ crc = 0xffffffff;
+ for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
+ crc ^= *cp++;
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+ /* Just want the 6 most significant bits. */
+ crc >>= 26;
+
+ /* Set the corresponding bit in the hash table. */
+ mchash[crc >> 4] |= 1 << (crc & 0xf);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ goto sethash;
+
+ allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0xffff;
+
+ sethash:
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC0, mchash[0]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC1, mchash[1]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC2, mchash[2]);
+ bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC3, mchash[3]);
+}
diff --git a/sys/dev/ic/smc83c170reg.h b/sys/dev/ic/smc83c170reg.h
new file mode 100644
index 00000000000..475dfa54edc
--- /dev/null
+++ b/sys/dev/ic/smc83c170reg.h
@@ -0,0 +1,492 @@
+/* $NetBSD: smc83c170reg.h,v 1.1 1998/06/02 01:29:42 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * 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.
+ */
+
+#ifndef _DEV_IC_SMC83C170REG_H_
+#define _DEV_IC_SMC83C170REG_H_
+
+/*
+ * Register description for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100).
+ */
+
+/*
+ * EPIC transmit descriptor. Must be 4-byte aligned.
+ */
+struct epic_txdesc {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t et_txlength; /* transmit length */
+ u_int16_t et_txstatus; /* transmit status; see below */
+#else
+ u_int16_t et_txstatus; /* transmit status; see below */
+ u_int16_t et_txlength; /* transmit length */
+#endif
+ u_int32_t et_bufaddr; /* buffer address */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t et_control; /* control word; see below */
+ u_int16_t et_buflength; /* buffer length */
+#else
+ u_int16_t et_buflength; /* buffer length */
+ u_int16_t et_control; /* control word; see below */
+#endif
+ u_int32_t et_nextdesc; /* next descriptor pointer */
+};
+
+/* et_txstatus */
+#define ET_TXSTAT_OWNER 0x8000 /* NIC owns descriptor */
+#define ET_TXSTAT_COLLMASK 0x1f00 /* collisions */
+#define ET_TXSTAT_DEFERRING 0x0080 /* deferring due to jabber */
+#define ET_TXSTAT_OOWCOLL 0x0040 /* out of window collision */
+#define ET_TXSTAT_CDHB 0x0020 /* collision detect heartbeat */
+#define ET_TXSTAT_UNDERRUN 0x0010 /* DMA underrun */
+#define ET_TXSTAT_CARSENSELOST 0x0008 /* carrier lost */
+#define ET_TXSTAT_TXWITHCOLL 0x0004 /* encountered collisions during tx */
+#define ET_TXSTAT_NONDEFERRED 0x0002 /* transmitted without deferring */
+#define ET_TXSTAT_PACKETTX 0x0001 /* packet transmitted successfully */
+
+#define TXSTAT_COLLISIONS(x) (((x) & ET_TXSTAT_COLLMASK) >> 8)
+
+/* et_control */
+#define ET_TXCTL_LASTDESC 0x0010 /* last descriptor in frame */
+#define ET_TXCTL_NOCRC 0x0008 /* disable CRC generation */
+#define ET_TXCTL_IAF 0x0004 /* interrupt after frame */
+#define ET_TXCTL_LFFORM 0x0002 /* alternate fraglist format */
+#define ET_TXCTL_FRAGLIST 0x0001 /* descriptor points to fraglist */
+
+/*
+ * EPIC receive descriptor. Must be 4-byte aligned.
+ */
+struct epic_rxdesc {
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t er_rxlength; /* receive frame length */
+ u_int16_t er_rxstatus; /* receive status; see below */
+#else
+ u_int16_t er_rxstatus; /* receive status; see below */
+ u_int16_t er_rxlength; /* receive frame length */
+#endif
+ u_int32_t er_bufaddr; /* buffer address */
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int16_t er_control; /* control word; see below */
+ u_int16_t er_buflength; /* buffer length */
+#else
+ u_int16_t er_buflength; /* buffer length */
+ u_int16_t er_control; /* control word; see below */
+#endif
+ u_int32_t er_nextdesc; /* next descriptor pointer */
+};
+
+/* er_rxstatus */
+#define ER_RXSTAT_OWNER 0x8000 /* NIC owns descriptor */
+#define ER_RXSTAT_HDRCOPIED 0x4000 /* rx status posted after hdr copy */
+#define ER_RXSTAT_FRAGLISTERR 0x2000 /* ran out of frags to copy frame */
+#define ER_RXSTAT_NETSTATVALID 0x1000 /* length and status are valid */
+#define ER_RXSTAT_RCVRDIS 0x0040 /* receiver disabled */
+#define ER_RXSTAT_BCAST 0x0020 /* broadcast address recognized */
+#define ER_RXSTAT_MCAST 0x0010 /* multicast address recognized */
+#define ER_RXSTAT_MISSEDPKT 0x0008 /* missed packet */
+#define ER_RXSTAT_CRCERROR 0x0004 /* EPIC or MII asserted CRC error */
+#define ER_RXSTAT_ALIGNERROR 0x0002 /* frame not byte-aligned */
+#define ER_RXSTAT_PKTINTACT 0x0001 /* packet received without error */
+
+/* er_control */
+#define ER_RXCTL_HEADER 0x0004 /* descriptor is for hdr copy */
+#define ER_RXCTL_LFFORM 0x0002 /* alternate fraglist format */
+#define ER_RXCTL_FRAGLIST 0x0001 /* descriptor points to fraglist */
+
+#define EPIC_NFRAGS 63 /* maximum number of frags in list */
+
+/*
+ * EPIC fraglist descriptor.
+ */
+struct epic_fraglist {
+ u_int32_t ef_nfrags; /* number of frags in list */
+ struct {
+ u_int32_t ef_addr; /* address of frag */
+ u_int32_t ef_length; /* length of frag */
+ } ef_frags[EPIC_NFRAGS];
+};
+
+/*
+ * EPIC control registers.
+ */
+
+#define EPIC_COMMAND 0x00 /* COMMAND */
+#define COMMAND_TXUGO 0x00000080 /* start tx after underrun */
+#define COMMAND_STOP_RDMA 0x00000040 /* stop rx dma */
+#define COMMAND_STOP_TDMA 0x00000020 /* stop tx dma */
+#define COMMAND_NEXTFRAME 0x00000010 /* move onto next rx frame */
+#define COMMAND_RXQUEUED 0x00000008 /* queue a rx descriptor */
+#define COMMAND_TXQUEUED 0x00000004 /* queue a tx descriptor */
+#define COMMAND_START_RX 0x00000002 /* start receiver */
+#define COMMAND_STOP_RX 0x00000001 /* stop receiver */
+
+#define EPIC_INTSTAT 0x04 /* INTERRUPT STATUS */
+#define INTSTAT_PTA 0x08000000 /* PCI target abort */
+#define INTSTAT_PMA 0x04000000 /* PCI master abort */
+#define INTSTAT_APE 0x02000000 /* PCI address parity error */
+#define INTSTAT_DPE 0x01000000 /* PCI data parity error */
+#define INTSTAT_RSV 0x00800000 /* rx status valid */
+#define INTSTAT_RCTS 0x00400000 /* rx copy threshold status */
+#define INTSTAT_RBE 0x00200000 /* rx buffers empty */
+#define INTSTAT_TCIP 0x00100000 /* tx copy in progress */
+#define INTSTAT_RCIP 0x00080000 /* rx copy in progress */
+#define INTSTAT_TXIDLE 0x00040000 /* transmit idle */
+#define INTSTAT_RXIDLE 0x00020000 /* receive idle */
+#define INTSTAT_INT_ACTV 0x00010000 /* interrupt active */
+#define INTSTAT_GP2_INT 0x00008000 /* gpio2 low (PHY event) */
+#define INTSTAT_FATAL_INT 0x00001000 /* fatal error occured */
+#define INTSTAT_RCT 0x00000800 /* rx copy threshold crossed */
+#define INTSTAT_PREI 0x00000400 /* preemptive interrupt */
+#define INTSTAT_CNT 0x00000200 /* counter overflow */
+#define INTSTAT_TXU 0x00000100 /* transmit underrun */
+#define INTSTAT_TQE 0x00000080 /* transmit queue empty */
+#define INTSTAT_TCC 0x00000040 /* transmit chain complete */
+#define INTSTAT_TXC 0x00000020 /* transmit complete */
+#define INTSTAT_RXE 0x00000010 /* receive error */
+#define INTSTAT_OVW 0x00000008 /* rx buffer overflow */
+#define INTSTAT_RQE 0x00000004 /* receive queue empty */
+#define INTSTAT_HCC 0x00000002 /* header copy complete */
+#define INTSTAT_RCC 0x00000001 /* receive copy complete */
+
+#define EPIC_INTMASK 0x08 /* INTERRUPT MASK */
+ /* Bits 0-15 enable the corresponding interrupt in INTSTAT. */
+
+#define EPIC_GENCTL 0x0c /* GENERAL CONTROL */
+#define GENCTL_RESET_PHY 0x00004000 /* reset PHY */
+#define GENCTL_SOFT1 0x00002000 /* software use */
+#define GENCTL_SOFT0 0x00001000 /* software use */
+#define GENCTL_MEM_READ_CTL1 0x00000800 /* PCI memory control */
+#define GENCTL_MEM_READ_CTL0 0x00000400 /* (see below) */
+#define GENCTL_RX_FIFO_THRESH1 0x00000200 /* rx fifo thresh */
+#define GENCTL_RX_FIFO_THRESH0 0x00000100 /* (see below) */
+#define GENCTL_BIG_ENDIAN 0x00000020 /* big endian mode */
+#define GENCTL_ONECOPY 0x00000010 /* auto-NEXTFRAME */
+#define GENCTL_POWERDOWN 0x00000008 /* powersave sleep mode */
+#define GENCTL_SOFTINT 0x00000004 /* software-generated intr */
+#define GENCTL_INTENA 0x00000002 /* interrupt enable */
+#define GENCTL_SOFTRESET 0x00000001 /* initialize EPIC */
+
+/*
+ * Explanation of MEMORY READ CONTROL:
+ *
+ * These bits control which PCI command the transmit DMA will use when
+ * bursting data over the PCI bus. When CTL1 is set, the transmit DMA
+ * will use the PCI "memory read line" command. When CTL0 is set, the
+ * transmit DMA will use the PCI "memory read multiple" command. When
+ * neither bit is set, the transmit DMA will use the "memory read" command.
+ * Use of "memory read line" or "memory read multiple" may enhance
+ * performance on some systems.
+ */
+
+/*
+ * Explanation of RECEIVE FIFO THRESHOLD:
+ *
+ * Controls the level at which the PCI burst state machine begins to
+ * empty the receive FIFO. Default is "1/2 full" (0,1).
+ *
+ * 0,0 1/4 full 32 bytes
+ * 0,1 1/2 full 64 bytes
+ * 1,0 3/4 full 96 bytes
+ * 1,1 full 128 bytes
+ */
+
+#define EPIC_NVCTL 0x10 /* NON-VOLATILE CONTROL */
+#define NVCTL_IPG_DLY_MASK 0x00000780 /* interpacket delay gap */
+#define NVCTL_CB_MODE 0x00000040 /* CardBus mode */
+#define NVCTL_GPIO2 0x00000020 /* general purpose i/o */
+#define NVCTL_GPIO1 0x00000010 /* ... */
+#define NVCTL_GPOE2 0x00000008 /* general purpose output ena */
+#define NVCTL_GPOE1 0x00000004 /* ... */
+#define NVCTL_CLKRUNSUPP 0x00000002 /* clock run supported */
+#define NVCTL_ENAMEMMAP 0x00000001 /* enable memory map */
+
+#define NVCTL_IPG_DLY(x) (((x) & NVCTL_IPG_DLY_MASK) >> 7)
+
+#define EPIC_EECTL 0x14 /* EEPROM CONTROL */
+#define EECTL_EEPROMSIZE 0x00000040 /* eeprom size; see below */
+#define EECTL_EERDY 0x00000020 /* eeprom ready */
+#define EECTL_EEDO 0x00000010 /* eeprom data out (from) */
+#define EECTL_EEDI 0x00000008 /* eeprom data in (to) */
+#define EECTL_EESK 0x00000004 /* eeprom clock */
+#define EECTL_EECS 0x00000002 /* eeprom chip select */
+#define EECTL_ENABLE 0x00000001 /* eeprom enable */
+
+/*
+ * Explanation of EEPROM SIZE:
+ *
+ * Indicates the size of the serial EEPROM:
+ *
+ * 1 16x16 or 64x16
+ * 0 128x16 or 256x16
+ */
+
+/*
+ * Serial EEPROM opcodes, including start bit:
+ */
+#define EPIC_EEPROM_OPC_WRITE 0x05
+#define EPIC_EEPROM_OPC_READ 0x06
+
+#define EPIC_PBLCNT 0x18 /* PBLCNT */
+#define PBLCNT_MASK 0x0000003f /* programmable burst length */
+
+#define EPIC_TEST 0x1c /* TEST */
+#define TEST_INIT 0x00000008
+
+#define EPIC_CRCCNT 0x20 /* CRC ERROR COUNTER */
+#define CRCCNT_MASK 0x0000000f /* crc errs since last read */
+
+#define EPIC_ALICNT 0x24 /* FRAME ALIGNMENT ERROR COUNTER */
+#define ALICNT_MASK 0x0000000f /* align errs since last read */
+
+#define EPIC_MPCNT 0x28 /* MISSED PACKET COUNTER */
+#define MPCNT_MASK 0x0000000f /* miss. pkts since last read */
+
+#define EPIC_RXFIFO 0x2c
+
+#define EPIC_MMCTL 0x30 /* MII MANAGEMENT INTERFACE CONTROL */
+#define MMCTL_PHY_ADDR_MASK 0x00003e00 /* phy address field */
+#define MMCTL_PHY_REG_ADDR_MASK 0x000001f0 /* phy register address field */
+#define MMCTL_RESPONDER 0x00000008 /* phy responder */
+#define MMCTL_WRITE 0x00000002 /* write to phy */
+#define MMCTL_READ 0x00000001 /* read from phy */
+
+#define EPIC_MMDATA 0x34 /* MII MANAGEMENT INTERFACE DATA */
+#define MMDATA_MASK 0x0000ffff /* MII frame data */
+
+#define EPIC_MIICFG 0x38 /* MII CONFIGURATION */
+#define MIICFG_ALTDIR 0x00000080 /* alternate direction */
+#define MIICFG_ALTDATA 0x00000040 /* alternate data */
+#define MIICFG_ALTCLOCK 0x00000020 /* alternate clock source */
+#define MIICFG_ENASER 0x00000010 /* enable serial manag intf */
+#define MIICFG_PHYPRESENT 0x00000008 /* phy present on MII */
+#define MIICFG_LINKSTATUS 0x00000004 /* 694 link status */
+#define MIICFG_ENABLE 0x00000002 /* enable 694 */
+#define MIICFG_SERMODEENA 0x00000001 /* serial mode enable */
+
+#define EPIC_IPG 0x3c /* INTERPACKET GAP */
+#define IPG_INTERFRAME_MASK 0x00007f00 /* interframe gap time */
+#define IPG_INTERPKT_MASK 0x000000ff /* interpacket gap time */
+
+#define EPIC_LAN0 0x40 /* LAN ADDRESS */
+
+#define EPIC_LAN1 0x44
+
+#define EPIC_LAN2 0x48
+
+#define LANn_MASK 0x0000ffff
+
+/*
+ * Explanation of LAN ADDRESS registers:
+ *
+ * LAN address is described as:
+ *
+ * 0000 [n1][n0][n3][n2] | 0000 [n5][n4][n7][n6] | 0000 [n9][n8][n11][n10]
+ *
+ * n == one nibble, mapped as follows:
+ *
+ * LAN0 [15-12] n3
+ * LAN0 [11-8] n2
+ * LAN0 [7-4] n1
+ * LAN0 [3-0] n0
+ * LAN1 [15-12] n7
+ * LAN1 [11-8] n6
+ * LAN1 [7-4] n5
+ * LAN1 [3-0] n4
+ * LAN2 [15-12] n11
+ * LAN2 [11-8] n10
+ * LAN2 [7-4] n9
+ * LAN2 [3-0] n8
+ *
+ * The LAN address is automatically recalled from the EEPROM after a
+ * hard reseet.
+ */
+
+#define EPIC_IDCHK 0x4c /* BOARD ID/CHECKSUM */
+#define IDCHK_ID_MASK 0x0000ff00 /* board ID */
+#define IDCHK_CKSUM_MASK 0x000000ff /* checksum (should be 0xff) */
+
+#define EPIC_MC0 0x50 /* MULTICAST ADDDRESS HASH TABLE */
+
+#define EPIC_MC1 0x54
+
+#define EPIC_MC2 0x58
+
+#define EPIC_MC3 0x5c
+
+/*
+ * Explanation of MULTICAST ADDRESS HASH TABLE registers:
+ *
+ * Bits in the hash table are encoded as follows:
+ *
+ * MC0 [15-0]
+ * MC1 [31-16]
+ * MC2 [47-32]
+ * MC3 [53-48]
+ */
+
+#define EPIC_RXCON 0x60 /* RECEIVE CONTROL */
+#define RXCON_EXTBUFSIZESEL1 0x00000200 /* ext buf size; see below */
+#define RXCON_EXTBUFSIZESEL0 0x00000100 /* ... */
+#define RXCON_EARLYRXENABLE 0x00000080 /* early receive enable */
+#define RXCON_MONITORMODE 0x00000040 /* monitor mode */
+#define RXCON_PROMISCMODE 0x00000020 /* promiscuous mode */
+#define RXCON_RXINVADDR 0x00000010 /* rx inv individual addr */
+#define RXCON_RXMULTICAST 0x00000008 /* receive multicast */
+#define RXCON_RXBROADCAST 0x00000004 /* receive broadcast */
+#define RXCON_RXRUNT 0x00000002 /* receive runt frames */
+#define RXCON_SAVEERRPKTS 0x00000001 /* save errored packets */
+
+/*
+ * Explanation of EXTERNAL BUFFER SIZE SELECT:
+ *
+ * 0,0 external buffer access is disabled
+ * 0,1 16k
+ * 1,0 32k
+ * 1,1 128k
+ */
+
+#define EPIC_RXSTAT 0x64 /* RECEIVE STATUS */
+
+#define EPIC_RXCNT 0x68
+
+#define EPIC_RXTEST 0x6c
+
+#define EPIC_TXCON 0x70 /* TRANSMIT CONTROL */
+#define TXCON_SLOTTIME_MASK 0x000000f8 /* slot time */
+#define TXCON_LOOPBACK_D2 0x00000004 /* loopback mode bit 2 */
+#define TXCON_LOOPBACK_D1 0x00000002 /* loopback mode bit 1 */
+#define TXCON_EARLYTX_ENABLE 0x00000001 /* early transmit enable */
+
+/*
+ * Explanation of LOOPBACK MODE BIT:
+ *
+ * 0,0 normal operation
+ * 0,1 internal loopback (before PHY)
+ * 1,0 external loopback (after PHY)
+ * 1,1 full duplex - decouples transmit and receive blocks
+ */
+
+#define EPIC_TXSTAT 0x74 /* TRANSMIT STATUS */
+
+#define EPIC_TDPAR 0x78
+
+#define EPIC_TXTEST 0x7c
+
+#define EPIC_PRFDAR 0x80
+
+#define EPIC_PRCDAR 0x84 /* PCI RECEIVE CURRENT DESCRIPTOR ADDR */
+
+#define EPIC_PRHDAR 0x88
+
+#define EPIC_PRFLAR 0x8c
+
+#define EPIC_PRDLGTH 0x90
+
+#define EPIC_PRFCNT 0x94
+
+#define EPIC_PRLCAR 0x98
+
+#define EPIC_PRLPAR 0x9c
+
+#define EPIC_PREFAR 0xa0
+
+#define EPIC_PRSTAT 0xa4 /* PCI RECEIVE DMA STATUS */
+
+#define EPIC_PRBUF 0xa8
+
+#define EPIC_RDNCAR 0xac
+
+#define EPIC_PRCPTHR 0xb0 /* PCI RECEIVE COPY THRESHOLD */
+
+#define EPIC_ROMDATA 0xb4
+
+#define EPIC_PREEMPR 0xbc
+
+#define EPIC_PTFDAR 0xc0
+
+#define EPIC_PTCDAR 0xc4 /* PCI TRANSMIT CURRENT DESCRIPTOR ADDR */
+
+#define EPIC_PTHDAR 0xc8
+
+#define EPIC_PTFLAR 0xcc
+
+#define EPIC_PTDLGTH 0xd0
+
+#define EPIC_PTFCNT 0xd4
+
+#define EPIC_PTLCAR 0xd8
+
+#define EPIC_ETXTHR 0xdc /* EARLY TRANSMIT THRESHOLD */
+
+#define EPIC_PTETXC 0xe0
+
+#define EPIC_PTSTAT 0xe4
+
+#define EPIC_PTBUF 0xe8
+
+#define EPIC_PTFDAR2 0xec
+
+#define EPIC_FEVTR 0xf0 /* FEVTR (CardBus) */
+
+#define EPIC_FEVTRMSKR 0xf4 /* FEVTRMSKR (CardBus) */
+
+#define EPIC_FPRSTSTR 0xf8 /* FPRSTR (CardBus) */
+
+#define EPIC_FFRCEVTR 0xfc /* PPRCEVTR (CardBus) */
+
+/*
+ * EEPROM format:
+ *
+ * Word Bits Description
+ * ---- ---- -----------
+ * 0 7-0 LAN Address Byte 0
+ * 0 15-8 LAN Address Byte 1
+ * 1 7-0 LAN Address Byte 2
+ * 1 15-8 LAN Address Byte 3
+ * 2 7-0 LAN Address Byte 4
+ * 2 15-8 LAN Address Byte 5
+ * 3 7-0 Board ID
+ * 3 15-8 Checksum
+ * 4 5-0 Non-Volatile Control Register Contents
+ * 5 7-0 PCI Minimum Grant Desired Setting
+ * 5 15-8 PCI Maximum Latency Desired Setting
+ * 6 15-0 Subsystem Vendor ID
+ * 7 14-0 Subsystem ID
+ */
+
+#endif /* _DEV_IC_SMC83C170REG_H_ */
diff --git a/sys/dev/ic/smc83c170var.h b/sys/dev/ic/smc83c170var.h
new file mode 100644
index 00000000000..e386d9927e2
--- /dev/null
+++ b/sys/dev/ic/smc83c170var.h
@@ -0,0 +1,133 @@
+/* $NetBSD: smc83c170var.h,v 1.1 1998/06/02 01:29:42 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * 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.
+ */
+
+#ifndef _DEV_IC_SMC83C170VAR_H_
+#define _DEV_IC_SMC83C170VAR_H_
+
+/*
+ * Misc. definitions for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100) driver.
+ */
+
+/*
+ * Transmit descriptor list size.
+ */
+#define EPIC_NTXDESC 128
+#define EPIC_NTXDESC_MASK (EPIC_NTXDESC - 1)
+#define EPIC_NEXTTX(x) ((x + 1) & EPIC_NTXDESC_MASK)
+
+/*
+ * Receive descriptor list size.
+ */
+#define EPIC_NRXDESC 64
+#define EPIC_NRXDESC_MASK (EPIC_NRXDESC - 1)
+#define EPIC_NEXTRX(x) ((x + 1) & EPIC_NRXDESC_MASK)
+
+/*
+ * Control structures are DMA'd to the EPIC chip. We allocate them in
+ * a single clump that maps to a single DMA segment to make several things
+ * easier.
+ */
+struct epic_control_data {
+ /*
+ * The transmit descriptors.
+ */
+ struct epic_txdesc ecd_txdescs[EPIC_NTXDESC];
+
+ /*
+ * The receive descriptors.
+ */
+ struct epic_rxdesc ecd_rxdescs[EPIC_NRXDESC];
+
+ /*
+ * The transmit fraglists.
+ */
+ struct epic_fraglist ecd_txfrags[EPIC_NTXDESC];
+};
+
+#define EPIC_CDOFF(x) offsetof(struct epic_control_data, x)
+
+/*
+ * Software state for transmit and receive desciptors.
+ */
+struct epic_descsoft {
+ struct mbuf *ds_mbuf; /* head of mbuf chain */
+ bus_dmamap_t ds_dmamap; /* our DMA map */
+};
+
+/*
+ * Software state per device.
+ */
+struct epic_softc {
+ struct device sc_dev; /* generic device information */
+ bus_space_tag_t sc_st; /* bus space tag */
+ bus_space_handle_t sc_sh; /* bus space handle */
+ bus_dma_tag_t sc_dmat; /* bus DMA tag */
+ struct ethercom sc_ethercom; /* ethernet common data */
+ void *sc_sdhook; /* shutdown hook */
+
+ struct ifmedia sc_media; /* media information */
+
+ bus_dmamap_t sc_cddmamap; /* control data DMA map */
+#define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
+
+ /*
+ * Software state for transmit and receive descriptors.
+ */
+ struct epic_descsoft sc_txsoft[EPIC_NTXDESC];
+ struct epic_descsoft sc_rxsoft[EPIC_NRXDESC];
+
+ /*
+ * Control data structures.
+ */
+ struct epic_control_data *sc_control_data;
+
+ int sc_txpending; /* number of TX requests pending */
+ int sc_txdirty; /* first dirty TX descriptor */
+ int sc_txlast; /* last used TX descriptor */
+
+ int sc_rxptr; /* next ready RX descriptor */
+};
+
+#ifdef _KERNEL
+void epic_attach __P((struct epic_softc *));
+int epic_intr __P((void *));
+#endif /* _KERNEL */
+
+#endif /* _DEV_IC_SMC83C170VAR_H_ */
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 18f82d5513c..f65d49d1b91 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $NetBSD: files.pci,v 1.38 1998/05/31 06:03:44 cgd Exp $
+# $NetBSD: files.pci,v 1.39 1998/06/02 01:29:41 thorpej Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@@ -114,3 +114,7 @@ file dev/pci/tga_bt485.c tga
device eap: audio, auconv, mulaw
attach eap at pci
file dev/pci/eap.c eap
+
+# SMC EPIC/100 Fast Ethernet on PCI
+attach epic at pci with epic_pci
+file dev/pci/if_epic_pci.c epic_pci
diff --git a/sys/dev/pci/if_epic_pci.c b/sys/dev/pci/if_epic_pci.c
new file mode 100644
index 00000000000..3e88e1b970c
--- /dev/null
+++ b/sys/dev/pci/if_epic_pci.c
@@ -0,0 +1,193 @@
+/* $NetBSD: if_epic_pci.c,v 1.1 1998/06/02 01:29:41 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * 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.
+ */
+
+/*
+ * PCI bus front-end for the Standard Microsystems Corp. 83C170
+ * Ethernet PCI Integrated Controller (EPIC/100) driver.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_inarp.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ic/smc83c170reg.h>
+#include <dev/ic/smc83c170var.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+
+/*
+ * PCI configuration space registers used by the EPIC.
+ */
+#define EPIC_PCI_IOBA 0x10 /* i/o mapped base */
+#define EPIC_PCI_MMBA 0x14 /* memory mapped base */
+
+struct epic_pci_softc {
+ struct epic_softc sc_epic; /* real EPIC softc */
+
+ /* PCI-specific goo. */
+ void *sc_ih; /* interrupt handle */
+};
+
+#ifdef __BROKEN_INDIRECT_CONFIG
+int epic_pci_match __P((struct device *, void *, void *));
+#else
+int epic_pci_match __P((struct device *, struct cfdata *, void *));
+#endif
+void epic_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach epic_pci_ca = {
+ sizeof(struct epic_pci_softc), epic_pci_match, epic_pci_attach,
+};
+
+int
+epic_pci_match(parent, match, aux)
+ struct device *parent;
+#ifdef __BROKEN_INDIRECT_CONFIG
+ void *match;
+#else
+ struct cfdata *match;
+#endif
+ void *aux;
+{
+ struct pci_attach_args *pa = aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SMC &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SMC_83C170)
+ return (1);
+
+ return (0);
+}
+
+void
+epic_pci_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct epic_pci_softc *psc = (struct epic_pci_softc *)self;
+ struct epic_softc *sc = &psc->sc_epic;
+ struct pci_attach_args *pa = aux;
+ pci_chipset_tag_t pc = pa->pa_pc;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ bus_space_tag_t iot, memt;
+ bus_space_handle_t ioh, memh;
+ int ioh_valid, memh_valid;
+
+ /*
+ * Map the device.
+ */
+ ioh_valid = (pci_mapreg_map(pa, EPIC_PCI_IOBA,
+ PCI_MAPREG_TYPE_IO, 0,
+ &iot, &ioh, NULL, NULL) == 0);
+ memh_valid = (pci_mapreg_map(pa, EPIC_PCI_MMBA,
+ PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
+ &memt, &memh, NULL, NULL) == 0);
+
+ if (memh_valid) {
+ sc->sc_st = memt;
+ sc->sc_sh = memh;
+ } else if (ioh_valid) {
+ sc->sc_st = iot;
+ sc->sc_sh = ioh;
+ } else {
+ printf(": unable to map device registers\n");
+ return;
+ }
+
+ sc->sc_dmat = pa->pa_dmat;
+
+ printf(": SMC EPIC/100 Fast Ethernet\n");
+
+ /*
+ * Map and establish our interrupt.
+ */
+ if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: unable to map interrupt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pc, ih);
+ psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, epic_intr, sc);
+ if (psc->sc_ih == NULL) {
+ printf("%s: unable to establish interrupt",
+ sc->sc_dev.dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
+
+ /*
+ * Finish off the attach.
+ */
+ epic_attach(sc);
+}