summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1995-02-26 19:34:34 +0000
committerrgrimes <rgrimes@FreeBSD.org>1995-02-26 19:34:34 +0000
commit892bd7f135d907ae1536941f91acc6713e7b53ea (patch)
treebab6d0dc87179ae923a0fdaa871b3aea2879f2b6
parent79622643239b9e0bcea1f7f49479c0626c08d56f (diff)
downloadFreeBSD-src-892bd7f135d907ae1536941f91acc6713e7b53ea.zip
FreeBSD-src-892bd7f135d907ae1536941f91acc6713e7b53ea.tar.gz
Last 1.x version of Intel EtherExpress driver.
-rw-r--r--sys/i386/isa/if_ix.c1652
-rw-r--r--sys/i386/isa/if_ixreg.h330
2 files changed, 1982 insertions, 0 deletions
diff --git a/sys/i386/isa/if_ix.c b/sys/i386/isa/if_ix.c
new file mode 100644
index 0000000..16fb705
--- /dev/null
+++ b/sys/i386/isa/if_ix.c
@@ -0,0 +1,1652 @@
+#define DIAGNOSTIC
+/*
+ * Copyright (c) 1993 Rodney W. Grimes All rights reserved.
+ *
+ * $Id: if_ix.c,v 1.6 1993/12/14 10:18:38 root Exp root $
+ */
+
+#include "ix.h"
+#if NIX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_types.h"
+#include "net/if_dl.h"
+#include "net/netisr.h"
+#include "net/route.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif /* INET */
+
+#ifdef NS /*ZZZ no work done on this, this is just here to remind me*/
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif /* NS */
+
+#ifdef ISO /*ZZZ no work done on this, this is just here to remind me*/
+#include "netiso/iso.h"
+#include "netiso/iso_var.h"
+extern char all_es_snpa[], all_is_snpa[], all_l1is_snpa[], all_l2is_snpa[];
+#endif /* ISO */
+
+/*ZZZ no work done on this, this is just here to remind me*/
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif /* NBPFILTER > 0 */
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+
+#include "i386/include/pio.h"
+
+#include "i386/isa/if_ixreg.h"
+
+ix_softc_t ix_softc[NIX];
+
+#define DEBUGNONE 0x0000
+#define DEBUGPROBE 0x0001
+#define DEBUGATTACH (DEBUGPROBE << 1)
+#define DEBUGINIT (DEBUGATTACH << 1)
+#define DEBUGINIT_RFA (DEBUGINIT << 1)
+#define DEBUGINIT_TFA (DEBUGINIT_RFA << 1)
+#define DEBUGINTR (DEBUGINIT_TFA << 1)
+#define DEBUGINTR_FR (DEBUGINTR << 1)
+#define DEBUGINTR_CX (DEBUGINTR_FR << 1)
+#define DEBUGSTART (DEBUGINTR_CX << 1)
+#define DEBUGSTOP (DEBUGSTART << 1)
+#define DEBUGRESET (DEBUGSTOP << 1)
+#define DEBUGDONE (DEBUGRESET << 1)
+#define DEBUGIOCTL (DEBUGDONE << 1)
+#define DEBUGACK (DEBUGIOCTL << 1)
+#define DEBUGCA (DEBUGACK << 1)
+#define DEBUGCB_WAIT (DEBUGCA << 1)
+#define DEBUGALL 0xFFFFFFFF
+
+/*
+#define IXDEBUG (DEBUGPROBE | DEBUGINIT | DEBUGSTOP | DEBUGCB_WAIT)
+*/
+
+#ifdef IXDEBUG
+int ixdebug=IXDEBUG;
+#define DEBUGBEGIN(flag) \
+ {\
+ if (ixdebug & flag)\
+ {
+#define DEBUGEND \
+ }\
+ }
+#define DEBUGDO(x) x
+
+#else /* IXDEBUG */
+
+#define DEBUGBEGIN(flag)
+#define DEBUGEND
+#define DEBUGDO(x)
+#endif /* IXDEBUG */
+
+/*
+ * Enable the exteneded ixcounters by using #define IXCOUNTERS, note that
+ * this requires a modification to the ifnet structure to add the counters
+ * in. Some day a standard extended ifnet structure will be done so that
+ * additional statistics can be gathered for any board that supports these
+ * counters.
+ */
+#ifdef IXCOUNTERS
+#define IXCOUNTER(x) x
+#else /* IXCOUNTERS */
+#define IXCOUNTER(x)
+#endif /* IXCOUNTERS */
+
+/*
+ * Function Prototypes
+ */
+static inline void ixinterrupt_enable(int);
+static inline void ixinterrupt_disable(int);
+static inline void ixchannel_attention(int);
+u_short ixacknowledge(int);
+int ix_cb_wait(cb_t *, char *);
+int ix_scb_wait(scb_t *, u_short, char *);
+int ixprobe(struct isa_device *);
+int ixattach(struct isa_device *);
+void ixinit(int);
+void ixinit_rfa(int);
+void ixinit_tfa(int);
+int ixintr(int);
+static inline void ixintr_cx(int);
+static inline void ixintr_cx_free(int, cb_t *);
+static inline void ixintr_fr(int);
+static inline void ixintr_fr_copy(int, rfd_t *);
+static inline void ixintr_fr_free(int, rfd_t *);
+void ixstart(struct ifnet *);
+int ixstop(struct ifnet *);
+int ixdone(struct ifnet *);
+int ixioctl(struct ifnet *, int, caddr_t);
+void ixreset(int, int);
+void ixwatchdog(int);
+u_short ixeeprom_read(int, int);
+void ixeeprom_outbits(int, int, int);
+int ixeeprom_inbits(int);
+void ixeeprom_clock(int, int);
+/*
+RRR */
+
+struct isa_driver ixdriver = {ixprobe, ixattach, "ix"};
+
+/*
+ * Enable the interrupt signal on the board so that it may interrupt
+ * the host.
+ */
+static inline void
+ixinterrupt_enable(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+
+ outb(sc->iobase + sel_irq, sc->irq_encoded | IRQ_ENABLE);
+}
+
+/*
+ * Disable the interrupt signal on the board so that it will not interrupt
+ * the host.
+ */
+static inline void
+ixinterrupt_disable(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+
+ outb(sc->iobase + sel_irq, sc->irq_encoded);
+}
+
+/*
+ * Send a channel attention to the 82586 chip
+ */
+static inline void
+ixchannel_attention(int unit) {
+ DEBUGBEGIN(DEBUGCA)
+ DEBUGDO(printf("ca");)
+ DEBUGEND
+ outb(ix_softc[unit].iobase + ca_ctrl, 0);
+}
+
+u_short
+ixacknowledge(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ scb_t *scb = (scb_t *)(sc->maddr + SCB_ADDR);
+ u_short status;
+ int i;
+
+ DEBUGBEGIN(DEBUGACK)
+ DEBUGDO(printf("ack:");)
+ DEBUGEND
+ status = scb->status;
+ scb->command = status & SCB_ACK_MASK;
+ if ((status & SCB_ACK_MASK) != 0) {
+ ixchannel_attention(unit);
+ for (i = 1000000; scb->command && (i > 0); i--); /*ZZZ timeout*/
+ if (i == 0) {
+ printf(".TO=%x:", scb->command);
+ printf("\nshutting down\n");
+ ixinterrupt_disable(unit);
+ sc->flags = IXF_NONE;
+ status = 0;
+ } else {
+ DEBUGBEGIN(DEBUGACK)
+ DEBUGDO(printf(".ok:");)
+ DEBUGEND
+ }
+ } else {
+ /* nothing to acknowledge */
+ DEBUGBEGIN(DEBUGACK)
+ DEBUGDO(printf("NONE:");)
+ DEBUGEND
+ }
+ DEBUGBEGIN(DEBUGACK)
+ DEBUGDO(printf("%x ", status);)
+ DEBUGEND
+ return(status);
+}
+
+int
+ix_cb_wait(cb_t *cb, char *message) {
+ int i;
+ int status;
+
+ for (i=1000000; i>0; i--) {
+ if (cb->status & CB_COMPLETE) break; /* Wait for done */
+ }
+ if (i == 0) {
+ printf("%s timeout cb->status = %x\n", message, cb->status);
+ status = 1;
+ } else {
+ DEBUGBEGIN(DEBUGCB_WAIT)
+ DEBUGDO(printf("%s cb ok count = %d\n", message, i);)
+ DEBUGEND
+ status = 0;
+ }
+ return (status);
+}
+
+int
+ix_scb_wait(scb_t *scb, u_short expect, char *message) {
+ int i;
+ int status;
+
+ for (i=1000000; i>0; i--) {
+ if (scb->status == expect) break; /* Wait for done */
+ }
+ if (i == 0) {
+ printf("%s timeout scb->status = %x\n", message, scb->status);
+ status = 1;
+ } else {
+ DEBUGBEGIN(DEBUGINIT)
+ DEBUGDO(printf("%s scb ok count = %d\n", message, i);)
+ DEBUGEND
+ status = 0;
+ }
+ return (status);
+}
+
+int
+ixprobe(struct isa_device *dvp) {
+ int unit = dvp->id_unit;
+ ix_softc_t *sc = &ix_softc[unit];
+ char tempid, idstate;
+ int i;
+ int status = 0;
+ u_short boardid,
+ checksum,
+ connector,
+ eaddrtemp,
+ irq;
+ /* ZZZ irq_translate should really be unsigned, but until
+ * isa_device.h and all uses are fixed we have to live with it */
+ short irq_translate[] = {0, IRQ9, IRQ3, IRQ4, IRQ5, IRQ10, IRQ11, 0};
+
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("ixprobe:");)
+ DEBUGEND
+
+ /*
+ * Since Intel gives us such a nice way to ID this board lets
+ * see if we really have one at this I/O address
+ */
+ idstate = inb(dvp->id_iobase + autoid) & 0x03;
+ for (i=0, boardid=0; i < 4; i++) {
+ tempid = inb(dvp->id_iobase + autoid);
+ boardid |= ((tempid & 0xF0) >> 4) << ((tempid & 0x03) << 2);
+ if ((tempid & 0x03) != (++idstate & 0x03)) {
+ /* out of sequence, destroy boardid and bail out */
+ boardid = 0;
+ break;
+ }
+ }
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf("boardid = %x\n", boardid);)
+ DEBUGEND
+ if (boardid != BOARDID) {
+ goto ixprobe_exit;
+ }
+
+ /*
+ * We now know that we have a board, so save the I/O base
+ * address in the softc and use the softc from here on out
+ */
+ sc->iobase = dvp->id_iobase;
+
+ /*
+ * Reset the Bart ASIC by pulsing the reset bit and waiting
+ * the required 240 uSecounds. Also place the 82856 in the reset
+ * mode so that we can access the EEPROM
+ */
+ outb(sc->iobase + ee_ctrl, GA_RESET);
+ outb(sc->iobase + ee_ctrl, 0);
+ DELAY(240);
+ outb(sc->iobase + ee_ctrl, I586_RESET);
+
+ /*
+ * Checksum the EEPROM, should be equal to BOARDID
+ */
+ for (i=0, checksum=0; i<64; i++) {
+ checksum += ixeeprom_read(unit, i);
+ }
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("checksum = %x\n", checksum);)
+ DEBUGEND
+ if (checksum != BOARDID) {
+ goto ixprobe_exit;
+ }
+
+ /*
+ * Do the I/O channel ready test
+ */
+ {
+ u_char lock_bit;
+
+ lock_bit = ixeeprom_read(unit, eeprom_lock_address);
+ if (lock_bit & EEPROM_LOCKED) {
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("lockbit set, no doing io channel ready test\n");)
+ DEBUGEND
+ } else {
+ u_char bart_config,
+ junk;
+
+ bart_config = inb(sc->iobase + config);
+ bart_config |= BART_IOCHRDY_LATE | BART_IO_TEST_EN;
+ outb(sc->iobase + config, bart_config);
+ junk = inb(sc->iobase + 0x4000); /*XXX read junk */
+ bart_config = inb(sc->iobase + config);
+ outb(sc->iobase + config, bart_config & ~(BART_IO_TEST_EN));
+ if (bart_config & BART_IO_RESULT) {
+ printf ("iochannel ready test failed!!\n");
+ } else {
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("iochannel ready test passed\n");)
+ DEBUGEND
+ }
+ }
+ }
+
+ /*
+ * Size and test the memory on the board. The size of the memory
+ * can be one of 16k, 32k, 48k or 64k. It can be located in the
+ * address range 0xC0000 to 0xEFFFF on 16k boundaries. Although
+ * the board can be configured for 0xEC0000 to 0xEEFFFF,
+ * or 0xFC0000 to 0xFFFFFF these ranges are not supported by 386bsd.
+ *
+ * If the size does not match the passed in memory allocation size
+ * issue a warning, but continue with the minimum of the two sizes.
+ */
+ {
+ u_short memory_page;
+ u_short memory_adjust;
+ u_short memory_decode;
+ u_short memory_edecode;
+
+ switch (dvp->id_msize) {
+ case 65536:
+ case 32768: /* XXX Only support 32k and 64k right now */
+ { break; }
+ case 16384:
+ case 49512:
+ default: {
+ printf("ixprobe mapped memory size out of range\n");
+ goto ixprobe_exit;
+ }
+ }
+
+ if ((kvtop(dvp->id_maddr) < 0xC0000) ||
+ (kvtop(dvp->id_maddr) + dvp->id_msize > 0xF0000)) {
+ printf("ixprobe mapped memory address out of range\n");
+ goto ixprobe_exit;
+ }
+
+ memory_page = (kvtop(dvp->id_maddr) & 0x3C000) >> 14;
+ memory_adjust = MEMCTRL_FMCS16 | (memory_page & 0x3) << 2;
+ memory_decode = ((1 << (dvp->id_msize / 16384)) - 1) << memory_page;
+ memory_edecode = ((~memory_decode >> 4) & 0xF0) | (memory_decode >> 8);
+
+ /* ZZZ This should be checked against eeprom location 6, low byte */
+ outb(sc->iobase + memdec, memory_decode & 0xFF);
+ /* ZZZ This should be checked against eeprom location 1, low byte */
+ outb(sc->iobase + memctrl, memory_adjust);
+ /* ZZZ Now if I could find this one I would have it made */
+ outb(sc->iobase + mempc, (~memory_decode & 0xFF));
+ /* ZZZ I think this is location 6, high byte */
+ outb(sc->iobase + memectrl, memory_edecode); /*XXX disable Exxx */
+
+ sc->maddr = dvp->id_maddr;
+ sc->msize = dvp->id_msize;
+
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf("Physical address = %x\n", kvtop(sc->maddr));)
+ DEBUGEND
+ }
+
+ /*
+ * first prime the stupid bart DRAM controller so that it
+ * works, then zero out all or memory.
+ */
+ bzero(sc->maddr, 32);
+ bzero(sc->maddr, sc->msize);
+
+ /*
+ * Get the type of connector used, either AUI, BNC or TPE.
+ */
+ connector = ixeeprom_read(unit, eeprom_config1);
+ if (connector & CONNECT_BNCTPE) {
+ connector = ixeeprom_read(unit, eeprom_config2);
+ if (connector & CONNECT_TPE) {
+ sc->connector = TPE;
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("Using TPE connector\n");)
+ DEBUGEND
+ } else {
+ sc->connector = BNC;
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("Using BNC connector\n");)
+ DEBUGEND
+ }
+ } else {
+ sc->connector = AUI;
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("Using AUI connector\n");)
+ DEBUGEND
+ }
+
+ /*
+ * Get the encoded interrupt number from the EEPROM, check it
+ * against the passed in IRQ. Issue a warning if they do not
+ * match. Always use the passed in IRQ, not the one in the EEPROM.
+ */
+ irq = ixeeprom_read(unit, eeprom_config1);
+ irq = (irq & IRQ) >> IRQ_SHIFT;
+ sc->irq_encoded = irq;
+ irq = irq_translate[irq];
+ if (irq != dvp->id_irq) {
+ printf("Warning board is configured for IRQ %d\n", irq);
+ }
+
+ /*
+ * Get the slot width, either 8 bit or 16 bit.
+ */
+ if (inb(sc->iobase + config) & SLOT_WIDTH) {
+ sc->width = WIDTH_16;
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf("Using 16-bit slot\n");)
+ DEBUGEND
+ } else {
+ sc->width = WIDTH_8;
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf("Using 8-bit slot\n");)
+ DEBUGEND
+ }
+
+ /*
+ * Get the hardware ethernet address from the EEPROM and
+ * save it in the softc for use by the 586 setup code.
+ */
+ eaddrtemp = ixeeprom_read(unit, eeprom_enetaddr_high);
+ sc->arpcom.ac_enaddr[1] = eaddrtemp & 0xFF;
+ sc->arpcom.ac_enaddr[0] = eaddrtemp >> 8;
+ eaddrtemp = ixeeprom_read(unit, eeprom_enetaddr_mid);
+ sc->arpcom.ac_enaddr[3] = eaddrtemp & 0xFF;
+ sc->arpcom.ac_enaddr[2] = eaddrtemp >> 8;
+ eaddrtemp = ixeeprom_read(unit, eeprom_enetaddr_low);
+ sc->arpcom.ac_enaddr[5] = eaddrtemp & 0xFF;
+ sc->arpcom.ac_enaddr[4] = eaddrtemp >> 8;
+
+ sc->flags = IXF_NONE; /* make sure the flag word is NONE */
+ status = IX_IO_PORTS;
+
+ixprobe_exit:
+ DEBUGBEGIN(DEBUGPROBE)
+ DEBUGDO(printf ("ixprobe exited\n");)
+ DEBUGEND
+ return(status);
+}
+
+int
+ixattach(struct isa_device *dvp) {
+ int unit = dvp->id_unit;
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ DEBUGBEGIN(DEBUGATTACH)
+ DEBUGDO(printf("ixattach:");)
+ DEBUGEND
+
+ /*
+ * Fill in the interface parameters for if_attach
+ * Note: We could save some code here by first using a
+ * bzero(ifp, sizeof(ifp)); and then not doing all
+ * the = 0;'s
+ * Infact we should bzero this just to make sure
+ * that something does not get missed.
+ */
+ bzero(ifp, sizeof(ifp));
+ ifp->if_name = ixdriver.name;
+ ifp->if_unit = unit;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_NOTRAILERS | IFF_BROADCAST;
+ /*
+ * This is commented out to save memory and cpu time
+ * ifp->if_timer = 0;
+ * ifp->if_metric = 0;
+ * ifp->if_addrlist = 0;
+ * ifp->if_snd.ifq_head = 0;
+ * ifp->if_snd.ifq_tail = 0;
+ * ifp->if_snd.ifq_len = 0;
+ * ifp->if_snd.ifq_maxlen = 0;
+ * ifp->if_snd.ifq_drops = 0;
+ * end of commented out block
+ */
+ ifp->if_init = ixinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = ixstart;
+ ifp->if_done = ixdone;
+ ifp->if_ioctl = ixioctl;
+ ifp->if_reset = ixreset;
+ ifp->if_watchdog = ixwatchdog;
+ /*
+ * This is commented out to save memory and cpu time
+ * ifp->if_ipackets = 0;
+ * ifp->if_ierrors = 0;
+ * ifp->if_opackets = 0;
+ * ifp->if_oerrors = 0;
+ * ifp->if_collisions = 0;
+ * ifp->if_next = 0;
+ * end of commented out block
+ */
+ ifp->if_type = IFT_ETHER;
+ ifp->if_addrlen = ETHER_ADDRESS_LENGTH;
+ ifp->if_hdrlen = ETHER_HEADER_LENGTH;
+ /*
+ * This is commented out to save memory and cpu time
+ * ifp->if_index = 0;
+ * ifp->if_lastchange.tv_sec = 0;
+ * ifp->if_lastchange.tv_usec = 0;
+ * ifp->if_ibytes = 0;
+ * ifp->if_obytes = 0;
+ * ifp->if_imcasts = 0;
+ * ifp->if_omcasts = 0;
+ * ifp->if_iqdrops = 0;
+ * ifp->if_noproto = 0;
+ * ifp->if_baudrate = 0;
+ * ifp->if_pcount = 0;
+ * end of commented out block
+ */
+#ifdef IXCOUNTERS
+ /*
+ * ZZZ more counters added, but bzero gets them
+ */
+#endif /* IXCOUNTERS */
+
+ if_attach(ifp);
+
+ /* Search down the ifa address list looking for the AF_LINK type entry */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) &&
+ (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK)) {
+ ifa = ifa->ifa_next;
+ }
+ /* If we find an AF_LINK type entry, we well fill in the hardware addr */
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ /* Fill in the link level address for this interface */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDRESS_LENGTH;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDRESS_LENGTH);
+ }
+ printf("ix%d: address %s\n", unit, ether_sprintf(sc->arpcom.ac_enaddr));
+ return(0);
+}
+
+void
+ixinit(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ scp_t *scp = (scp_t *)(sc->maddr + SCP_ADDR);
+ iscp_t *iscp = (iscp_t *)(sc->maddr + ISCP_ADDR);
+ scb_t *scb = (scb_t *)(sc->maddr + SCB_ADDR);
+ cb_t *cb;
+ tbd_t *tbd;
+ int i;
+ u_char bart_config; /* bart config byte */
+ int status = 0;
+
+ DEBUGBEGIN(DEBUGINIT)
+ DEBUGDO(printf("ixinit:");)
+ DEBUGEND
+
+ /* Put bart into loopback until we are done intializing to
+ * make sure that packets don't hit the wire */
+ bart_config = inb(sc->iobase + config);
+ bart_config |= BART_LOOPBACK;
+ bart_config |= BART_MCS16_TEST; /* inb does not get this bit! */
+ outb(sc->iobase + config, bart_config);
+ bart_config = inb(sc->iobase + config);
+
+ scp->unused1 = 0; /* Intel says to put zeros in it */
+ scp->sysbus = sc->width; /* ZZZ need to fix for 596 */
+ scp->unused2 = 0; /* Intel says to put zeros in it */
+ scp->unused3 = 0; /* Intel says to put zeros in it */
+ scp->iscp = ISCP_ADDR;
+
+ iscp->busy = ISCP_BUSY;
+ iscp->scb_offset = SCB_ADDR;
+ iscp->scb_base = TFA_START;
+
+ scb->status = SCB_STAT_NULL;
+ scb->command = SCB_RESET;
+ scb->cbl_offset = TFA_START;
+ scb->rfa_offset = RFA_START;
+ scb->crc_errors = 0;
+ scb->aln_errors = 0;
+ scb->rsc_errors = 0;
+ scb->ovr_errors = 0;
+
+ ixinit_tfa(unit);
+ ixinit_rfa(unit);
+ cb = sc->cb_head;
+ tbd = sc->tbd_head;
+
+ /*
+ * remove the reset signal and start the 586 up, the 586 well read
+ * the SCP, ISCP and the reset CB. This should put it into a
+ * known state: RESET!
+ */
+ outb(sc->iobase + ee_ctrl, EENORMAL);
+ ixchannel_attention(unit);
+
+ for (i=100000; iscp->busy && (i>0); i--); /* Wait for done */
+ if (i == 0) {
+ printf("iscp->busy time out\n");
+ status = 1;
+ } else {
+ DEBUGBEGIN(DEBUGINIT)
+ DEBUGDO(printf ("iscp->busy did not timeout = %d\n", i);)
+ DEBUGEND
+ }
+
+ status |= ix_scb_wait(scb, (u_short)(SCB_STAT_CX | SCB_STAT_CNA),
+ "Reset");
+ ixacknowledge(unit);
+
+/* XXX this belongs some place else, run diagnostics on the 586 */
+ {
+ cb_diagnose_t *cb_diag = (cb_diagnose_t *)(cb);
+
+ cb_diag->common.status = 0;
+ cb_diag->common.command = CB_CMD_EL | CB_CMD_DIAGNOSE;
+ scb->command = SCB_CUC_START;
+ ixchannel_attention(unit);
+ status |= ix_cb_wait((cb_t *)cb_diag, "Diagnose");
+ status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Diagnose");
+ ixacknowledge(unit);
+ }
+/* XXX end this belongs some place else, run diagnostics on the 586 */
+
+/* XXX this belongs some place else, run configure on the 586 */
+ {
+ cb_configure_t *cb_conf = (cb_configure_t *)(cb);
+
+ cb_conf->common.status = 0;
+ cb_conf->common.command = CB_CMD_EL | CB_CMD_CONF;
+ cb_conf->byte[0] = 12; /* 12 byte configure block */
+ cb_conf->byte[1] = 8; /* fifo limit at 8 bytes */
+ cb_conf->byte[2] = 0x40; /* don't save bad frames,
+ srdy/ardy is srdy */
+ cb_conf->byte[3] = 0x2E; /* address length is 6 bytes,
+ address and length are in tb,
+ preamble length is 8 bytes,
+ internal loopback off,
+ external loopback off */
+ cb_conf->byte[4] = 0; /* linear priority is 0,
+ ACR (Exponential priorty) is 0,
+ exponential backoff is 802.3 */
+ cb_conf->byte[5] = 96; /* interframe spacing in TxC clocks */
+ cb_conf->byte[6] = 0; /* lower 8 bits of slot time */
+ cb_conf->byte[7] = 0xf2; /* upper slot time (512 bits),
+ 15 transmision retries */
+ cb_conf->byte[8] = 0; /* promiscuous mode off,
+ broadcast enabled,
+ nrz encodeing,
+ cease transmission if ^CRS,
+ insert crc,
+ end of carrier mode bit stuffing,
+ no padding */
+ cb_conf->byte[9] = 0; /* carrier sense filter = 0 bits,
+ carrier sense source external,
+ collision detect filter = 0 bits,
+ collision detect source external */
+ cb_conf->byte[10] = 60; /* minimum number of bytes is a frame */
+ cb_conf->byte[11] = 0; /* unused */
+
+ scb->command = SCB_CUC_START;
+ ixchannel_attention(unit);
+ status |= ix_cb_wait((cb_t *)cb_conf, "Configure");
+ status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "Configure");
+ ixacknowledge(unit);
+ }
+/* XXX end this belongs some place else, run configure on the 586 */
+
+/* XXX this belongs some place else, run ias on the 586 */
+ {
+ cb_ias_t *cb_ias = (cb_ias_t *)(cb);
+
+ cb_ias->common.status = 0;
+ cb_ias->common.command = CB_CMD_EL | CB_CMD_IAS;
+ bcopy(sc->arpcom.ac_enaddr, cb_ias->source, ETHER_ADDRESS_LENGTH);
+ scb->command = SCB_CUC_START;
+ ixchannel_attention(unit);
+ status |= ix_cb_wait((cb_t *)cb_ias, "IAS");
+ status |= ix_scb_wait(scb, (u_short)SCB_STAT_CNA, "IAS");
+ ixacknowledge(unit);
+ }
+/* XXX end this belongs some place else, run ias on the 586 */
+
+ if (status == 0) {
+ /* Take bart out of loopback as we are done intializing */
+ bart_config = inb(sc->iobase + config);
+ bart_config &= ~BART_LOOPBACK;
+ bart_config |= BART_MCS16_TEST; /* inb does not get this bit! */
+ outb(sc->iobase + config, bart_config);
+
+ /* The above code screwed with the tfa, reinit it! */
+ ixinit_tfa(unit);
+ scb->command = SCB_RUC_START; /* start up the receive unit */
+ ixchannel_attention(unit);
+ sc->flags |= IXF_INITED; /* we have been initialized */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ixinterrupt_enable(unit); /* Let err fly!!! */
+ }
+
+ DEBUGBEGIN(DEBUGINIT)
+ DEBUGDO(printf("ixinit exited\n");)
+ DEBUGEND
+ return;
+}
+
+/*
+ * ixinit_rfa(int unit)
+ *
+ * This routine initializes the Receive Frame Area for the 82586
+ *
+ * input the unit number to build the RFA for
+ * access the softc for memory address
+ * output an initialized RFA, ready for packet receiption
+ * the following queue pointers in the softc structure are
+ * also initialize
+ * sc->rfd_head sc->rfd_tail
+ * sc->rbd_head sc->rbd_tail
+ * defines RFA_START the starting offset of the RFA
+ * RFA_SIZE size of the RFA area
+ * RB_SIZE size of the receive buffer, this must
+ * be even and should be greater than the
+ * minumum packet size and less than the
+ * maximum packet size
+ */
+
+void
+ixinit_rfa(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ scb_t *scb;
+ rfd_t *rfd;
+ rbd_t *rbd;
+ caddr_t rb;
+ int i,
+ complete_frame_size,
+ how_many_frames;
+
+ DEBUGBEGIN(DEBUGINIT_RFA)
+ DEBUGDO(printf("\nix%d: ixinit_rfa\n", unit);)
+ DEBUGEND
+
+ complete_frame_size = sizeof(rfd_t) + sizeof(rbd_t) + RB_SIZE;
+ how_many_frames = RFA_SIZE / complete_frame_size;
+
+ /* build the list of rfd's, rbd's and rb's */
+ rfd = (rfd_t *)(sc->maddr + RFA_START);
+ rbd = (rbd_t *)(sc->maddr +
+ RFA_START +
+ (how_many_frames * sizeof(rfd_t)));
+ rb = sc->maddr + RFA_START +
+ (how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
+ sc->rfd_head = rfd;
+ sc->rbd_head = rbd;
+ for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
+ rfd->status = 0;
+ rfd->command = 0;
+ rfd->next = KVTOBOARD(rfd) + sizeof(rfd_t);
+ rfd->rbd_offset = INTEL586NULL;
+ /* ZZZ could bzero this, but just leave a note for now */
+ /* ZZZ bzero(rfd->destination); */
+ /* ZZZ bzero(rfd->source); */
+ rfd->length = 0;
+
+ rbd->act_count = 0;
+ rbd->next = KVTOBOARD(rbd) + sizeof(rbd_t);
+ rbd->buffer = KVTOBOARD(rb);
+ rbd->size = RB_SIZE;
+
+ /*
+ * handle the boundary conditions here. for the zeroth
+ * rfd we must set the rbd_offset to point at the zeroth
+ * rbd. for the last rfd and rbd we need to close the
+ * list into a ring and set the end of list bits.
+ */
+
+ if (i == 0) {
+ rfd->rbd_offset = KVTOBOARD(rbd);
+ }
+ if (i == how_many_frames - 1) {
+ rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
+ rfd->next = KVTOBOARD(sc->rfd_head);
+
+ rbd->next = KVTOBOARD(sc->rbd_head);
+ rbd->size = RBD_SIZE_EL | RB_SIZE;
+ }
+
+ }
+ sc->rfd_tail = (--rfd);
+ sc->rbd_tail = (--rbd);
+
+#ifdef IXDEBUG
+ DEBUGBEGIN(DEBUGINIT_RFA)
+ rfd = (rfd_t *)(sc->maddr + RFA_START);
+ rbd = (rbd_t *)(sc->maddr +
+ RFA_START +
+ (how_many_frames * sizeof(rfd_t)));
+ rb = sc->maddr + RFA_START +
+ (how_many_frames * (sizeof(rfd_t) + sizeof(rbd_t)));
+ printf(" complete_frame_size = %d\n", complete_frame_size);
+ printf(" how_many_frames = %d\n", how_many_frames);
+ printf(" rfd_head = %x\t\trfd_tail = %x\n",
+ kvtop(sc->rfd_head), kvtop(sc->rfd_tail));
+ printf(" rbd_head = %x\t\trbd_tail = %x\n",
+ kvtop(sc->rbd_head), kvtop(sc->rbd_tail));
+ for (i = 0; i < how_many_frames; i++, rfd++, rbd++, rb += RB_SIZE) {
+ printf(" %d:\trfd = %x\t\trbd = %x\t\trb = %x\n",
+ i, kvtop(rfd), kvtop(rbd), kvtop(rb));
+ printf("\trfd->command = %x\n", rfd->command);
+ printf("\trfd->next = %x\trfd->rbd_offset = %x\n",
+ rfd->next, rfd->rbd_offset);
+ printf("\trbd->next = %x\trbd->size = %x",
+ rbd->next, rbd->size);
+ printf("\trbd->buffer = %x\n\n",
+ rbd->buffer);
+ }
+ DEBUGEND
+#endif /* IXDEBUG */
+
+ /*
+ * ZZZ need to add sanity check to see if last rb runs into
+ * the stuff after it in memory, this should not be possible
+ * but if someone screws up with the defines it can happen
+ */
+ DEBUGBEGIN(DEBUGINIT_RFA)
+ DEBUGDO(printf (" next rb would be at %x\n", kvtop(rb));)
+ DEBUGDO(printf("ix%d: ixinit_rfa exit\n", unit);)
+ DEBUGEND
+}
+
+/*
+ * ixinit_tfa(int unit)
+ *
+ * This routine initializes the Transmit Frame Area for the 82586
+ *
+ * input the unit number to build the TFA for
+ * access the softc for memory address
+ * output an initialized TFA, ready for packet transmission
+ * the following queue pointers in the softc structure are
+ * also initialize
+ * sc->cb_head sc->cb_tail
+ * sc->tbd_head sc->tbd_tail
+ * defines TB_COUNT home many transmit buffers to create
+ * TB_SIZE size of the tranmit buffer, this must
+ * be even and should be greater than the
+ * minumum packet size and less than the
+ * maximum packet size
+ * TFA_START the starting offset of the TFA
+ */
+
+void
+ixinit_tfa(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ scb_t *scb;
+ cb_transmit_t *cb;
+ tbd_t *tbd;
+ caddr_t tb;
+ int i;
+
+ DEBUGBEGIN(DEBUGINIT_TFA)
+ DEBUGDO(printf("\nix%d: ixinit_tfa\n", unit);)
+ DEBUGEND
+
+ /* build the list of cb's, tbd's and tb's */
+ cb = (cb_transmit_t *)(sc->maddr + TFA_START);
+ tbd = (tbd_t *)(sc->maddr +
+ TFA_START +
+ (TB_COUNT * sizeof(cb_transmit_t)));
+ tb = sc->maddr + TFA_START +
+ (TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
+ sc->cb_head = (cb_t *)cb;
+ sc->tbd_head = tbd;
+ for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
+ cb->common.status = 0;
+ cb->common.command = CB_CMD_NOP;
+ cb->common.next = KVTOBOARD(cb) + sizeof(cb_transmit_t);
+ cb->tbd_offset = KVTOBOARD(tbd);
+ /* ZZZ could bzero this, but just leave a note for now */
+ /* ZZZ bzero(cb->destination); */
+ cb->length = 0;
+
+ tbd->act_count = 0;
+ tbd->act_count = TBD_STAT_EOF;
+ tbd->next = KVTOBOARD(tbd) + sizeof(tbd_t);
+ tbd->buffer = KVTOBOARD(tb);
+
+ /*
+ * handle the boundary conditions here.
+ */
+
+ if (i == TB_COUNT - 1) {
+ cb->common.command = CB_CMD_EL | CB_CMD_NOP;
+ cb->common.next = INTEL586NULL; /*RRR KVTOBOARD(sc->cb_head);*/
+ tbd->next = INTEL586NULL; /*RRR KVTOBOARD(sc->tbd_head);*/
+ }
+ }
+ sc->cb_tail = (cb_t *)(--cb);
+ sc->tbd_tail = (--tbd);
+
+#ifdef IXDEBUG
+ DEBUGBEGIN(DEBUGINIT_TFA)
+ cb = (cb_transmit_t *)(sc->maddr + TFA_START);
+ tbd = (tbd_t *)(sc->maddr +
+ TFA_START +
+ (TB_COUNT * sizeof(cb_transmit_t)));
+ tb = sc->maddr + TFA_START +
+ (TB_COUNT * (sizeof(cb_transmit_t) + sizeof(tbd_t)));
+ printf(" TB_COUNT = %d\n", TB_COUNT);
+ printf(" cb_head = %x\t\tcb_tail = %x\n",
+ kvtop(sc->cb_head), kvtop(sc->cb_tail));
+ printf(" tbd_head = %x\t\ttbd_tail = %x\n",
+ kvtop(sc->tbd_head), kvtop(sc->tbd_tail));
+ for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) {
+ printf(" %d:\tcb = %x\t\ttbd = %x\t\ttb = %x\n",
+ i, kvtop(cb), kvtop(tbd), kvtop(tb));
+ printf("\tcb->common.command = %x\n", cb->common.command);
+ printf("\tcb->common.next = %x\tcb->tbd_offset = %x\n",
+ cb->common.next, cb->tbd_offset);
+ printf("\ttbd->act_count = %x", tbd->act_count);
+ printf("\ttbd->next = %x", tbd->next);
+ printf("\ttbd->buffer = %x\n\n",
+ tbd->buffer);
+ }
+ DEBUGEND
+#endif /* IXDEBUG */
+
+ /*
+ * ZZZ need to add sanity check to see if last tb runs into
+ * the stuff after it in memory, this should not be possible
+ * but if someone screws up with the defines it can happen
+ */
+ DEBUGBEGIN(DEBUGINIT_TFA)
+ DEBUGDO(printf (" next tb would be at %x\n", kvtop(tb));)
+ DEBUGDO(printf("ix%d: ixinit_tfa exit\n", unit);)
+ DEBUGEND
+}
+
+int
+ixintr(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ scb_t *scb = (scb_t *)(sc->maddr + SCB_ADDR);
+ int check_queue; /* flag to tell us to check the queue */
+ u_short status;
+
+ DEBUGBEGIN(DEBUGINTR)
+ DEBUGDO(printf("ixintr: ");)
+ DEBUGEND
+
+ if ((sc->flags & IXF_INITED) == 0) {
+ printf ("\n ixintr without being inited!!\n"); /* ZZZ */
+ ixinterrupt_disable(unit);
+ goto ixintr_exit;
+ }
+ if (ifp->if_flags & IFF_RUNNING == 0) {
+ printf("\n ixintr when device not running!!\n"); /* ZZZ */
+ ixinterrupt_disable(unit);
+ goto ixintr_exit;
+ }
+
+ /* The sequence, disable ints, status=ack must be done
+ * as quick as possible to avoid missing things */
+ ixinterrupt_disable(unit);
+ status = ixacknowledge(unit);
+ check_queue = 0;
+ while ((status & SCB_STAT_MASK) != 0) {
+ if (status & SCB_STAT_FR) {
+ ixintr_fr(unit);
+ }
+ if (status & SCB_STAT_CX) {
+ ixintr_cx(unit);
+ check_queue++;
+ }
+ if (status & SCB_STAT_CNA) {
+ DEBUGBEGIN(DEBUGINTR)
+ DEBUGDO(printf("cna:");)
+ DEBUGEND
+ }
+ if ((status & SCB_STAT_RNR) ||
+ ((status & SCB_RUS_MASK) == SCB_RUS_NRSC)) {
+ DEBUGBEGIN(DEBUGINTR)
+ printf("RNR:"); /* ZZZ this means trouble */
+ DEBUGEND
+ IXCOUNTER(ifp->if_rnr++;)
+ ixinit_rfa(unit);
+ scb->status = SCB_STAT_NULL;
+ scb->command = SCB_RUC_START;
+ scb->rfa_offset = RFA_START;
+ ixchannel_attention(unit);
+ }
+ if (scb->status & SCB_STAT_MASK) {
+ status = ixacknowledge(unit);
+ } else {
+ status = 0;
+ }
+ }
+
+ ixinterrupt_enable(unit);
+ if (check_queue && ifp->if_snd.ifq_head != 0) {
+ ixstart(ifp); /* we have stuff on the queue */
+ }
+
+ixintr_exit:
+ DEBUGBEGIN(DEBUGINTR)
+ DEBUGDO(printf(" ixintr exited\n");)
+ DEBUGEND
+ return(0 /* XXX Should be ??? */);
+}
+
+static inline void
+ixintr_cx(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ cb_t *cb;
+
+ DEBUGBEGIN(DEBUGINTR_CX)
+ DEBUGDO(printf("cx:");)
+ DEBUGEND
+ cb = sc->cb_head;
+ do {
+ if (cb->status & CB_BUSY) {
+ IXCOUNTER(ifp->if_busy++;)
+ printf("ix.cx.busy"); /* This should never occur */
+ }
+ if (cb->status & CB_COMPLETE) {
+ IXCOUNTER(ifp->if_complete++;)
+ switch(cb->command & CB_CMD_MASK) {
+ case CB_CMD_NOP: { break; }
+ case CB_CMD_IAS: { break; }
+ case CB_CMD_CONF: { break; }
+ case CB_CMD_MCAS: { break; }
+ case CB_CMD_TRANSMIT: {
+ if (cb->status & CB_OK) {
+ ifp->if_opackets++;
+ IXCOUNTER(ifp->if_ok++;)
+ } else {
+ if (cb->status & CB_ABORT) {
+ IXCOUNTER(ifp->if_abort++;)
+ printf("ix.cx.abort");
+ }
+ if (cb->status & CB_LATECOLL) {
+ IXCOUNTER(ifp->if_latecoll++;)
+ printf("ix.cx.latecoll");
+ }
+ if (cb->status & CB_NOCS) {
+ IXCOUNTER(ifp->if_nocs++;)
+ printf("ix.cx.nocs");
+ }
+ if (cb->status & CB_NOCTS) {
+ IXCOUNTER(ifp->if_nocts++;)
+ printf("ix.cx.nocts");
+ }
+ if (cb->status & CB_DMAUNDER) {
+ IXCOUNTER(ifp->if_dmaunder++;)
+ printf("ix.cx.dmaunder");
+ }
+ if (cb->status & CB_DEFER) {
+ IXCOUNTER(ifp->if_defer++;)
+ printf("ix.cx.defer");
+ }
+ if (cb->status & CB_HEARTBEAT) {
+ IXCOUNTER(ifp->if_heartbeat++;)
+ printf("ix.cx.heartbeat");
+ }
+ if (cb->status & CB_EXCESSCOLL) {
+ IXCOUNTER(ifp->if_excesscoll++;)
+ printf("ix.cx.excesscoll");
+ }
+ ifp->if_oerrors++;
+ }
+ ifp->if_collisions += cb->status & CB_COLLISIONS;
+ ifp->if_timer = 0; /* clear watchdog timeout */
+ break;
+ }
+ case CB_CMD_TDR: { break; }
+ case CB_CMD_DUMP: { break; }
+ case CB_CMD_DIAGNOSE: { break; }
+ default: { break; }
+ }
+ ixintr_cx_free(unit, cb);
+ } else {
+ }
+ if (cb->next == INTEL586NULL) {
+ break;
+ } else {
+ cb = (cb_t *)BOARDTOKV(cb->next);
+ }
+ }
+ while (1);
+ /*
+ * clear the IFF_OACTIVE flag because the CU should now be
+ * idle, this only holds true as long as the last CB is the
+ * only one with the CB_CMD_INT bit set. If the start routine
+ * violates this rule this code well have to change.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ }
+
+static inline void
+ixintr_cx_free(int unit, cb_t *cb) {
+ ix_softc_t *sc = &ix_softc[unit];
+
+ DEBUGBEGIN(DEBUGINTR_CX)
+ DEBUGDO(printf("cb=%x:cb->status=%x:", KVTOBOARD(cb), cb->status);)
+ DEBUGEND
+/*1*/ cb->command = CB_CMD_EL | CB_CMD_NOP;
+/*2*/ cb->status = 0;
+}
+
+static inline void
+ixintr_fr(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+
+ DEBUGBEGIN(DEBUGINTR_FR)
+ DEBUGDO(printf("fr:");)
+ DEBUGEND
+ /* find each frame in the rfa and copy it up, then free it */
+ while ((sc->rfd_head->status & (RFD_COMPLETE | RFD_BUSY)) == RFD_COMPLETE) {
+ ixintr_fr_copy(unit, sc->rfd_head);
+ ixintr_fr_free(unit, sc->rfd_head);
+ }
+}
+
+static inline void
+ixintr_fr_copy(int unit, rfd_t *rfd) {
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ rbd_t *rbd;
+ caddr_t rb;
+ struct mbuf *m0, *m;
+ struct ether_header *eh;
+ int i,
+ length,
+ bytesleft;
+
+ rbd = (rbd_t *)(sc->maddr + rfd->rbd_offset);
+ rb = (caddr_t)(sc->maddr + rbd->buffer);
+ DEBUGBEGIN(DEBUGINTR_FR)
+ DEBUGDO(printf("rfd=%x:", KVTOBOARD(rfd));)
+ DEBUGDO(printf("rfd->status=%x:", rfd->status);)
+ DEBUGDO(printf("rbd->act_count=%x:", rbd->act_count);)
+ DEBUGDO(printf("data=");)
+ DEBUGDO(for (i = 0; i < 16; i ++) printf ("%02x", rb[i] & 0xFF);)
+ DEBUGDO(printf(":");)
+ DEBUGEND
+ /* trickery here, eh points right at memory on
+ * the board. eh is only used by ether_input,
+ * it is not passed to the upper layer */
+ eh = (struct ether_header *)rb;
+ /* ether_input expects the ether_type to be in host order */
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+
+ /* here we go, lets build an mbuf chain up to hold all this */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ printf ("MGETHDR:"); /* ZZZ need to add drop counters */
+ return;
+ }
+ m0 = m;
+ length = rbd->act_count & RBD_STAT_SIZE;
+ bytesleft = length - sizeof(struct ether_header);
+ rb += sizeof(struct ether_header);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = bytesleft;
+ m->m_len = MHLEN;
+ while (bytesleft > 0) {
+ if (bytesleft > MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT) {
+ m->m_len = MCLBYTES;
+ } else {
+ printf ("MCLGET:");
+ m_freem(m0); /* ZZZ need to add drop counters */
+ return;
+ }
+ }
+ m->m_len = min(m->m_len, bytesleft);
+ bcopy(rb, mtod(m, caddr_t), m->m_len);
+ rb += m->m_len;
+ bytesleft -= m->m_len;
+ if (bytesleft > 0) {
+ MGET(m->m_next, M_DONTWAIT, MT_DATA);
+ if (m->m_next == 0) {
+ printf ("MGET");
+ m_freem(m0); /* ZZZ need to add drop counters */
+ return;
+ }
+ m = m->m_next;
+ m->m_len = MLEN;
+ }
+ }
+
+ ether_input(ifp, eh, m0);
+ ifp->if_ipackets++;
+ return;
+}
+
+static inline void
+ixintr_fr_free(int unit, rfd_t *rfd) {
+ ix_softc_t *sc = &ix_softc[unit];
+ rbd_t *rbd;
+
+ rbd = (rbd_t *)(sc->maddr + rfd->rbd_offset);
+
+ /* XXX this still needs work, does not handle chained rbd's */
+/*1*/ rbd->act_count = 0;
+/*2*/ rbd->size = RBD_SIZE_EL | RB_SIZE;
+/*3*/ sc->rbd_tail->size = RB_SIZE;
+/*4*/ sc->rbd_tail = rbd;
+
+ /* Free the rfd buy putting it back on the rfd queue */
+/*1*/ rfd->command = RFD_CMD_EL | RFD_CMD_SUSP;
+/*2*/ rfd->status = 0;
+/*3*/ rfd->rbd_offset = INTEL586NULL;
+/*4*/ sc->rfd_head = (rfd_t *)BOARDTOKV(rfd->next);
+/*5*/ sc->rfd_tail->command &= ~(RFD_CMD_EL | RFD_CMD_SUSP);
+/*6*/ sc->rfd_tail = rfd;
+}
+
+/* Psuedo code:
+ * Do consistency check:
+ * IFF_UP should be set.
+ * IFF_RUNNING should be set.
+ * IFF_OACTIVE should be clear.
+ * ifp->snd.ifq_head should point to an MBUF
+ * I82586 CU should be in the idle state.
+ * All cb's should have CUC = NOP.
+ * The real work:
+ * while there are packets to send & free cb's do:
+ * build a cb, tbd, and tb
+ * copy the MBUF chain to a tb
+ * setup the scb for a start CU
+ * start the CU
+ * set IFF_OACTIVE
+ * set ifp->if_timer for watchdog timeout
+ * Exit:
+ */
+void
+ixstart(struct ifnet *ifp) {
+ int unit = ifp->if_unit;
+ ix_softc_t *sc = &ix_softc[unit];
+ scb_t *scb = (scb_t *)BOARDTOKV(SCB_ADDR);
+ cb_t *cb = sc->cb_head;
+ tbd_t *tbd;
+ caddr_t tb;
+ struct mbuf *m, *m_temp;
+ u_short length;
+ IXCOUNTER(int queued;)
+
+ DEBUGBEGIN(DEBUGSTART)
+ DEBUGDO(printf("ixstart:");)
+ DEBUGEND
+
+ /* check that if is up and running */
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) {
+ goto ixstart_exit;
+ }
+
+ /* check to see that we are not already active */
+ if ((ifp->if_flags & IFF_OACTIVE) == IFF_OACTIVE) {
+ goto ixstart_exit;
+ }
+
+ /* check that there are packets to send */
+ if (ifp->if_snd.ifq_head == 0) {
+ goto ixstart_exit;
+ }
+
+ /* check that the command unit is idle */
+ if ((scb->status & SCB_CUS_MASK) != SCB_CUS_IDLE) {
+ goto ixstart_exit;
+ }
+
+ /* check that all cb's on the list are free */
+#ifdef THISDONTDONOTHING
+ cb = sc->cb_head;
+ IXCOUNTER(ifp->if_could_queue = 0;)
+ do {
+ /* XXX this does nothing right now! */
+ DEBUGBEGIN(DEBUGSTART)
+ DEBUGDO(printf("chk_cb=%x:", KVTOBOARD(cb));)
+ DEBUGEND
+ IXCOUNTER(ifp->if_could_queue++;)
+ if (cb->next == INTEL586NULL) {
+ break;
+ } else {
+ cb = (cb_t *)BOARDTOKV(cb->next);
+ }
+ }
+ while (1);
+#endif /* THISDONTDONOTHING */
+
+ /* build as many cb's as we can */
+ IXCOUNTER(queued = 0;)
+ cb = sc->cb_head;
+ do {
+ cb->status = 0;
+ cb->command = CB_CMD_TRANSMIT;
+ tbd = (tbd_t *)BOARDTOKV(((cb_transmit_t *)cb)->tbd_offset);
+ tb = (caddr_t)BOARDTOKV(tbd->buffer);
+ DEBUGBEGIN(DEBUGSTART)
+ DEBUGDO(printf("cb=%x:", KVTOBOARD(cb));)
+ DEBUGDO(printf("tbd=%x:", KVTOBOARD(tbd));)
+ DEBUGDO(printf("tb=%x:", KVTOBOARD(tb));)
+ DEBUGEND
+
+ IF_DEQUEUE(&ifp->if_snd, m);
+ length = 0;
+ for (m_temp = m; m_temp != 0; m_temp = m_temp->m_next) {
+ bcopy(mtod(m_temp, caddr_t), tb, m_temp->m_len);
+ tb += m_temp->m_len;
+ length += m_temp->m_len;
+ }
+ m_freem(m);
+ if (length < ETHER_MIN_LENGTH) length = ETHER_MIN_LENGTH;
+#ifdef DIAGNOSTIC
+ if (length > ETHER_MAX_LENGTH) {
+ /* XXX
+ * This should never ever happen, if it does
+ * we probable screwed up all sorts of board data
+ * in the above bcopy's and should probably shut
+ * down, but for now just issue a warning that
+ * something is real wrong
+ */
+ printf("ix%d: ixstart: Packet length=%d > MTU=%d\n",
+ unit, length, ETHER_MAX_LENGTH);
+ }
+#endif /* DIAGNOSTIC */
+ tbd->act_count = TBD_STAT_EOF | length;
+ IXCOUNTER(queued++;)
+ /* check to see if we have used the last cb */
+ if (cb->next == INTEL586NULL) {
+ IXCOUNTER(ifp->if_filled_queue++;)
+ break;
+ } else {
+ cb = (cb_t *)BOARDTOKV(cb->next);
+ }
+ } while (ifp->if_snd.ifq_head != 0);
+ IXCOUNTER(ifp->if_high_queue = max(ifp->if_high_queue, queued);)
+
+ /* set the end of list and interrupt bits in the last cb */
+ cb->command |= (CB_CMD_EL | CB_CMD_INT);
+
+ /* build the scb */
+ scb->status = SCB_STAT_NULL;
+ scb->command = SCB_CUC_START;
+ scb->cbl_offset = KVTOBOARD(sc->cb_head);/* This should not be needed */
+
+ /* start the cu */
+ ixchannel_attention(unit);
+
+ /* mark the interface as having output active */
+ ifp->if_flags |= IFF_OACTIVE;
+
+ /*
+ * set the watchdog timer so that if the board fails to interrupt
+ * we will go clean up
+ */
+ ifp->if_timer = 2;
+
+ixstart_exit:
+ DEBUGBEGIN(DEBUGSTART)
+ DEBUGDO(printf("ixstart exited\n");)
+ DEBUGEND
+ return;
+}
+
+int
+ixstop(struct ifnet *ifp) {
+ int unit = ifp->if_unit;
+ ix_softc_t *sc = &ix_softc[unit];
+ scp_t *scp = (scp_t *)(sc->maddr + SCP_ADDR);
+ iscp_t *iscp = (iscp_t *)(sc->maddr + ISCP_ADDR);
+ scb_t *scb = (scb_t *)(sc->maddr + SCB_ADDR);
+ cb_t *cb;
+ tbd_t *tbd;
+
+ DEBUGBEGIN(DEBUGSTOP)
+ DEBUGDO(printf("ixstop:");)
+ DEBUGEND
+
+ /* XXX Need to find out what spl we are at, and maybe add splx */
+
+ ifp->if_flags &= ~IFF_RUNNING;
+ ixinterrupt_disable(unit);
+
+ /* force the 82586 reset pin high */
+ outb(sc->iobase + ee_ctrl, I586_RESET);
+
+ DEBUGBEGIN(DEBUGSTOP)
+ DEBUGDO(printf("ixstop exiting\n");)
+ DEBUGEND
+ return(0);
+}
+
+/*
+ * I can't find any calls to if_done, it may be deprecated, but I left
+ * it here until I find out. rwgrimes 1993/01/15
+ */
+int
+ixdone(struct ifnet *ifp) {
+ DEBUGBEGIN(DEBUGDONE)
+ DEBUGDO(printf("ixdone:");)
+ DEBUGEND
+ DEBUGBEGIN(DEBUGDONE)
+ DEBUGDO(printf("ixdone exited\n");)
+ DEBUGEND
+ return(0);
+}
+
+int
+ixioctl(struct ifnet *ifp, int cmd, caddr_t data) {
+ int unit = ifp->if_unit;
+ int status = 0;
+
+ DEBUGBEGIN(DEBUGIOCTL)
+ DEBUGDO(printf("ixioctl:");)
+ DEBUGEND
+ switch(cmd) {
+
+ case SIOCSIFADDR: {
+ struct ifaddr *ifa = (struct ifaddr *)data;
+
+ if (ifp->if_flags & IFF_RUNNING) ixstop(ifp);
+ ifp->if_flags |= IFF_UP;
+ ixinit(unit);
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET: {
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+ }
+#endif /* INET */
+#ifdef NS
+ case AF_NS: {
+ /*ZZZ*/printf("Address family NS not supported by ixioctl\n");
+ break;
+ }
+#endif /* NS */
+ default: {
+ DEBUGBEGIN(DEBUGIOCTL)
+ DEBUGDO(printf("Unknow Address Family in ixioctl\n");)
+ DEBUGEND
+ status = EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+
+ case SIOCSIFFLAGS: {
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ixstop(ifp);
+ }
+ else if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0)) {
+ ixinit(unit);
+ }
+ break;
+ }
+
+ default: {
+ DEBUGBEGIN(DEBUGIOCTL)
+ DEBUGDO(printf("Unknown cmd in ixioctl\n");)
+ DEBUGEND
+ status = EINVAL;
+ break;
+ }
+ }
+
+ DEBUGBEGIN(DEBUGIOCTL)
+ DEBUGDO(printf("ixioctl exit\n");)
+ DEBUGEND
+ return(status);
+}
+
+void
+ixreset(int unit, int uban) { /* XXX uban is no longer used!!! */
+ ix_softc_t *sc = &ix_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s;
+
+ s = splimp();
+ DEBUGBEGIN(DEBUGRESET)
+ DEBUGDO(printf("ixreset:");)
+ DEBUGEND
+
+ ixstop(ifp);
+ ixinit(unit);
+
+ DEBUGBEGIN(DEBUGRESET)
+ DEBUGDO(printf("ixreset exit\n");)
+ DEBUGEND
+ (void) splx(s);
+ return;
+}
+/*
+ * The ixwatchdog routine gets called if the transmitter failed to interrupt
+ * within ifp->if_timer XXXseconds. The interrupt service routine must reset
+ * ifp->if_timer to 0 after an transmitter interrupt occurs to stop the
+ * watchdog from happening.
+ */
+void
+ixwatchdog(int unit) {
+ ix_softc_t *sc = &ix_softc[unit];
+
+ log(LOG_ERR, "ix%d: device timeout\n", unit);
+ sc->arpcom.ac_if.if_oerrors++;
+ ixreset(unit,unit);
+ return;
+}
+
+u_short
+ixeeprom_read(int unit, int location) {
+ int eeprom_control,
+ data;
+
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ eeprom_control &= 0xB2; /* XXX fix 0xB2 */
+ eeprom_control |= EECS;
+ outb(ix_softc[unit].iobase + ee_ctrl, eeprom_control);
+ ixeeprom_outbits(unit, eeprom_read_op, eeprom_opsize1);
+ ixeeprom_outbits(unit, location, eeprom_addr_size);
+ data = ixeeprom_inbits(unit);
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ eeprom_control &= ~(GA_RESET | EEDI | EECS);
+ outb(ix_softc[unit].iobase + ee_ctrl, eeprom_control);
+ ixeeprom_clock(unit, 1);
+ ixeeprom_clock(unit, 0);
+ return(data);
+}
+
+void
+ixeeprom_outbits(int unit, int data, int count) {
+ int eeprom_control,
+ i;
+
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ eeprom_control &= ~GA_RESET;
+ for(i=count-1; i>=0; i--) {
+ eeprom_control &= ~EEDI;
+ if (data & (1 << i)) {
+ eeprom_control |= EEDI;
+ }
+ outb(ix_softc[unit].iobase + ee_ctrl, eeprom_control);
+ DELAY(1); /* eeprom data must be setup for 0.4 uSec */
+ ixeeprom_clock(unit, 1);
+ ixeeprom_clock(unit, 0);
+ }
+ eeprom_control &= ~EEDI;
+ outb(ix_softc[unit].iobase + ee_ctrl, eeprom_control);
+ DELAY(1); /* eeprom data must be held for 0.4 uSec */
+}
+
+int
+ixeeprom_inbits(int unit) {
+ int eeprom_control,
+ data,
+ i;
+
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ eeprom_control &= ~GA_RESET;
+ for(data=0, i=0; i<16; i++) {
+ data = data << 1;
+ ixeeprom_clock(unit, 1);
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ if (eeprom_control & EEDO) {
+ data |= 1;
+ }
+ ixeeprom_clock(unit, 0);
+ }
+ return(data);
+}
+
+void
+ixeeprom_clock(int unit, int state) {
+ int eeprom_control;
+
+ eeprom_control = inb(ix_softc[unit].iobase + ee_ctrl);
+ eeprom_control &= ~(GA_RESET | EESK);
+ if (state) {
+ eeprom_control = eeprom_control | EESK;
+ }
+ outb(ix_softc[unit].iobase + ee_ctrl, eeprom_control);
+ DELAY(9); /* EESK must be stable for 8.38 uSec */
+}
+
+#endif /* NIX > 0 */
diff --git a/sys/i386/isa/if_ixreg.h b/sys/i386/isa/if_ixreg.h
new file mode 100644
index 0000000..268a4da
--- /dev/null
+++ b/sys/i386/isa/if_ixreg.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 1993 Rodney W. Grimes All rights reserved.
+ *
+ * $Id: if_ixreg.h,v 1.4 1993/12/14 10:18:45 root Exp root $
+ */
+
+/*
+ * These really belong some place else, but I can't find them right
+ * now. I'll look again latter
+ */
+#define ETHER_ADDRESS_LENGTH 6 /* Length of an ethernet address */
+#define ETHER_HEADER_LENGTH 14 /* Length of an ethernet header */
+#define ETHER_DATA_LENGTH ETHERMTU
+#define ETHER_CRC_LENGTH 4
+#define ETHER_MIN_LENGTH 64 /* Minimum length of an ethernet packet */
+#define ETHER_MAX_LENGTH (ETHER_HEADER_LENGTH + \
+ ETHERMTU + \
+ ETHER_CRC_LENGTH)
+
+#define IX_IO_PORTS 16 /* Number of I/O ports used, note
+ * this is not true, due to shadow
+ * ports at 400X,800X and C00X
+ */
+
+#define dxreg 0x00 /* Data transfer register Word R/W */
+#define wrptr 0x02 /* Write address pointer Word R/W */
+#define rdptr 0x04 /* Read address pointer Word R/W */
+#define ca_ctrl 0x06 /* Channel attention control Byte R/W */
+#define sel_irq 0x07 /* IRQ select Byte R/W */
+#define IRQ_ENABLE 0x08 /* Enable board interrupts */
+#define smb_ptr 0x08 /* Shadow memory bank pointer Word R/W */
+#define memdec 0x0A /* Memory address decode Byte W */
+#define memctrl 0x0B /* Memory mapped control Byte R/W */
+#define MEMCTRL_UNUSED 0x83 /* Unused bits */
+#define MEMCTRL_MEMMEG 0x60 /* Which megabyte of memory, 0, E or F */
+#define MEMCTRL_FMCS16 0x10 /* MEMCS16- for F000 */
+#define MEMCTRL_MEMADJ 0xC0 /* memory adjust value */
+#define mempc 0x0C /* MEMCS16- page control Byte R/W */
+#define config 0x0D /* Configuration, test Byte R/W */
+#define BART_LINK 0x01 /* link integrity active, TPE */
+#define BART_LOOPBACK 0x02 /* Loopback, 0=none, 1=loopback */
+#define SLOT_WIDTH 0x04 /* 0 = 8bit, 1 = 16bit */
+#define BART_USEWIDTH 0x08 /* use SLOT_WIDTH for bus size */
+#define BART_IOCHRDY_LATE 0x10 /* iochrdy late control bit */
+#define BART_IO_TEST_EN 0x20 /* enable iochrdy timing test */
+#define BART_IO_RESULT 0x40 /* result of the iochrdy test */
+#define BART_MCS16_TEST 0x80 /* enable memcs16 select test */
+#define ee_ctrl 0x0E /* EEPROM control, reset Byte R/W */
+#define EENORMAL 0x00 /* normal state of ee_ctrl */
+#define EESK 0x01 /* EEPROM clock bit */
+#define EECS 0x02 /* EEPROM chip select */
+#define EEDI 0x04 /* EEPROM data in bit (write EEPROM) */
+#define EEDO 0x08 /* EEPROM data out bit (read EEPROM) */
+#define EEUNUSED 0x30 /* unused bits in ee_ctrl */
+#define GA_RESET 0x40 /* BART ASIC chip reset pin */
+#define I586_RESET 0x80 /* 82586 chip reset pin */
+#define memectrl 0x0F /* Memory control, E000h seg Byte W */
+#define autoid 0x0F /* Auto ID register Byte R */
+
+#define BOARDID 0xBABA /* Intel PCED board ID for EtherExpress */
+
+#define eeprom_opsize1 0x03 /* Size of opcodes for r/w/e */
+#define eeprom_read_op 0x06 /* EEPROM read op code */
+#define eeprom_write_op 0x05 /* EEPROM write op code */
+#define eeprom_erase_op 0x07 /* EEPROM erase op code */
+#define eeprom_opsize2 0x05 /* Size of opcodes for we/wdr */
+#define eeprom_wenable_op 0x13 /* EEPROM write enable op code */
+#define eeprom_wdisable_op 0x10 /* EEPROM write disable op code */
+
+#define eeprom_addr_size 0x06 /* Size of EEPROM address */
+
+/* These are the locations in the EEPROM */
+#define eeprom_config1 0x00 /* Configuration register 1 */
+#define CONNECT_BNCTPE 0x1000 /* 0 = AUI, 1 = BNC/TPE */
+#define IRQ 0xE000 /* Encoded IRQ */
+#define IRQ_SHIFT 13 /* To shift IRQ to lower bits */
+#define eeprom_lock_address 0x01 /* contains the lock bit */
+#define EEPROM_LOCKED 0x01 /* means that it is locked */
+#define eeprom_enetaddr_low 0x02 /* Ethernet address, low word */
+#define eeprom_enetaddr_mid 0x03 /* Ethernet address, middle word */
+#define eeprom_enetaddr_high 0x04 /* Ethernet address, high word */
+#define eeprom_config2 0x05 /* Configureation register 2 */
+#define CONNECT_TPE 0x0001 /* 0 = BNC, 1 = TPE */
+
+/* this converts a kernal virtual address to a board offset */
+#define KVTOBOARD(addr) ((int)addr - (int)sc->maddr)
+#define BOARDTOKV(addr) ((int)addr + (int)sc->maddr)
+
+/* XXX This belongs is ic/i825x6.h, but is here for editing for now */
+
+#define INTEL586NULL 0xFFFF /* NULL pointer for 82586 */
+#define INTEL596NULL 0xFFFFFFFF /* NULL pointer for 82596 */
+
+/*
+ * Layout of memory for the 825x6 chip:
+ * Low: Control Blocks
+ * Transmit Frame Descriptor(s)
+ * Transmit Frame Buffer(s)
+ * Receive Frame Descriptors
+ * Receive Frames
+ * SCB_ADDR System Control Block
+ * ISCP_ADDR Intermediate System Configuration Pointer
+ * High: SCP_ADDR System Configuration Pointer
+ */
+#define SCP_ADDR (sc->msize - sizeof(scp_t))
+#define ISCP_ADDR (SCP_ADDR - sizeof(iscp_t))
+#define SCB_ADDR (ISCP_ADDR - sizeof(scb_t))
+
+#define TB_COUNT 3 /* How many transfer buffers in the TFA */
+#define TB_SIZE (ETHER_MAX_LENGTH) /* size of transmit buffer */
+#define TFA_START 0x0000 /* Start of the TFA */
+#define TFA_SIZE (TB_COUNT * \
+ (sizeof(cb_transmit_t) + sizeof(tbd_t) + TB_SIZE))
+
+#define RFA_START (TFA_SIZE)
+#define RFA_SIZE (SCP_ADDR - RFA_START)
+#define RB_SIZE (ETHER_MAX_LENGTH) /* size of receive buffer */
+
+typedef volatile struct /* System Configuration Pointer */
+ {
+ u_short unused1; /* should be zeros for 82596 compatibility */
+ u_short sysbus; /* width of the 82586 data bus 0=16, 1=8 */
+ u_short unused2; /* should be zeros for 82596 compatibility */
+ u_short unused3; /* should be zeros for 82596 compatibility */
+ u_long iscp; /* iscp address (24bit 586, 32bit 596) */
+ } scp_t;
+
+typedef volatile struct /* Intermediate System Configuration Pointer */
+ {
+ u_short busy; /* Set to 1 by host before its first CA,
+ cleared by 82586 after reading */
+#define ISCP_BUSY 0x01 /* 82586 is busy reading the iscp */
+ u_short scb_offset; /* Address of System Control Block */
+ u_long scb_base; /* scb base address (24bit 586, 32bit 596) */
+ } iscp_t;
+
+typedef volatile struct /* System Control Block */
+ {
+ u_short status; /* status bits */
+#define SCB_RUS_MASK 0x0070 /* receive unit status mask */
+#define SCB_RUS_IDLE 0x0000 /* receive unit status idle */
+#define SCB_RUS_SUSP 0x0010 /* receive unit status suspended */
+#define SCB_RUS_NRSC 0x0020 /* receive unit status no resources */
+#define SCB_RUS_READY 0x0040 /* receive unit status ready */
+#define SCB_CUS_MASK 0x0700 /* command unit status mask */
+#define SCB_CUS_IDLE 0x0000 /* command unit status idle */
+#define SCB_CUS_SUSP 0x0100 /* command unit status suspended */
+#define SCB_CUS_ACT 0x0200 /* command unit status active */
+#define SCB_STAT_MASK 0xF000 /* command unit status mask */
+#define SCB_STAT_RNR 0x1000 /* receive unit left the ready state */
+#define SCB_STAT_CNA 0x2000 /* command unit left the active state */
+#define SCB_STAT_FR 0x4000 /* the ru finished receiving a frame */
+#define SCB_STAT_CX 0x8000 /* the cu finished executing a command
+ with its I (interrupt) bit set */
+#define SCB_STAT_NULL 0x0000 /* used to clear the status work */
+ u_short command; /* command bits */
+#define SCB_RUC_MASK 0x0070 /* receive unit command mask */
+#define SCB_RUC_NOP 0x0000 /* receive unit command nop */
+#define SCB_RUC_START 0x0010 /* receive unit command start */
+#define SCB_RUC_RESUME 0x0020 /* receive unit command resume */
+#define SCB_RUC_SUSP 0x0030 /* receive unit command suspend */
+#define SCB_RUC_ABORT 0x0040 /* receive unit command abort */
+#define SCB_RESET 0x0080 /* reset the chip, same as hardware reset */
+#define SCB_CUC_MASK 0x0700 /* command unit command mask */
+#define SCB_CUC_NOP 0x0000 /* command unit command nop */
+#define SCB_CUC_START 0x0100 /* start execution of the first command */
+#define SCB_CUC_RESUME 0x0200 /* resume execution of the next command */
+#define SCB_CUC_SUSP 0x0300 /* suspend execution after the current command */
+#define SCB_CUC_ABORT 0x0400 /* abort execution of the current command */
+#define SCB_ACK_MASK 0xF000 /* command unit acknowledge mask */
+#define SCB_ACK_RNR 0x1000 /* ack receive unit left the ready state */
+#define SCB_ACK_CNA 0x2000 /* ack command unit left the active state */
+#define SCB_ACK_FR 0x4000 /* ack the ru finished receiving a frame */
+#define SCB_ACK_CX 0x8000 /* ack the cu finished executing a command
+ with its I (interrupt) bit set */
+ u_short cbl_offset; /* first command block on the cbl */
+ u_short rfa_offset; /* receive frame area */
+ u_short crc_errors; /* frame was aligned, but bad crc */
+ u_short aln_errors; /* frame was not aligned, and had bad crc */
+ u_short rsc_errors; /* did not have resources to receive */
+ u_short ovr_errors; /* system bus was not availiable to receive */
+ } scb_t;
+
+typedef volatile struct /* command block - nop (also the common part of cb's */
+ {
+ u_short status; /* status bits */
+#define CB_COLLISIONS 0x000F /* the number of collisions that occured */
+#define CB_BIT4 0x0010 /* reserved by intel */
+#define CB_EXCESSCOLL 0x0020 /* the number of collisions > MAX allowed */
+#define CB_HEARTBEAT 0x0040 /* */
+#define CB_DEFER 0x0080 /* had to defer due to trafic */
+#define CB_DMAUNDER 0x0100 /* dma underrun */
+#define CB_NOCTS 0x0200 /* lost clear to send */
+#define CB_NOCS 0x0400 /* lost carrier sense */
+#define CB_LATECOLL 0x0800 /* late collision occured (82596 only) */
+#define CB_ABORT 0x1000 /* command was aborted by CUC abort command */
+#define CB_OK 0x2000 /* command executed without error */
+#define CB_BUSY 0x4000 /* command is being executed */
+#define CB_COMPLETE 0x8000 /* command completed */
+ u_short command; /* command bits */
+#define CB_CMD_MASK 0x0007 /* command mask */
+#define CB_CMD_NOP 0x0000 /* nop command */
+#define CB_CMD_IAS 0x0001 /* individual address setup command */
+#define CB_CMD_CONF 0x0002 /* configure command */
+#define CB_CMD_MCAS 0x0003 /* multicast address setup command */
+#define CB_CMD_TRANSMIT 0x0004 /* transmit command */
+#define CB_CMD_TDR 0x0005 /* time domain reflectometry command */
+#define CB_CMD_DUMP 0x0006 /* dump command */
+#define CB_CMD_DIAGNOSE 0x0007 /* diagnose command */
+#define CB_CMD_INT 0x2000 /* interrupt when command completed */
+#define CB_CMD_SUSP 0x4000 /* suspend CU when command completed */
+#define CB_CMD_EL 0x8000 /* end of the command block list */
+ u_short next; /* pointer to the next cb */
+ } cb_t;
+
+typedef volatile struct /* command block - individual address setup command */
+ {
+ cb_t common; /* common part of all command blocks */
+ u_char source[ETHER_ADDRESS_LENGTH];
+ /* ethernet hardware address */
+ } cb_ias_t;
+
+typedef volatile struct /* command block - configure command */
+ {
+ cb_t common; /* common part of all command blocks */
+ u_char byte[12]; /* ZZZ this is ugly, but it works */
+ } cb_configure_t;
+
+typedef volatile struct /* command block - multicast address setup command */
+ {
+ cb_t common; /* common part of all command blocks */
+ } cb_mcas_t;
+
+typedef volatile struct /* command block - transmit command */
+ {
+ cb_t common; /* common part of all command blocks */
+ u_short tbd_offset; /* transmit buffer descriptor offset */
+ u_char destination[ETHER_ADDRESS_LENGTH];
+ /* ethernet destination address field */
+ u_short length; /* ethernet length field */
+ u_char byte[16]; /* XXX stupid fill tell I fix the ixinit
+ * code for the special cb's */
+ } cb_transmit_t;
+
+typedef volatile struct /* command block - tdr command */
+ {
+ cb_t common; /* common part of all command blocks */
+ } cb_tdr_t;
+
+typedef volatile struct /* command block - dump command */
+ {
+ cb_t common; /* common part of all command blocks */
+ } cb_dump_t;
+
+typedef volatile struct /* command block - diagnose command */
+ {
+ cb_t common; /* common part of all command blocks */
+ } cb_diagnose_t;
+
+typedef volatile struct /* Transmit Buffer Descriptor */
+ {
+ u_short act_count; /* size of buffer actual count of valid bytes */
+#define TBD_STAT_EOF 0x8000 /* end of frame */
+ u_short next; /* pointer to the next tbd */
+ u_long buffer; /* transmit buffer address (24bit 586, 32bit 596) */
+ } tbd_t;
+
+typedef volatile struct /* Receive Frame Descriptor */
+ {
+ u_short status; /* status bits */
+#define RFD_BUSY 0x4000 /* frame is being received */
+#define RFD_COMPLETE 0x8000 /* this frame is complete */
+ u_short command; /* command bits */
+#define RFD_CMD_SUSP 0x4000 /* suspend the ru after this rfd is used */
+#define RFD_CMD_EL 0x8000 /* end of the rfd list */
+ u_short next; /* pointer to the next rfd */
+ u_short rbd_offset; /* pointer to the first rbd for this frame */
+ u_char destination[6]; /* ethernet destination address */
+ u_char source[6]; /* ethernet source address */
+ u_short length; /* ethernet length field */
+ } rfd_t;
+
+typedef volatile struct /* Receive Buffer Descriptor */
+ {
+ u_short act_count; /* Actual Count (size) and status bits */
+#define RBD_STAT_SIZE 0x3FFF /* size mask */
+#define RBD_STAT_VALID 0x4000 /* act_count field is valid */
+#define RBD_STAT_EOF 0x8000 /* end of frame */
+ u_short next; /* pointer to the next rbd */
+ u_long buffer; /* receive buffer address */
+ u_short size; /* size of buffer in bytes, must be even */
+#define RBD_SIZE_EL 0x8000 /* end of rbd list */
+ } rbd_t;
+
+/*
+ * Ethernet software status per interface.
+ *
+ * Each interface is referenced by a network interface structure,
+ * arpcom.ac_if, which the routing code uses to locate the interface.
+ * This structure contains the output queue for the interface, its address, ...
+ */
+typedef struct
+ {
+ struct arpcom arpcom; /* Ethernet common part see net/if.h */
+ int iobase; /* I/O base address for this interface */
+ caddr_t maddr; /* Memory base address for this interface */
+ int msize; /* Size of memory */
+ int flags; /* Software state */
+#define IXF_NONE 0x00000000 /* Clear all flags */
+#define IXF_INITED 0x00000001 /* Device has been inited */
+#define IXF_BPFATTACHED 0x80000000 /* BPF has been attached */
+ int connector; /* Type of connector used on board */
+#define AUI 0x00 /* Using AUI connector */
+#define BNC 0x01 /* Using BNC connector */
+#define TPE 0x02 /* Using TPE connector */
+ u_short irq_encoded; /* Encoded interrupt for use on bart */
+ int width; /* Width of slot the board is in, these
+ * constants are defined to match what
+ * the 82586/596 wants in scp->sysbus */
+#define WIDTH_8 0x01 /* 8-bit slot */
+#define WIDTH_16 0x00 /* 16-bit slot */
+ cb_t *cb_head; /* head of cb list */
+ cb_t *cb_tail; /* tail of cb list */
+ tbd_t *tbd_head; /* head of the tbd list */
+ tbd_t *tbd_tail; /* tail of the tbd list */
+ rfd_t *rfd_head; /* head of the rfd list */
+ rfd_t *rfd_tail; /* tail of the rfd list */
+ rbd_t *rbd_head; /* head of the rbd list */
+ rbd_t *rbd_tail; /* tail of the rbd list */
+ } ix_softc_t;
OpenPOWER on IntegriCloud