1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 #include "../port/netif.h" 9 10 #include "etherif.h" 11 #include "ether8390.h" 12 13 /* 14 * Western Digital/Standard Microsystems Corporation cards (WD80[01]3). 15 * Also handles 8216 cards (Elite Ultra). 16 * Configuration code based on that provided by SMC a long time ago. 17 */ 18 enum { /* 83C584 Bus Interface Controller */ 19 Msr = 0x00, /* Memory Select Register */ 20 Icr = 0x01, /* Interface Configuration Register */ 21 Iar = 0x02, /* I/O Address Register */ 22 Bio = 0x03, /* BIOS ROM Address Register */ 23 Ear = 0x03, /* EEROM Address Register (shared with Bio) */ 24 Irr = 0x04, /* Interrupt Request Register */ 25 Hcr = 0x04, /* 8216 hardware control */ 26 Laar = 0x05, /* LA Address Register */ 27 Ijr = 0x06, /* Initialisation Jumpers */ 28 Gp2 = 0x07, /* General Purpose Data Register */ 29 Lar = 0x08, /* LAN Address Registers */ 30 Id = 0x0E, /* Card ID byte */ 31 Cksum = 0x0F, /* Checksum */ 32 }; 33 34 enum { /* Msr */ 35 Rst = 0x80, /* software reset */ 36 Menb = 0x40, /* memory enable */ 37 }; 38 39 enum { /* Icr */ 40 Bit16 = 0x01, /* 16-bit bus */ 41 Other = 0x02, /* other register access */ 42 Ir2 = 0x04, /* IR2 */ 43 Msz = 0x08, /* SRAM size */ 44 Rla = 0x10, /* recall LAN address */ 45 Rx7 = 0x20, /* recall all but I/O and LAN address */ 46 Rio = 0x40, /* recall I/O address from EEROM */ 47 Sto = 0x80, /* non-volatile EEROM store */ 48 }; 49 50 enum { /* Laar */ 51 ZeroWS16 = 0x20, /* zero wait states for 16-bit ops */ 52 L16en = 0x40, /* enable 16-bit LAN operation */ 53 M16en = 0x80, /* enable 16-bit memory access */ 54 }; 55 56 enum { /* Ijr */ 57 Ienable = 0x01, /* 8216 interrupt enable */ 58 }; 59 60 /* 61 * Mapping from configuration bits to interrupt level. 62 */ 63 static int irq8003[8] = { 64 9, 3, 5, 7, 10, 11, 15, 4, 65 }; 66 67 static int irq8216[8] = { 68 0, 9, 3, 5, 7, 10, 11, 15, 69 }; 70 71 static void 72 reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8]) 73 { 74 Dp8390 *ctlr; 75 ulong port; 76 77 ctlr = ether->ctlr; 78 port = ether->port; 79 80 /* 81 * Check for old, dumb 8003E, which doesn't have an interface 82 * chip. Only Msr exists out of the 1st eight registers, reads 83 * of the others just alias the 2nd eight registers, the LAN 84 * address ROM. Can check Icr, Irr and Laar against the ethernet 85 * address read above and if they match it's an 8003E (or an 86 * 8003EBT, 8003S, 8003SH or 8003WT, doesn't matter), in which 87 * case the default irq gets used. 88 */ 89 if(memcmp(&ea[1], &ic[1], 5) == 0){ 90 memset(ic, 0, sizeof(ic)); 91 ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F; 92 } 93 else{ 94 /* 95 * As a final sanity check for the 8013EBT, which doesn't have 96 * the 83C584 interface chip, but has 2 real registers, write Gp2 97 * and if it reads back the same, it's not an 8013EBT. 98 */ 99 outb(port+Gp2, 0xAA); 100 inb(port+Msr); /* wiggle bus */ 101 if(inb(port+Gp2) != 0xAA){ 102 memset(ic, 0, sizeof(ic)); 103 ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F; 104 } 105 else 106 ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)]; 107 108 /* 109 * Check if 16-bit card. 110 * If Bit16 is read/write, then it's an 8-bit card. 111 * If Bit16 is set, it's in a 16-bit slot. 112 */ 113 outb(port+Icr, ic[Icr]^Bit16); 114 inb(port+Msr); /* wiggle bus */ 115 if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){ 116 ctlr->width = 2; 117 ic[Icr] &= ~Bit16; 118 } 119 outb(port+Icr, ic[Icr]); 120 121 if(ctlr->width == 2 && (inb(port+Icr) & Bit16) == 0) 122 ctlr->width = 1; 123 } 124 125 ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13); 126 if(ctlr->width == 2) 127 ether->mem |= (ic[Laar] & 0x1F)<<19; 128 else 129 ether->mem |= 0x80000; 130 131 if(ic[Icr] & (1<<3)) 132 ether->size = 32*1024; 133 if(ctlr->width == 2) 134 ether->size <<= 1; 135 136 /* 137 * Enable interface RAM, set interface width. 138 */ 139 outb(port+Msr, ic[Msr]|Menb); 140 if(ctlr->width == 2) 141 outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16); 142 } 143 144 static void 145 reset8216(Ether* ether, uchar[8]) 146 { 147 uchar hcr, irq, x; 148 ulong addr, port; 149 Dp8390 *ctlr; 150 151 ctlr = ether->ctlr; 152 port = ether->port; 153 154 ctlr->width = 2; 155 156 /* 157 * Switch to the alternate register set and retrieve the memory 158 * and irq information. 159 */ 160 hcr = inb(port+Hcr); 161 outb(port+Hcr, 0x80|hcr); 162 addr = inb(port+0x0B) & 0xFF; 163 irq = inb(port+0x0D); 164 outb(port+Hcr, hcr); 165 166 ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13)); 167 ether->size = 8192*(1<<((addr>>4) & 0x03)); 168 ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)]; 169 170 /* 171 * Enable interface RAM, set interface width, and enable interrupts. 172 */ 173 x = inb(port+Msr) & ~Rst; 174 outb(port+Msr, Menb|x); 175 x = inb(port+Laar); 176 outb(port+Laar, M16en|x); 177 outb(port+Ijr, Ienable); 178 } 179 180 /* 181 * Get configuration parameters, enable memory. 182 * There are opportunities here for buckets of code, try to resist. 183 */ 184 static int 185 reset(Ether* ether) 186 { 187 int i; 188 uchar ea[Eaddrlen], ic[8], id, nullea[Eaddrlen], sum; 189 ulong port; 190 Dp8390 *ctlr; 191 192 /* 193 * Set up the software configuration. 194 * Use defaults for port, irq, mem and size if not specified. 195 * Defaults are set for the dumb 8003E which can't be 196 * autoconfigured. 197 */ 198 if(ether->port == 0) 199 ether->port = 0x280; 200 if(ether->irq == 0) 201 ether->irq = 3; 202 if(ether->mem == 0) 203 ether->mem = 0xD0000; 204 if(ether->size == 0) 205 ether->size = 8*1024; 206 if(ioalloc(ether->port, 0x20, 0, "wd8003") < 0) 207 return -1; 208 209 /* 210 * Look for the interface. Read the LAN address ROM 211 * and validate the checksum - the sum of all 8 bytes 212 * should be 0xFF. 213 * At the same time, get the (possible) interface chip 214 * registers, they'll be used later to check for aliasing. 215 */ 216 port = ether->port; 217 sum = 0; 218 for(i = 0; i < sizeof(ea); i++){ 219 ea[i] = inb(port+Lar+i); 220 sum += ea[i]; 221 ic[i] = inb(port+i); 222 } 223 id = inb(port+Id); 224 sum += id; 225 sum += inb(port+Cksum); 226 if(sum != 0xFF){ 227 iofree(ether->port); 228 return -1; 229 } 230 231 ether->ctlr = malloc(sizeof(Dp8390)); 232 ctlr = ether->ctlr; 233 if(ctlr == nil) 234 error(Enomem); 235 ctlr->ram = 1; 236 237 if((id & 0xFE) == 0x2A) 238 reset8216(ether, ic); 239 else 240 reset8003(ether, ea, ic); 241 242 /* 243 * Set the DP8390 ring addresses. 244 */ 245 ctlr->port = port+0x10; 246 ctlr->tstart = 0; 247 ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz); 248 ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz); 249 250 /* 251 * Finally, init the 8390, set the ethernet address 252 * and claim the memory used. 253 */ 254 dp8390reset(ether); 255 memset(nullea, 0, Eaddrlen); 256 if(memcmp(nullea, ether->ea, Eaddrlen) == 0){ 257 for(i = 0; i < sizeof(ether->ea); i++) 258 ether->ea[i] = ea[i]; 259 } 260 dp8390setea(ether); 261 262 if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0) 263 print("ether8003: warning - 0x%luX unavailable\n", 264 PADDR(ether->mem)); 265 266 return 0; 267 } 268 269 void 270 ether8003link(void) 271 { 272 addethercard("WD8003", reset); 273 } 274