- 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.
This commit is contained in:
Matthew N. Dodd 2003-03-29 13:36:41 +00:00
parent 3330d5fb09
commit 50e960d918
8 changed files with 1124 additions and 541 deletions

View File

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

View File

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

View File

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

885
sys/dev/ie/if_ie_isa.c Normal file
View File

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

View File

@ -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 */

91
sys/dev/ie/if_ievar.h Normal file
View File

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

View File

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

View File

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