summaryrefslogtreecommitdiffstats
path: root/sys/dev/ie
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1997-04-14 00:37:53 +0000
committergibbs <gibbs@FreeBSD.org>1997-04-14 00:37:53 +0000
commita35f2233319c3f681246314ae3399e81d0943fdb (patch)
tree9d134091254d79fdf1b90835d31a6027807b2ada /sys/dev/ie
parentf1730f3a0ad9ba7560c9baf9e04abc106b4fcdcc (diff)
downloadFreeBSD-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/dev/ie')
-rw-r--r--sys/dev/ie/if_ie.c596
1 files changed, 496 insertions, 100 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;
}
OpenPOWER on IntegriCloud