summaryrefslogtreecommitdiffstats
path: root/sys/dev/ie
diff options
context:
space:
mode:
authormdodd <mdodd@FreeBSD.org>2003-03-29 13:36:41 +0000
committermdodd <mdodd@FreeBSD.org>2003-03-29 13:36:41 +0000
commitededebc1a4663fdc2452865586200d45a8fef1fe (patch)
treed4414c2e03011651886d8255ba82bb7d6f7f893c /sys/dev/ie
parent2e756697baa6efb267ada7ae2beb9d60e2614632 (diff)
downloadFreeBSD-src-ededebc1a4663fdc2452865586200d45a8fef1fe.zip
FreeBSD-src-ededebc1a4663fdc2452865586200d45a8fef1fe.tar.gz
- Move driver to newbus.
- Provide identify methods for EtherExpress and 3c507 cards; this means these cards no longer need wired configs. - Provide a detach method.
Diffstat (limited to 'sys/dev/ie')
-rw-r--r--sys/dev/ie/if_ie.c668
-rw-r--r--sys/dev/ie/if_ie_isa.c885
-rw-r--r--sys/dev/ie/if_iereg.h2
-rw-r--r--sys/dev/ie/if_ievar.h91
4 files changed, 1115 insertions, 531 deletions
diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c
index 9582ad1..60d5f89 100644
--- a/sys/dev/ie/if_ie.c
+++ b/sys/dev/ie/if_ie.c
@@ -110,10 +110,6 @@
* 16-pointers, we subtract iomem and and with 0xffff.
*/
-#include "ie.h"
-#include "opt_inet.h"
-#include "opt_ipx.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/eventhandler.h>
@@ -124,6 +120,14 @@
#include <sys/sockio.h>
#include <sys/syslog.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -132,11 +136,8 @@
#include <netinet/in.h>
#include <netinet/if_ether.h>
-#include <machine/md_var.h>
-
-#include <i386/isa/isa_device.h>
-#include <i386/isa/icu.h>
#include <dev/ic/i82586.h>
+#include <dev/ie/if_ievar.h>
#include <dev/ie/if_iereg.h>
#include <dev/ie/if_ie507.h>
#include <dev/ie/if_iee16.h>
@@ -144,10 +145,6 @@
#include <net/bpf.h>
-#ifndef COMPAT_OLDISA
-#error "The ie device requires the old isa compatibility shims"
-#endif
-
#ifdef DEBUG
#define IED_RINT 0x01
#define IED_TINT 0x02
@@ -163,27 +160,11 @@ static int ie_debug = IED_RNR;
/* Forward declaration */
struct ie_softc;
-static int ieprobe (struct isa_device * dvp);
-static int ieattach (struct isa_device * dvp);
-static ointhand2_t ieintr;
-static int sl_probe (struct isa_device * dvp);
-static int el_probe (struct isa_device * dvp);
-static int ee16_probe (struct isa_device * dvp);
-
-static int check_ie_present (struct ie_softc *, caddr_t, unsigned);
static void ieinit (void *);
static void ie_stop (struct ie_softc *);
static int ieioctl (struct ifnet *, u_long, caddr_t);
static void iestart (struct ifnet *);
-static void el_reset_586 (struct ie_softc *);
-static void el_chan_attn (struct ie_softc *);
-
-static void sl_reset_586 (struct ie_softc *);
-static void sl_chan_attn (struct ie_softc *);
-
-static void ee16_reset_586 (struct ie_softc *);
-static void ee16_chan_attn (struct ie_softc *);
static __inline void
ee16_interrupt_enable (struct ie_softc *);
static void ee16_eeprom_outbits (struct ie_softc *, int, int);
@@ -197,7 +178,6 @@ static __inline void
static void iereset (struct ie_softc *);
static void ie_readframe (struct ie_softc *, int);
static void ie_drop_packet_buffer (struct ie_softc *);
-static void sl_read_ether (struct ie_softc *, unsigned char *);
static void find_ie_mem_size (struct ie_softc *);
static void chan_attn_timeout (void *);
static int command_and_wait (struct ie_softc *,
@@ -216,32 +196,12 @@ static void ie_mc_reset (struct ie_softc *);
#ifdef DEBUG
static void print_rbd (volatile struct ie_recv_buf_desc * rbd);
-
static int in_ierint = 0;
static int in_ietint = 0;
-
#endif
-/*
- * This tells the autoconf code how to set us up.
- */
-struct isa_driver iedriver = {
- INTR_TYPE_NET,
- ieprobe, ieattach, "ie"
-};
-COMPAT_ISA_DRIVER(ie, iedriver);
-
-enum ie_hardware {
- IE_STARLAN10,
- IE_EN100,
- IE_SLFIBER,
- IE_3C507,
- IE_NI5210,
- IE_EE16,
- IE_UNKNOWN
-};
-
static const char *ie_hardware_names[] = {
+ "None",
"StarLAN 10",
"EN100",
"StarLAN Fiber",
@@ -281,238 +241,9 @@ static const char *ie_hardware_names[] = {
#define NTXBUFS 1 /* number of transmit commands */
#define IE_TBUF_SIZE ETHER_MAX_LEN /* size of transmit buffer */
-/*
- * Ethernet status, per interface.
- */
-static struct ie_softc {
- struct arpcom arpcom;
- void (*ie_reset_586) (struct ie_softc *);
- void (*ie_chan_attn) (struct ie_softc *);
- enum ie_hardware hard_type;
- int hard_vers;
- int unit;
-
- 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 */
-
- int want_mcsetup;
- int promisc;
- int nframes;
- int nrxbufs;
- int ntxbufs;
- volatile struct ie_int_sys_conf_ptr *iscp;
- volatile struct ie_sys_ctl_block *scb;
- volatile struct ie_recv_frame_desc **rframes; /* nframes worth */
- volatile struct ie_recv_buf_desc **rbuffs; /* nrxbufs worth */
- volatile u_char **cbuffs; /* nrxbufs worth */
- int rfhead, rftail, rbhead, rbtail;
-
- volatile struct ie_xmit_cmd **xmit_cmds; /* ntxbufs worth */
- volatile struct ie_xmit_buf **xmit_buffs; /* ntxbufs worth */
- volatile u_char **xmit_cbuffs; /* ntxbufs worth */
- int xmit_count;
-
- 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)((uintptr_t)ptr - (uintptr_t)base))
#define MK_16(base, ptr) ((u_short)(uintptr_t)MK_24(base, ptr))
-#define PORT(sc) (sc->port)
-#define MEM(sc) (sc->iomem)
-
-static int
-ieprobe(struct isa_device *dvp)
-{
- int ret;
-
- ret = sl_probe(dvp);
- if (!ret)
- ret = el_probe(dvp);
- if (!ret)
- ret = ee16_probe(dvp);
-
- return (ret);
-}
-
-static int
-sl_probe(struct isa_device *dvp)
-{
- struct ie_softc * sc = &ie_softc[dvp->id_unit];
- u_char c;
-
- sc->port = dvp->id_iobase;
- sc->iomembot = dvp->id_maddr;
- sc->iomem = 0;
- sc->bus_use = 0;
-
- c = inb(PORT(sc) + IEATT_REVISION);
- switch (SL_BOARD(c)) {
- case SL10_BOARD:
- sc->hard_type = IE_STARLAN10;
- break;
- case EN100_BOARD:
- sc->hard_type = IE_EN100;
- break;
- case SLFIBER_BOARD:
- sc->hard_type = IE_SLFIBER;
- break;
- case 0x00:
- if (inb(PORT(sc) + IEATT_ATTRIB) != 0x55)
- return (0);
-
- sc->hard_type = IE_NI5210;
- sc->bus_use = 1;
-
- break;
-
- /*
- * Anything else is not recognized or cannot be used.
- */
- default:
- return (0);
- }
-
- sc->ie_reset_586 = sl_reset_586;
- sc->ie_chan_attn = sl_chan_attn;
-
- sc->hard_vers = SL_REV(c);
-
- /*
- * Divine memory size on-board the card. Ususally 16k.
- */
- find_ie_mem_size(sc);
-
- if (!sc->iosize) {
- return (0);
- }
-
- if (!dvp->id_msize) {
- dvp->id_msize = sc->iosize;
- } else if (dvp->id_msize != sc->iosize) {
- printf("ie%d: kernel configured msize %d "
- "doesn't match board configured msize %d\n",
- sc->unit,
- dvp->id_msize,
- sc->iosize);
- return (0);
- }
-
- switch (sc->hard_type) {
- case IE_EN100:
- case IE_STARLAN10:
- case IE_SLFIBER:
- case IE_NI5210:
- sl_read_ether(sc, sc->arpcom.ac_enaddr);
- break;
- default:
- if (bootverbose)
- printf("ie%d: unknown AT&T board type code %d\n",
- sc->unit,
- sc->hard_type);
- return (0);
- }
-
- return (16);
-}
-
-static int
-el_probe(struct isa_device *dvp)
-{
- struct ie_softc *sc = &ie_softc[dvp->id_unit];
- u_char c;
- int i;
- u_char signature[] = "*3COM*";
-
- sc->unit = dvp->id_unit;
- sc->port = dvp->id_iobase;
- sc->iomembot = dvp->id_maddr;
- sc->bus_use = 0;
-
- /* Need this for part of the probe. */
- sc->ie_reset_586 = el_reset_586;
- sc->ie_chan_attn = el_chan_attn;
-
- /* Reset and put card in CONFIG state without changing address. */
- elink_reset();
- outb(ELINK_ID_PORT, 0x00);
- elink_idseq(ELINK_507_POLY);
- elink_idseq(ELINK_507_POLY);
- outb(ELINK_ID_PORT, 0xff);
-
- c = inb(PORT(sc) + IE507_MADDR);
- if (c & 0x20) {
-#ifdef DEBUG
- printf("ie%d: can't map 3C507 RAM in high memory\n", sc->unit);
-#endif
- return (0);
- }
- /* go to RUN state */
- outb(ELINK_ID_PORT, 0x00);
- elink_idseq(ELINK_507_POLY);
- outb(ELINK_ID_PORT, 0x00);
-
- outb(PORT(sc) + IE507_CTRL, EL_CTRL_NRST);
-
- for (i = 0; i < 6; i++)
- if (inb(PORT(sc) + i) != signature[i])
- return (0);
-
- c = inb(PORT(sc) + IE507_IRQ) & 0x0f;
-
- if (dvp->id_irq != (1 << c)) {
- printf("ie%d: kernel configured irq %d "
- "doesn't match board configured irq %d\n",
- sc->unit, ffs(dvp->id_irq) - 1, c);
- return (0);
- }
- c = (inb(PORT(sc) + IE507_MADDR) & 0x1c) + 0xc0;
-
- if (kvtop(dvp->id_maddr) != ((int) c << 12)) {
- printf("ie%d: kernel configured maddr %lx "
- "doesn't match board configured maddr %x\n",
- sc->unit, (u_long)kvtop(dvp->id_maddr), (int) c << 12);
- return (0);
- }
- outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL);
-
- sc->hard_type = IE_3C507;
- sc->hard_vers = 0; /* 3C507 has no version number. */
-
- /*
- * Divine memory size on-board the card.
- */
- find_ie_mem_size(sc);
-
- if (!sc->iosize) {
- printf("ie%d: can't find shared memory\n", sc->unit);
- outb(PORT(sc) + IE507_CTRL, EL_CTRL_NRST);
- return (0);
- }
- if (!dvp->id_msize)
- dvp->id_msize = sc->iosize;
- else if (dvp->id_msize != sc->iosize) {
- printf("ie%d: kernel configured msize %d "
- "doesn't match board configured msize %d\n",
- sc->unit, dvp->id_msize, sc->iosize);
- outb(PORT(sc) + IE507_CTRL, EL_CTRL_NRST);
- return (0);
- }
- sl_read_ether(sc, sc->arpcom.ac_enaddr);
-
- /* Clear the interrupt latch just in case. */
- outb(PORT(sc) + IE507_ICTRL, 1);
-
- return (16);
-}
-
-
static void
ee16_shutdown(void *xsc, int howto)
{
@@ -523,236 +254,28 @@ ee16_shutdown(void *xsc, int howto)
outb(PORT(sc) + IEE16_ECTRL, 0);
}
-
-/* Taken almost exactly from Rod's if_ix.c. */
-
-static int
-ee16_probe(struct isa_device *dvp)
-{
- struct ie_softc *sc = &ie_softc[dvp->id_unit];
-
- int i;
- 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) {
- if (bootverbose)
- printf("ie%d: unknown board_id: %x\n", sc->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 %lx\n",
- sc->unit, (u_long)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(sc) + 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", sc->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",
- sc->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 %p out of range\n",
- sc->unit, (void *)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(sc) + IEE16_MEMDEC, decode & 0xFF);
- /* ZZZ This should be checked against eeprom location 1, low byte */
- outb(PORT(sc) + IEE16_MCTRL, adjust);
- /* ZZZ Now if I could find this one I would have it made */
- outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
- /* ZZZ I think this is location 6, high byte */
- outb(PORT(sc) + 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 %u, using %u\n",
- dvp->id_unit, dvp->id_irq, 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(sc) + IEE16_IRQ, sc->irq_encoded);
-
- /* enable loopback to keep bad packets off the wire */
- if (sc->hard_type == IE_EE16) {
- bart_config = inb(PORT(sc) + IEE16_CONFIG);
- bart_config |= IEE16_BART_LOOPBACK;
- bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
- outb(PORT(sc) + IEE16_CONFIG, bart_config);
- bart_config = inb(PORT(sc) + IEE16_CONFIG);
- }
- /* take the board out of reset state */
- outb(PORT(sc) + IEE16_ECTRL, 0);
- DELAY(100);
-
- if (!check_ie_present(sc, 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.
*/
-static int
-ieattach(struct isa_device *dvp)
+int
+ie_attach(device_t dev)
{
- int factor;
- struct ie_softc *sc = &ie_softc[dvp->id_unit];
- struct ifnet *ifp = &sc->arpcom.ac_if;
- size_t allocsize;
+ struct ie_softc * sc;
+ struct ifnet * ifp;
+ size_t allocsize;
+ int factor;
- dvp->id_ointr = ieintr;
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ sc->dev = dev;
+ sc->unit = device_get_unit(dev);
/*
* based on the amount of memory we have, allocate our tx and rx
* resources.
*/
- factor = dvp->id_msize / 8192;
+ factor = rman_get_size(sc->mem_res) / 8192;
sc->nframes = factor * NFRAMES;
sc->nrxbufs = factor * NRXBUFS;
sc->ntxbufs = factor * NTXBUFS;
@@ -768,7 +291,7 @@ ieattach(struct isa_device *dvp)
M_DEVBUF,
M_NOWAIT);
if (sc->rframes == NULL)
- return (0);
+ return (ENXIO);
sc->rbuffs =
(volatile struct ie_recv_buf_desc **)&sc->rframes[sc->nframes];
sc->cbuffs = (volatile u_char **)&sc->rbuffs[sc->nrxbufs];
@@ -778,15 +301,14 @@ ieattach(struct isa_device *dvp)
(volatile struct ie_xmit_buf **)&sc->xmit_cmds[sc->ntxbufs];
sc->xmit_cbuffs = (volatile u_char **)&sc->xmit_buffs[sc->ntxbufs];
+ if (bootverbose)
+ device_printf(sc->dev, "hardware type %s, revision %d\n",
+ ie_hardware_names[sc->hard_type], sc->hard_vers + 1);
+
ifp->if_softc = sc;
- ifp->if_unit = dvp->id_unit;
+ ifp->if_unit = sc->unit;
ifp->if_name = "ie";
ifp->if_mtu = ETHERMTU;
- printf("ie%d: <%s R%d> address %6D\n", sc->unit,
- ie_hardware_names[sc->hard_type],
- sc->hard_vers + 1,
- sc->arpcom.ac_enaddr, ":");
-
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_start = iestart;
ifp->if_ioctl = ieioctl;
@@ -797,17 +319,20 @@ ieattach(struct isa_device *dvp)
EVENTHANDLER_REGISTER(shutdown_post_sync, ee16_shutdown,
sc, SHUTDOWN_PRI_DEFAULT);
+ device_printf(sc->dev, "Ethernet address %6D\n",
+ sc->arpcom.ac_enaddr, ":");
+
ether_ifattach(ifp, sc->arpcom.ac_enaddr);
- return (1);
+ return (0);
}
/*
* What to do upon receipt of an interrupt.
*/
-static void
-ieintr(int unit)
+void
+ie_intr(void *xsc)
{
- struct ie_softc *sc = &ie_softc[unit];
+ struct ie_softc *sc = (struct ie_softc *)xsc;
u_short status;
/* Clear the interrupt latch on the 3C507. */
@@ -1457,8 +982,8 @@ iestart(struct ifnet *ifp)
/*
* Check to see if there's an 82586 out there.
*/
-static int
-check_ie_present(struct ie_softc *sc, caddr_t where, unsigned size)
+int
+check_ie_present(struct ie_softc *sc)
{
volatile struct ie_sys_conf_ptr *scp;
volatile struct ie_int_sys_conf_ptr *iscp;
@@ -1468,7 +993,7 @@ check_ie_present(struct ie_softc *sc, caddr_t where, unsigned size)
s = splimp();
- realbase = (uintptr_t) where + size - (1 << 24);
+ realbase = (uintptr_t) sc->iomembot + sc->iosize - (1 << 24);
scp = (volatile struct ie_sys_conf_ptr *) (uintptr_t)
(realbase + IE_SCP_ADDR);
@@ -1480,10 +1005,10 @@ check_ie_present(struct ie_softc *sc, caddr_t where, unsigned size)
* controller's. This is NOT where the ISCP will be in normal
* operation.
*/
- iscp = (volatile struct ie_int_sys_conf_ptr *) where;
+ iscp = (volatile struct ie_int_sys_conf_ptr *) sc->iomembot;
bzero((volatile char *)iscp, sizeof *iscp);
- scb = (volatile struct ie_sys_ctl_block *) where;
+ scb = (volatile struct ie_sys_ctl_block *) sc->iomembot;
bzero((volatile char *)scb, sizeof *scb);
scp->ie_bus_use = sc->bus_use; /* 8-bit or 16-bit */
@@ -1526,7 +1051,6 @@ check_ie_present(struct ie_softc *sc, caddr_t where, unsigned size)
splx(s);
return (0);
}
- sc->iosize = size;
sc->iomem = (caddr_t) (uintptr_t) realbase;
sc->iscp = iscp;
@@ -1553,7 +1077,7 @@ find_ie_mem_size(struct ie_softc *sc)
sc->iosize = 0;
for (size = 65536; size >= 8192; size -= 8192) {
- if (check_ie_present(sc, sc->iomembot, size)) {
+ if (check_ie_present(sc)) {
return;
}
}
@@ -1561,7 +1085,7 @@ find_ie_mem_size(struct ie_softc *sc)
return;
}
-static void
+void
el_reset_586(struct ie_softc *sc)
{
outb(PORT(sc) + IE507_CTRL, EL_CTRL_RESET);
@@ -1570,13 +1094,13 @@ el_reset_586(struct ie_softc *sc)
DELAY(100);
}
-static void
+void
sl_reset_586(struct ie_softc *sc)
{
outb(PORT(sc) + IEATT_RESET, 0);
}
-static void
+void
ee16_reset_586(struct ie_softc *sc)
{
outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
@@ -1585,25 +1109,25 @@ ee16_reset_586(struct ie_softc *sc)
DELAY(100);
}
-static void
+void
el_chan_attn(struct ie_softc *sc)
{
outb(PORT(sc) + IE507_ATTN, 1);
}
-static void
+void
sl_chan_attn(struct ie_softc *sc)
{
outb(PORT(sc) + IEATT_ATTN, 0);
}
-static void
+void
ee16_chan_attn(struct ie_softc *sc)
{
outb(PORT(sc) + IEE16_ATTN, 0);
}
-static u_short
+u_short
ee16_read_eeprom(struct ie_softc *sc, int location)
{
int ectrl, edata;
@@ -1687,7 +1211,7 @@ ee16_interrupt_enable(struct ie_softc *sc)
DELAY(100);
}
-static void
+void
sl_read_ether(struct ie_softc *sc, unsigned char *addr)
{
int i;
@@ -1709,10 +1233,6 @@ iereset(struct ie_softc *sc)
{
int s = splimp();
- if (sc->unit >= NIE) {
- splx(s);
- return;
- }
printf("ie%d: reset\n", sc->unit);
sc->arpcom.ac_if.if_flags &= ~IFF_UP;
ieioctl(&sc->arpcom.ac_if, SIOCSIFFLAGS, 0);
@@ -1727,7 +1247,7 @@ iereset(struct ie_softc *sc)
printf("ie%d: disable commands timed out\n", sc->unit);
#ifdef notdef
- if (!check_ie_present(sc, sc->iomembot, sc->iosize))
+ if (!check_ie_present(sc))
panic("ie disappeared!");
#endif
@@ -2187,3 +1707,91 @@ print_rbd(volatile struct ie_recv_buf_desc * rbd)
}
#endif /* DEBUG */
+
+int
+ie_alloc_resources (device_t dev)
+{
+ struct ie_softc * sc;
+ int error;
+
+ error = 0;
+ sc = device_get_softc(dev);
+
+ sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->io_res) {
+ device_printf(dev, "No I/O space?!\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->io_bt = rman_get_bustag(sc->io_res);
+ sc->io_bh = rman_get_bushandle(sc->io_res);
+
+ sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->mem_res) {
+ device_printf(dev, "No Memory!\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ sc->mem_bt = rman_get_bustag(sc->mem_res);
+ sc->mem_bh = rman_get_bushandle(sc->mem_res);
+
+ sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
+ 0, ~0, 1, RF_ACTIVE);
+ if (!sc->irq_res) {
+ device_printf(dev, "No IRQ!\n");
+ error = ENOMEM;
+ goto bad;
+ }
+
+ sc->port = rman_get_start(sc->io_res); /* XXX hack */
+ sc->iomembot = rman_get_virtual(sc->mem_res);
+ sc->iosize = rman_get_size(sc->mem_res);
+
+ return (0);
+bad:
+ return (error);
+}
+
+void
+ie_release_resources (device_t dev)
+{
+ struct ie_softc * sc;
+
+ sc = device_get_softc(dev);
+
+ if (sc->irq_ih)
+ bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
+ if (sc->io_res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ sc->io_rid, sc->io_res);
+ if (sc->irq_res)
+ bus_release_resource(dev, SYS_RES_IRQ,
+ sc->irq_rid, sc->irq_res);
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ sc->mem_rid, sc->mem_res);
+
+ return;
+}
+
+int
+ie_detach (device_t dev)
+{
+ struct ie_softc * sc;
+ struct ifnet * ifp;
+
+ sc = device_get_softc(dev);
+ ifp = &sc->arpcom.ac_if;
+
+ if (sc->hard_type == IE_EE16)
+ ee16_shutdown(sc, 0);
+
+ ie_stop(sc);
+ ifp->if_flags &= ~IFF_RUNNING;
+ ether_ifdetach(ifp);
+ ie_release_resources(dev);
+
+ return (0);
+}
diff --git a/sys/dev/ie/if_ie_isa.c b/sys/dev/ie/if_ie_isa.c
new file mode 100644
index 0000000..bcb50b6
--- /dev/null
+++ b/sys/dev/ie/if_ie_isa.c
@@ -0,0 +1,885 @@
+/*-
+ * Copyright (c) 2003 Matthew N. Dodd
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
+ *
+ * Portions:
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ * Copyright (c) 1993, 1994, Charles M. Hannum
+ * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes
+ * Copyright (c) 1997, Aaron C. Smith
+ *
+ * See if_ie.c for applicable license.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus_pio.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <machine/clock.h>
+#include <machine/md_var.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_media.h>
+
+#include <isa/isavar.h>
+#include <isa/pnpvar.h>
+
+#include <i386/isa/elink.h>
+
+#include <dev/ic/i82586.h>
+#include <dev/ie/if_ie507.h>
+#include <dev/ie/if_iee16.h>
+#include <dev/ie/if_iereg.h>
+#include <dev/ie/if_ievar.h>
+
+static int ie_modevent (module_t, int, void *);
+
+static void ie_isa_3C507_identify (driver_t *, device_t);
+static int ie_isa_3C507_probe (device_t);
+static int ie_isa_3C507_attach (device_t);
+static int ie_3C507_port_check (u_int32_t);
+
+static void ie_isa_ee16_identify (driver_t *, device_t);
+static int ie_isa_ee16_probe (device_t);
+static int ie_isa_ee16_attach (device_t);
+static int ie_ee16_port_check (u_int32_t port);
+static u_int16_t ie_ee16_hw_read_eeprom (u_int32_t port, int loc);
+
+static int ie_isa_sl_probe (device_t);
+static int ie_isa_sl_attach (device_t);
+static enum ie_hardware ie_isa_sl_get_hard_type (u_int32_t);
+
+/*
+ * 3Com 3C507 Etherlink 16
+ */
+#define IE_3C507_IOBASE_LOW 0x200
+#define IE_3C507_IOBASE_HIGH 0x3e0
+#define IE_3C507_IOSIZE 16
+
+#define IE_3C507_IRQ_MASK 0x0f
+
+#define IE_3C507_MADDR_HIGH 0x20
+#define IE_3C507_MADDR_MASK 0x1c
+#define IE_3C507_MADDR_BASE 0xc0000
+#define IE_3C507_MADDR_SHIFT 12
+
+#define IE_3C507_MSIZE_MASK 3
+#define IE_3C507_MSIZE_SHIFT 14
+
+static void
+ie_isa_3C507_identify (driver_t *driver, device_t parent)
+{
+ char * desc = "3Com 3C507 Etherlink 16";
+ device_t child;
+ u_int32_t port, maddr, msize;
+ u_int8_t irq, data;
+ int error;
+
+ /* Reset and put card in CONFIG state without changing address. */
+ elink_reset();
+ elink_idseq(ELINK_507_POLY);
+ elink_idseq(ELINK_507_POLY);
+ outb(ELINK_ID_PORT, 0xff);
+
+ for (port = IE_3C507_IOBASE_LOW;
+ port <= IE_3C507_IOBASE_HIGH;
+ port += IE_3C507_IOSIZE) {
+
+ if (ie_3C507_port_check(port)) {
+#if DEBUG
+ if (bootverbose) {
+ device_printf(parent,
+ "(if_ie) (3C507) not found at port %#x\n",
+ port);
+ }
+#endif
+ continue;
+ }
+
+ outb(port + IE507_CTRL, EL_CTRL_NRST);
+
+ data = inb(port + IE507_IRQ);
+ irq = data & IE_3C507_IRQ_MASK;
+
+ data = inb(port + IE507_MADDR);
+
+ if (data & IE_3C507_MADDR_HIGH) {
+ if (bootverbose) {
+ device_printf(parent,
+ "(if_ie) can't map 3C507 RAM in high memory\n");
+ }
+ continue;
+ }
+
+ maddr = IE_3C507_MADDR_BASE +
+ ((data & IE_3C507_MADDR_MASK)
+ << IE_3C507_MADDR_SHIFT);
+ msize = ((data & IE_3C507_MSIZE_MASK) + 1)
+ << IE_3C507_MSIZE_SHIFT;
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
+ device_set_desc_copy(child, desc);
+ device_set_driver(child, driver);
+
+ error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
+ irq);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_3C507_IOSIZE);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
+ port, port+IE_3C507_IOSIZE);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
+ maddr, maddr+msize);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ if (bootverbose) {
+ device_printf(parent,
+ "(if_ie) <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
+ desc,
+ port, (port + IE_3C507_IOSIZE) - 1,
+ irq,
+ (u_long)maddr, (u_long)(maddr + msize) - 1,
+ (msize / 1024));
+ }
+ }
+
+ /* go to RUN state */
+ outb(ELINK_ID_PORT, 0x00);
+ elink_idseq(ELINK_507_POLY);
+ outb(ELINK_ID_PORT, 0x00);
+
+ return;
+}
+
+static int
+ie_isa_3C507_probe (device_t dev)
+{
+ u_int32_t iobase;
+
+ /* No ISA-PnP support */
+ if (isa_get_vendorid(dev)) {
+ return (ENXIO);
+ }
+
+ /* No ISA-HINT support */
+ if (!device_get_desc(dev)) {
+ return (EBUSY);
+ }
+
+ /* Have we at least an ioport? */
+ if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) {
+ return (ENXIO);
+ }
+
+ /* Is this thing really a 3c507? */
+ if (ie_3C507_port_check(iobase)) {
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+ie_isa_3C507_attach (device_t dev)
+{
+ struct ie_softc * sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ sc->io_rid = 0;
+ sc->irq_rid = 0;
+ sc->mem_rid = 0;
+
+ error = ie_alloc_resources(dev);
+ if (error) {
+ goto bad;
+ }
+
+ sc->bus_use = 0;
+ sc->ie_reset_586 = el_reset_586;
+ sc->ie_chan_attn = el_chan_attn;
+ sc->hard_type = IE_3C507;
+ sc->hard_vers = 0;
+
+ outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL);
+
+ if (!check_ie_present(sc)) {
+ error = ENXIO;
+ goto bad;
+ }
+
+ sl_read_ether(sc, sc->arpcom.ac_enaddr);
+
+ /* Clear the interrupt latch just in case. */
+ outb(PORT(sc) + IE507_ICTRL, 1);
+
+ error = ie_attach(dev);
+ if (error) {
+ device_printf(dev, "ie_attach() failed.\n");
+ goto bad;
+ }
+
+ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
+ ie_intr, sc, &sc->irq_ih);
+ if (error) {
+ device_printf(dev, "Unable to register interrupt handler\n");
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ie_release_resources(dev);
+
+ return (error);
+}
+
+/*
+ * If a 3c507 is present, return 0
+ * else, return 1.
+ */
+static int
+ie_3C507_port_check (u_int32_t port)
+{
+ u_char * signature = "*3COM*";
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (inb(port + i) != signature[i])
+ return (ENXIO);
+
+ return (0);
+}
+
+/*
+ * Intel EtherExpress 16
+ */
+#define IE_EE16_ID_PORT 0x0f
+#define IE_EE16_ID 0xbaba
+#define IE_EE16_EEPROM_CONFIG1 0x00
+#define IE_EE16_EEPROM_IRQ_MASK 0xe000
+#define IE_EE16_EEPROM_IRQ_SHIFT 13
+#define IE_EE16_EEPROM_MEMCFG 0x06
+#define IE_EE16_IOSIZE 16
+
+/*
+ * TODO:
+ * Test for 8/16 bit mode.
+ * Test for invalid mem sizes.
+ */
+static void
+ie_isa_ee16_identify (driver_t *driver, device_t parent)
+{
+ char * desc = "Intel EtherExpress 16";
+ device_t child;
+ u_int16_t ports[] = {
+ 0x300, 0x310, 0x320, 0x330,
+ 0x340, 0x350, 0x360, 0x370,
+ 0x200, 0x210, 0x220, 0x230,
+ 0x240, 0x250, 0x260, 0x270,
+ 0
+ };
+ u_int16_t irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 };
+ u_int32_t port, maddr, msize;
+ u_int8_t irq;
+ u_int16_t data;
+ int i, error;
+
+ for (i = 0; ports[i]; i++) {
+ port = ports[i];
+
+ if (ie_ee16_port_check(port)) {
+#if DEBUG
+ if (bootverbose) {
+ device_printf(parent,
+ "if_ie: (EE16) not found at port %#x\n",
+ port);
+ }
+#endif
+ continue;
+ }
+
+ /* reset any ee16 at the current iobase */
+ outb(port + IEE16_ECTRL, IEE16_RESET_ASIC);
+ outb(port + IEE16_ECTRL, 0);
+ DELAY(240);
+
+ data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1);
+ irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK)
+ >> IE_EE16_EEPROM_IRQ_SHIFT)];
+
+ data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG);
+ maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000);
+ msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1)))
+ * 0x4000;
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
+ device_set_desc_copy(child, desc);
+ device_set_driver(child, driver);
+
+ error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
+ irq);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
+ port, port+IE_EE16_IOSIZE);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
+ if (error) {
+ device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
+ maddr, maddr+msize);
+ error = device_delete_child(parent, child);
+ continue;
+ }
+
+ if (bootverbose) {
+ device_printf(parent,
+ "if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
+ desc,
+ port, (port + IE_EE16_IOSIZE) - 1,
+ irq,
+ (u_long)maddr, (u_long)(maddr + msize) - 1,
+ (msize / 1024));
+ }
+ }
+
+ return;
+}
+
+static int
+ie_isa_ee16_probe (device_t dev)
+{
+ u_int32_t iobase;
+
+ /* No ISA-PnP support */
+ if (isa_get_vendorid(dev))
+ return (ENXIO);
+
+ /* No ISA-HINT support */
+ if (!device_get_desc(dev))
+ return (EBUSY);
+
+ /* Have we at least an ioport? */
+ if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
+ return (ENXIO);
+
+ /* Is this really an EE16? */
+ if (ie_ee16_port_check(iobase))
+ return (ENXIO);
+
+ return (0);
+}
+
+static int
+ie_isa_ee16_attach (device_t dev)
+{
+ struct ie_softc * sc;
+ int i, error;
+ u_int16_t checksum;
+ u_short eaddrtemp, pg, adjust, decode, edecode;
+ u_char bart_config;
+
+ sc = device_get_softc(dev);
+
+ sc->io_rid = 0;
+ sc->irq_rid = 0;
+ sc->mem_rid = 0;
+
+ error = ie_alloc_resources(dev);
+ if (error) {
+ goto bad;
+ }
+
+ sc->bus_use = 0;
+ sc->ie_reset_586 = ee16_reset_586;
+ sc->ie_chan_attn = ee16_chan_attn;
+ sc->hard_type = IE_EE16;
+ sc->hard_vers = 0;
+ sc->iomem = 0;
+
+ /* reset any ee16 at the current iobase */
+ outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC);
+ outb(PORT(sc) + IEE16_ECTRL, 0);
+ DELAY(240);
+
+ /* Is this really an EE16? */
+ if (ie_ee16_port_check(PORT(sc))) {
+ device_printf(dev, "ie_ee16_port_check() failed\n");
+ error = ENXIO;
+ goto bad;
+ }
+
+ /* need to put the 586 in RESET while we access the eeprom. */
+ outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
+
+ /* read the eeprom and checksum it, should == IE_E16_ID */
+ checksum = 0;
+ for (i = 0; i < 0x40; i++)
+ checksum += ie_ee16_hw_read_eeprom(PORT(sc), i);
+
+ if (checksum != IE_EE16_ID) {
+ device_printf(dev, "invalid eeprom checksum: %x\n", checksum);
+ error = ENXIO;
+ goto bad;
+ }
+
+ if ((kvtop(sc->iomembot) < 0xC0000) ||
+ (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) {
+ device_printf(sc->dev, "mapped memory location %p out of range\n",
+ (void *)sc->iomembot);
+ error = ENXIO;
+ goto bad;
+ }
+
+ pg = ((kvtop(sc->iomembot)) & 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(sc) + IEE16_MEMDEC, decode & 0xFF);
+ /* ZZZ This should be checked against eeprom location 1, low byte */
+ outb(PORT(sc) + IEE16_MCTRL, adjust);
+ /* ZZZ Now if I could find this one I would have it made */
+ outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
+ /* ZZZ I think this is location 6, high byte */
+ outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */
+
+#if 0
+ (void) kvtop(sc->iomembot);
+#endif
+
+ /*
+ * 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 */
+ sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc),
+ IE_EE16_EEPROM_CONFIG1);
+ sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >>
+ IE_EE16_EEPROM_IRQ_SHIFT;
+
+ /*
+ * Get the hardware ethernet address from the EEPROM and save it in
+ * the softc for use by the 586 setup code.
+ */
+ eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH);
+ sc->arpcom.ac_enaddr[1] = eaddrtemp & 0xFF;
+ sc->arpcom.ac_enaddr[0] = eaddrtemp >> 8;
+ eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID);
+ sc->arpcom.ac_enaddr[3] = eaddrtemp & 0xFF;
+ sc->arpcom.ac_enaddr[2] = eaddrtemp >> 8;
+ eaddrtemp = ie_ee16_hw_read_eeprom(PORT(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(sc) + IEE16_IRQ, sc->irq_encoded);
+
+ /* enable loopback to keep bad packets off the wire */
+ bart_config = inb(PORT(sc) + IEE16_CONFIG);
+ bart_config |= IEE16_BART_LOOPBACK;
+ bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
+ outb(PORT(sc) + IEE16_CONFIG, bart_config);
+ bart_config = inb(PORT(sc) + IEE16_CONFIG);
+
+ /* take the board out of reset state */
+ outb(PORT(sc) + IEE16_ECTRL, 0);
+ DELAY(100);
+
+ if (!check_ie_present(sc)) {
+ device_printf(dev, "check_ie_present() returned false.\n");
+ error = ENXIO;
+ goto bad;
+ }
+
+ error = ie_attach(dev);
+ if (error) {
+ device_printf(dev, "ie_attach() failed.\n");
+ goto bad;
+ }
+
+ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
+ ie_intr, sc, &sc->irq_ih);
+ if (error) {
+ device_printf(dev, "Unable to register interrupt handler\n");
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ie_release_resources(dev);
+
+ return (error);
+}
+
+/*
+ * If an EE16 is present, return 0
+ * else, return 1.
+ */
+static int
+ie_ee16_port_check (u_int32_t port)
+{
+ int i;
+ u_int16_t board_id;
+ u_int8_t data;
+
+ board_id = 0;
+ for (i = 0; i < 4; i++) {
+ data = inb(port + IE_EE16_ID_PORT);
+ board_id |= ((data >> 4) << ((data & 0x03) << 2));
+ }
+
+ if (board_id != IE_EE16_ID)
+ return (1);
+
+ return (0);
+}
+
+static void
+ie_ee16_hw_eeprom_clock (u_int32_t port, int state)
+{
+ u_int8_t ectrl;
+
+ ectrl = inb(port + IEE16_ECTRL);
+ ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK);
+
+ if (state) {
+ ectrl |= IEE16_ECTRL_EESK;
+ }
+ outb(port + IEE16_ECTRL, ectrl);
+ DELAY(9); /* EESK must be stable for 8.38 uSec */
+}
+
+static void
+ie_ee16_hw_eeprom_out (u_int32_t port, u_int16_t edata, int count)
+{
+ u_int8_t ectrl;
+ int i;
+
+ ectrl = inb(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(port + IEE16_ECTRL, ectrl);
+ DELAY(1); /* eeprom data must be setup for 0.4 uSec */
+ ie_ee16_hw_eeprom_clock(port, 1);
+ ie_ee16_hw_eeprom_clock(port, 0);
+ }
+ ectrl &= ~IEE16_ECTRL_EEDI;
+ outb(port + IEE16_ECTRL, ectrl);
+ DELAY(1); /* eeprom data must be held for 0.4 uSec */
+
+ return;
+}
+
+static u_int16_t
+ie_ee16_hw_eeprom_in (u_int32_t port)
+{
+ u_int8_t ectrl;
+ u_int16_t edata;
+ int i;
+
+ ectrl = inb(port + IEE16_ECTRL);
+ ectrl &= ~IEE16_RESET_ASIC;
+
+ for (edata = 0, i = 0; i < 16; i++) {
+ edata = edata << 1;
+ ie_ee16_hw_eeprom_clock(port, 1);
+ ectrl = inb(port + IEE16_ECTRL);
+ if (ectrl & IEE16_ECTRL_EEDO) {
+ edata |= 1;
+ }
+ ie_ee16_hw_eeprom_clock(port, 0);
+ }
+ return (edata);
+}
+
+static u_int16_t
+ie_ee16_hw_read_eeprom (u_int32_t port, int loc)
+{
+ u_int8_t ectrl;
+ u_int16_t edata;
+
+ ectrl = inb(port + IEE16_ECTRL);
+ ectrl &= IEE16_ECTRL_MASK;
+ ectrl |= IEE16_ECTRL_EECS;
+ outb(port + IEE16_ECTRL, ectrl);
+
+ ie_ee16_hw_eeprom_out(port, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1);
+ ie_ee16_hw_eeprom_out(port, loc, IEE16_EEPROM_ADDR_SIZE);
+ edata = ie_ee16_hw_eeprom_in(port);
+
+ ectrl = inb(port + IEE16_ECTRL);
+ ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS);
+ outb(port + IEE16_ECTRL, ectrl);
+
+ ie_ee16_hw_eeprom_clock(port, 1);
+ ie_ee16_hw_eeprom_clock(port, 0);
+
+ return (edata);
+}
+
+/*
+ * AT&T StarLan/
+ */
+
+static int
+ie_isa_sl_probe (device_t dev)
+{
+ u_int32_t iobase;
+
+ /* No ISA-PnP support */
+ if (isa_get_vendorid(dev))
+ return (ENXIO);
+
+ /* ISA-HINT support only! */
+ if (device_get_desc(dev))
+ return (EBUSY);
+
+ /* Have we at least an ioport? */
+ if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
+ return (ENXIO);
+
+ /* Is this really an SL board? */
+ if (ie_isa_sl_get_hard_type(iobase) == IE_NONE)
+ return (ENXIO);
+
+ return (ENXIO);
+}
+
+static int
+ie_isa_sl_attach (device_t dev)
+{
+ struct ie_softc * sc;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ sc->io_rid = 0;
+ sc->irq_rid = 0;
+ sc->mem_rid = 0;
+
+ error = ie_alloc_resources(dev);
+ if (error) {
+ goto bad;
+ }
+
+ /* Is this really an SL board? */
+ if ((sc->hard_type = ie_isa_sl_get_hard_type(PORT(sc))) == IE_NONE) {
+ error = ENXIO;
+ goto bad;
+ }
+
+ sc->hard_vers = SL_REV(inb(PORT(sc) + IEATT_REVISION));
+ if (sc->hard_type == IE_NI5210) {
+ sc->bus_use = 1;
+ } else {
+ sc->bus_use = 0;
+ }
+
+ sc->ie_reset_586 = sl_reset_586;
+ sc->ie_chan_attn = sl_chan_attn;
+
+ if (!check_ie_present(sc)) {
+ error = ENXIO;
+ goto bad;
+ }
+
+ switch (sc->hard_type) {
+ case IE_EN100:
+ case IE_STARLAN10:
+ case IE_SLFIBER:
+ case IE_NI5210:
+ sl_read_ether(sc, sc->arpcom.ac_enaddr);
+ break;
+ default:
+ if (bootverbose)
+ device_printf(sc->dev, "unknown AT&T board type code %d\n", sc->hard_type);
+ error = ENXIO;
+ goto bad;
+ break;
+ }
+
+ error = ie_attach(dev);
+ if (error) {
+ device_printf(dev, "ie_attach() failed.\n");
+ goto bad;
+ }
+
+ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
+ ie_intr, sc, &sc->irq_ih);
+ if (error) {
+ device_printf(dev, "Unable to register interrupt handler\n");
+ goto bad;
+ }
+
+ return (0);
+bad:
+ ie_release_resources(dev);
+
+ return (error);
+}
+
+static enum ie_hardware
+ie_isa_sl_get_hard_type (u_int32_t port)
+{
+ u_char c;
+ enum ie_hardware retval;
+
+ c = inb(port + IEATT_REVISION);
+ switch (SL_BOARD(c)) {
+ case SL1_BOARD:
+ if (inb(port + IEATT_ATTRIB) != NI5210_BOARD)
+ retval = IE_NONE;
+ retval = IE_NI5210;
+ break;
+ case SL10_BOARD:
+ retval = IE_STARLAN10;
+ break;
+ case EN100_BOARD:
+ retval = IE_EN100;
+ break;
+ case SLFIBER_BOARD:
+ retval = IE_SLFIBER;
+ break;
+ default:
+ retval = IE_NONE;
+ }
+ return (retval);
+}
+
+static devclass_t ie_devclass;
+
+static device_method_t ie_isa_3C507_methods[] = {
+ DEVMETHOD(device_identify, ie_isa_3C507_identify),
+ DEVMETHOD(device_probe, ie_isa_3C507_probe),
+ DEVMETHOD(device_attach, ie_isa_3C507_attach),
+ DEVMETHOD(device_detach, ie_detach),
+ { 0, 0 }
+};
+static driver_t ie_isa_3C507_driver = {
+ "ie",
+ ie_isa_3C507_methods,
+ sizeof(struct ie_softc),
+};
+DRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
+MODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
+
+static device_method_t ie_isa_ee16_methods[] = {
+ DEVMETHOD(device_identify, ie_isa_ee16_identify),
+ DEVMETHOD(device_probe, ie_isa_ee16_probe),
+ DEVMETHOD(device_attach, ie_isa_ee16_attach),
+ DEVMETHOD(device_detach, ie_detach),
+ { 0, 0 }
+};
+static driver_t ie_isa_ee16_driver = {
+ "ie",
+ ie_isa_ee16_methods,
+ sizeof(struct ie_softc),
+};
+DRIVER_MODULE(ie_EE16, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0);
+
+static device_method_t ie_isa_sl_methods[] = {
+ DEVMETHOD(device_probe, ie_isa_sl_probe),
+ DEVMETHOD(device_attach, ie_isa_sl_attach),
+ DEVMETHOD(device_detach, ie_detach),
+ { 0, 0 }
+};
+static driver_t ie_isa_sl_driver = {
+ "ie",
+ ie_isa_sl_methods,
+ sizeof(struct ie_softc),
+};
+DRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0);
+
+static int
+ie_modevent (mod, what, arg)
+ module_t mod;
+ int what;
+ void * arg;
+{
+ device_t * devs;
+ int count;
+ int i;
+
+ switch (what) {
+ case MOD_LOAD:
+ break;
+ case MOD_UNLOAD:
+ devclass_get_devices(ie_devclass, &devs, &count);
+ for (i = 0; i < count; i++)
+ device_delete_child(device_get_parent(devs[i]), devs[i]);
+ break;
+ default:
+ break;
+ };
+
+ return (0);
+}
diff --git a/sys/dev/ie/if_iereg.h b/sys/dev/ie/if_iereg.h
index aabc402..d3b0f22 100644
--- a/sys/dev/ie/if_iereg.h
+++ b/sys/dev/ie/if_iereg.h
@@ -15,7 +15,7 @@
#define SL10_BOARD 0x01
#define EN100_BOARD 0x02
#define SLFIBER_BOARD 0x03
-#define NI5210_BOARD 0x0055
+#define NI5210_BOARD 0x55
#define SL_ATTR_WIDTH 0x04 /* bus width: clear -> 8-bit */
#define SL_ATTR_SPEED 0x08 /* medium speed: clear -> 10 Mbps */
diff --git a/sys/dev/ie/if_ievar.h b/sys/dev/ie/if_ievar.h
new file mode 100644
index 0000000..c41d7ee
--- /dev/null
+++ b/sys/dev/ie/if_ievar.h
@@ -0,0 +1,91 @@
+/*-
+ * $FreeBSD$
+ */
+
+enum ie_hardware {
+ IE_NONE,
+ IE_STARLAN10,
+ IE_EN100,
+ IE_SLFIBER,
+ IE_3C507,
+ IE_NI5210,
+ IE_EE16,
+ IE_UNKNOWN
+};
+
+/*
+ * Ethernet status, per interface.
+ */
+struct ie_softc {
+ struct arpcom arpcom;
+ void (*ie_reset_586) (struct ie_softc *);
+ void (*ie_chan_attn) (struct ie_softc *);
+ enum ie_hardware hard_type;
+ int hard_vers;
+ int unit;
+
+ device_t dev;
+
+ struct resource * io_res;
+ int io_rid;
+ bus_space_tag_t io_bt;
+ bus_space_handle_t io_bh;
+
+ struct resource * irq_res;
+ int irq_rid;
+ void * irq_ih;
+
+ struct resource * mem_res;
+ int mem_rid;
+ bus_space_tag_t mem_bt;
+ bus_space_handle_t mem_bh;
+
+ 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 */
+
+ int want_mcsetup;
+ int promisc;
+ int nframes;
+ int nrxbufs;
+ int ntxbufs;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ volatile struct ie_recv_frame_desc **rframes; /* nframes worth */
+ volatile struct ie_recv_buf_desc **rbuffs; /* nrxbufs worth */
+ volatile u_char **cbuffs; /* nrxbufs worth */
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd **xmit_cmds; /* ntxbufs worth */
+ volatile struct ie_xmit_buf **xmit_buffs; /* ntxbufs worth */
+ volatile u_char **xmit_cbuffs; /* ntxbufs worth */
+ int xmit_count;
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+ u_short irq_encoded; /* encoded interrupt on IEE16 */
+};
+#define PORT(sc) sc->port
+#define MEM(sc) sc->iomem
+
+void ie_intr (void *);
+int ie_alloc_resources (device_t);
+void ie_release_resources (device_t);
+int ie_attach (device_t);
+int ie_detach (device_t);
+
+void el_reset_586 (struct ie_softc *);
+void el_chan_attn (struct ie_softc *);
+
+void sl_reset_586 (struct ie_softc *);
+void sl_chan_attn (struct ie_softc *);
+
+void ee16_reset_586 (struct ie_softc *);
+void ee16_chan_attn (struct ie_softc *);
+
+void sl_read_ether (struct ie_softc *, unsigned char *);
+int check_ie_present (struct ie_softc *);
+
OpenPOWER on IntegriCloud