summaryrefslogtreecommitdiffstats
path: root/c/src/libchip/network
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--c/src/libchip/network/Makefile.am8
-rw-r--r--c/src/libchip/network/README.i825865
-rw-r--r--c/src/libchip/network/i82586.c2195
-rw-r--r--c/src/libchip/network/i82586reg.h436
-rw-r--r--c/src/libchip/network/i82586var.h319
5 files changed, 2959 insertions, 4 deletions
diff --git a/c/src/libchip/network/Makefile.am b/c/src/libchip/network/Makefile.am
index 68adba9e43..f8ced4bf2e 100644
--- a/c/src/libchip/network/Makefile.am
+++ b/c/src/libchip/network/Makefile.am
@@ -10,10 +10,10 @@ LIBNAME = libnetchip
LIB = $(ARCH)/$(LIBNAME).a
# add cs8900.c to work with it and make it compile
-C_FILES = dec21140.c sonic.c
+C_FILES = dec21140.c i82586.h sonic.c
C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
-include_libchip_HEADERS = cs8900.h sonic.h
+include_libchip_HEADERS = cs8900.h i82586var.h sonic.h
OBJS = $(C_O_FILES)
@@ -52,7 +52,7 @@ endif
.PRECIOUS: $(LIB)
-EXTRA_DIST = README README.cs8900 README.dec21140 README.sonic \
- cs8900.c dec21140.c sonic.c
+EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 README.sonic \
+ cs8900.c dec21140.c i82586.c sonic.c
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libchip/network/README.i82586 b/c/src/libchip/network/README.i82586
new file mode 100644
index 0000000000..01c6522d9c
--- /dev/null
+++ b/c/src/libchip/network/README.i82586
@@ -0,0 +1,5 @@
+#
+# $Id$
+#
+
+TBD
diff --git a/c/src/libchip/network/i82586.c b/c/src/libchip/network/i82586.c
new file mode 100644
index 0000000000..6d0006272b
--- /dev/null
+++ b/c/src/libchip/network/i82586.c
@@ -0,0 +1,2195 @@
+/* $NetBSD: i82586.c,v 1.38 2001/07/07 05:35:39 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg and Charles M. Hannum.
+ *
+ * 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) 1997 Paul Kranenburg.
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1994, 1995, Rafal K. Boni
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * RTEMS:
+ * Copyright (c) 2001, Chris Johns, Cybertec Pty Ltd,
+ * http://www.cybertec.com.au/.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of Vermont
+ * and State Agricultural College and Garrett A. Wollman, by William F.
+ * Jolitz, and by the University of California, Berkeley, Lawrence
+ * Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * 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 UNIVERSITY OR AUTHORS 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Original StarLAN driver written by Garrett Wollman with reference to the
+ * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
+ *
+ * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
+ *
+ * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
+ *
+ * Majorly cleaned up and 3C507 code merged by Charles Hannum.
+ *
+ * Converted to SUN ie driver by Charles D. Cranor,
+ * October 1994, January 1995.
+ * This sun version based on i386 version 1.30.
+ */
+
+/*
+ * The i82586 is a very painful chip, found in sun3's, sun-4/100's
+ * sun-4/200's, and VME based suns. The byte order is all wrong for a
+ * SUN, making life difficult. Programming this chip is mostly the same,
+ * but certain details differ from system to system. This driver is
+ * written so that different "ie" interfaces can be controled by the same
+ * driver.
+ */
+
+/*
+Mode of operation:
+
+ We run the 82586 in a standard Ethernet mode. We keep NFRAMES
+ received frame descriptors around for the receiver to use, and
+ NRXBUF associated receive buffer descriptors, both in a circular
+ list. Whenever a frame is received, we rotate both lists as
+ necessary. (The 586 treats both lists as a simple queue.) We also
+ keep a transmit command around so that packets can be sent off
+ quickly.
+
+ We configure the adapter in AL-LOC = 1 mode, which means that the
+ Ethernet/802.3 MAC header is placed at the beginning of the receive
+ buffer rather than being split off into various fields in the RFD.
+ This also means that we must include this header in the transmit
+ buffer as well.
+
+ By convention, all transmit commands, and only transmit commands,
+ shall have the I (IE_CMD_INTR) bit set in the command. This way,
+ when an interrupt arrives at i82586_intr(), it is immediately possible
+ to tell what precisely caused it. ANY OTHER command-sending
+ routines should run at splnet(), and should post an acknowledgement
+ to every interrupt they generate.
+
+ To save the expense of shipping a command to 82586 every time we
+ want to send a frame, we use a linked list of commands consisting
+ of alternate XMIT and NOP commands. The links of these elements
+ are manipulated (in iexmit()) such that the NOP command loops back
+ to itself whenever the following XMIT command is not yet ready to
+ go. Whenever an XMIT is ready, the preceding NOP link is pointed
+ at it, while its own link field points to the following NOP command.
+ Thus, a single transmit command sets off an interlocked traversal
+ of the xmit command chain, with the host processor in control of
+ the synchronization.
+*/
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "i82586reg.h"
+#include "i82586var.h"
+
+/*
+ * A global way to change all async cmd requests at once. For RTEMS and running
+ * as tasks I wanted to see if the tx race condition is effected by this.
+ */
+#define ASYNC_OPTION (1)
+
+void i82586_reset (struct ie_softc *, int);
+void i82586_watchdog (struct ifnet *);
+void i82586_init (void *);
+int i82586_ioctl (struct ifnet *, int cmd, caddr_t data);
+void i82586_start (struct ifnet *);
+
+void i82586_stop (struct ifnet *, int);
+int i82586_rint (struct ie_softc *, int);
+int i82586_tint (struct ie_softc *, int);
+
+int i82586_mediachange (struct ifnet *);
+void i82586_mediastatus (struct ifnet *, struct ifmediareq *);
+
+static void i82586_tx_task(void *arg);
+static void i82586_start_tx(struct ie_softc *sc);
+
+static int ie_readframe (struct ie_softc *, int);
+static struct mbuf *ieget (struct ie_softc *, int, int);
+static int i82586_get_rbd_list (struct ie_softc *, u_int16_t *,
+ u_int16_t *, int *);
+static void i82586_release_rbd_list (struct ie_softc *,
+ u_int16_t, u_int16_t);
+static int i82586_drop_frames (struct ie_softc *);
+static int i82586_chk_rx_ring (struct ie_softc *);
+
+static __inline__ void ie_ack (struct ie_softc *, u_int);
+static __inline__ void iexmit (struct ie_softc *);
+static void i82586_start_transceiver (struct ie_softc *);
+
+static void i82586_count_errors (struct ie_softc *);
+static void i82586_rx_errors (struct ie_softc *, int, int);
+static void i82586_setup_bufs (struct ie_softc *);
+static void setup_simple_command (struct ie_softc *, int, int);
+static int ie_cfg_setup (struct ie_softc *, int, int, int);
+static int ie_ia_setup (struct ie_softc *, int);
+static void ie_run_tdr (struct ie_softc *, int);
+static int ie_mc_setup (struct ie_softc *, int);
+static void ie_mc_reset (struct ie_softc *);
+static int i82586_start_cmd (struct ie_softc *, int, int, int, int);
+static int i82586_cmd_wait (struct ie_softc *);
+
+#if I82586_DEBUG
+static void print_softie(struct ie_softc *sc);
+static void print_rbd (struct ie_softc *, int);
+#endif
+
+#define min(l,r) ((l) < (r) ? (l) : (r))
+#define max(l,r) ((l) > (r) ? (l) : (r))
+
+#define delay(p) rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (p))
+
+#define i82586_WAKE_EVENT RTEMS_EVENT_1
+#define i82586_TX_EVENT RTEMS_EVENT_2
+
+char *bitmask_snprintf(unsigned long value, const char *format, char *buf, int blen)
+{
+ char *b = buf;
+ int bit = 31;
+
+ while (bit-- > *format)
+ value <<= 1;
+
+ format++;
+
+ while (*format)
+ {
+ if (value & 0x80000000)
+ while (isalnum(*format))
+ *b++ = *format;
+ else
+ *b++ = '0';
+
+ *b++ = ',';
+
+ while (bit-- > *format)
+ value <<= 1;
+
+ format++;
+ }
+
+ *b = '\0';
+ return buf;
+}
+
+char *ether_sprintf(unsigned char *addr)
+{
+ static char buf[32];
+ char *b = buf;
+ int i;
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ {
+ sprintf(b, "%02x:", *addr++);
+ b += 3;
+ }
+ b--;
+ b = "\0";
+ return buf;
+}
+
+/*
+ * Front-ends call this function to attach to the MI driver.
+ *
+ * The front-end has responsibility for managing the ICP and ISCP
+ * structures. Both of these are opaque to us. Also, the front-end
+ * chooses a location for the SCB which is expected to be addressable
+ * (through `sc->scb') as an offset against the shared-memory bus handle.
+ *
+ * The following MD interface function must be setup by the front-end
+ * before calling here:
+ *
+ * hwreset - board dependent reset
+ * hwinit - board dependent initialization
+ * chan_attn - channel attention
+ * intrhook - board dependent interrupt processing
+ * memcopyin - shared memory copy: board to KVA
+ * memcopyout - shared memory copy: KVA to board
+ * ie_bus_read16 - read a sixteen-bit i82586 pointer
+ * ie_bus_write16 - write a sixteen-bit i82586 pointer
+ * ie_bus_write24 - write a twenty-four-bit i82586 pointer
+ *
+ */
+int
+i82586_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+ struct ie_softc *sc;
+ struct ifnet *ifp;
+ char *name;
+ int unit;
+ int mtu;
+
+ /*
+ * Parse driver name
+ */
+
+ if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
+ return 0;
+
+ sc = config->drv_ctrl;
+ ifp = &sc->arpcom.ac_if;
+
+#if I82586_DEBUG
+ sc->sc_debug = 0; //IED_TINT | IED_XMIT;
+#endif
+
+ if (attaching)
+ {
+ if (ifp->if_softc)
+ {
+ printf ("Driver `%s' already in use.\n", config->name);
+ return 0;
+ }
+
+ /*
+ * Process options
+ */
+
+ memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ ifp->if_softc = sc;
+ ifp->if_unit = unit;
+ ifp->if_name = name;
+ ifp->if_mtu = mtu;
+ ifp->if_init = i82586_init;
+ ifp->if_ioctl = i82586_ioctl;
+ ifp->if_start = i82586_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Interrupt Acknowledge. Mask in native byte-order.
+ */
+static __inline__ void
+ie_ack(struct ie_softc *sc, u_int mask)
+{
+ u_int status;
+
+ IE_BUS_BARRIER(sc, 0, 0, BUS_SPACE_BARRIER_READ);
+ status = sc->ie_bus_read16(sc, IE_SCB_STATUS(sc->scb));
+ i82586_start_cmd(sc, status & mask, 0, 0, 0);
+ if (sc->intrhook)
+ sc->intrhook(sc, INTR_ACK);
+}
+
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static __inline struct mbuf *
+ieget(struct ie_softc *sc, int head, int totlen)
+{
+ struct mbuf *m, *m0, *newm;
+ int len, resid;
+ int thisrboff, thismboff;
+ struct ether_header eh;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ (sc->memcopyin)(sc, &eh, IE_RBUF_ADDR(sc, head),
+ sizeof(struct ether_header));
+
+ resid = totlen;
+
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 == 0)
+ return (0);
+ m0->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m0->m_pkthdr.len = totlen;
+ len = MHLEN;
+ m = m0;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ while (totlen > 0) {
+ if (totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0)
+ goto bad;
+ len = MCLBYTES;
+ }
+
+ if (m == m0) {
+ caddr_t newdata = (caddr_t)
+ ALIGN(m->m_data + sizeof(struct ether_header)) -
+ sizeof(struct ether_header);
+ len -= newdata - m->m_data;
+ m->m_data = newdata;
+ }
+
+ m->m_len = len = min(totlen, len);
+
+ totlen -= len;
+ if (totlen > 0) {
+ MGET(newm, M_DONTWAIT, MT_DATA);
+ if (newm == 0)
+ goto bad;
+ len = MLEN;
+ m = m->m_next = newm;
+ }
+ }
+
+ m = m0;
+ thismboff = 0;
+
+ /*
+ * Copy the Ethernet header into the mbuf chain.
+ */
+ memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header));
+ thismboff = sizeof(struct ether_header);
+ thisrboff = sizeof(struct ether_header);
+ resid -= sizeof(struct ether_header);
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures
+ * at or after this point.
+ */
+ while (resid > 0) {
+ int thisrblen = IE_RBUF_SIZE - thisrboff,
+ thismblen = m->m_len - thismboff;
+ len = min(thisrblen, thismblen);
+
+ (sc->memcopyin)(sc, mtod(m, caddr_t) + thismboff,
+ IE_RBUF_ADDR(sc,head) + thisrboff,
+ (u_int)len);
+ resid -= len;
+
+ if (len == thismblen) {
+ m = m->m_next;
+ thismboff = 0;
+ } else
+ thismboff += len;
+
+ if (len == thisrblen) {
+ if (++head == sc->nrxbuf)
+ head = 0;
+ thisrboff = 0;
+ } else
+ thisrboff += len;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy,
+ * we have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return (m0);
+
+ bad:
+ m_freem(m0);
+ return (0);
+}
+
+/*
+ * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
+ * command to the chip to be executed.
+ */
+static __inline__ void
+iexmit(struct ie_softc *sc)
+{
+ int off;
+ int cur, prev;
+
+ cur = sc->xctail;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_EMIT, cur);
+#endif
+
+#if I82586_DEBUG
+ if (sc->sc_debug & IED_XMIT)
+ printf("%s: xmit buffer %d\n", sc->arpcom.ac_if.if_name, cur);
+#endif
+
+ /*
+ * Setup the transmit command.
+ */
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_DESC(sc->xmit_cmds, cur),
+ IE_XBD_ADDR(sc->xbds, cur));
+
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds, cur), 0);
+
+ if (sc->do_xmitnopchain) {
+ /*
+ * Gate this XMIT command to the following NOP
+ */
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds, cur),
+ IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
+ IE_CMD_XMIT | IE_CMD_INTR);
+
+ /*
+ * Loopback at following NOP
+ */
+ sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, cur), 0);
+ sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, cur),
+ IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
+
+ /*
+ * Gate preceding NOP to this XMIT command
+ */
+ prev = (cur + NTXBUF - 1) % NTXBUF;
+ sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, prev), 0);
+ sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, prev),
+ IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
+
+ off = IE_SCB_STATUS(sc->scb);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ if ((sc->ie_bus_read16(sc, off) & IE_CUS_ACTIVE) == 0) {
+ printf("iexmit: CU not active\n");
+ i82586_start_transceiver(sc);
+ }
+ } else {
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds,cur),
+ 0xffff);
+
+ sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
+ IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST);
+
+ off = IE_SCB_CMDLST(sc->scb);
+ sc->ie_bus_write16(sc, off, IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+
+ if (i82586_start_cmd(sc, IE_CUC_START, 0, 0, ASYNC_OPTION))
+ printf("%s: iexmit: start xmit command timed out\n",
+ sc->arpcom.ac_if.if_name);
+ }
+
+ sc->arpcom.ac_if.if_timer = 5;
+}
+
+
+/*
+ * Device timeout/watchdog routine.
+ * Entered if the device neglects to generate an interrupt after a
+ * transmit has been started on it.
+ */
+void
+i82586_watchdog(struct ifnet *ifp)
+{
+ struct ie_softc *sc = ifp->if_softc;
+ printf("%s: device timeout\n", ifp->if_name);
+ ++ifp->if_oerrors;
+ i82586_reset(sc, 1);
+}
+
+static int
+i82586_cmd_wait(struct ie_softc *sc)
+{
+ /* spin on i82586 command acknowledge; wait at most 0.9 (!) seconds */
+ int i, off;
+ u_int16_t cmd;
+
+ for (i = 0; i < 900000; i++) {
+ /* Read the command word */
+ off = IE_SCB_CMD(sc->scb);
+
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ if ((cmd = sc->ie_bus_read16(sc, off)) == 0)
+ return (0);
+ delay(1);
+ }
+
+ off = IE_SCB_STATUS(sc->scb);
+ printf("i82586_cmd_wait: timo(%ssync): scb status: 0x%x, cmd: 0x%x\n",
+ sc->async_cmd_inprogress?"a":"",
+ sc->ie_bus_read16(sc, off), cmd);
+
+ return (1); /* Timeout */
+}
+
+/*
+ * Send a command to the controller and wait for it to either complete
+ * or be accepted, depending on the command. If the command pointer
+ * is null, then pretend that the command is not an action command.
+ * If the command pointer is not null, and the command is an action
+ * command, wait for one of the MASK bits to turn on in the command's
+ * status field.
+ * If ASYNC is set, we just call the chip's attention and return.
+ * We may have to wait for the command's acceptance later though.
+ */
+static int
+i82586_start_cmd(struct ie_softc *sc, int cmd, int iecmdbuf, int mask, int async)
+{
+ int i;
+ int off;
+
+ if (sc->async_cmd_inprogress != 0) {
+ /*
+ * If previous command was issued asynchronously, wait
+ * for it now.
+ */
+ if (i82586_cmd_wait(sc) != 0)
+ return (1);
+ sc->async_cmd_inprogress = 0;
+ }
+
+ off = IE_SCB_CMD(sc->scb);
+ sc->ie_bus_write16(sc, off, cmd);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
+ (sc->chan_attn)(sc, CARD_RESET);
+
+ if (async != 0) {
+ sc->async_cmd_inprogress = 1;
+ return (0);
+ }
+
+ if (IE_ACTION_COMMAND(cmd) && iecmdbuf) {
+ int status;
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, and can kill performance pretty well...
+ * According to the packet driver, the minimum timeout
+ * should be .369 seconds.
+ */
+ for (i = 0; i < 369000; i++) {
+ /* Read the command status */
+ off = IE_CMD_COMMON_STATUS(iecmdbuf);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ status = sc->ie_bus_read16(sc, off);
+ if (status & mask)
+ return (0);
+ delay(1);
+ }
+
+ } else {
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ return (i82586_cmd_wait(sc));
+ }
+
+ /* Timeout */
+ return (1);
+}
+
+
+/*
+ * Transfer accumulated chip error counters to IF.
+ */
+static __inline void
+i82586_count_errors(struct ie_softc *sc)
+{
+ int scb = sc->scb;
+
+ sc->arpcom.ac_if.if_ierrors +=
+ sc->ie_bus_read16(sc, IE_SCB_ERRCRC(scb)) +
+ sc->ie_bus_read16(sc, IE_SCB_ERRALN(scb)) +
+ sc->ie_bus_read16(sc, IE_SCB_ERRRES(scb)) +
+ sc->ie_bus_read16(sc, IE_SCB_ERROVR(scb));
+
+ /* Clear error counters */
+ sc->ie_bus_write16(sc, IE_SCB_ERRCRC(scb), 0);
+ sc->ie_bus_write16(sc, IE_SCB_ERRALN(scb), 0);
+ sc->ie_bus_write16(sc, IE_SCB_ERRRES(scb), 0);
+ sc->ie_bus_write16(sc, IE_SCB_ERROVR(scb), 0);
+}
+
+
+static void
+i82586_rx_errors(struct ie_softc *sc, int fn, int status)
+{
+ char bits[128];
+
+ printf("%s: rx error (frame# %d): %s\n", sc->arpcom.ac_if.if_name, fn,
+ bitmask_snprintf(status, IE_FD_STATUSBITS, bits, sizeof(bits)));
+}
+
+/*
+ * i82586 interrupt entry point.
+ */
+rtems_isr
+i82586_intr(rtems_vector_number vec, void *arg)
+{
+ struct ie_softc *sc = arg;
+
+#if I82586_DEBUG
+ static unsigned long icnt = 0;
+ I82586_TRACE(sc, I82586_INTS_REQ, icnt++);
+#endif
+
+ /*
+ * Implementation dependent interrupt handling. It must at least
+ * disabled interrupts from the i82586. It is hoped this can
+ * happen somewhere outside the i82586.
+ */
+ if (sc->intrhook)
+ (sc->intrhook)(sc, INTR_ENTER);
+
+ /*
+ * Wake the task to handle the interrupt. It will
+ * enabled the interrupts when it has finished.
+ */
+ rtems_event_send (sc->intr_task, i82586_WAKE_EVENT);
+}
+
+/*
+ * i82586 interrupt task. The task is actually an extension of the interrupt
+ * with a context switch in the middle. The RTEMS TCP/IP stack requires a task
+ * be used to talk to the stack as a network semaphore is claimed. This
+ * cannot happen during an interrupt.
+ */
+static void
+i82586_intr_task(void *arg)
+{
+ struct ie_softc *sc = arg;
+ rtems_event_set events;
+ u_int status;
+ int off;
+ int reset;
+
+ /*
+ * Not sure this is a good idea but as a out path exists and
+ * roads lead to it, it seems ok.
+ */
+ for (;;) {
+ rtems_bsdnet_event_receive (i82586_WAKE_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ 0, &events);
+
+ off = IE_SCB_STATUS(sc->scb);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ status = sc->ie_bus_read16(sc, off) & IE_ST_WHENCE;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_INTS_IN, status);
+#endif
+
+ reset = 0;
+
+ while ((status & IE_ST_WHENCE) != 0) {
+#if I82586_DEBUG
+ if (sc->sc_debug)
+ printf ("%s: -------\n%s: scbstatus=0x%x\n",
+ sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_name, status);
+#endif
+
+#if 1
+ /* Ack interrupts FIRST in case we receive more during the ISR. */
+ ie_ack(sc, status & IE_ST_WHENCE);
+#endif
+
+ i82586_start_cmd(sc, status & IE_ST_WHENCE, 0, 0, ASYNC_OPTION);
+
+ if (status & (IE_ST_FR | IE_ST_RNR))
+ if (i82586_rint(sc, status) != 0) {
+ reset = 1;
+ break;
+ }
+
+ if (status & IE_ST_CX)
+ if (i82586_tint(sc, status) != 0) {
+ reset = 1;
+ break;
+ }
+
+#if I82586_DEBUG
+ if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))
+ printf("%s: cna; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
+#endif
+
+#if 0
+ if (sc->intrhook)
+ (sc->intrhook)(sc, INTR_LOOP);
+#endif
+
+#if 1
+ /*
+ * Interrupt ACK was posted asynchronously; wait for
+ * completion here before reading SCB status again.
+ *
+ * If ACK fails, try to reset the chip, in hopes that
+ * it helps.
+ */
+ if (i82586_cmd_wait(sc) != 0) {
+ reset = 1;
+ break;
+ }
+#endif
+
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ status = sc->ie_bus_read16(sc, off);
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_INTS_LOOPS, status);
+#endif
+ }
+
+ if (reset) {
+#if I82586_DEBUG
+ printf("%s: intr reset; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
+#endif
+ i82586_cmd_wait(sc);
+ i82586_reset(sc, 1);
+ }
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_INTS_OUT, status);
+#endif
+
+ if (sc->intrhook)
+ (sc->intrhook)(sc, INTR_EXIT);
+ }
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+int
+i82586_rint(struct ie_softc *sc, int scbstatus)
+{
+ static int timesthru = 1024;
+ int i, status, off;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_RX_INT, scbstatus);
+
+ if (sc->sc_debug & IED_RINT)
+ printf("%s: rint: status 0x%x\n",
+ sc->arpcom.ac_if.if_name, scbstatus);
+#endif
+
+ for (;;) {
+ int drop = 0;
+
+ i = sc->rfhead;
+ off = IE_RFRAME_STATUS(sc->rframes, i);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ status = sc->ie_bus_read16(sc, off);
+
+#if I82586_DEBUG
+ if (sc->sc_debug & IED_RINT)
+ printf("%s: rint: frame(%d) status 0x%x\n",
+ sc->arpcom.ac_if.if_name, i, status);
+#endif
+ if ((status & IE_FD_COMPLETE) == 0) {
+ if ((status & IE_FD_OK) != 0) {
+ printf("%s: rint: weird: ",
+ sc->arpcom.ac_if.if_name);
+ i82586_rx_errors(sc, i, status);
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_RX_ERR, status);
+#endif
+ break;
+ }
+ if (--timesthru == 0) {
+ /* Account the accumulated errors */
+ i82586_count_errors(sc);
+ timesthru = 1024;
+ }
+ break;
+ } else if ((status & IE_FD_OK) == 0) {
+ /*
+ * If the chip is configured to automatically
+ * discard bad frames, the only reason we can
+ * get here is an "out-of-resource" condition.
+ */
+ i82586_rx_errors(sc, i, status);
+ drop = 1;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_RX_DROP, status);
+#endif
+ }
+
+#if I82586_DEBUG
+ if ((status & IE_FD_BUSY) != 0)
+ printf("%s: rint: frame(%d) busy; status=0x%x\n",
+ sc->arpcom.ac_if.if_name, i, status);
+#endif
+
+ /*
+ * Advance the RFD list, since we're done with
+ * this descriptor.
+ */
+
+ /* Clear frame status */
+ sc->ie_bus_write16(sc, off, 0);
+
+ /* Put fence at this frame (the head) */
+ off = IE_RFRAME_LAST(sc->rframes, i);
+ sc->ie_bus_write16(sc, off, IE_FD_EOL|IE_FD_SUSP);
+
+ /* and clear RBD field */
+ off = IE_RFRAME_BUFDESC(sc->rframes, i);
+ sc->ie_bus_write16(sc, off, 0xffff);
+
+ /* Remove fence from current tail */
+ off = IE_RFRAME_LAST(sc->rframes, sc->rftail);
+ sc->ie_bus_write16(sc, off, 0);
+
+ if (++sc->rftail == sc->nframes)
+ sc->rftail = 0;
+ if (++sc->rfhead == sc->nframes)
+ sc->rfhead = 0;
+
+ /* Pull the frame off the board */
+ if (drop) {
+ i82586_drop_frames(sc);
+ if ((status & IE_FD_RNR) != 0)
+ sc->rnr_expect = 1;
+ sc->arpcom.ac_if.if_ierrors++;
+ } else if (ie_readframe(sc, i) != 0)
+ return (1);
+ }
+
+ if ((scbstatus & IE_ST_RNR) != 0) {
+
+ /*
+ * Receiver went "Not Ready". We try to figure out
+ * whether this was an expected event based on past
+ * frame status values.
+ */
+
+ if ((scbstatus & IE_RUS_SUSPEND) != 0) {
+ /*
+ * We use the "suspend on last frame" flag.
+ * Send a RU RESUME command in response, since
+ * we should have dealt with all completed frames
+ * by now.
+ */
+ printf("RINT: SUSPENDED; scbstatus=0x%x\n",
+ scbstatus);
+ if (i82586_start_cmd(sc, IE_RUC_RESUME, 0, 0, 0) == 0)
+ return (0);
+ printf("%s: RU RESUME command timed out\n",
+ sc->arpcom.ac_if.if_name);
+ return (1); /* Ask for a reset */
+ }
+
+ if (sc->rnr_expect != 0) {
+ /*
+ * The RNR condition was announced in the previously
+ * completed frame. Assume the receive ring is Ok,
+ * so restart the receiver without further delay.
+ */
+ i82586_start_transceiver(sc);
+ sc->rnr_expect = 0;
+ return (0);
+
+ } else if ((scbstatus & IE_RUS_NOSPACE) != 0) {
+ /*
+ * We saw no previous IF_FD_RNR flag.
+ * We check our ring invariants and, if ok,
+ * just restart the receiver at the current
+ * point in the ring.
+ */
+ if (i82586_chk_rx_ring(sc) != 0)
+ return (1);
+
+ i82586_start_transceiver(sc);
+ sc->arpcom.ac_if.if_ierrors++;
+ return (0);
+ } else
+ printf("%s: receiver not ready; scbstatus=0x%x\n",
+ sc->arpcom.ac_if.if_name, scbstatus);
+
+ sc->arpcom.ac_if.if_ierrors++;
+ return (1); /* Ask for a reset */
+ }
+
+ return (0);
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by the
+ * transmission of frames. This routine is deceptively simple, since most
+ * of the real work is done by i82586_start().
+ */
+int
+i82586_tint(struct ie_softc *sc, int scbstatus)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int status;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_INT, sc->xmit_busy);
+#endif
+
+#if I82586_DEBUG
+ if (sc->xmit_busy <= 0) {
+ printf("i82586_tint: (%d), WEIRD: xmit_busy=%d, xctail=%d, xchead=%d\n",
+ sc->trace_flow_in / 2, sc->xmit_busy, sc->xctail, sc->xchead);
+ I82586_TRACE(sc, I82586_TX_BAD, sc->xctail);
+ return (0);
+ }
+#endif
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ status = sc->ie_bus_read16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds,
+ sc->xctail));
+
+#if I82586_DEBUG
+ if (sc->sc_debug & IED_TINT)
+ printf("%s: tint: SCB status 0x%x; xmit status 0x%x\n",
+ sc->arpcom.ac_if.if_name, scbstatus, status);
+#endif
+
+ if ((status & IE_STAT_COMPL) == 0 || (status & IE_STAT_BUSY)) {
+ printf("i82586_tint: (%d) command still busy; status=0x%x; tail=%d\n",
+ sc->trace_flow_in / 2, status, sc->xctail);
+ printf("iestatus = 0x%x\n", scbstatus);
+// sc->sc_debug = IED_ALL;
+ }
+
+ if (status & IE_STAT_OK) {
+ ifp->if_opackets++;
+ ifp->if_collisions += (status & IE_XS_MAXCOLL);
+ } else {
+ ifp->if_oerrors++;
+ /*
+ * Check SQE and DEFERRED?
+ * What if more than one bit is set?
+ */
+ if (status & IE_STAT_ABORT)
+ printf("%s: send aborted\n", sc->arpcom.ac_if.if_name);
+ else if (status & IE_XS_NOCARRIER)
+ printf("%s: no carrier\n", sc->arpcom.ac_if.if_name);
+ else if (status & IE_XS_LOSTCTS)
+ printf("%s: lost CTS\n", sc->arpcom.ac_if.if_name);
+ else if (status & IE_XS_UNDERRUN)
+ printf("%s: DMA underrun\n", sc->arpcom.ac_if.if_name);
+ else if (status & IE_XS_EXCMAX) {
+ printf("%s: too many collisions\n",
+ sc->arpcom.ac_if.if_name);
+ sc->arpcom.ac_if.if_collisions += 16;
+ }
+ }
+
+ /*
+ * If multicast addresses were added or deleted while transmitting,
+ * ie_mc_reset() set the want_mcsetup flag indicating that we
+ * should do it.
+ */
+ if (sc->want_mcsetup) {
+ ie_mc_setup(sc, IE_XBUF_ADDR(sc, sc->xctail));
+ sc->want_mcsetup = 0;
+ }
+
+ /* Done with the buffer. */
+ sc->xmit_busy--;
+ sc->xctail = (sc->xctail + 1) % NTXBUF;
+
+ /* Start the next packet, if any, transmitting. */
+ if (sc->xmit_busy > 0)
+ iexmit(sc);
+
+ i82586_start_tx(sc);
+ return (0);
+}
+
+/*
+ * Get a range of receive buffer descriptors that represent one packet.
+ */
+static int
+i82586_get_rbd_list(struct ie_softc *sc, u_int16_t *start, u_int16_t *end, int *pktlen)
+{
+ int off, rbbase = sc->rbds;
+ int rbindex, count = 0;
+ int plen = 0;
+ int rbdstatus;
+
+ *start = rbindex = sc->rbhead;
+
+ do {
+ off = IE_RBD_STATUS(rbbase, rbindex);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ rbdstatus = sc->ie_bus_read16(sc, off);
+ if ((rbdstatus & IE_RBD_USED) == 0) {
+ /*
+ * This means we are somehow out of sync. So, we
+ * reset the adapter.
+ */
+#if I82586_DEBUG
+ print_rbd(sc, rbindex);
+#endif
+ printf("%s: receive descriptors out of sync at %d\n",
+ sc->arpcom.ac_if.if_name, rbindex);
+ return (0);
+ }
+ plen += (rbdstatus & IE_RBD_CNTMASK);
+
+ if (++rbindex == sc->nrxbuf)
+ rbindex = 0;
+
+ ++count;
+ } while ((rbdstatus & IE_RBD_LAST) == 0);
+ *end = rbindex;
+ *pktlen = plen;
+ return (count);
+}
+
+
+/*
+ * Release a range of receive buffer descriptors after we've copied the packet.
+ */
+static void
+i82586_release_rbd_list(struct ie_softc *sc, u_int16_t start, u_int16_t end)
+{
+ int off, rbbase = sc->rbds;
+ int rbindex = start;
+
+ do {
+ /* Clear buffer status */
+ off = IE_RBD_STATUS(rbbase, rbindex);
+ sc->ie_bus_write16(sc, off, 0);
+ if (++rbindex == sc->nrxbuf)
+ rbindex = 0;
+ } while (rbindex != end);
+
+ /* Mark EOL at new tail */
+ rbindex = ((rbindex == 0) ? sc->nrxbuf : rbindex) - 1;
+ off = IE_RBD_BUFLEN(rbbase, rbindex);
+ sc->ie_bus_write16(sc, off, IE_RBUF_SIZE|IE_RBD_EOL);
+
+ /* Remove EOL from current tail */
+ off = IE_RBD_BUFLEN(rbbase, sc->rbtail);
+ sc->ie_bus_write16(sc, off, IE_RBUF_SIZE);
+
+ /* New head & tail pointer */
+/* hmm, why have both? head is always (tail + 1) % NRXBUF */
+ sc->rbhead = end;
+ sc->rbtail = rbindex;
+}
+
+/*
+ * Drop the packet at the head of the RX buffer ring.
+ * Called if the frame descriptor reports an error on this packet.
+ * Returns 1 if the buffer descriptor ring appears to be corrupt;
+ * and 0 otherwise.
+ */
+static int
+i82586_drop_frames(struct ie_softc *sc)
+{
+ u_int16_t bstart, bend;
+ int pktlen;
+
+ if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0)
+ return (1);
+ i82586_release_rbd_list(sc, bstart, bend);
+ return (0);
+}
+
+/*
+ * Check the RX frame & buffer descriptor lists for our invariants,
+ * i.e.: EOL bit set iff. it is pointed at by the r*tail pointer.
+ *
+ * Called when the receive unit has stopped unexpectedly.
+ * Returns 1 if an inconsistency is detected; 0 otherwise.
+ *
+ * The Receive Unit is expected to be NOT RUNNING.
+ */
+static int
+i82586_chk_rx_ring(struct ie_softc *sc)
+{
+ int n, off, val;
+
+ for (n = 0; n < sc->nrxbuf; n++) {
+ off = IE_RBD_BUFLEN(sc->rbds, n);
+ val = sc->ie_bus_read16(sc, off);
+ if ((n == sc->rbtail) ^ ((val & IE_RBD_EOL) != 0)) {
+ /* `rbtail' and EOL flag out of sync */
+ printf("%s: rx buffer descriptors out of sync at %d\n",
+ sc->arpcom.ac_if.if_name, n);
+ return (1);
+ }
+
+ /* Take the opportunity to clear the status fields here ? */
+ }
+
+ for (n = 0; n < sc->nframes; n++) {
+ off = IE_RFRAME_LAST(sc->rframes, n);
+ val = sc->ie_bus_read16(sc, off);
+ if ((n == sc->rftail) ^ ((val & (IE_FD_EOL|IE_FD_SUSP)) != 0)) {
+ /* `rftail' and EOL flag out of sync */
+ printf("%s: rx frame list out of sync at %d\n",
+ sc->arpcom.ac_if.if_name, n);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from the list
+ * of RBD, then rotates the RBD list so that the receiver doesn't start
+ * complaining. Trailers are DROPPED---there's no point in wasting time
+ * on confusing code to deal with them. Hopefully, this machine will
+ * never ARP for trailers anyway.
+ */
+static int
+ie_readframe(struct ie_softc *sc, int num) /* frame number to read */
+{
+ struct ether_header *eh;
+ struct mbuf *m;
+ u_int16_t bstart, bend;
+ int pktlen;
+
+ if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) {
+ sc->arpcom.ac_if.if_ierrors++;
+ return (1);
+ }
+
+ m = ieget(sc, bstart, pktlen);
+ i82586_release_rbd_list(sc, bstart, bend);
+
+ if (m == 0) {
+ sc->arpcom.ac_if.if_ierrors++;
+ return (0);
+ }
+
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof (struct ether_header);
+
+#if I82586_DEBUG
+ if (sc->sc_debug & IED_READFRAME) {
+
+ printf("%s: frame from ether %s type 0x%x len %d\n",
+ sc->arpcom.ac_if.if_name,
+ ether_sprintf(eh->ether_shost),
+ (u_int)ntohs(eh->ether_type),
+ pktlen);
+ }
+#endif
+
+#if NBPFILTER > 0
+ /* Check for a BPF filter; if so, hand it up. */
+ if (sc->arpcom.ac_if.if_bpf != 0)
+ /* Pass it up. */
+ bpf_mtap(sc->arpcom.ac_if.if_bpf, m);
+#endif /* NBPFILTER > 0 */
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input (&sc->arpcom.ac_if, eh, m);
+ sc->arpcom.ac_if.if_ipackets++;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_RX_OK, sc->arpcom.ac_if.if_ipackets);
+#endif
+
+ return (0);
+}
+
+/*
+ * Start transmission on an interface.
+ */
+void
+i82586_start(struct ifnet *ifp)
+{
+ struct ie_softc *sc = ifp->if_softc;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_REQ, sc->xmit_busy);
+#endif
+
+ rtems_event_send (sc->tx_task, i82586_TX_EVENT);
+}
+
+static void
+i82586_tx_task(void *arg)
+{
+ struct ie_softc *sc = arg;
+ rtems_event_set events;
+
+ for (;;) {
+ rtems_bsdnet_event_receive (i82586_TX_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ 0, &events);
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_EVT, sc->xmit_busy);
+
+ if (sc->sc_debug)
+ printf ("%s: =======\n", sc->arpcom.ac_if.if_name);
+#endif
+
+ i82586_start_tx(sc);
+ }
+}
+
+static void
+i82586_start_tx(struct ie_softc *sc)
+{
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m0, *m;
+ int buffer, head, xbase;
+ u_short len;
+ int s;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_START_TX, sc->xmit_busy);
+#endif
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ {
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_ACTIVE, ifp->if_snd.ifq_len);
+#endif
+ return;
+ }
+
+ for (;;) {
+ if (sc->xmit_busy == NTXBUF) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ head = sc->xchead;
+ xbase = sc->xbds;
+
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == 0)
+ break;
+
+ /* We need to use m->m_pkthdr.len, so require the header */
+ if ((m0->m_flags & M_PKTHDR) == 0)
+ panic("i82586_start: no header mbuf");
+
+#if NBPFILTER > 0
+ /* Tap off here if there is a BPF listener. */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m0);
+#endif
+
+#if I82586_DEBUG
+ if (sc->sc_debug & IED_ENQ)
+ printf("%s: fill buffer %d\n", sc->arpcom.ac_if.if_name,
+ sc->xchead);
+#endif
+
+ if (m0->m_pkthdr.len > IE_TBUF_SIZE)
+ printf("%s: tbuf overflow\n", sc->arpcom.ac_if.if_name);
+
+ buffer = IE_XBUF_ADDR(sc, head);
+ for (m = m0; m != 0; m = m->m_next) {
+ (sc->memcopyout)(sc, mtod(m,caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ }
+
+ len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
+ m_freem(m0);
+
+ /*
+ * Setup the transmit buffer descriptor here, while we
+ * know the packet's length.
+ */
+ sc->ie_bus_write16(sc, IE_XBD_FLAGS(xbase, head),
+ len | IE_TBD_EOL);
+ sc->ie_bus_write16(sc, IE_XBD_NEXT(xbase, head), 0xffff);
+ sc->ie_bus_write24(sc, IE_XBD_BUF(xbase, head),
+ IE_XBUF_ADDR(sc, head));
+
+ if (++head == NTXBUF)
+ head = 0;
+ sc->xchead = head;
+
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_TX_START, sc->xmit_busy);
+#endif
+
+ s = splnet();
+ /* Start the first packet transmitting. */
+ if (sc->xmit_busy == 0)
+ iexmit(sc);
+
+ sc->xmit_busy++;
+
+ splx(s);
+ }
+}
+
+/*
+ * Probe IE's ram setup [ Move all this into MD front-end!? ]
+ * Use only if SCP and ISCP represent offsets into shared ram space.
+ */
+int
+i82586_proberam(struct ie_softc *sc)
+{
+ int result, off;
+
+ /* Put in 16-bit mode */
+ off = IE_SCP_BUS_USE(sc->scp);
+ sc->ie_bus_write16(sc, off, 0);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
+
+ /* Set the ISCP `busy' bit */
+ off = IE_ISCP_BUSY(sc->iscp);
+ sc->ie_bus_write16(sc, off, 1);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
+
+ if (sc->hwreset)
+ (sc->hwreset)(sc, CHIP_PROBE);
+
+ (sc->chan_attn) (sc, CHIP_PROBE);
+
+ delay(100); /* wait a while... */
+
+ /* Read back the ISCP `busy' bit; it should be clear by now */
+ off = IE_ISCP_BUSY(sc->iscp);
+ IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
+ result = sc->ie_bus_read16(sc, off) == 0;
+
+ /* Acknowledge any interrupts we may have caused. */
+ ie_ack(sc, IE_ST_WHENCE);
+
+ return (result);
+}
+
+void
+i82586_reset(struct ie_softc *sc, int hard)
+{
+ int s = splnet();
+
+ if (hard)
+ printf("%s: reset\n", sc->arpcom.ac_if.if_name);
+
+ /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
+ sc->arpcom.ac_if.if_timer = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if (i82586_start_cmd(sc, IE_RUC_ABORT | IE_CUC_ABORT, 0, 0, 0))
+ printf("%s: abort commands timed out\n", sc->arpcom.ac_if.if_name);
+
+ /*
+ * This can really slow down the i82586_reset() on some cards, but it's
+ * necessary to unwedge other ones (eg, the Sun VME ones) from certain
+ * lockups.
+ */
+ if (hard && sc->hwreset)
+ (sc->hwreset)(sc, CARD_RESET);
+
+ delay(100);
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if ((sc->arpcom.ac_if.if_flags & IFF_UP) != 0) {
+ i82586_init(&sc->arpcom.ac_if);
+ }
+
+ splx(s);
+}
+
+static void
+setup_simple_command(struct ie_softc *sc, int cmd, int cmdbuf)
+{
+ /* Setup a simple command */
+ sc->ie_bus_write16(sc, IE_CMD_COMMON_STATUS(cmdbuf), 0);
+ sc->ie_bus_write16(sc, IE_CMD_COMMON_CMD(cmdbuf), cmd | IE_CMD_LAST);
+ sc->ie_bus_write16(sc, IE_CMD_COMMON_LINK(cmdbuf), 0xffff);
+
+ /* Assign the command buffer to the SCB command list */
+ sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb), cmdbuf);
+}
+
+/*
+ * Run the time-domain reflectometer.
+ */
+static void
+ie_run_tdr(struct ie_softc *sc, int cmd)
+{
+ int result;
+
+ setup_simple_command(sc, IE_CMD_TDR, cmd);
+ sc->ie_bus_write16(sc, IE_CMD_TDR_TIME(cmd), 0);
+
+ if (i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0) ||
+ (sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd)) & IE_STAT_OK) == 0)
+ result = 0x10000; /* XXX */
+ else
+ result = sc->ie_bus_read16(sc, IE_CMD_TDR_TIME(cmd));
+
+ /* Squash any pending interrupts */
+ ie_ack(sc, IE_ST_WHENCE);
+
+ if (result & IE_TDR_SUCCESS)
+ return;
+
+ if (result & 0x10000)
+ printf("%s: TDR command failed\n", sc->arpcom.ac_if.if_name);
+ else if (result & IE_TDR_XCVR)
+ printf("%s: transceiver problem\n", sc->arpcom.ac_if.if_name);
+ else if (result & IE_TDR_OPEN)
+ printf("%s: TDR detected incorrect termination %d clocks away\n",
+ sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
+ else if (result & IE_TDR_SHORT)
+ printf("%s: TDR detected a short circuit %d clocks away\n",
+ sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
+ else
+ printf("%s: TDR returned unknown status 0x%x\n",
+ sc->arpcom.ac_if.if_name, result);
+}
+
+
+/*
+ * i82586_setup_bufs: set up the buffers
+ *
+ * We have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
+ * this is to be used for the buffers. The chip indexs its control data
+ * structures with 16 bit offsets, and it indexes actual buffers with
+ * 24 bit addresses. So we should allocate control buffers first so that
+ * we don't overflow the 16 bit offset field. The number of transmit
+ * buffers is fixed at compile time.
+ *
+ */
+static void
+i82586_setup_bufs(struct ie_softc *sc)
+{
+ int ptr = sc->buf_area; /* memory pool */
+ int n, r;
+
+ /*
+ * step 0: zero memory and figure out how many recv buffers and
+ * frames we can have.
+ */
+ ptr = (ptr + 3) & ~3; /* set alignment and stick with it */
+
+
+ /*
+ * step 1: lay out data structures in the shared-memory area
+ */
+
+ /* The no-op commands; used if "nop-chaining" is in effect */
+ sc->nop_cmds = ptr;
+ ptr += NTXBUF * IE_CMD_NOP_SZ;
+
+ /* The transmit commands */
+ sc->xmit_cmds = ptr;
+ ptr += NTXBUF * IE_CMD_XMIT_SZ;
+
+ /* The transmit buffers descriptors */
+ sc->xbds = ptr;
+ ptr += NTXBUF * IE_XBD_SZ;
+
+ /* The transmit buffers */
+ sc->xbufs = ptr;
+ ptr += NTXBUF * IE_TBUF_SIZE;
+
+ ptr = (ptr + 3) & ~3; /* re-align.. just in case */
+
+ /* Compute free space for RECV stuff */
+ n = sc->buf_area_sz - (ptr - sc->buf_area);
+
+ /* Compute size of one RECV frame */
+ r = IE_RFRAME_SZ + ((IE_RBD_SZ + IE_RBUF_SIZE) * B_PER_F);
+
+ sc->nframes = n / r;
+
+ if (sc->nframes <= 0)
+ panic("ie: bogus buffer calc\n");
+
+ sc->nrxbuf = sc->nframes * B_PER_F;
+
+ /* The receice frame descriptors */
+ sc->rframes = ptr;
+ ptr += sc->nframes * IE_RFRAME_SZ;
+
+ /* The receive buffer descriptors */
+ sc->rbds = ptr;
+ ptr += sc->nrxbuf * IE_RBD_SZ;
+
+ /* The receive buffers */
+ sc->rbufs = ptr;
+ ptr += sc->nrxbuf * IE_RBUF_SIZE;
+
+#if I82586_DEBUG
+ printf("%s: %d frames %d bufs\n", sc->arpcom.ac_if.if_name, sc->nframes,
+ sc->nrxbuf);
+#endif
+
+ /*
+ * step 2: link together the recv frames and set EOL on last one
+ */
+ for (n = 0; n < sc->nframes; n++) {
+ int m = (n == sc->nframes - 1) ? 0 : n + 1;
+
+ /* Clear status */
+ sc->ie_bus_write16(sc, IE_RFRAME_STATUS(sc->rframes,n), 0);
+
+ /* RBD link = NULL */
+ sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,n),
+ 0xffff);
+
+ /* Make a circular list */
+ sc->ie_bus_write16(sc, IE_RFRAME_NEXT(sc->rframes,n),
+ IE_RFRAME_ADDR(sc->rframes,m));
+
+ /* Mark last as EOL */
+ sc->ie_bus_write16(sc, IE_RFRAME_LAST(sc->rframes,n),
+ ((m==0)? (IE_FD_EOL|IE_FD_SUSP) : 0));
+ }
+
+ /*
+ * step 3: link the RBDs and set EOL on last one
+ */
+ for (n = 0; n < sc->nrxbuf; n++) {
+ int m = (n == sc->nrxbuf - 1) ? 0 : n + 1;
+
+ /* Clear status */
+ sc->ie_bus_write16(sc, IE_RBD_STATUS(sc->rbds,n), 0);
+
+ /* Make a circular list */
+ sc->ie_bus_write16(sc, IE_RBD_NEXT(sc->rbds,n),
+ IE_RBD_ADDR(sc->rbds,m));
+
+ /* Link to data buffers */
+ sc->ie_bus_write24(sc, IE_RBD_BUFADDR(sc->rbds, n),
+ IE_RBUF_ADDR(sc, n));
+ sc->ie_bus_write16(sc, IE_RBD_BUFLEN(sc->rbds,n),
+ IE_RBUF_SIZE | ((m==0)?IE_RBD_EOL:0));
+ }
+
+ /*
+ * step 4: all xmit no-op commands loopback onto themselves
+ */
+ for (n = 0; n < NTXBUF; n++) {
+ sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, n), 0);
+
+ sc->ie_bus_write16(sc, IE_CMD_NOP_CMD(sc->nop_cmds, n),
+ IE_CMD_NOP);
+
+ sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, n),
+ IE_CMD_NOP_ADDR(sc->nop_cmds, n));
+ }
+
+
+ /*
+ * step 6: set the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used.
+ */
+
+ /* Pointers to last packet sent and next available transmit buffer. */
+ sc->xchead = sc->xctail = 0;
+
+ /* Clear transmit-busy flag and set number of free transmit buffers. */
+ sc->xmit_busy = 0;
+
+ /*
+ * Pointers to first and last receive frame.
+ * The RFD pointed to by rftail is the only one that has EOL set.
+ */
+ sc->rfhead = 0;
+ sc->rftail = sc->nframes - 1;
+
+ /*
+ * Pointers to first and last receive descriptor buffer.
+ * The RBD pointed to by rbtail is the only one that has EOL set.
+ */
+ sc->rbhead = 0;
+ sc->rbtail = sc->nrxbuf - 1;
+
+/* link in recv frames * and buffer into the scb. */
+#if I82586_DEBUG
+ printf("%s: reserved %d bytes\n",
+ sc->arpcom.ac_if.if_name, ptr - sc->buf_area);
+#endif
+}
+
+static int
+ie_cfg_setup(struct ie_softc *sc, int cmd, int promiscuous, int manchester)
+{
+ int cmdresult, status;
+ u_int8_t buf[IE_CMD_CFG_SZ]; /* XXX malloc? */
+
+ *IE_CMD_CFG_CNT(buf) = 0x0c;
+ *IE_CMD_CFG_FIFO(buf) = 8;
+ *IE_CMD_CFG_SAVEBAD(buf) = 0x40;
+ *IE_CMD_CFG_ADDRLEN(buf) = 0x2e;
+ *IE_CMD_CFG_PRIORITY(buf) = 0;
+ *IE_CMD_CFG_IFS(buf) = 0x60;
+ *IE_CMD_CFG_SLOT_LOW(buf) = 0;
+ *IE_CMD_CFG_SLOT_HIGH(buf) = 0xf2;
+ *IE_CMD_CFG_PROMISC(buf) = !!promiscuous | manchester << 2;
+ *IE_CMD_CFG_CRSCDT(buf) = 0;
+ *IE_CMD_CFG_MINLEN(buf) = 64;
+ *IE_CMD_CFG_JUNK(buf) = 0xff;
+ sc->memcopyout(sc, buf, cmd, IE_CMD_CFG_SZ);
+ setup_simple_command(sc, IE_CMD_CONFIG, cmd);
+ IE_BUS_BARRIER(sc, cmd, IE_CMD_CFG_SZ, BUS_SPACE_BARRIER_WRITE);
+
+ cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0);
+ status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd));
+ if (cmdresult != 0) {
+ printf("%s: configure command timed out; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+ if ((status & IE_STAT_OK) == 0) {
+ printf("%s: configure command failed; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+
+ /* Squash any pending interrupts */
+ ie_ack(sc, IE_ST_WHENCE);
+ return (1);
+}
+
+static int
+ie_ia_setup(struct ie_softc *sc, int cmdbuf)
+{
+ int cmdresult, status;
+
+ setup_simple_command(sc, IE_CMD_IASETUP, cmdbuf);
+
+ (sc->memcopyout)(sc, sc->arpcom.ac_enaddr,
+ IE_CMD_IAS_EADDR(cmdbuf), ETHER_ADDR_LEN);
+
+ cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
+ status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
+ if (cmdresult != 0) {
+ printf("%s: individual address command timed out; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+ if ((status & IE_STAT_OK) == 0) {
+ printf("%s: individual address command failed; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+
+ /* Squash any pending interrupts */
+ ie_ack(sc, IE_ST_WHENCE);
+ return (1);
+}
+
+/*
+ * Run the multicast setup command.
+ * Called at splnet().
+ */
+static int
+ie_mc_setup(struct ie_softc *sc, int cmdbuf)
+{
+ int cmdresult, status;
+
+ if (sc->mcast_count == 0)
+ return (1);
+
+ setup_simple_command(sc, IE_CMD_MCAST, cmdbuf);
+
+ (sc->memcopyout)(sc, (caddr_t)sc->mcast_addrs,
+ IE_CMD_MCAST_MADDR(cmdbuf),
+ sc->mcast_count * ETHER_ADDR_LEN);
+
+ sc->ie_bus_write16(sc, IE_CMD_MCAST_BYTES(cmdbuf),
+ sc->mcast_count * ETHER_ADDR_LEN);
+
+ /* Start the command */
+ cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
+ status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
+ if (cmdresult != 0) {
+ printf("%s: multicast setup command timed out; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+ if ((status & IE_STAT_OK) == 0) {
+ printf("%s: multicast setup command failed; status %x\n",
+ sc->arpcom.ac_if.if_name, status);
+ return (0);
+ }
+
+ /* Squash any pending interrupts */
+ ie_ack(sc, IE_ST_WHENCE);
+ return (1);
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present() and adds
+ * to it all the other structures we need to operate the adapter. This
+ * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
+ * the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
+ */
+void
+i82586_init(void *arg)
+{
+ struct ie_softc *sc = arg;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int cmd;
+
+ sc->async_cmd_inprogress = 0;
+ sc->xmit_busy = 0;
+
+#if I82586_DEBUG
+ memset(sc->trace_flow, 0, sizeof(sc->trace_flow));
+ sc->trace_flow_wrap = 0;
+#endif
+ sc->trace_flow_in = 0;
+
+ cmd = sc->buf_area;
+
+#if I82586_DEBUG
+ printf ("%s: sc_debug at 0x%08x\n", sc->arpcom.ac_if.if_name, (unsigned int) &sc->sc_debug);
+#endif
+
+ /*
+ * Send the configure command first.
+ */
+ if (ie_cfg_setup(sc, cmd, sc->promisc, 0) == 0)
+ return;
+
+ /*
+ * Send the Individual Address Setup command.
+ */
+ if (ie_ia_setup(sc, cmd) == 0)
+ return;
+
+ /*
+ * Run the time-domain reflectometer.
+ */
+ ie_run_tdr(sc, cmd);
+
+ /*
+ * Set the multi-cast filter, if any
+ */
+ if (ie_mc_setup(sc, cmd) == 0)
+ return;
+
+ /*
+ * If no tasks exist, create them. Need to add something to allow
+ * different names for the different devices.
+ */
+ if (sc->intr_task == 0)
+ sc->intr_task = rtems_bsdnet_newproc ("IEi0", 2048, i82586_intr_task, sc);
+ if (sc->tx_task == 0)
+ sc->tx_task = rtems_bsdnet_newproc ("IEt0", 2048, i82586_tx_task, sc);
+
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(sc, IE_ST_WHENCE);
+
+ /*
+ * Set up the transmit and recv buffers.
+ */
+ i82586_setup_bufs(sc);
+
+ if (sc->hwinit)
+ (sc->hwinit)(sc);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ if (NTXBUF < 2)
+ sc->do_xmitnopchain = 0;
+
+ i82586_start_transceiver(sc);
+}
+
+/*
+ * Start the RU and possibly the CU unit
+ */
+static void
+i82586_start_transceiver(struct ie_softc *sc)
+{
+#if I82586_DEBUG
+ I82586_TRACE(sc, I82586_RX_START, 0);
+#endif
+
+ /*
+ * Start RU at current position in frame & RBD lists.
+ */
+ sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,sc->rfhead),
+ IE_RBD_ADDR(sc->rbds, sc->rbhead));
+
+ sc->ie_bus_write16(sc, IE_SCB_RCVLST(sc->scb),
+ IE_RFRAME_ADDR(sc->rframes,sc->rfhead));
+
+ if (sc->do_xmitnopchain) {
+ /* Stop transmit command chain */
+ if (i82586_start_cmd(sc, IE_CUC_SUSPEND|IE_RUC_SUSPEND, 0, 0, 0))
+ printf("%s: CU/RU stop command timed out\n",
+ sc->arpcom.ac_if.if_name);
+
+ /* Start the receiver & transmitter chain */
+ /* sc->scb->ie_command_list =
+ IEADDR(sc->nop_cmds[(sc->xctail+NTXBUF-1) % NTXBUF]);*/
+ sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb),
+ IE_CMD_NOP_ADDR(
+ sc->nop_cmds,
+ (sc->xctail + NTXBUF - 1) % NTXBUF));
+
+ if (i82586_start_cmd(sc, IE_CUC_START|IE_RUC_START, 0, 0, 0))
+ printf("%s: CU/RU command timed out\n",
+ sc->arpcom.ac_if.if_name);
+ } else {
+ if (i82586_start_cmd(sc, IE_RUC_START, 0, 0, 0))
+ printf("%s: RU command timed out\n",
+ sc->arpcom.ac_if.if_name);
+ }
+}
+
+void
+i82586_stop(struct ifnet *ifp, int disable)
+{
+ struct ie_softc *sc = ifp->if_softc;
+
+ if (i82586_start_cmd(sc, IE_RUC_SUSPEND | IE_CUC_SUSPEND, 0, 0, 0))
+ printf("%s: iestop: disable commands timed out\n",
+ sc->arpcom.ac_if.if_name);
+}
+
+int
+i82586_ioctl(struct ifnet *ifp, int cmd, caddr_t data)
+{
+ struct ie_softc *sc = ifp->if_softc;
+// struct ifreq *ifr = (struct ifreq *)data;
+ int s;
+ int error = 0;
+
+ s = splnet();
+ switch(cmd) {
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ break;
+ case SIO_RTEMS_SHOW_STATS:
+#if I82586_DEBUG
+ print_softie(sc);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ ie_mc_reset(sc);
+ error = 0;
+ }
+ break;
+ }
+#if I82586_DEBUG
+ if (cmd == SIOCSIFFLAGS)
+ sc->sc_debug = (ifp->if_flags & IFF_DEBUG) ? IED_ALL : 0;
+#endif
+ splx(s);
+ return (error);
+}
+
+static void
+ie_mc_reset(struct ie_softc *sc)
+{
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ int size;
+
+ /*
+ * Step through the list of addresses.
+ */
+ again:
+ size = 0;
+ sc->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+ while (enm) {
+ size += 6;
+ if (sc->mcast_count >= IE_MAXMCAST ||
+ memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ sc->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ i82586_ioctl(&sc->arpcom.ac_if,
+ SIOCSIFFLAGS, (void *)0);
+ return;
+ }
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ if (size > sc->mcast_addrs_size) {
+ /* Need to allocate more space */
+ if (sc->mcast_addrs_size)
+ free(sc->mcast_addrs, M_IPMADDR);
+ sc->mcast_addrs = (char *)
+ malloc(size, M_IPMADDR, M_WAITOK);
+ sc->mcast_addrs_size = size;
+ }
+
+ /*
+ * We've got the space; now copy the addresses
+ */
+ ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
+ while (enm) {
+ if (sc->mcast_count >= IE_MAXMCAST)
+ goto again; /* Just in case */
+
+ memcpy(&sc->mcast_addrs[sc->mcast_count], enm->enm_addrlo, 6);
+ sc->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ sc->want_mcsetup = 1;
+}
+
+/*
+ * Media change callback.
+ */
+int
+i82586_mediachange(struct ifnet *ifp)
+{
+ struct ie_softc *sc = ifp->if_softc;
+
+ if (sc->sc_mediachange)
+ return ((*sc->sc_mediachange)(sc));
+ return (0);
+}
+
+/*
+ * Media status callback.
+ */
+void
+i82586_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct ie_softc *sc = ifp->if_softc;
+
+ if (sc->sc_mediastatus)
+ (*sc->sc_mediastatus)(sc, ifmr);
+}
+
+#if I82586_DEBUG
+static void
+print_softie(struct ie_softc *sc)
+{
+ static char *trace_labels[] = {
+ "INTS_REQ",
+ "INTS_IN",
+ "INTS_LOOPS",
+ "INTS_OUT",
+ "RX_INT",
+ "RX_DROP",
+ "RX_ERR",
+ "RX_OK",
+ "RX_START",
+ "START_TX",
+ "TX_START",
+ "TX_INT",
+ "TX_REQ",
+ "TX_EVT",
+ "TX_EMIT",
+ "TX_BAD",
+ "TX_ACTIVE",
+ "TRACE_CNT"
+ };
+
+ int i;
+
+ printf("i82586 %s:\n", sc->arpcom.ac_if.if_name);
+
+ printf(" iobase=%p\n", sc->sc_iobase);
+
+ printf(" scp=0x%08x\t\tiscp=0x%08x\t\tscb=0x%08x\n",
+ sc->scp, sc->iscp, sc->scb);
+ printf(" buf_area=0x%08x\tbuf_area_sz=0x%08x\n",
+ sc->buf_area, sc->buf_area_sz);
+ printf(" rframes=0x%08x\trbds=0x%08x\t\trbufs=0x%08x\n",
+ sc->rframes, sc->rbds, sc->rbufs);
+ printf(" nop_cmds=0x%08x\txmit_cmds=0x%08x\n",
+ sc->nop_cmds, sc->xmit_cmds);
+ printf(" xbds=0x%08x\txbufs=0x%08x\n\n",
+ sc->xbds, sc->xbufs);
+ printf(" rfhead=%d\trftail=%d\n",
+ sc->rfhead, sc->rftail);
+ printf(" rbhead=%d\trbtail=%d\n",
+ sc->rbhead, sc->rbtail);
+ printf(" nframes=%d\tnrxbuf=%d\trnr_expect=%d\n",
+ sc->nframes, sc->nrxbuf, sc->rnr_expect);
+ printf(" xchead=%d\txctail=%d\n",
+ sc->xchead, sc->xctail);
+ printf(" xmit_busy=%d\txmit_req=%d\tdo_xmitnopchain=%d\n",
+ sc->xmit_busy, sc->xmit_req, sc->do_xmitnopchain);
+ printf(" promisc=%d\tasync_cmd_inprogress=%d\n\n",
+ sc->promisc, sc->async_cmd_inprogress);
+
+ {
+ int cnt;
+ int in;
+ int lfdone = 0;
+ char *tabs;
+
+ if (!sc->trace_flow_wrap) {
+ cnt = sc->trace_flow_in;
+ in = 0;
+ }
+ else {
+ cnt = I82586_TRACE_FLOW;
+ in = sc->trace_flow_in;
+ }
+
+ sc->trace_flow_in = sc->trace_flow_wrap = 0;
+
+ cnt /= 2;
+
+ for (i = 0; i < cnt; i++) {
+ if (!lfdone) {
+ switch (sc->trace_flow[in]) {
+ case I82586_INTS_REQ:
+ case I82586_INTS_IN:
+ printf("\n");
+ }
+ }
+
+ lfdone = 0;
+
+ if (strlen(trace_labels[sc->trace_flow[in]]) < 8)
+ tabs = "\t\t";
+ else
+ tabs = "\t";
+
+ printf(" %d\t%s%s0x%08x (%d)\n",
+ i, trace_labels[sc->trace_flow[in]], tabs,
+ sc->trace_flow[in + 1], sc->trace_flow[in + 1]);
+
+ switch (sc->trace_flow[in]) {
+ case I82586_INTS_REQ:
+ case I82586_INTS_OUT:
+ lfdone = 1;
+ printf("\n");
+ }
+
+ in += 2;
+
+ if (in >= I82586_TRACE_FLOW)
+ in = 0;
+ }
+ }
+}
+
+static void
+print_rbd(struct ie_softc *sc, int n)
+{
+ printf("RBD at %08x:\n status %04x, next %04x, buffer %lx\n"
+ "length/EOL %04x\n", IE_RBD_ADDR(sc->rbds,n),
+ sc->ie_bus_read16(sc, IE_RBD_STATUS(sc->rbds,n)),
+ sc->ie_bus_read16(sc, IE_RBD_NEXT(sc->rbds,n)),
+ (u_long)0,/*bus_space_read_4(sc->bt, sc->bh, IE_RBD_BUFADDR(sc->rbds,n)),-* XXX */
+ sc->ie_bus_read16(sc, IE_RBD_BUFLEN(sc->rbds,n)));
+}
+
+#endif
diff --git a/c/src/libchip/network/i82586reg.h b/c/src/libchip/network/i82586reg.h
new file mode 100644
index 0000000000..bd5024563c
--- /dev/null
+++ b/c/src/libchip/network/i82586reg.h
@@ -0,0 +1,436 @@
+/* $NetBSD: i82586reg.h,v 1.7 1998/02/28 01:07:45 pk Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg.
+ *
+ * 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, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * 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 UNIVERSITY OR AUTHOR 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+/*
+ * NOTE, the structure definitions in here are for reference only.
+ * We use integer offsets exclusively to access the i82586 data structures.
+ */
+
+
+/*
+ * This is the master configuration block.
+ * It tells the hardware where all the rest of the stuff is.
+ *-
+struct __ie_sys_conf_ptr {
+ u_int16_t mbz; // must be zero
+ u_int8_t ie_bus_use; // true if 8-bit only
+ u_int8_t mbz2[5]; // must be zero
+ u_int32_t ie_iscp_ptr; // 24-bit physaddr of ISCP
+};
+ */
+#define IE_SCP_SZ 12
+#define IE_SCP_BUS_USE(base) ((base) + 2)
+#define IE_SCP_ISCP(base) ((base) + 8)
+
+/*
+ * Note that this is wired in hardware; the SCP is always located here, no
+ * matter what.
+ */
+#define IE_SCP_ADDR 0xfffff4
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ *-
+struct __ie_int_sys_conf_ptr {
+ u_int8_t ie_busy; // zeroed after init
+ u_int8_t mbz;
+ u_int16_t ie_scb_offset; // 16-bit physaddr of next struct
+ caddr_t ie_base; // 24-bit physaddr for all 16-bit vars
+};
+ */
+#define IE_ISCP_SZ 8
+#define IE_ISCP_BUSY(base) ((base) + 0)
+#define IE_ISCP_SCB(base) ((base) + 2)
+#define IE_ISCP_BASE(base) ((base) + 4)
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ *-
+struct __ie_sys_ctl_block {
+ u_int16_t ie_status; // status word
+ u_int16_t ie_command; // command word
+ u_int16_t ie_command_list; // 16-pointer to command block list
+ u_int16_t ie_recv_list; // 16-pointer to receive frame list
+ u_int16_t ie_err_crc; // CRC errors
+ u_int16_t ie_err_align; // Alignment errors
+ u_int16_t ie_err_resource; // Resource errors
+ u_int16_t ie_err_overrun; // Overrun errors
+};
+ */
+#define IE_SCB_SZ 16
+#define IE_SCB_STATUS(base) ((base) + 0)
+#define IE_SCB_CMD(base) ((base) + 2)
+#define IE_SCB_CMDLST(base) ((base) + 4)
+#define IE_SCB_RCVLST(base) ((base) + 6)
+#define IE_SCB_ERRCRC(base) ((base) + 8)
+#define IE_SCB_ERRALN(base) ((base) + 10)
+#define IE_SCB_ERRRES(base) ((base) + 12)
+#define IE_SCB_ERROVR(base) ((base) + 14)
+
+/* Command values */
+#define IE_RUC_MASK 0x0070 /* mask for RU command */
+#define IE_RUC_NOP 0 /* for completeness */
+#define IE_RUC_START 0x0010 /* start receive unit command */
+#define IE_RUC_RESUME 0x0020 /* resume a suspended receiver command */
+#define IE_RUC_SUSPEND 0x0030 /* suspend receiver command */
+#define IE_RUC_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CUC_MASK 0x0700 /* mask for CU command */
+#define IE_CUC_NOP 0 /* included for completeness */
+#define IE_CUC_START 0x0100 /* do-command command */
+#define IE_CUC_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CUC_SUSPEND 0x0300 /* suspend current command */
+#define IE_CUC_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_CX */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_FR */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_CNA */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CUC_MASK) == IE_CUC_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_CX 0x8000 /* command with I bit completed */
+#define IE_ST_FR 0x4000 /* frame received */
+#define IE_ST_CNA 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CUS_MASK 0x0700 /* mask for command unit status */
+#define IE_CUS_ACTIVE 0x0200 /* command unit is active */
+#define IE_CUS_SUSPEND 0x0100 /* command unit is suspended */
+
+#define IE_RUS_MASK 0x0070 /* mask for receiver unit status */
+#define IE_RUS_SUSPEND 0x0010 /* receiver is suspended */
+#define IE_RUS_NOSPACE 0x0020 /* receiver has no resources */
+#define IE_RUS_READY 0x0040 /* receiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ *-
+struct __ie_recv_frame_desc {
+ u_int16_t ie_fd_status; // status for this frame
+ u_int16_t ie_fd_last; // end of frame list flag
+ u_int16_t ie_fd_next; // 16-pointer to next RFD
+ u_int16_t ie_fd_buf_desc; // 16-pointer to list of buffer descs
+ struct __ie_en_addr dest; // destination ether
+ struct __ie_en_addr src; // source ether
+ u_int16_t ie_length; // 802 length/Ether type
+ u_short mbz; // must be zero
+};
+ */
+#define IE_RFRAME_SZ 24
+#define IE_RFRAME_ADDR(base,i) ((base) + (i) * IE_RFRAME_SZ)
+#define IE_RFRAME_STATUS(b,i) (IE_RFRAME_ADDR(b,i) + 0)
+#define IE_RFRAME_LAST(b,i) (IE_RFRAME_ADDR(b,i) + 2)
+#define IE_RFRAME_NEXT(b,i) (IE_RFRAME_ADDR(b,i) + 4)
+#define IE_RFRAME_BUFDESC(b,i) (IE_RFRAME_ADDR(b,i) + 6)
+#define IE_RFRAME_EDST(b,i) (IE_RFRAME_ADDR(b,i) + 8)
+#define IE_RFRAME_ESRC(b,i) (IE_RFRAME_ADDR(b,i) + 14)
+#define IE_RFRAME_ELEN(b,i) (IE_RFRAME_ADDR(b,i) + 20)
+
+/* "last" bits */
+#define IE_FD_EOL 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+/* status field bits */
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is ok */
+#define IE_FD_CRC 0x0800 /* CRC error */
+#define IE_FD_ALGN 0x0400 /* Alignment error */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+#define IE_FD_OVR 0x0100 /* DMA overrun */
+#define IE_FD_SHORT 0x0080 /* Short frame */
+#define IE_FD_NOEOF 0x0040 /* no EOF (?) */
+#define IE_FD_ERRMASK /* all error bits */ \
+ (IE_FD_CRC|IE_FD_ALGN|IE_FD_RNR|IE_FD_OVR|IE_FD_SHORT|IE_FD_NOEOF)
+#define IE_FD_STATUSBITS \
+ "\20\20COMPLT\17BUSY\16OK\14CRC\13ALGN\12RNR\11OVR\10SHORT\7NOEOF"
+
+/*
+ * linked list of buffers...
+ *-
+struct __ie_recv_buf_desc {
+ u_int16_t ie_rbd_status; // status for this buffer
+ u_int16_t ie_rbd_next; // 16-pointer to next RBD
+ caddr_t ie_rbd_buffer; // 24-pointer to buffer for this RBD
+ u_int16_t ie_rbd_length; // length of the buffer
+ u_int16_t mbz; // must be zero
+};
+ */
+#define IE_RBD_SZ 12
+#define IE_RBD_ADDR(base,i) ((base) + (i) * IE_RBD_SZ)
+#define IE_RBD_STATUS(b,i) (IE_RBD_ADDR(b,i) + 0)
+#define IE_RBD_NEXT(b,i) (IE_RBD_ADDR(b,i) + 2)
+#define IE_RBD_BUFADDR(b,i) (IE_RBD_ADDR(b,i) + 4)
+#define IE_RBD_BUFLEN(b,i) (IE_RBD_ADDR(b,i) + 8)
+
+/* RBD status fields */
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+#define IE_RBD_CNTMASK 0x3fff /* byte count of buffer data */
+
+/* RDB `End Of List' flag; encoded in `buffer length' field */
+#define IE_RBD_EOL 0x8000 /* last buffer */
+
+
+/*
+ * All commands share this in common.
+ *-
+struct __ie_cmd_common {
+ u_int16_t ie_cmd_status; // status of this command
+ u_int16_t ie_cmd_cmd; // command word
+ u_int16_t ie_cmd_link; // link to next command
+};
+ */
+#define IE_CMD_COMMON_SZ 6
+#define IE_CMD_COMMON_STATUS(base) ((base) + 0)
+#define IE_CMD_COMMON_CMD(base) ((base) + 2)
+#define IE_CMD_COMMON_LINK(base) ((base) + 4)
+
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+#define IE_STAT_ABORT 0x1000 /* command was aborted */
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * No-op commands; just like COMMON but "indexable"
+ */
+#define IE_CMD_NOP_SZ IE_CMD_COMMON_SZ
+#define IE_CMD_NOP_ADDR(base,i) ((base) + (i) * IE_CMD_NOP_SZ)
+#define IE_CMD_NOP_STATUS(b,i) (IE_CMD_NOP_ADDR(b,i) + 0)
+#define IE_CMD_NOP_CMD(b,i) (IE_CMD_NOP_ADDR(b,i) + 2)
+#define IE_CMD_NOP_LINK(b,i) (IE_CMD_NOP_ADDR(b,i) + 4)
+
+
+/*
+ * This is the command to transmit a frame.
+ *-
+struct __ie_xmit_cmd {
+ struct __ie_cmd_common com; // common part
+#define __ie_xmit_status com.ie_cmd_status
+
+ u_int16_t ie_xmit_desc; // pointer to buffer descriptor
+ struct __ie_en_addr ie_xmit_addr; // destination address
+ u_int16_t ie_xmit_length; // 802.3 length/Ether type field
+};
+ */
+#define IE_CMD_XMIT_SZ (IE_CMD_COMMON_SZ + 10)
+#define IE_CMD_XMIT_ADDR(base,i) ((base) + (i) * IE_CMD_XMIT_SZ)
+#define IE_CMD_XMIT_STATUS(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + 0) /* == CMD_COMMON_STATUS */
+#define IE_CMD_XMIT_CMD(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + 2) /* == CMD_COMMON_CMD */
+#define IE_CMD_XMIT_LINK(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + 4) /* == CMD_COMMON_LINK */
+#define IE_CMD_XMIT_DESC(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 0)
+#define IE_CMD_XMIT_EADDR(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 2)
+#define IE_CMD_XMIT_LEN(b,i) \
+ (IE_CMD_XMIT_ADDR(b,i) + IE_CMD_COMMON_SZ + 8)
+
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+#define IE_XS_LATECOLL 0x0800 /* Late collision */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ *-
+struct __ie_xmit_buf {
+ u_int16_t ie_xmit_flags; // see below
+ u_int16_t ie_xmit_next; // 16-pointer to next desc
+ caddr_t ie_xmit_buf; // 24-pointer to the actual buffer
+};
+ */
+#define IE_XBD_SZ 8
+#define IE_XBD_ADDR(base,i) ((base) + (i) * IE_XBD_SZ)
+#define IE_XBD_FLAGS(b,i) (IE_XBD_ADDR(b,i) + 0)
+#define IE_XBD_NEXT(b,i) (IE_XBD_ADDR(b,i) + 2)
+#define IE_XBD_BUF(b,i) (IE_XBD_ADDR(b,i) + 4)
+
+#define IE_TBD_EOL 0x8000 /* this TBD is the last one */
+#define IE_TBD_CNTMASK 0x3fff /* The rest of the `flags' word
+ is actually the length. */
+
+
+/*
+ * Multicast setup command.
+ *-
+struct __ie_mcast_cmd {
+ struct __ie_cmd_common com; // common part
+#define ie_mcast_status com.ie_cmd_status
+
+ // size (in bytes) of multicast addresses
+ u_short ie_mcast_bytes;
+ struct __ie_en_addr ie_mcast_addrs[IE_MAXMCAST + 1];// space for them
+};
+ */
+#define IE_CMD_MCAST_SZ (IE_CMD_COMMON_SZ + 2 /* + XXX */)
+#define IE_CMD_MCAST_BYTES(base) ((base) + IE_CMD_COMMON_SZ + 0)
+#define IE_CMD_MCAST_MADDR(base) ((base) + IE_CMD_COMMON_SZ + 2)
+
+/*
+ * Time Domain Reflectometer command.
+ *-
+struct __ie_tdr_cmd {
+ struct __ie_cmd_common com; // common part
+#define ie_tdr_status com.ie_cmd_status
+ u_short ie_tdr_time; // error bits and time
+};
+ */
+#define IE_CMD_TDR_SZ (IE_CMD_COMMON_SZ + 2)
+#define IE_CMD_TDR_TIME(base) ((base) + IE_CMD_COMMON_SZ + 0)
+
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an incorrect termination ("open") */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short circuit */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ *-
+struct __ie_iasetup_cmd {
+ struct __ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+ struct __ie_en_addr ie_address;
+};
+ */
+#define IE_CMD_IAS_SZ (IE_CMD_COMMON_SZ + 6)
+#define IE_CMD_IAS_EADDR(base) ((base) + IE_CMD_COMMON_SZ + 0)
+
+/*
+ * Configuration command
+ *-
+struct __ie_config_cmd {
+ struct __ie_cmd_common com; // common part
+#define ie_config_status com.ie_cmd_status
+
+ u_int8_t ie_config_count; // byte count (0x0c)
+ u_int8_t ie_fifo; // fifo (8)
+ u_int8_t ie_save_bad; // save bad frames (0x40)
+ u_int8_t ie_addr_len; // address length (0x2e) (AL-LOC == 1)
+ u_int8_t ie_priority; // priority and backoff (0x0)
+ u_int8_t ie_ifs; // inter-frame spacing (0x60)
+ u_int8_t ie_slot_low; // slot time, LSB (0x0)
+ u_int8_t ie_slot_high; // slot time, MSN, and retries (0xf2)
+ u_int8_t ie_promisc; // 1 if promiscuous, else 0
+ u_int8_t ie_crs_cdt; // CSMA/CD parameters (0x0)
+ u_int8_t ie_min_len; // min frame length (0x40)
+ u_int8_t ie_junk; // stuff for 82596 (0xff)
+};
+ */
+#define IE_CMD_CFG_SZ (IE_CMD_COMMON_SZ + 12)
+#define IE_CMD_CFG_CNT(base) ((base) + IE_CMD_COMMON_SZ + 0)
+#define IE_CMD_CFG_FIFO(base) ((base) + IE_CMD_COMMON_SZ + 1)
+#define IE_CMD_CFG_SAVEBAD(base) ((base) + IE_CMD_COMMON_SZ + 2)
+#define IE_CMD_CFG_ADDRLEN(base) ((base) + IE_CMD_COMMON_SZ + 3)
+#define IE_CMD_CFG_PRIORITY(base) ((base) + IE_CMD_COMMON_SZ + 4)
+#define IE_CMD_CFG_IFS(base) ((base) + IE_CMD_COMMON_SZ + 5)
+#define IE_CMD_CFG_SLOT_LOW(base) ((base) + IE_CMD_COMMON_SZ + 6)
+#define IE_CMD_CFG_SLOT_HIGH(base) ((base) + IE_CMD_COMMON_SZ + 7)
+#define IE_CMD_CFG_PROMISC(base) ((base) + IE_CMD_COMMON_SZ + 8)
+#define IE_CMD_CFG_CRSCDT(base) ((base) + IE_CMD_COMMON_SZ + 9)
+#define IE_CMD_CFG_MINLEN(base) ((base) + IE_CMD_COMMON_SZ + 10)
+#define IE_CMD_CFG_JUNK(base) ((base) + IE_CMD_COMMON_SZ + 11)
diff --git a/c/src/libchip/network/i82586var.h b/c/src/libchip/network/i82586var.h
new file mode 100644
index 0000000000..f250fe03d0
--- /dev/null
+++ b/c/src/libchip/network/i82586var.h
@@ -0,0 +1,319 @@
+/* $NetBSD: i82586var.h,v 1.15 2001/01/22 22:28:45 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg and Charles M. Hannum.
+ *
+ * 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, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1994, 1995, Rafal K. Boni
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of Vermont
+ * and State Agricultural College and Garrett A. Wollman, by William F.
+ * Jolitz, and by the University of California, Berkeley, Lawrence
+ * Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * 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 UNIVERSITY OR AUTHORS 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.
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Original StarLAN driver written by Garrett Wollman with reference to the
+ * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
+ *
+ * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
+ *
+ * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
+ *
+ * Majorly cleaned up and 3C507 code merged by Charles Hannum.
+ *
+ * Converted to SUN ie driver by Charles D. Cranor,
+ * October 1994, January 1995.
+ * This sun version based on i386 version 1.30.
+ */
+
+#ifndef I82586_DEBUG
+#define I82586_DEBUG 0
+#endif
+
+/* Debug elements */
+#define IED_RINT 0x01
+#define IED_TINT 0x02
+#define IED_RNR 0x04
+#define IED_CNA 0x08
+#define IED_READFRAME 0x10
+#define IED_ENQ 0x20
+#define IED_XMIT 0x40
+#define IED_ALL 0x7f
+
+#define B_PER_F 3 /* recv buffers per frame */
+#define IE_RBUF_SIZE 256 /* size of each receive buffer;
+ MUST BE POWER OF TWO */
+#define NTXBUF 2 /* number of transmit commands */
+#define IE_TBUF_SIZE ETHER_MAX_LEN /* length of transmit buffer */
+
+#define IE_MAXMCAST (IE_TBUF_SIZE/6)/* must fit in transmit buffer */
+
+
+#define INTR_ENTER 0 /* intr hook called on ISR entry */
+#define INTR_EXIT 1 /* intr hook called on ISR exit */
+#define INTR_LOOP 2 /* intr hook called on ISR loop */
+#define INTR_ACK 3 /* intr hook called on ie_ack */
+
+#define CHIP_PROBE 0 /* reset called from chip probe */
+#define CARD_RESET 1 /* reset called from card reset */
+
+#if I82586_DEBUG
+#define I82586_INTS_REQ 0
+#define I82586_INTS_IN 1
+#define I82586_INTS_LOOPS 2
+#define I82586_INTS_OUT 3
+#define I82586_RX_INT 4
+#define I82586_RX_DROP 5
+#define I82586_RX_ERR 6
+#define I82586_RX_OK 7
+#define I82586_RX_START 8
+#define I82586_START_TX 9
+#define I82586_TX_START 10
+#define I82586_TX_INT 11
+#define I82586_TX_REQ 12
+#define I82586_TX_EVT 13
+#define I82586_TX_EMIT 14
+#define I82586_TX_BAD 15
+#define I82586_TX_ACTIVE 16
+#define I82586_TRACE_CNT 17
+
+#define I82586_TRACE_FLOW (10000)
+#endif
+
+/*
+ * Ethernet status, per interface.
+ *
+ * The chip uses two types of pointers: 16 bit and 24 bit
+ * 24 bit pointers cover the board's memory.
+ * 16 bit pointers are offsets from the ISCP's `ie_base'
+ *
+ * The board's memory is represented by the bus handle `bh'. The MI
+ * i82586 driver deals exclusively with offsets relative to the
+ * board memory bus handle. The `ie_softc' fields below that are marked
+ * `MD' are in the domain of the front-end driver; they opaque to the
+ * MI driver part.
+ *
+ * The front-end is required to manage the SCP and ISCP structures. i.e.
+ * allocate room for them on the board's memory, and arrange to point the
+ * chip at the SCB stucture, the offset of which is passed to the MI
+ * driver in `sc_scb'.
+ *
+ * The following functions provide the glue necessary to deal with
+ * host and bus idiosyncracies:
+ *
+ * hwreset - board reset
+ * hwinit - board initialization
+ * chan_attn - get chip to look at prepared commands
+ * intrhook - board dependent interrupt processing
+ *
+ * All of the following shared-memory access function use an offset
+ * relative to the bus handle to indicate the shared memory location.
+ * The bus_{read/write}N function take or return offset into the
+ * shared memory in the host's byte-order.
+ *
+ * memcopyin - copy device memory: board to KVA
+ * memcopyout - copy device memory: KVA to board
+ * bus_read16 - read a 16-bit i82586 pointer
+ `offset' argument will be 16-bit aligned
+ * bus_write16 - write a 16-bit i82586 pointer
+ `offset' argument will be 16-bit aligned
+ * bus_write24 - write a 24-bit i82586 pointer
+ `offset' argument will be 32-bit aligned
+ * bus_barrier - perform a bus barrier operation, forcing
+ all outstanding reads/writes to complete
+ *
+ */
+
+struct ie_softc {
+ struct arpcom arpcom;
+
+ /*
+ * For RTEMS we run the tx and rx handlers under a task due to the
+ * network semaphore stuff.
+ */
+
+ rtems_id intr_task;
+ rtems_id tx_task;
+
+ void *sc_iobase; /* (MD) KVA of base of 24 bit addr space */
+ void *sc_maddr; /* (MD) KVA of base of chip's RAM
+ (16bit addr space) */
+ u_int sc_msize; /* (MD) how much RAM we have/use */
+
+ /* Bus glue */
+ void (*hwreset) (struct ie_softc *, int);
+ void (*hwinit) (struct ie_softc *);
+ void (*chan_attn) (struct ie_softc *, int);
+ int (*intrhook) (struct ie_softc *, int where);
+
+ void (*memcopyin) (struct ie_softc *, void *, int, size_t);
+ void (*memcopyout) (struct ie_softc *, const void *,
+ int, size_t);
+ u_int16_t (*ie_bus_read16) (struct ie_softc *, int offset);
+ void (*ie_bus_write16) (struct ie_softc *, int offset,
+ u_int16_t value);
+ void (*ie_bus_write24) (struct ie_softc *, int offset,
+ int addr);
+ void (*ie_bus_barrier) (struct ie_softc *, int offset,
+ int length, int flags);
+
+ /* Media management */
+ int (*sc_mediachange) (struct ie_softc *);
+ /* card dependent media change */
+ void (*sc_mediastatus) (struct ie_softc *, struct ifmediareq *);
+ /* card dependent media status */
+
+ /*
+ * Offsets (relative to bus handle) of the i82586 SYSTEM structures.
+ */
+ int scp; /* Offset to the SCP (set by front-end) */
+ int iscp; /* Offset to the ISCP (set by front-end) */
+ int scb; /* Offset to SCB (set by front-end) */
+
+ /*
+ * Offset and size of a block of board memory where the buffers
+ * are to be allocated from (initialized by front-end).
+ */
+ int buf_area; /* Start of descriptors and buffers */
+ int buf_area_sz; /* Size of above */
+
+ /*
+ * The buffers & descriptors (recv and xmit)
+ */
+ int rframes; /* Offset to `nrxbuf' frame descriptors */
+ int rbds; /* Offset to `nrxbuf' buffer descriptors */
+ int rbufs; /* Offset to `nrxbuf' receive buffers */
+#define IE_RBUF_ADDR(sc, i) (sc->rbufs + ((i) * IE_RBUF_SIZE))
+ int rfhead, rftail;
+ int rbhead, rbtail;
+ int nframes; /* number of frames in use */
+ int nrxbuf; /* number of recv buffs in use */
+ int rnr_expect; /* XXX - expect a RCVR not ready interrupt */
+
+ int nop_cmds; /* Offset to NTXBUF no-op commands */
+ int xmit_cmds; /* Offset to NTXBUF transmit commands */
+ int xbds; /* Offset to NTXBUF buffer descriptors */
+ int xbufs; /* Offset to NTXBUF transmit buffers */
+#define IE_XBUF_ADDR(sc, i) (sc->xbufs + ((i) * IE_TBUF_SIZE))
+
+ int xchead, xctail;
+ int xmit_busy;
+ int do_xmitnopchain; /* Controls use of xmit NOP chains */
+ int xmit_req;
+
+ /* Multicast addresses */
+ char *mcast_addrs; /* Current MC filter addresses */
+ int mcast_addrs_size; /* Current size of MC buffer */
+ int mcast_count; /* Current # of addrs in buffer */
+ int want_mcsetup; /* run mcsetup at next opportunity */
+
+ int promisc; /* are we in promisc mode? */
+ int async_cmd_inprogress; /* we didn't wait for 586 to accept
+ a command */
+
+#if I82586_DEBUG
+#define I82586_TRACE(s, e, d) \
+do { rtems_interrupt_level level; rtems_interrupt_disable (level); \
+ (s)->trace_flow[(s)->trace_flow_in++] = (e); \
+ (s)->trace_flow[(s)->trace_flow_in++] = (unsigned int)(d); \
+ if ((s)->trace_flow_in >= I82586_TRACE_FLOW) { \
+ (s)->trace_flow_in = 0; \
+ (s)->trace_flow_wrap = 1; \
+ } \
+ rtems_interrupt_enable (level); \
+ } while (0)
+
+ int sc_debug;
+ unsigned int trace_flow[I82586_TRACE_FLOW * 2];
+ unsigned int trace_flow_wrap;
+#endif
+ unsigned int trace_flow_in;
+};
+
+/* Exported functions */
+rtems_isr i82586_intr (rtems_vector_number , void *);
+int i82586_proberam (struct ie_softc *);
+int i82586_attach (struct rtems_bsdnet_ifconfig *config, int attaching);
+
+/* Shortcut macros to optional (driver uses default if unspecified) callbacks */
+#define xIE_BUS_BARRIER(sc, offset, length, flags) \
+do { \
+ if ((sc)->ie_bus_barrier) \
+ ((sc)->ie_bus_barrier)((sc), (offset), (length), (flags));\
+ else \
+ bus_space_barrier((sc)->bt, (sc)->bh, (offset), (length), \
+ (flags)); \
+} while (0)
+
+#define IE_BUS_BARRIER(sc, offset, length, flags)