diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1995-02-26 19:34:34 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1995-02-26 19:34:34 +0000 |
commit | 892bd7f135d907ae1536941f91acc6713e7b53ea (patch) | |
tree | bab6d0dc87179ae923a0fdaa871b3aea2879f2b6 | |
parent | 79622643239b9e0bcea1f7f49479c0626c08d56f (diff) | |
download | FreeBSD-src-892bd7f135d907ae1536941f91acc6713e7b53ea.zip FreeBSD-src-892bd7f135d907ae1536941f91acc6713e7b53ea.tar.gz |
Last 1.x version of Intel EtherExpress driver.
-rw-r--r-- | sys/i386/isa/if_ix.c | 1652 | ||||
-rw-r--r-- | sys/i386/isa/if_ixreg.h | 330 |
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; |