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