@@ 11,6 11,7 @@
/*
* Western Digital/Standard Microsystems Corporation cards (WD80[01]3).
+ * Also handles 8216 cards (Elite Ultra).
* Configuration code based on that provided by SMC.
*/
enum { /* 83C584 Bus Interface Controller */
@@ 20,6 21,7 @@ enum { /* 83C584 Bus Interface Controller */
Bio = 0x03, /* BIOS ROM Address Register */
Ear = 0x03, /* EEROM Address Register (shared with Bio) */
Irr = 0x04, /* Interrupt Request Register */
+ Hcr = 0x04, /* 8216 hardware control */
Laar = 0x05, /* LA Address Register */
Ijr = 0x06, /* Initialisation Jumpers */
Gp2 = 0x07, /* General Purpose Data Register */
@@ 45,68 47,34 @@ enum { /* Icr */
};
enum { /* Laar */
- ZeroWS16 = (1<<5), /* zero wait states for 16-bit ops */
- L16en = (1<<6), /* enable 16-bit LAN operation */
- M16en = (1<<7), /* enable 16-bit memory access */
+ ZeroWS16 = 0x20, /* zero wait states for 16-bit ops */
+ L16en = 0x40, /* enable 16-bit LAN operation */
+ M16en = 0x80, /* enable 16-bit memory access */
+};
+
+enum { /* Ijr */
+ Ienable = 0x01, /* 8216 interrupt enable */
};
/*
* Mapping from configuration bits to interrupt level.
*/
-static int intrmap[] = {
+static int irq8003[8] = {
9, 3, 5, 7, 10, 11, 15, 4,
};
-/*
- * Get configuration parameters, enable memory.
- * There are opportunities here for buckets of code.
- * We'll try to resist.
- */
-static int
-reset(Ether *ether)
+static int irq8216[8] = {
+ 0, 9, 3, 5, 7, 10, 11, 15,
+};
+
+static void
+reset8003(Ether *ether, uchar ea[Eaddrlen], uchar ic[8])
{
- int i;
- uchar ea[Eaddrlen], ic[8], sum;
- ulong port;
Dp8390 *dp8390;
+ ulong port;
- /*
- * Set up the software configuration.
- * Use defaults for port, irq, mem and size if not specified.
- * Defaults are set for the dumb 8003E which can't be
- * autoconfigured.
- */
- if(ether->port == 0)
- ether->port = 0x280;
- if(ether->irq == 0)
- ether->irq = 3;
- if(ether->mem == 0)
- ether->mem = 0xD0000;
- if(ether->size == 0)
- ether->size = 8*1024;
-
- /*
- * Look for the interface. We read the LAN address ROM
- * and validate the checksum - the sum of all 8 bytes
- * should be 0xFF.
- * While we're at it, get the (possible) interface chip
- * registers, we'll use them to check for aliasing later.
- */
- port = ether->port;
- sum = 0;
- for(i = 0; i < sizeof(ea); i++){
- ea[i] = inb(port+Lar+i);
- sum += ea[i];
- ic[i] = inb(port+i);
- }
- sum += inb(port+Id);
- sum += inb(port+Cksum);
- if(sum != 0xFF)
- return -1;
-
- ether->ctlr = malloc(sizeof(Dp8390));
dp8390 = ether->ctlr;
- dp8390->ram = 1;
+ port = ether->port;
/*
* Check for old, dumb 8003E, which doesn't have an interface
@@ 117,7 85,7 @@ reset(Ether *ether)
* 8003EBT, 8003S, 8003SH or 8003WT, we don't care), in which
* case the default irq gets used.
*/
- if(memcmp(ðer->ea[1], &ic[1], 5) == 0){
+ if(memcmp(&ea[1], &ic[1], 5) == 0){
memset(ic, 0, sizeof(ic));
ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
}
@@ 134,7 102,7 @@ reset(Ether *ether)
ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
}
else
- ether->irq = intrmap[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
+ ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
/*
* Check if 16-bit card.
@@ 165,6 133,107 @@ reset(Ether *ether)
ether->size <<= 1;
/*
+ * Enable interface RAM, set interface width.
+ */
+ outb(port+Msr, ic[Msr]|Menb);
+ if(dp8390->bit16)
+ outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
+}
+
+static void
+reset8216(Ether *ether, uchar[8])
+{
+ uchar hcr, irq, x;
+ ulong addr, port;
+ Dp8390 *dp8390;
+
+ dp8390 = ether->ctlr;
+ dp8390->bit16 = 1;
+ port = ether->port;
+
+ /*
+ * Switch to the alternate register set and retrieve the memory
+ * and irq information.
+ */
+ hcr = inb(port+Hcr);
+ outb(port+Hcr, 0x80|hcr);
+ addr = inb(port+0x0B) & 0xFF;
+ irq = inb(port+0x0D);
+ outb(port+Hcr, hcr);
+
+ ether->mem = KZERO|(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
+ ether->size = 8192*(1<<((addr>>4) & 0x03));
+ ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)];
+
+ /*
+ * Enable interface RAM, set interface width,
+ * and enable interrupts.
+ */
+ x = inb(port+Msr) & ~Rst;
+ outb(port+Msr, Menb|x);
+ x = inb(port+Laar);
+ outb(port+Laar, M16en|x);
+ outb(port+Ijr, Ienable);
+}
+
+/*
+ * Get configuration parameters, enable memory.
+ * There are opportunities here for buckets of code.
+ * We'll try to resist.
+ */
+static int
+reset(Ether *ether)
+{
+ int i;
+ uchar ea[Eaddrlen], ic[8], id, sum;
+ ulong port;
+ Dp8390 *dp8390;
+
+ /*
+ * Set up the software configuration.
+ * Use defaults for port, irq, mem and size if not specified.
+ * Defaults are set for the dumb 8003E which can't be
+ * autoconfigured.
+ */
+ if(ether->port == 0)
+ ether->port = 0x280;
+ if(ether->irq == 0)
+ ether->irq = 3;
+ if(ether->mem == 0)
+ ether->mem = 0xD0000;
+ if(ether->size == 0)
+ ether->size = 8*1024;
+
+ /*
+ * Look for the interface. We read the LAN address ROM
+ * and validate the checksum - the sum of all 8 bytes
+ * should be 0xFF.
+ * While we're at it, get the (possible) interface chip
+ * registers, we'll use them to check for aliasing later.
+ */
+ port = ether->port;
+ sum = 0;
+ for(i = 0; i < sizeof(ea); i++){
+ ea[i] = inb(port+Lar+i);
+ sum += ea[i];
+ ic[i] = inb(port+i);
+ }
+ id = inb(port+Id);
+ sum += id;
+ sum += inb(port+Cksum);
+ if(sum != 0xFF)
+ return -1;
+
+ ether->ctlr = malloc(sizeof(Dp8390));
+ dp8390 = ether->ctlr;
+ dp8390->ram = 1;
+
+ if((id & 0xFE) == 0x2A)
+ reset8216(ether, ic);
+ else
+ reset8003(ether, ea, ic);
+
+ /*
* Set the DP8390 ring addresses.
*/
dp8390->dp8390 = port+0x10;
@@ 173,13 242,6 @@ reset(Ether *ether)
dp8390->pstop = HOWMANY(ether->size, Dp8390BufSz);
/*
- * Enable interface RAM, set interface width.
- */
- outb(port+Msr, ic[Msr]|Menb);
- if(dp8390->bit16)
- outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
-
- /*
* Finally, init the 8390 and set the
* ethernet address.
*/
@@ 562,15 562,13 @@ overflow(Ether *ether)
}
static void
-interrupt(Ureg *ur, void *arg)
+interrupt(Ureg*, void *arg)
{
Ether *ether;
Dp8390 *dp8390;
ulong port;
uchar isr, r;
- USED(ur);
-
ether = arg;
dp8390 = ether->ctlr;
port = dp8390->dp8390;
@@ 580,7 578,7 @@ interrupt(Ureg *ur, void *arg)
* clear all the interrupts and process.
*/
slowoutb(port+Imr, 0x00);
- while(isr = slowinb(port+Isr)){
+ while(isr = (slowinb(port+Isr) & (Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe))){
if(isr & Ovw){
overflow(ether);
@@ 657,7 655,7 @@ attach(Ether *ether)
x = Ab;
if(ether->prom)
x |= Pro;
- slowoutb(dp8390->dp8390+Rcr, Ab);
+ slowoutb(dp8390->dp8390+Rcr, x);
slowinb(dp8390->dp8390+Cntr2);
}