diff options
author | gibbs <gibbs@FreeBSD.org> | 1997-04-14 00:37:53 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1997-04-14 00:37:53 +0000 |
commit | a35f2233319c3f681246314ae3399e81d0943fdb (patch) | |
tree | 9d134091254d79fdf1b90835d31a6027807b2ada /sys | |
parent | f1730f3a0ad9ba7560c9baf9e04abc106b4fcdcc (diff) | |
download | FreeBSD-src-a35f2233319c3f681246314ae3399e81d0943fdb.zip FreeBSD-src-a35f2233319c3f681246314ae3399e81d0943fdb.tar.gz |
Add Intel EtherExpress16 support into the ie driver, removing the need
for the ix driver.
Add a shutdown hook that resets the etherexpress so that Windoze can find
the card after a warm boot.
Submitted by: Aaron Smith <aaron@tau.veritas.com>
Obtained From: NetBSD
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ie/if_ie.c | 596 | ||||
-rw-r--r-- | sys/i386/isa/if_ie.c | 596 | ||||
-rw-r--r-- | sys/i386/isa/if_ix.c | 1634 | ||||
-rw-r--r-- | sys/i386/isa/if_ixreg.h | 359 |
4 files changed, 992 insertions, 2193 deletions
diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c index 083ffae..023e9d3 100644 --- a/sys/dev/ie/if_ie.c +++ b/sys/dev/ie/if_ie.c @@ -10,6 +10,10 @@ * 3Com 3C507 support: * Copyright (c) 1993, 1994, Charles M. Hannum * + * EtherExpress 16 support: + * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes + * Copyright (c) 1997, Aaron C. Smith + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,10 +27,10 @@ * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of - * Vermont and State Agricultural College and Garrett A. Wollman, - * by William F. Jolitz, by the University of California, - * Berkeley, by Larwence Berkeley Laboratory, by Charles M. Hannum, - * and their contributors. + * Vermont and State Agricultural College and Garrett A. Wollman, by + * William F. Jolitz, by the University of California, Berkeley, + * Lawrence Berkeley Laboratory, and their contributors, by + * Charles M. Hannum, by Rodney W. Grimes, and by Aaron C. Smith. * 4. Neither the names of the Universities nor the names of the authors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -43,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_ie.c,v 1.39 1997/02/22 09:36:29 peter Exp $ + * $Id: if_ie.c,v 1.40 1997/03/24 11:32:51 bde Exp $ */ /* @@ -53,23 +57,21 @@ * Written by GAW with reference to the Clarkson Packet Driver code for this * chip written by Russ Nelson and others. * - * BPF support code stolen directly from hpdev/if_le.c, supplied with - * tcpdump. + * Intel EtherExpress 16 support from if_ix.c, written by Rodney W. Grimes. */ /* * The i82586 is a very versatile chip, found in many implementations. * Programming this chip is mostly the same, but certain details differ * from card to card. This driver is written so that different cards - * can be automatically detected at run-time. Currently, only the - * AT&T EN100/StarLAN 10 series are supported. + * can be automatically detected at run-time. */ /* Mode of operation: We run the 82586 in a standard Ethernet mode. We keep NFRAMES received -frame descriptors around for the receiver to use, and NBUFFS associated +frame descriptors around for the receiver to use, and NRXBUF associated receive buffer descriptors, both in a circular list. Whenever a frame is received, we rotate both lists as necessary. (The 586 treats both lists as a simple queue.) We also keep a transmit command around so that packets @@ -87,20 +89,20 @@ what precisely caused it. ANY OTHER command-sending routines should run at splimp(), and should post an acknowledgement to every interrupt they generate. -The 82586 has a 24-bit address space internally, and the adaptor's -memory is located at the top of this region. However, the value we are -given in configuration is normally the *bottom* of the adaptor RAM. So, -we must go through a few gyrations to come up with a kernel virtual address -which represents the actual beginning of the 586 address space. First, -we autosize the RAM by running through several possible sizes and trying -to initialize the adapter under the assumption that the selected size -is correct. Then, knowing the correct RAM size, we set up our pointers -in ie_softc[unit]. `iomem' represents the computed base of the 586 -address space. `iomembot' represents the actual configured base -of adapter RAM. Finally, `iosize' represents the calculated size -of 586 RAM. Then, when laying out commands, we use the interval -[iomembot, iomembot + iosize); to make 24-pointers, we subtract -iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. +The 82586 has a 24-bit address space internally, and the adaptor's memory +is located at the top of this region. However, the value we are given in +configuration is normally the *bottom* of the adaptor RAM. So, we must go +through a few gyrations to come up with a kernel virtual address which +represents the actual beginning of the 586 address space. First, we +autosize the RAM by running through several possible sizes and trying to +initialize the adapter under the assumption that the selected size is +correct. Then, knowing the correct RAM size, we set up our pointers in +ie_softc[unit]. `iomem' represents the computed base of the 586 address +space. `iomembot' represents the actual configured base of adapter RAM. +Finally, `iosize' represents the calculated size of 586 RAM. Then, when +laying out commands, we use the interval [iomembot, iomembot + iosize); to +make 24-pointers, we subtract iomem, and to make 16-pointers, we subtract +iomem and and with 0xffff. */ @@ -148,8 +150,10 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. #include <i386/isa/isa_device.h> #include <i386/isa/ic/i82586.h> +#include <i386/isa/icu.h> #include <i386/isa/if_iereg.h> #include <i386/isa/if_ie507.h> +#include <i386/isa/if_iee16.h> #include <i386/isa/elink.h> #include <vm/vm.h> @@ -159,38 +163,57 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. #include <net/bpfdesc.h> #endif -static int check_ie_present __P((int unit, caddr_t where, unsigned size)); - -static struct mbuf *last_not_for_us; - #ifdef DEBUG -#define IED_RINT 1 -#define IED_TINT 2 -#define IED_RNR 4 -#define IED_CNA 8 -#define IED_READFRAME 16 +#define IED_RINT 0x01 +#define IED_TINT 0x02 +#define IED_RNR 0x04 +#define IED_CNA 0x08 +#define IED_READFRAME 0x10 int ie_debug = IED_RNR; #endif -#ifndef ETHERMINLEN -#define ETHERMINLEN 60 +#if 0 +/* these values are defined in net/ethernet.h -acs */ +#define ETHER_MIN_LEN 60 +#define ETHER_MAX_LEN 1512 +#define ETHER_ADDR_LEN 6 #endif -#define IE_BUF_LEN 1512 /* length of transmit buffer */ +#define IE_BUF_LEN ETHER_MAX_LEN /* length of transmit buffer */ /* Forward declaration */ struct ie_softc; +static struct mbuf *last_not_for_us; + static int ieprobe(struct isa_device *dvp); static int ieattach(struct isa_device *dvp); +static int sl_probe(struct isa_device *dvp); +static int el_probe(struct isa_device *dvp); +static int ni_probe(struct isa_device *dvp); +static int ee16_probe(struct isa_device *dvp); + +static int check_ie_present __P((int unit, caddr_t where, unsigned size)); static void ieinit(int unit); static void ie_stop __P((int unit)); -static int ieioctl(struct ifnet *ifp, int command, caddr_t data); +static int ieioctl(struct ifnet *ifp, int command, caddr_t data); static void iestart(struct ifnet *ifp); + static void el_reset_586(int unit); static void el_chan_attn(int unit); + static void sl_reset_586(int unit); static void sl_chan_attn(int unit); + +static void ee16_reset_586(int unit); +static void ee16_chan_attn(int unit); +static void ee16_interrupt_enable __P((struct ie_softc *ie)); +static void ee16_eeprom_outbits __P((struct ie_softc *ie, int edata, int cnt)); +static void ee16_eeprom_clock __P((struct ie_softc *ie, int state)); +static u_short ee16_read_eeprom __P((struct ie_softc *ie, int location)); +static int ee16_eeprom_inbits __P((struct ie_softc *ie)); +static void ee16_shutdown(int howto, void *sc); + static void iereset(int unit); static void ie_readframe(int unit, struct ie_softc *ie, int bufno); static void ie_drop_packet_buffer(int unit, struct ie_softc *ie); @@ -229,6 +252,7 @@ enum ie_hardware { IE_SLFIBER, IE_3C507, IE_NI5210, + IE_EE16, IE_UNKNOWN }; @@ -238,6 +262,7 @@ static const char *ie_hardware_names[] = { "StarLAN Fiber", "3C507", "NI5210", + "EtherExpress 16", "Unknown" }; @@ -251,12 +276,12 @@ sizeof(transmit buffer desc) == 8 ----- 1946 -NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12 -NBUFFS * IE_RBUF_SIZE == NBUFFS*256 +NRXBUF * sizeof(rbd) == NRXBUF*(2+2+4+2+2) == NRXBUF*12 +NRXBUF * IE_RBUF_SIZE == NRXBUF*256 -NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53 +NRXBUF should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53 -With NBUFFS == 48, this leaves us 1574 bytes for another command or +With NRXBUF == 48, this leaves us 1574 bytes for another command or more buffers. Another transmit command would be 18+8+1512 == 1538 ---just barely fits! @@ -265,9 +290,12 @@ With a larger memory, it would be possible to roughly double the number of both transmit and receive buffers. */ -#define NFRAMES 16 /* number of frames to allow for receive */ -#define NBUFFS 48 /* number of buffers to allocate */ -#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */ +#define NFRAMES 16 /* number of receive frames */ +#define NRXBUF 48 /* number of buffers to allocate */ +#define IE_RBUF_SIZE 256 /* size of each buffer, + MUST BE POWER OF TWO */ +#define NTXBUF 2 /* number of transmit commands */ +#define IE_TBUF_SIZE ETHER_MAX_LEN /* size of transmit buffer */ /* * Ethernet status, per interface. @@ -279,9 +307,9 @@ static struct ie_softc { enum ie_hardware hard_type; int hard_vers; - u_short port; - caddr_t iomem; - caddr_t iomembot; + u_short port; /* i/o base address for this interface */ + caddr_t iomem; /* memory size */ + caddr_t iomembot; /* memory base address */ unsigned iosize; int bus_use; /* 0 means 16bit, 1 means 8 bit adapter */ @@ -290,42 +318,44 @@ static struct ie_softc { volatile struct ie_int_sys_conf_ptr *iscp; volatile struct ie_sys_ctl_block *scb; volatile struct ie_recv_frame_desc *rframes[NFRAMES]; - volatile struct ie_recv_buf_desc *rbuffs[NBUFFS]; - volatile char *cbuffs[NBUFFS]; + volatile struct ie_recv_buf_desc *rbuffs[NRXBUF]; + volatile char *cbuffs[NRXBUF]; int rfhead, rftail, rbhead, rbtail; - volatile struct ie_xmit_cmd *xmit_cmds[2]; - volatile struct ie_xmit_buf *xmit_buffs[2]; + volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF]; + volatile struct ie_xmit_buf *xmit_buffs[NTXBUF]; + u_char *xmit_cbuffs[NTXBUF]; int xmit_count; - u_char *xmit_cbuffs[2]; struct ie_en_addr mcast_addrs[MAXMCAST + 1]; int mcast_count; + + u_short irq_encoded; /* encoded interrupt on IEE16 */ + } ie_softc[NIE]; #define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base)) #define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr)) #define PORT ie_softc[unit].port -#define MEM ie_softc[unit].iomem +#define MEM ie_softc[unit].iomem -static int sl_probe(struct isa_device *); -static int el_probe(struct isa_device *); -static int ni_probe(struct isa_device *); - -/* This routine written by Charles Martin Hannum. */ -int ieprobe(dvp) - struct isa_device *dvp; +int +ieprobe(dvp) + struct isa_device *dvp; { int ret; ret = sl_probe(dvp); - if(!ret) ret = el_probe(dvp); - if(!ret) ret = ni_probe(dvp); - return(ret); + if (!ret) ret = el_probe(dvp); + if (!ret) ret = ni_probe(dvp); + if (!ret) ret = ee16_probe(dvp); + + return (ret); } -static int sl_probe(dvp) +static int +sl_probe(dvp) struct isa_device *dvp; { int unit = dvp->id_unit; @@ -390,8 +420,9 @@ static int sl_probe(dvp) return 1; } -/* This routine written by Charles Martin Hannum. */ -static int el_probe(dvp) + +static int +el_probe(dvp) struct isa_device *dvp; { struct ie_softc *sc = &ie_softc[dvp->id_unit]; @@ -538,6 +569,237 @@ static int ni_probe(dvp) } +static void +ee16_shutdown(howto, sc) + int howto; + void *sc; +{ + struct ie_softc *ie = (struct ie_softc *)sc; + int unit = ie - &ie_softc[0]; + + ee16_reset_586(unit); + outb(PORT + IEE16_ECTRL, IEE16_RESET_ASIC); + outb(PORT + IEE16_ECTRL, 0); +} + + +/* Taken almost exactly from Rod's if_ix.c. */ + +int +ee16_probe(dvp) + struct isa_device *dvp; +{ + struct ie_softc *sc = &ie_softc[dvp->id_unit]; + + int i; + int unit = dvp->id_unit; + u_short board_id, id_var1, id_var2, checksum = 0; + u_short eaddrtemp, irq; + u_short pg, adjust, decode, edecode; + u_char bart_config; + u_long bd_maddr; + + short irq_translate[] = {0, IRQ9, IRQ3, IRQ4, IRQ5, IRQ10, IRQ11, 0}; + char irq_encode[] = { 0, 0, 0, 2, 3, 4, 0, 0, + 0, 1, 5, 6, 0, 0, 0, 0 }; + + /* Need this for part of the probe. */ + sc->ie_reset_586 = ee16_reset_586; + sc->ie_chan_attn = ee16_chan_attn; + + /* unsure if this is necessary */ + sc->bus_use = 0; + + /* reset any ee16 at the current iobase */ + outb(dvp->id_iobase + IEE16_ECTRL, IEE16_RESET_ASIC); + outb(dvp->id_iobase + IEE16_ECTRL, 0); + DELAY(240); + + /* now look for ee16. */ + board_id = id_var1 = id_var2 = 0; + for (i=0; i<4 ; i++) { + id_var1 = inb(dvp->id_iobase + IEE16_ID_PORT); + id_var2 = ((id_var1 & 0x03) << 2); + board_id |= (( id_var1 >> 4) << id_var2); + } + + if (board_id != IEE16_ID) { + printf("ie%d: unknown board_id: %x\n", unit, board_id); + return 0; + } + + /* need sc->port for ee16_read_eeprom */ + sc->port = dvp->id_iobase; + sc->hard_type = IE_EE16; + + /* + * The shared RAM location on the EE16 is encoded into bits + * 3-7 of EEPROM location 6. We zero the upper byte, and + * shift the 5 bits right 3. The resulting number tells us + * the RAM location. Because the EE16 supports either 16k or 32k + * of shared RAM, we only worry about the 32k locations. + * + * NOTE: if a 64k EE16 exists, it should be added to this switch. + * then the ia->ia_msize would need to be set per case statement. + * + * value msize location + * ===== ===== ======== + * 0x03 0x8000 0xCC000 + * 0x06 0x8000 0xD0000 + * 0x0C 0x8000 0xD4000 + * 0x18 0x8000 0xD8000 + * + */ + + bd_maddr = 0; + i = (ee16_read_eeprom(sc, 6) & 0x00ff ) >> 3; + switch(i) { + case 0x03: + bd_maddr = 0xCC000; + break; + case 0x06: + bd_maddr = 0xD0000; + break; + case 0x0c: + bd_maddr = 0xD4000; + break; + case 0x18: + bd_maddr = 0xD8000; + break; + default: + bd_maddr = 0 ; + break; + } + dvp->id_msize = 0x8000; + if (kvtop(dvp->id_maddr) != bd_maddr) { + printf("ie%d: kernel configured maddr %lx doesn't match board configured maddr %x\n", + unit, kvtop(dvp->id_maddr), bd_maddr); + } + + + sc->iomembot = dvp->id_maddr; + sc->iomem = 0; /* XXX some probes set this and some don't */ + sc->iosize = dvp->id_msize; + + /* need to put the 586 in RESET while we access the eeprom. */ + outb( PORT + IEE16_ECTRL, IEE16_RESET_586); + + /* read the eeprom and checksum it, should == IEE16_ID */ + for(i = 0; i < 0x40; i++) + checksum += ee16_read_eeprom(sc, i); + + if (checksum != IEE16_ID) { + printf("ie%d: invalid eeprom checksum: %x\n", unit, checksum); + return 0; + } + + /* + * 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. + * + * If the size does not match the passed in memory allocation size + * issue a warning, but continue with the minimum of the two sizes. + */ + + switch (dvp->id_msize) { + case 65536: + case 32768: /* XXX Only support 32k and 64k right now */ + break; + case 16384: + case 49512: + default: + printf("ie%d: mapped memory size %d not supported\n", unit, + dvp->id_msize); + return 0; + break; /* NOTREACHED */ + } + + if ((kvtop(dvp->id_maddr) < 0xC0000) || + (kvtop(dvp->id_maddr) + sc->iosize > 0xF0000)) { + printf("ie%d: mapped memory location %x out of range\n", unit, + dvp->id_maddr); + return 0; + } + + pg = (kvtop(dvp->id_maddr) & 0x3C000) >> 14; + adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2; + decode = ((1 << (sc->iosize / 16384)) - 1) << pg; + edecode = ((~decode >> 4) & 0xF0) | (decode >> 8); + + /* ZZZ This should be checked against eeprom location 6, low byte */ + outb(PORT + IEE16_MEMDEC, decode & 0xFF); + /* ZZZ This should be checked against eeprom location 1, low byte */ + outb(PORT + IEE16_MCTRL, adjust); + /* ZZZ Now if I could find this one I would have it made */ + outb(PORT + IEE16_MPCTRL, (~decode & 0xFF)); + /* ZZZ I think this is location 6, high byte */ + outb(PORT + IEE16_MECTRL, edecode); /*XXX disable Exxx */ + + (void)kvtop(dvp->id_maddr); + + /* + * first prime the stupid bart DRAM controller so that it + * works, then zero out all of memory. + */ + bzero(sc->iomembot, 32); + bzero(sc->iomembot, sc->iosize); + + /* + * 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 = ee16_read_eeprom(sc, IEE16_EEPROM_CONFIG1); + irq = (irq & IEE16_EEPROM_IRQ) >> IEE16_EEPROM_IRQ_SHIFT; + irq = irq_translate[irq]; + if (dvp->id_irq > 0) { + if (irq != dvp->id_irq) { + printf("ie%d: WARNING: board configured at irq %d, using %d\n", + dvp->id_unit, irq); + irq = dvp->id_unit; + } + } else { + dvp->id_irq = irq; + } + sc->irq_encoded = irq_encode[ffs(irq) - 1]; + + /* + * Get the hardware ethernet address from the EEPROM and + * save it in the softc for use by the 586 setup code. + */ + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_HIGH); + sc->arpcom.ac_enaddr[1] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[0] = eaddrtemp >> 8; + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_MID); + sc->arpcom.ac_enaddr[3] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[2] = eaddrtemp >> 8; + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_LOW); + sc->arpcom.ac_enaddr[5] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[4] = eaddrtemp >> 8; + + /* disable the board interrupts */ + outb(PORT + IEE16_IRQ, sc->irq_encoded); + + /* enable loopback to keep bad packets off the wire */ + if(sc->hard_type == IE_EE16) { + bart_config = inb(PORT + IEE16_CONFIG); + bart_config |= IEE16_BART_LOOPBACK; + bart_config |= IEE16_BART_MCS16_TEST; /*inb doesn't get bit! */ + outb(PORT + IEE16_CONFIG, bart_config); + bart_config = inb(PORT + IEE16_CONFIG); + } + + /* take the board out of reset state */ + outb(PORT + IEE16_ECTRL, 0); + DELAY(100); + + if (!check_ie_present(unit, dvp->id_maddr, sc->iosize)) + return 0; + + return 16; /* return the number of I/O ports */ +} + /* * Taken almost exactly from Bill's if_is.c, then modified beyond recognition. */ @@ -553,7 +815,7 @@ ieattach(dvp) ifp->if_unit = unit; ifp->if_name = iedriver.name; ifp->if_mtu = ETHERMTU; - printf(" <%s R%d> ethernet address %6D\n", + printf("ie%d: <%s R%d> address %6D\n", unit, ie_hardware_names[ie->hard_type], ie->hard_vers + 1, ie->arpcom.ac_enaddr, ":"); @@ -566,6 +828,9 @@ ieattach(dvp) ifp->if_addrlen = 6; ifp->if_hdrlen = 14; + if (ie->hard_type == IE_EE16) + at_shutdown(ee16_shutdown, ie, SHUTDOWN_POST_SYNC); + #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif @@ -578,21 +843,22 @@ ieattach(dvp) /* * What to do upon receipt of an interrupt. */ -void ieintr(unit) - int unit; +void +ieintr(unit) + int unit; { register struct ie_softc *ie = &ie_softc[unit]; register u_short status; - status = ie->scb->ie_status; + /* Clear the interrupt latch on the 3C507. */ + if (ie->hard_type == IE_3C507 && (inb(PORT + IE507_CTRL) & EL_CTRL_INTL)) + outb(PORT + IE507_ICTRL, 1); - /* This if statement written by Charles Martin Hannum. */ - if ((status & IE_ST_WHENCE) == 0) { - /* Clear the interrupt latch on the 3C507. */ - if (ie->hard_type == IE_3C507 && - (inb(PORT + IE507_CTRL) & EL_CTRL_INTL)) - outb(PORT + IE507_ICTRL, 1); - } + /* disable interrupts on the EE16. */ + if (ie->hard_type == IE_EE16) + outb(PORT + IEE16_IRQ, ie->irq_encoded); + + status = ie->scb->ie_status; loop: if(status & (IE_ST_RECV | IE_ST_RNR)) { @@ -632,25 +898,30 @@ loop: && (ie_debug & IED_CNA)) printf("ie%d: cna\n", unit); #endif - + /* Don't ack interrupts which we didn't receive */ ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn); - if((status = ie->scb->ie_status) & IE_ST_WHENCE) - goto loop; + if ((status = ie->scb->ie_status) & IE_ST_WHENCE) + goto loop; - /* This comment and if statement written by Charles Martin Hannum. */ /* Clear the interrupt latch on the 3C507. */ if (ie->hard_type == IE_3C507) - outb(PORT + IE507_ICTRL, 1); + outb(PORT + IE507_ICTRL, 1); + + /* enable interrupts on the EE16. */ + if (ie->hard_type == IE_EE16) + outb(PORT + IEE16_IRQ, ie->irq_encoded | IEE16_IRQ_ENABLE); + } /* * Process a received-frame interrupt. */ -static int ierint(unit, ie) - int unit; - struct ie_softc *ie; +static int +ierint(unit, ie) + int unit; + struct ie_softc *ie; { int i, status; static int timesthru = 1024; @@ -662,8 +933,9 @@ static int ierint(unit, ie) if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) { ie->arpcom.ac_if.if_ipackets++; if(!--timesthru) { - ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align + - ie->scb->ie_err_resource + ie->scb->ie_err_overrun; + ie->arpcom.ac_if.if_ierrors += + ie->scb->ie_err_crc + ie->scb->ie_err_align + + ie->scb->ie_err_resource + ie->scb->ie_err_overrun; ie->scb->ie_err_crc = 0; ie->scb->ie_err_align = 0; ie->scb->ie_err_resource = 0; @@ -918,7 +1190,7 @@ static inline int ie_packet_len(int unit, struct ie_softc *ie) { i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST; acc += ie_buflen(ie, head); - head = (head + 1) % NBUFFS; + head = (head + 1) % NRXBUF; } while(!i); return acc; @@ -1086,9 +1358,9 @@ nextbuf: offset = 0; ie->rbuffs[head]->ie_rbd_actual = 0; ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST; - ie->rbhead = head = (head + 1) % NBUFFS; + ie->rbhead = head = (head + 1) % NRXBUF; ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; - ie->rbtail = (ie->rbtail + 1) % NBUFFS; + ie->rbtail = (ie->rbtail + 1) % NRXBUF; } /* @@ -1223,9 +1495,9 @@ static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) { ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST; ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0; - ie->rbhead = (ie->rbhead + 1) % NBUFFS; + ie->rbhead = (ie->rbhead + 1) % NRXBUF; ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; - ie->rbtail = (ie->rbtail + 1) % NBUFFS; + ie->rbtail = (ie->rbtail + 1) % NRXBUF; } while(!i); } @@ -1264,7 +1536,7 @@ iestart(ifp) } m_freem(m0); - len = max(len, ETHERMINLEN); + len = max(len, ETHER_MIN_LEN); #if NBPFILTER > 0 /* @@ -1288,7 +1560,7 @@ iestart(ifp) *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]); bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link; ie->xmit_count++; - } while(ie->xmit_count < 2); + } while (ie->xmit_count < NTXBUF); /* * If we queued up anything for transmission, send it. @@ -1433,6 +1705,16 @@ void sl_reset_586(unit) outb(PORT + IEATT_RESET, 0); } +void +ee16_reset_586(unit) + int unit; +{ + outb(PORT + IEE16_ECTRL, IEE16_RESET_586); + DELAY(100); + outb(PORT + IEE16_ECTRL, 0); + DELAY(100); +} + void el_chan_attn(unit) int unit; { @@ -1445,6 +1727,105 @@ void sl_chan_attn(unit) outb(PORT + IEATT_ATTN, 0); } +void +ee16_chan_attn(unit) + int unit; +{ + outb(PORT + IEE16_ATTN, 0); +} + +u_short +ee16_read_eeprom(sc, location) + struct ie_softc *sc; + int location; +{ + int ectrl, edata; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= IEE16_ECTRL_MASK; + ectrl |= IEE16_ECTRL_EECS; + outb(sc->port + IEE16_ECTRL, ectrl); + + ee16_eeprom_outbits(sc, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1); + ee16_eeprom_outbits(sc, location, IEE16_EEPROM_ADDR_SIZE); + edata = ee16_eeprom_inbits(sc); + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS); + outb(sc->port + IEE16_ECTRL, ectrl); + ee16_eeprom_clock(sc, 1); + ee16_eeprom_clock(sc, 0); + return edata; +} + +void +ee16_eeprom_outbits(sc, edata, count) + struct ie_softc *sc; + int edata, count; +{ + int ectrl, i; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~IEE16_RESET_ASIC; + for (i = count - 1; i >= 0; i--) { + ectrl &= ~IEE16_ECTRL_EEDI; + if (edata & (1 << i)) { + ectrl |= IEE16_ECTRL_EEDI; + } + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(1); /* eeprom data must be setup for 0.4 uSec */ + ee16_eeprom_clock(sc, 1); + ee16_eeprom_clock(sc, 0); + } + ectrl &= ~IEE16_ECTRL_EEDI; + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(1); /* eeprom data must be held for 0.4 uSec */ +} + +int +ee16_eeprom_inbits(sc) + struct ie_softc *sc; +{ + int ectrl, edata, i; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~IEE16_RESET_ASIC; + for (edata = 0, i = 0; i < 16; i++) { + edata = edata << 1; + ee16_eeprom_clock(sc, 1); + ectrl = inb(sc->port + IEE16_ECTRL); + if (ectrl & IEE16_ECTRL_EEDO) { + edata |= 1; + } + ee16_eeprom_clock(sc, 0); + } + return (edata); +} + +void +ee16_eeprom_clock(sc, state) + struct ie_softc *sc; + int state; +{ + int ectrl; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK); + if (state) { + ectrl |= IEE16_ECTRL_EESK; + } + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(9); /* EESK must be stable for 8.38 uSec */ +} + +static inline void +ee16_interrupt_enable(sc) + struct ie_softc *sc; +{ + DELAY(100); + outb(sc->port + IEE16_IRQ, sc->irq_encoded | IEE16_IRQ_ENABLE); + DELAY(100); +} + void sl_read_ether(unit, addr) int unit; unsigned char addr[6]; @@ -1651,7 +2032,7 @@ static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) { */ rbd = (void *)ptr; - for(i = 0; i < NBUFFS; i++) { + for(i = 0; i < NRXBUF; i++) { ie->rbuffs[i] = rbd; bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */ ptr = (caddr_t)Align(ptr + sizeof *rbd); @@ -1663,19 +2044,19 @@ static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) { } /* Now link them together */ - for(i = 0; i < NBUFFS; i++) { - ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]); + for(i = 0; i < NRXBUF; i++) { + ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NRXBUF]); } /* Tag EOF on the last one */ - ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST; + ie->rbuffs[NRXBUF - 1]->ie_rbd_length |= IE_RBD_LAST; /* We use the head and tail pointers on receive to keep track of * the order in which RFDs and RBDs are used. */ ie->rfhead = 0; ie->rftail = NFRAMES - 1; ie->rbhead = 0; - ie->rbtail = NBUFFS - 1; + ie->rbtail = NRXBUF - 1; ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]); ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]); @@ -1780,6 +2161,21 @@ ieinit(unit) */ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn); + /* take the ee16 out of loopback */ + { + u_char bart_config; + + if(ie->hard_type == IE_EE16) { + bart_config = inb(PORT + IEE16_CONFIG); + bart_config &= ~IEE16_BART_LOOPBACK; + /* inb doesn't get bit! */ + bart_config |= IEE16_BART_MCS16_TEST; + outb(PORT + IEE16_CONFIG, bart_config); + ee16_interrupt_enable(ie); + ee16_chan_attn(unit); + } + } + /* * Set up the RFA. */ @@ -1819,7 +2215,7 @@ ieinit(unit) */ ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL; - ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */ + ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels we're here */ start_receiver(unit); return; } diff --git a/sys/i386/isa/if_ie.c b/sys/i386/isa/if_ie.c index 083ffae..023e9d3 100644 --- a/sys/i386/isa/if_ie.c +++ b/sys/i386/isa/if_ie.c @@ -10,6 +10,10 @@ * 3Com 3C507 support: * Copyright (c) 1993, 1994, Charles M. Hannum * + * EtherExpress 16 support: + * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes + * Copyright (c) 1997, Aaron C. Smith + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,10 +27,10 @@ * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of - * Vermont and State Agricultural College and Garrett A. Wollman, - * by William F. Jolitz, by the University of California, - * Berkeley, by Larwence Berkeley Laboratory, by Charles M. Hannum, - * and their contributors. + * Vermont and State Agricultural College and Garrett A. Wollman, by + * William F. Jolitz, by the University of California, Berkeley, + * Lawrence Berkeley Laboratory, and their contributors, by + * Charles M. Hannum, by Rodney W. Grimes, and by Aaron C. Smith. * 4. Neither the names of the Universities nor the names of the authors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -43,7 +47,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: if_ie.c,v 1.39 1997/02/22 09:36:29 peter Exp $ + * $Id: if_ie.c,v 1.40 1997/03/24 11:32:51 bde Exp $ */ /* @@ -53,23 +57,21 @@ * Written by GAW with reference to the Clarkson Packet Driver code for this * chip written by Russ Nelson and others. * - * BPF support code stolen directly from hpdev/if_le.c, supplied with - * tcpdump. + * Intel EtherExpress 16 support from if_ix.c, written by Rodney W. Grimes. */ /* * The i82586 is a very versatile chip, found in many implementations. * Programming this chip is mostly the same, but certain details differ * from card to card. This driver is written so that different cards - * can be automatically detected at run-time. Currently, only the - * AT&T EN100/StarLAN 10 series are supported. + * can be automatically detected at run-time. */ /* Mode of operation: We run the 82586 in a standard Ethernet mode. We keep NFRAMES received -frame descriptors around for the receiver to use, and NBUFFS associated +frame descriptors around for the receiver to use, and NRXBUF associated receive buffer descriptors, both in a circular list. Whenever a frame is received, we rotate both lists as necessary. (The 586 treats both lists as a simple queue.) We also keep a transmit command around so that packets @@ -87,20 +89,20 @@ what precisely caused it. ANY OTHER command-sending routines should run at splimp(), and should post an acknowledgement to every interrupt they generate. -The 82586 has a 24-bit address space internally, and the adaptor's -memory is located at the top of this region. However, the value we are -given in configuration is normally the *bottom* of the adaptor RAM. So, -we must go through a few gyrations to come up with a kernel virtual address -which represents the actual beginning of the 586 address space. First, -we autosize the RAM by running through several possible sizes and trying -to initialize the adapter under the assumption that the selected size -is correct. Then, knowing the correct RAM size, we set up our pointers -in ie_softc[unit]. `iomem' represents the computed base of the 586 -address space. `iomembot' represents the actual configured base -of adapter RAM. Finally, `iosize' represents the calculated size -of 586 RAM. Then, when laying out commands, we use the interval -[iomembot, iomembot + iosize); to make 24-pointers, we subtract -iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. +The 82586 has a 24-bit address space internally, and the adaptor's memory +is located at the top of this region. However, the value we are given in +configuration is normally the *bottom* of the adaptor RAM. So, we must go +through a few gyrations to come up with a kernel virtual address which +represents the actual beginning of the 586 address space. First, we +autosize the RAM by running through several possible sizes and trying to +initialize the adapter under the assumption that the selected size is +correct. Then, knowing the correct RAM size, we set up our pointers in +ie_softc[unit]. `iomem' represents the computed base of the 586 address +space. `iomembot' represents the actual configured base of adapter RAM. +Finally, `iosize' represents the calculated size of 586 RAM. Then, when +laying out commands, we use the interval [iomembot, iomembot + iosize); to +make 24-pointers, we subtract iomem, and to make 16-pointers, we subtract +iomem and and with 0xffff. */ @@ -148,8 +150,10 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. #include <i386/isa/isa_device.h> #include <i386/isa/ic/i82586.h> +#include <i386/isa/icu.h> #include <i386/isa/if_iereg.h> #include <i386/isa/if_ie507.h> +#include <i386/isa/if_iee16.h> #include <i386/isa/elink.h> #include <vm/vm.h> @@ -159,38 +163,57 @@ iomem, and to make 16-pointers, we subtract iomem and and with 0xffff. #include <net/bpfdesc.h> #endif -static int check_ie_present __P((int unit, caddr_t where, unsigned size)); - -static struct mbuf *last_not_for_us; - #ifdef DEBUG -#define IED_RINT 1 -#define IED_TINT 2 -#define IED_RNR 4 -#define IED_CNA 8 -#define IED_READFRAME 16 +#define IED_RINT 0x01 +#define IED_TINT 0x02 +#define IED_RNR 0x04 +#define IED_CNA 0x08 +#define IED_READFRAME 0x10 int ie_debug = IED_RNR; #endif -#ifndef ETHERMINLEN -#define ETHERMINLEN 60 +#if 0 +/* these values are defined in net/ethernet.h -acs */ +#define ETHER_MIN_LEN 60 +#define ETHER_MAX_LEN 1512 +#define ETHER_ADDR_LEN 6 #endif -#define IE_BUF_LEN 1512 /* length of transmit buffer */ +#define IE_BUF_LEN ETHER_MAX_LEN /* length of transmit buffer */ /* Forward declaration */ struct ie_softc; +static struct mbuf *last_not_for_us; + static int ieprobe(struct isa_device *dvp); static int ieattach(struct isa_device *dvp); +static int sl_probe(struct isa_device *dvp); +static int el_probe(struct isa_device *dvp); +static int ni_probe(struct isa_device *dvp); +static int ee16_probe(struct isa_device *dvp); + +static int check_ie_present __P((int unit, caddr_t where, unsigned size)); static void ieinit(int unit); static void ie_stop __P((int unit)); -static int ieioctl(struct ifnet *ifp, int command, caddr_t data); +static int ieioctl(struct ifnet *ifp, int command, caddr_t data); static void iestart(struct ifnet *ifp); + static void el_reset_586(int unit); static void el_chan_attn(int unit); + static void sl_reset_586(int unit); static void sl_chan_attn(int unit); + +static void ee16_reset_586(int unit); +static void ee16_chan_attn(int unit); +static void ee16_interrupt_enable __P((struct ie_softc *ie)); +static void ee16_eeprom_outbits __P((struct ie_softc *ie, int edata, int cnt)); +static void ee16_eeprom_clock __P((struct ie_softc *ie, int state)); +static u_short ee16_read_eeprom __P((struct ie_softc *ie, int location)); +static int ee16_eeprom_inbits __P((struct ie_softc *ie)); +static void ee16_shutdown(int howto, void *sc); + static void iereset(int unit); static void ie_readframe(int unit, struct ie_softc *ie, int bufno); static void ie_drop_packet_buffer(int unit, struct ie_softc *ie); @@ -229,6 +252,7 @@ enum ie_hardware { IE_SLFIBER, IE_3C507, IE_NI5210, + IE_EE16, IE_UNKNOWN }; @@ -238,6 +262,7 @@ static const char *ie_hardware_names[] = { "StarLAN Fiber", "3C507", "NI5210", + "EtherExpress 16", "Unknown" }; @@ -251,12 +276,12 @@ sizeof(transmit buffer desc) == 8 ----- 1946 -NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12 -NBUFFS * IE_RBUF_SIZE == NBUFFS*256 +NRXBUF * sizeof(rbd) == NRXBUF*(2+2+4+2+2) == NRXBUF*12 +NRXBUF * IE_RBUF_SIZE == NRXBUF*256 -NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53 +NRXBUF should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53 -With NBUFFS == 48, this leaves us 1574 bytes for another command or +With NRXBUF == 48, this leaves us 1574 bytes for another command or more buffers. Another transmit command would be 18+8+1512 == 1538 ---just barely fits! @@ -265,9 +290,12 @@ With a larger memory, it would be possible to roughly double the number of both transmit and receive buffers. */ -#define NFRAMES 16 /* number of frames to allow for receive */ -#define NBUFFS 48 /* number of buffers to allocate */ -#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */ +#define NFRAMES 16 /* number of receive frames */ +#define NRXBUF 48 /* number of buffers to allocate */ +#define IE_RBUF_SIZE 256 /* size of each buffer, + MUST BE POWER OF TWO */ +#define NTXBUF 2 /* number of transmit commands */ +#define IE_TBUF_SIZE ETHER_MAX_LEN /* size of transmit buffer */ /* * Ethernet status, per interface. @@ -279,9 +307,9 @@ static struct ie_softc { enum ie_hardware hard_type; int hard_vers; - u_short port; - caddr_t iomem; - caddr_t iomembot; + u_short port; /* i/o base address for this interface */ + caddr_t iomem; /* memory size */ + caddr_t iomembot; /* memory base address */ unsigned iosize; int bus_use; /* 0 means 16bit, 1 means 8 bit adapter */ @@ -290,42 +318,44 @@ static struct ie_softc { volatile struct ie_int_sys_conf_ptr *iscp; volatile struct ie_sys_ctl_block *scb; volatile struct ie_recv_frame_desc *rframes[NFRAMES]; - volatile struct ie_recv_buf_desc *rbuffs[NBUFFS]; - volatile char *cbuffs[NBUFFS]; + volatile struct ie_recv_buf_desc *rbuffs[NRXBUF]; + volatile char *cbuffs[NRXBUF]; int rfhead, rftail, rbhead, rbtail; - volatile struct ie_xmit_cmd *xmit_cmds[2]; - volatile struct ie_xmit_buf *xmit_buffs[2]; + volatile struct ie_xmit_cmd *xmit_cmds[NTXBUF]; + volatile struct ie_xmit_buf *xmit_buffs[NTXBUF]; + u_char *xmit_cbuffs[NTXBUF]; int xmit_count; - u_char *xmit_cbuffs[2]; struct ie_en_addr mcast_addrs[MAXMCAST + 1]; int mcast_count; + + u_short irq_encoded; /* encoded interrupt on IEE16 */ + } ie_softc[NIE]; #define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base)) #define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr)) #define PORT ie_softc[unit].port -#define MEM ie_softc[unit].iomem +#define MEM ie_softc[unit].iomem -static int sl_probe(struct isa_device *); -static int el_probe(struct isa_device *); -static int ni_probe(struct isa_device *); - -/* This routine written by Charles Martin Hannum. */ -int ieprobe(dvp) - struct isa_device *dvp; +int +ieprobe(dvp) + struct isa_device *dvp; { int ret; ret = sl_probe(dvp); - if(!ret) ret = el_probe(dvp); - if(!ret) ret = ni_probe(dvp); - return(ret); + if (!ret) ret = el_probe(dvp); + if (!ret) ret = ni_probe(dvp); + if (!ret) ret = ee16_probe(dvp); + + return (ret); } -static int sl_probe(dvp) +static int +sl_probe(dvp) struct isa_device *dvp; { int unit = dvp->id_unit; @@ -390,8 +420,9 @@ static int sl_probe(dvp) return 1; } -/* This routine written by Charles Martin Hannum. */ -static int el_probe(dvp) + +static int +el_probe(dvp) struct isa_device *dvp; { struct ie_softc *sc = &ie_softc[dvp->id_unit]; @@ -538,6 +569,237 @@ static int ni_probe(dvp) } +static void +ee16_shutdown(howto, sc) + int howto; + void *sc; +{ + struct ie_softc *ie = (struct ie_softc *)sc; + int unit = ie - &ie_softc[0]; + + ee16_reset_586(unit); + outb(PORT + IEE16_ECTRL, IEE16_RESET_ASIC); + outb(PORT + IEE16_ECTRL, 0); +} + + +/* Taken almost exactly from Rod's if_ix.c. */ + +int +ee16_probe(dvp) + struct isa_device *dvp; +{ + struct ie_softc *sc = &ie_softc[dvp->id_unit]; + + int i; + int unit = dvp->id_unit; + u_short board_id, id_var1, id_var2, checksum = 0; + u_short eaddrtemp, irq; + u_short pg, adjust, decode, edecode; + u_char bart_config; + u_long bd_maddr; + + short irq_translate[] = {0, IRQ9, IRQ3, IRQ4, IRQ5, IRQ10, IRQ11, 0}; + char irq_encode[] = { 0, 0, 0, 2, 3, 4, 0, 0, + 0, 1, 5, 6, 0, 0, 0, 0 }; + + /* Need this for part of the probe. */ + sc->ie_reset_586 = ee16_reset_586; + sc->ie_chan_attn = ee16_chan_attn; + + /* unsure if this is necessary */ + sc->bus_use = 0; + + /* reset any ee16 at the current iobase */ + outb(dvp->id_iobase + IEE16_ECTRL, IEE16_RESET_ASIC); + outb(dvp->id_iobase + IEE16_ECTRL, 0); + DELAY(240); + + /* now look for ee16. */ + board_id = id_var1 = id_var2 = 0; + for (i=0; i<4 ; i++) { + id_var1 = inb(dvp->id_iobase + IEE16_ID_PORT); + id_var2 = ((id_var1 & 0x03) << 2); + board_id |= (( id_var1 >> 4) << id_var2); + } + + if (board_id != IEE16_ID) { + printf("ie%d: unknown board_id: %x\n", unit, board_id); + return 0; + } + + /* need sc->port for ee16_read_eeprom */ + sc->port = dvp->id_iobase; + sc->hard_type = IE_EE16; + + /* + * The shared RAM location on the EE16 is encoded into bits + * 3-7 of EEPROM location 6. We zero the upper byte, and + * shift the 5 bits right 3. The resulting number tells us + * the RAM location. Because the EE16 supports either 16k or 32k + * of shared RAM, we only worry about the 32k locations. + * + * NOTE: if a 64k EE16 exists, it should be added to this switch. + * then the ia->ia_msize would need to be set per case statement. + * + * value msize location + * ===== ===== ======== + * 0x03 0x8000 0xCC000 + * 0x06 0x8000 0xD0000 + * 0x0C 0x8000 0xD4000 + * 0x18 0x8000 0xD8000 + * + */ + + bd_maddr = 0; + i = (ee16_read_eeprom(sc, 6) & 0x00ff ) >> 3; + switch(i) { + case 0x03: + bd_maddr = 0xCC000; + break; + case 0x06: + bd_maddr = 0xD0000; + break; + case 0x0c: + bd_maddr = 0xD4000; + break; + case 0x18: + bd_maddr = 0xD8000; + break; + default: + bd_maddr = 0 ; + break; + } + dvp->id_msize = 0x8000; + if (kvtop(dvp->id_maddr) != bd_maddr) { + printf("ie%d: kernel configured maddr %lx doesn't match board configured maddr %x\n", + unit, kvtop(dvp->id_maddr), bd_maddr); + } + + + sc->iomembot = dvp->id_maddr; + sc->iomem = 0; /* XXX some probes set this and some don't */ + sc->iosize = dvp->id_msize; + + /* need to put the 586 in RESET while we access the eeprom. */ + outb( PORT + IEE16_ECTRL, IEE16_RESET_586); + + /* read the eeprom and checksum it, should == IEE16_ID */ + for(i = 0; i < 0x40; i++) + checksum += ee16_read_eeprom(sc, i); + + if (checksum != IEE16_ID) { + printf("ie%d: invalid eeprom checksum: %x\n", unit, checksum); + return 0; + } + + /* + * 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. + * + * If the size does not match the passed in memory allocation size + * issue a warning, but continue with the minimum of the two sizes. + */ + + switch (dvp->id_msize) { + case 65536: + case 32768: /* XXX Only support 32k and 64k right now */ + break; + case 16384: + case 49512: + default: + printf("ie%d: mapped memory size %d not supported\n", unit, + dvp->id_msize); + return 0; + break; /* NOTREACHED */ + } + + if ((kvtop(dvp->id_maddr) < 0xC0000) || + (kvtop(dvp->id_maddr) + sc->iosize > 0xF0000)) { + printf("ie%d: mapped memory location %x out of range\n", unit, + dvp->id_maddr); + return 0; + } + + pg = (kvtop(dvp->id_maddr) & 0x3C000) >> 14; + adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2; + decode = ((1 << (sc->iosize / 16384)) - 1) << pg; + edecode = ((~decode >> 4) & 0xF0) | (decode >> 8); + + /* ZZZ This should be checked against eeprom location 6, low byte */ + outb(PORT + IEE16_MEMDEC, decode & 0xFF); + /* ZZZ This should be checked against eeprom location 1, low byte */ + outb(PORT + IEE16_MCTRL, adjust); + /* ZZZ Now if I could find this one I would have it made */ + outb(PORT + IEE16_MPCTRL, (~decode & 0xFF)); + /* ZZZ I think this is location 6, high byte */ + outb(PORT + IEE16_MECTRL, edecode); /*XXX disable Exxx */ + + (void)kvtop(dvp->id_maddr); + + /* + * first prime the stupid bart DRAM controller so that it + * works, then zero out all of memory. + */ + bzero(sc->iomembot, 32); + bzero(sc->iomembot, sc->iosize); + + /* + * 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 = ee16_read_eeprom(sc, IEE16_EEPROM_CONFIG1); + irq = (irq & IEE16_EEPROM_IRQ) >> IEE16_EEPROM_IRQ_SHIFT; + irq = irq_translate[irq]; + if (dvp->id_irq > 0) { + if (irq != dvp->id_irq) { + printf("ie%d: WARNING: board configured at irq %d, using %d\n", + dvp->id_unit, irq); + irq = dvp->id_unit; + } + } else { + dvp->id_irq = irq; + } + sc->irq_encoded = irq_encode[ffs(irq) - 1]; + + /* + * Get the hardware ethernet address from the EEPROM and + * save it in the softc for use by the 586 setup code. + */ + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_HIGH); + sc->arpcom.ac_enaddr[1] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[0] = eaddrtemp >> 8; + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_MID); + sc->arpcom.ac_enaddr[3] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[2] = eaddrtemp >> 8; + eaddrtemp = ee16_read_eeprom(sc, IEE16_EEPROM_ENET_LOW); + sc->arpcom.ac_enaddr[5] = eaddrtemp & 0xFF; + sc->arpcom.ac_enaddr[4] = eaddrtemp >> 8; + + /* disable the board interrupts */ + outb(PORT + IEE16_IRQ, sc->irq_encoded); + + /* enable loopback to keep bad packets off the wire */ + if(sc->hard_type == IE_EE16) { + bart_config = inb(PORT + IEE16_CONFIG); + bart_config |= IEE16_BART_LOOPBACK; + bart_config |= IEE16_BART_MCS16_TEST; /*inb doesn't get bit! */ + outb(PORT + IEE16_CONFIG, bart_config); + bart_config = inb(PORT + IEE16_CONFIG); + } + + /* take the board out of reset state */ + outb(PORT + IEE16_ECTRL, 0); + DELAY(100); + + if (!check_ie_present(unit, dvp->id_maddr, sc->iosize)) + return 0; + + return 16; /* return the number of I/O ports */ +} + /* * Taken almost exactly from Bill's if_is.c, then modified beyond recognition. */ @@ -553,7 +815,7 @@ ieattach(dvp) ifp->if_unit = unit; ifp->if_name = iedriver.name; ifp->if_mtu = ETHERMTU; - printf(" <%s R%d> ethernet address %6D\n", + printf("ie%d: <%s R%d> address %6D\n", unit, ie_hardware_names[ie->hard_type], ie->hard_vers + 1, ie->arpcom.ac_enaddr, ":"); @@ -566,6 +828,9 @@ ieattach(dvp) ifp->if_addrlen = 6; ifp->if_hdrlen = 14; + if (ie->hard_type == IE_EE16) + at_shutdown(ee16_shutdown, ie, SHUTDOWN_POST_SYNC); + #if NBPFILTER > 0 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif @@ -578,21 +843,22 @@ ieattach(dvp) /* * What to do upon receipt of an interrupt. */ -void ieintr(unit) - int unit; +void +ieintr(unit) + int unit; { register struct ie_softc *ie = &ie_softc[unit]; register u_short status; - status = ie->scb->ie_status; + /* Clear the interrupt latch on the 3C507. */ + if (ie->hard_type == IE_3C507 && (inb(PORT + IE507_CTRL) & EL_CTRL_INTL)) + outb(PORT + IE507_ICTRL, 1); - /* This if statement written by Charles Martin Hannum. */ - if ((status & IE_ST_WHENCE) == 0) { - /* Clear the interrupt latch on the 3C507. */ - if (ie->hard_type == IE_3C507 && - (inb(PORT + IE507_CTRL) & EL_CTRL_INTL)) - outb(PORT + IE507_ICTRL, 1); - } + /* disable interrupts on the EE16. */ + if (ie->hard_type == IE_EE16) + outb(PORT + IEE16_IRQ, ie->irq_encoded); + + status = ie->scb->ie_status; loop: if(status & (IE_ST_RECV | IE_ST_RNR)) { @@ -632,25 +898,30 @@ loop: && (ie_debug & IED_CNA)) printf("ie%d: cna\n", unit); #endif - + /* Don't ack interrupts which we didn't receive */ ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn); - if((status = ie->scb->ie_status) & IE_ST_WHENCE) - goto loop; + if ((status = ie->scb->ie_status) & IE_ST_WHENCE) + goto loop; - /* This comment and if statement written by Charles Martin Hannum. */ /* Clear the interrupt latch on the 3C507. */ if (ie->hard_type == IE_3C507) - outb(PORT + IE507_ICTRL, 1); + outb(PORT + IE507_ICTRL, 1); + + /* enable interrupts on the EE16. */ + if (ie->hard_type == IE_EE16) + outb(PORT + IEE16_IRQ, ie->irq_encoded | IEE16_IRQ_ENABLE); + } /* * Process a received-frame interrupt. */ -static int ierint(unit, ie) - int unit; - struct ie_softc *ie; +static int +ierint(unit, ie) + int unit; + struct ie_softc *ie; { int i, status; static int timesthru = 1024; @@ -662,8 +933,9 @@ static int ierint(unit, ie) if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) { ie->arpcom.ac_if.if_ipackets++; if(!--timesthru) { - ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align + - ie->scb->ie_err_resource + ie->scb->ie_err_overrun; + ie->arpcom.ac_if.if_ierrors += + ie->scb->ie_err_crc + ie->scb->ie_err_align + + ie->scb->ie_err_resource + ie->scb->ie_err_overrun; ie->scb->ie_err_crc = 0; ie->scb->ie_err_align = 0; ie->scb->ie_err_resource = 0; @@ -918,7 +1190,7 @@ static inline int ie_packet_len(int unit, struct ie_softc *ie) { i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST; acc += ie_buflen(ie, head); - head = (head + 1) % NBUFFS; + head = (head + 1) % NRXBUF; } while(!i); return acc; @@ -1086,9 +1358,9 @@ nextbuf: offset = 0; ie->rbuffs[head]->ie_rbd_actual = 0; ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST; - ie->rbhead = head = (head + 1) % NBUFFS; + ie->rbhead = head = (head + 1) % NRXBUF; ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; - ie->rbtail = (ie->rbtail + 1) % NBUFFS; + ie->rbtail = (ie->rbtail + 1) % NRXBUF; } /* @@ -1223,9 +1495,9 @@ static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) { ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST; ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0; - ie->rbhead = (ie->rbhead + 1) % NBUFFS; + ie->rbhead = (ie->rbhead + 1) % NRXBUF; ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST; - ie->rbtail = (ie->rbtail + 1) % NBUFFS; + ie->rbtail = (ie->rbtail + 1) % NRXBUF; } while(!i); } @@ -1264,7 +1536,7 @@ iestart(ifp) } m_freem(m0); - len = max(len, ETHERMINLEN); + len = max(len, ETHER_MIN_LEN); #if NBPFILTER > 0 /* @@ -1288,7 +1560,7 @@ iestart(ifp) *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]); bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link; ie->xmit_count++; - } while(ie->xmit_count < 2); + } while (ie->xmit_count < NTXBUF); /* * If we queued up anything for transmission, send it. @@ -1433,6 +1705,16 @@ void sl_reset_586(unit) outb(PORT + IEATT_RESET, 0); } +void +ee16_reset_586(unit) + int unit; +{ + outb(PORT + IEE16_ECTRL, IEE16_RESET_586); + DELAY(100); + outb(PORT + IEE16_ECTRL, 0); + DELAY(100); +} + void el_chan_attn(unit) int unit; { @@ -1445,6 +1727,105 @@ void sl_chan_attn(unit) outb(PORT + IEATT_ATTN, 0); } +void +ee16_chan_attn(unit) + int unit; +{ + outb(PORT + IEE16_ATTN, 0); +} + +u_short +ee16_read_eeprom(sc, location) + struct ie_softc *sc; + int location; +{ + int ectrl, edata; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= IEE16_ECTRL_MASK; + ectrl |= IEE16_ECTRL_EECS; + outb(sc->port + IEE16_ECTRL, ectrl); + + ee16_eeprom_outbits(sc, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1); + ee16_eeprom_outbits(sc, location, IEE16_EEPROM_ADDR_SIZE); + edata = ee16_eeprom_inbits(sc); + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS); + outb(sc->port + IEE16_ECTRL, ectrl); + ee16_eeprom_clock(sc, 1); + ee16_eeprom_clock(sc, 0); + return edata; +} + +void +ee16_eeprom_outbits(sc, edata, count) + struct ie_softc *sc; + int edata, count; +{ + int ectrl, i; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~IEE16_RESET_ASIC; + for (i = count - 1; i >= 0; i--) { + ectrl &= ~IEE16_ECTRL_EEDI; + if (edata & (1 << i)) { + ectrl |= IEE16_ECTRL_EEDI; + } + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(1); /* eeprom data must be setup for 0.4 uSec */ + ee16_eeprom_clock(sc, 1); + ee16_eeprom_clock(sc, 0); + } + ectrl &= ~IEE16_ECTRL_EEDI; + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(1); /* eeprom data must be held for 0.4 uSec */ +} + +int +ee16_eeprom_inbits(sc) + struct ie_softc *sc; +{ + int ectrl, edata, i; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~IEE16_RESET_ASIC; + for (edata = 0, i = 0; i < 16; i++) { + edata = edata << 1; + ee16_eeprom_clock(sc, 1); + ectrl = inb(sc->port + IEE16_ECTRL); + if (ectrl & IEE16_ECTRL_EEDO) { + edata |= 1; + } + ee16_eeprom_clock(sc, 0); + } + return (edata); +} + +void +ee16_eeprom_clock(sc, state) + struct ie_softc *sc; + int state; +{ + int ectrl; + + ectrl = inb(sc->port + IEE16_ECTRL); + ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK); + if (state) { + ectrl |= IEE16_ECTRL_EESK; + } + outb(sc->port + IEE16_ECTRL, ectrl); + DELAY(9); /* EESK must be stable for 8.38 uSec */ +} + +static inline void +ee16_interrupt_enable(sc) + struct ie_softc *sc; +{ + DELAY(100); + outb(sc->port + IEE16_IRQ, sc->irq_encoded | IEE16_IRQ_ENABLE); + DELAY(100); +} + void sl_read_ether(unit, addr) int unit; unsigned char addr[6]; @@ -1651,7 +2032,7 @@ static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) { */ rbd = (void *)ptr; - for(i = 0; i < NBUFFS; i++) { + for(i = 0; i < NRXBUF; i++) { ie->rbuffs[i] = rbd; bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */ ptr = (caddr_t)Align(ptr + sizeof *rbd); @@ -1663,19 +2044,19 @@ static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) { } /* Now link them together */ - for(i = 0; i < NBUFFS; i++) { - ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]); + for(i = 0; i < NRXBUF; i++) { + ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NRXBUF]); } /* Tag EOF on the last one */ - ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST; + ie->rbuffs[NRXBUF - 1]->ie_rbd_length |= IE_RBD_LAST; /* We use the head and tail pointers on receive to keep track of * the order in which RFDs and RBDs are used. */ ie->rfhead = 0; ie->rftail = NFRAMES - 1; ie->rbhead = 0; - ie->rbtail = NBUFFS - 1; + ie->rbtail = NRXBUF - 1; ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]); ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]); @@ -1780,6 +2161,21 @@ ieinit(unit) */ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn); + /* take the ee16 out of loopback */ + { + u_char bart_config; + + if(ie->hard_type == IE_EE16) { + bart_config = inb(PORT + IEE16_CONFIG); + bart_config &= ~IEE16_BART_LOOPBACK; + /* inb doesn't get bit! */ + bart_config |= IEE16_BART_MCS16_TEST; + outb(PORT + IEE16_CONFIG, bart_config); + ee16_interrupt_enable(ie); + ee16_chan_attn(unit); + } + } + /* * Set up the RFA. */ @@ -1819,7 +2215,7 @@ ieinit(unit) */ ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL; - ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */ + ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels we're here */ start_receiver(unit); return; } diff --git a/sys/i386/isa/if_ix.c b/sys/i386/isa/if_ix.c deleted file mode 100644 index 998f690..0000000 --- a/sys/i386/isa/if_ix.c +++ /dev/null @@ -1,1634 +0,0 @@ -/* - * Copyright (c) 1993, 1994, 1995 - * Rodney W. Grimes, Milwaukie, Oregon 97222. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer as - * the first lines of this file unmodified. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Rodney W. Grimes. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL RODNEY W. GRIMES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_ix.c,v 1.25 1997/02/22 09:36:31 peter Exp $ - */ - -#include "ix.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/conf.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <sys/errno.h> -#include <sys/syslog.h> - -#include <machine/clock.h> -#include <machine/md_var.h> - -#include <net/if.h> -#include <net/if_types.h> -#include <net/if_dl.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 IPX /*ZZZ no work done on this, this is just here to remind me*/ -#include <netipx/ipx.h> -#include <netipx/ipx_if.h> -#endif /* IPX */ - -#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/isa/if_ixreg.h> - -static 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); -static u_short ixacknowledge(int); -static int ix_cb_wait(cb_t *, char *); -static int ix_scb_wait(scb_t *, u_short, char *); -static int ixprobe(struct isa_device *); -static int ixattach(struct isa_device *); -static void ixinit(int); -static void ixinit_rfa(int); -static void ixinit_tfa(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 *); -static void ixstart(struct ifnet *); -static int ixstop(struct ifnet *); -static int ixdone(struct ifnet *); -static int ixioctl(struct ifnet *, int, caddr_t); -static void ixreset(int); -static void ixwatchdog(struct ifnet *); -static u_short ixeeprom_read(int, int); -static void ixeeprom_outbits(int, int, int); -static int ixeeprom_inbits(int); -static 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}; - char irq_encode[] = { 0, 0, 0, 2, 3, 4, 0, 0, 0, 1, 5, 6, 0, 0, 0, 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 = %lx\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; - irq = irq_translate[irq]; - if (dvp->id_irq > 0) { - if (irq != dvp->id_irq) { - printf("ix%d: WARNING: board is configured for IRQ %d, using %d\n", - unit, ffs(irq) - 1, ffs(dvp->id_irq) - 1); - irq = dvp->id_irq; - } - } else { - dvp->id_irq = irq; - } - sc->irq_encoded = irq_encode[ffs(irq) - 1]; - if (sc->irq_encoded == 0) { - printf("ix%d: invalid irq (%d)\n", unit, ffs(irq) - 1); - goto ixprobe_exit; - } - - /* - * 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; - - 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. - * Further note by GW: - * Actually, it's a complete waste of time to zero any of - * this stuff because the C language guarantees that it's - * already zeroed. If this code is changed to do dynamic - * allocation, this will have to get revisited. - */ - bzero(ifp, sizeof(ifp)); - ifp->if_softc = sc; - ifp->if_name = ixdriver.name; - ifp->if_unit = unit; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; - ifp->if_output = ether_output; - ifp->if_start = ixstart; - ifp->if_done = ixdone; - ifp->if_ioctl = ixioctl; - ifp->if_watchdog = ixwatchdog; - ifp->if_type = IFT_ETHER; - ifp->if_addrlen = ETHER_ADDR_LEN; - ifp->if_hdrlen = ETHER_HDR_LEN; -#ifdef IXCOUNTERS - /* - * ZZZ more counters added, but bzero gets them - */ -#endif /* IXCOUNTERS */ - - if_attach(ifp); - ether_ifattach(ifp); - - printf("ix%d: address %6D\n", unit, 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_ADDR_LEN); - 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]; - 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 = %lx\t\trfd_tail = %lx\n", - kvtop(sc->rfd_head), kvtop(sc->rfd_tail)); - printf(" rbd_head = %lx\t\trbd_tail = %lx\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 = %lx\t\trbd = %lx\t\trb = %lx\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 = %lx\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 %lx\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]; - 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 = %lx\t\tcb_tail = %lx\n", - kvtop(sc->cb_head), kvtop(sc->cb_tail)); - printf(" tbd_head = %lx\t\ttbd_tail = %lx\n", - kvtop(sc->tbd_head), kvtop(sc->tbd_tail)); - for (i = 0; i < TB_COUNT; i++, cb++, tbd++, tb += TB_SIZE) { - printf(" %d:\tcb = %lx\t\ttbd = %lx\t\ttb = %lx\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 = %lx\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 %lx\n", kvtop(tb));) - DEBUGDO(printf("ix%d: ixinit_tfa exit\n", unit);) - DEBUGEND -} - -void -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 -} - -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) { - - DEBUGBEGIN(DEBUGINTR_CX) - DEBUGDO(ix_softc_t *sc = &ix_softc[unit];) - 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]; - - 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 length, - bytesleft; - - rbd = (rbd_t *)(sc->maddr + rfd->rbd_offset); - rb = (caddr_t)(sc->maddr + rbd->buffer); - DEBUGBEGIN(DEBUGINTR_FR) - DEBUGDO(int i;) - 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; - - /* 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 = ifp->if_softc; - 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_LEN) length = ETHER_MIN_LEN; -#ifdef DIAGNOSTIC - if (length > ETHER_MAX_LEN) { - /* 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_LEN); - } -#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 = ifp->if_softc; - - 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; - int s; - - DEBUGBEGIN(DEBUGIOCTL) - DEBUGDO(printf("ixioctl:");) - DEBUGEND - - s = splimp(); - - 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: { - arp_ifinit((struct arpcom *)ifp, ifa); - break; - } -#endif /* INET */ -#ifdef IPX - case AF_IPX: { - /*ZZZ*/printf("Address family IPX not supported by ixioctl\n"); - break; - } -#endif /* IPX */ -#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; - } - } - splx(s); - - DEBUGBEGIN(DEBUGIOCTL) - DEBUGDO(printf("ixioctl exit\n");) - DEBUGEND - return(status); -} - -void -ixreset(int unit) { - 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(struct ifnet *ifp) { - log(LOG_ERR, "ix%d: device timeout\n", ifp->if_unit); - ifp->if_oerrors++; - ixreset(ifp->if_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 */ -} diff --git a/sys/i386/isa/if_ixreg.h b/sys/i386/isa/if_ixreg.h deleted file mode 100644 index 8b22c73..0000000 --- a/sys/i386/isa/if_ixreg.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (c) 1993, 1994, 1995 - * Rodney W. Grimes, Milwaukie, Oregon 97222. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer as - * the first lines of this file unmodified. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Rodney W. Grimes. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL RODNEY W. GRIMES BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ - */ - -/* - * These really belong some place else, but I can't find them right - * now. I'll look again latter - */ - -#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 /* Configuration 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_LEN) /* 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_LEN) /* size of receive buffer */ - -typedef 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 struct /* Intermediate System Configuration Pointer */ - { - volatile - 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 struct /* System Control Block */ - { - volatile - 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 */ - volatile - u_short crc_errors; /* frame was aligned, but bad crc */ - volatile - u_short aln_errors; /* frame was not aligned, and had bad crc */ - volatile - u_short rsc_errors; /* did not have resources to receive */ - volatile - u_short ovr_errors; /* system bus was not available to receive */ - } scb_t; - -typedef struct /* command block - nop (also the common part of cb's */ - { - volatile - 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 struct /* command block - individual address setup command */ - { - cb_t common; /* common part of all command blocks */ - u_char source[ETHER_ADDR_LEN]; - /* ethernet hardware address */ - } cb_ias_t; - -typedef 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 struct /* command block - multicast address setup command */ - { - cb_t common; /* common part of all command blocks */ - } cb_mcas_t; - -typedef 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_ADDR_LEN]; - /* 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 struct /* command block - tdr command */ - { - cb_t common; /* common part of all command blocks */ - } cb_tdr_t; - -typedef struct /* command block - dump command */ - { - cb_t common; /* common part of all command blocks */ - } cb_dump_t; - -typedef struct /* command block - diagnose command */ - { - cb_t common; /* common part of all command blocks */ - } cb_diagnose_t; - -typedef struct /* Transmit Buffer Descriptor */ - { - volatile - 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 struct /* Receive Frame Descriptor */ - { - volatile - 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 struct /* Receive Buffer Descriptor */ - { - volatile - 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; |