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
This commit is contained in:
Justin T. Gibbs 1997-04-14 00:37:53 +00:00
parent c1aa7eb5f4
commit 5a2037874f
4 changed files with 992 additions and 2193 deletions

View File

@ -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 @@ void ieintr(unit)
&& (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 @@ static inline int ieget(unit, ie, mp, ehp, to_bpf)
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;
}

View File

@ -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 @@ void ieintr(unit)
&& (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 @@ static inline int ieget(unit, ie, mp, ehp, to_bpf)
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;