From 50e960d918e3400c7753b19d6089d5987d2ccae7 Mon Sep 17 00:00:00 2001 From: "Matthew N. Dodd" Date: Sat, 29 Mar 2003 13:36:41 +0000 Subject: [PATCH] - 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. --- sys/amd64/conf/GENERIC | 1 + sys/conf/files | 3 +- sys/dev/ie/if_ie.c | 668 +++++++------------------------ sys/dev/ie/if_ie_isa.c | 885 +++++++++++++++++++++++++++++++++++++++++ sys/dev/ie/if_iereg.h | 2 +- sys/dev/ie/if_ievar.h | 91 +++++ sys/i386/conf/GENERIC | 1 + sys/i386/conf/NOTES | 14 +- 8 files changed, 1124 insertions(+), 541 deletions(-) create mode 100644 sys/dev/ie/if_ie_isa.c create mode 100644 sys/dev/ie/if_ievar.h diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index fbb0689f3c55..730261ba6213 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -206,6 +206,7 @@ device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards device ex # Intel EtherExpress Pro/10 and Pro/10+ device ep # Etherlink III based cards device fe # Fujitsu MB8696x based cards +device ie # EtherExpress 8/16, 3C507, StarLAN 10 etc. device lnc # NE2100, NE32-VL Lance Ethernet cards device sn # SMC's 9000 series of ethernet chips device xe # Xircom pccard ethernet diff --git a/sys/conf/files b/sys/conf/files index 51b594073d35..111a12ec6d48 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -441,7 +441,8 @@ dev/ida/ida.c optional ida dev/ida/ida_disk.c optional ida dev/ida/ida_eisa.c optional ida eisa dev/ida/ida_pci.c optional ida pci -dev/ie/if_ie.c count ie isa nowerror +dev/ie/if_ie.c optional ie isa nowerror +dev/ie/if_ie_isa.c optional ie isa dev/iicbus/iicbb_if.m optional iicbb dev/iicbus/iicbus_if.m optional iicbus dev/iicbus/if_ic.c optional ic diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c index 9582ad1a0557..60d5f8902d30 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 #include #include @@ -124,6 +120,14 @@ #include #include +#include +#include + +#include +#include +#include +#include + #include #include #include @@ -132,11 +136,8 @@ #include #include -#include - -#include -#include #include +#include #include #include #include @@ -144,10 +145,6 @@ #include -#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 000000000000..bcb50b6252a1 --- /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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +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 aabc40245862..d3b0f228f957 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 000000000000..c41d7eed44ef --- /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 *); + diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index fbb0689f3c55..730261ba6213 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -206,6 +206,7 @@ device ed # NE[12]000, SMC Ultra, 3c503, DS8390 cards device ex # Intel EtherExpress Pro/10 and Pro/10+ device ep # Etherlink III based cards device fe # Fujitsu MB8696x based cards +device ie # EtherExpress 8/16, 3C507, StarLAN 10 etc. device lnc # NE2100, NE32-VL Lance Ethernet cards device sn # SMC's 9000 series of ethernet chips device xe # Xircom pccard ethernet diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 856b3ed85543..46bebddf4a10 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -505,15 +505,11 @@ device el 1 hint.el.0.at="isa" hint.el.0.port="0x300" hint.el.0.irq="9" -device ie 2 -hint.ie.0.at="isa" -hint.ie.0.port="0x300" -hint.ie.0.irq="5" -hint.ie.0.maddr="0xd0000" -hint.ie.1.at="isa" -hint.ie.1.port="0x360" -hint.ie.1.irq="7" -hint.ie.1.maddr="0xd0000" +device ie # Hints only required for Starlan +hint.ie.2.at="isa" +hint.ie.2.port="0x300" +hint.ie.2.irq="5" +hint.ie.2.maddr="0xd0000" device le 1 hint.le.0.at="isa" hint.le.0.port="0x300"