1 /* 2 * AMD79C970 3 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus 4 * To do: 5 * finish this rewrite 6 */ 7 #include "u.h" 8 #include "lib.h" 9 #include "mem.h" 10 #include "dat.h" 11 #include "fns.h" 12 #include "io.h" 13 14 #include "etherif.h" 15 16 enum { 17 Lognrdre = 6, 18 Nrdre = (1<<Lognrdre),/* receive descriptor ring entries */ 19 Logntdre = 4, 20 Ntdre = (1<<Logntdre),/* transmit descriptor ring entries */ 21 22 Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */ 23 }; 24 25 enum { /* DWIO I/O resource map */ 26 Aprom = 0x0000, /* physical address */ 27 Rdp = 0x0010, /* register data port */ 28 Rap = 0x0014, /* register address port */ 29 Sreset = 0x0018, /* software reset */ 30 Bdp = 0x001C, /* bus configuration register data port */ 31 }; 32 33 enum { /* CSR0 */ 34 Init = 0x0001, /* begin initialisation */ 35 Strt = 0x0002, /* enable chip */ 36 Stop = 0x0004, /* disable chip */ 37 Tdmd = 0x0008, /* transmit demand */ 38 Txon = 0x0010, /* transmitter on */ 39 Rxon = 0x0020, /* receiver on */ 40 Iena = 0x0040, /* interrupt enable */ 41 Intr = 0x0080, /* interrupt flag */ 42 Idon = 0x0100, /* initialisation done */ 43 Tint = 0x0200, /* transmit interrupt */ 44 Rint = 0x0400, /* receive interrupt */ 45 Merr = 0x0800, /* memory error */ 46 Miss = 0x1000, /* missed frame */ 47 Cerr = 0x2000, /* collision */ 48 Babl = 0x4000, /* transmitter timeout */ 49 Err = 0x8000, /* Babl|Cerr|Miss|Merr */ 50 }; 51 52 enum { /* CSR3 */ 53 Bswp = 0x0004, /* byte swap */ 54 Emba = 0x0008, /* enable modified back-off algorithm */ 55 Dxmt2pd = 0x0010, /* disable transmit two part deferral */ 56 Lappen = 0x0020, /* look-ahead packet processing enable */ 57 }; 58 59 enum { /* CSR4 */ 60 ApadXmt = 0x0800, /* auto pad transmit */ 61 }; 62 63 enum { /* CSR15 */ 64 Prom = 0x8000, /* promiscuous mode */ 65 }; 66 67 typedef struct { /* Initialisation Block */ 68 ushort mode; 69 uchar rlen; /* upper 4 bits */ 70 uchar tlen; /* upper 4 bits */ 71 uchar padr[6]; 72 uchar res[2]; 73 uchar ladr[8]; 74 ulong rdra; 75 ulong tdra; 76 } Iblock; 77 78 typedef struct { /* descriptor ring entry */ 79 ulong addr; 80 ulong md1; /* status|bcnt */ 81 ulong md2; /* rcc|rpc|mcnt */ 82 void* data; 83 } Dre; 84 85 enum { /* md1 */ 86 Enp = 0x01000000, /* end of packet */ 87 Stp = 0x02000000, /* start of packet */ 88 RxBuff = 0x04000000, /* buffer error */ 89 Def = 0x04000000, /* deferred */ 90 Crc = 0x08000000, /* CRC error */ 91 One = 0x08000000, /* one retry needed */ 92 Oflo = 0x10000000, /* overflow error */ 93 More = 0x10000000, /* more than one retry needed */ 94 Fram = 0x20000000, /* framing error */ 95 RxErr = 0x40000000, /* Fram|Oflo|Crc|RxBuff */ 96 TxErr = 0x40000000, /* Uflo|Lcol|Lcar|Rtry */ 97 Own = 0x80000000, 98 }; 99 100 enum { /* md2 */ 101 Rtry = 0x04000000, /* failed after repeated retries */ 102 Lcar = 0x08000000, /* loss of carrier */ 103 Lcol = 0x10000000, /* late collision */ 104 Uflo = 0x40000000, /* underflow error */ 105 TxBuff = 0x80000000, /* buffer error */ 106 }; 107 108 typedef struct Ctlr Ctlr; 109 struct Ctlr { 110 Lock; 111 int port; 112 Pcidev* pcidev; 113 Ctlr* next; 114 int active; 115 116 int init; /* initialisation in progress */ 117 Iblock iblock; 118 119 Dre* rdr; /* receive descriptor ring */ 120 int rdrx; 121 122 Dre* tdr; /* transmit descriptor ring */ 123 int tdrh; /* host index into tdr */ 124 int tdri; /* interface index into tdr */ 125 int ntq; /* descriptors active */ 126 127 ulong rxbuff; /* receive statistics */ 128 ulong crc; 129 ulong oflo; 130 ulong fram; 131 132 ulong rtry; /* transmit statistics */ 133 ulong lcar; 134 ulong lcol; 135 ulong uflo; 136 ulong txbuff; 137 138 ulong merr; /* bobf is such a whiner */ 139 ulong miss; 140 ulong babl; 141 142 int (*ior)(Ctlr*, int); 143 void (*iow)(Ctlr*, int, int); 144 }; 145 146 static Ctlr* ctlrhead; 147 static Ctlr* ctlrtail; 148 149 /* 150 * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above. 151 * To get to 16-bit offsets, scale down with 0x10 staying the same. 152 */ 153 static int 154 io16r(Ctlr* c, int r) 155 { 156 if(r >= Rdp) 157 r = (r-Rdp)/2+Rdp; 158 return ins(c->port+r); 159 } 160 161 static void 162 io16w(Ctlr* c, int r, int v) 163 { 164 if(r >= Rdp) 165 r = (r-Rdp)/2+Rdp; 166 outs(c->port+r, v); 167 } 168 169 static int 170 io32r(Ctlr* c, int r) 171 { 172 return inl(c->port+r); 173 } 174 175 static void 176 io32w(Ctlr* c, int r, int v) 177 { 178 outl(c->port+r, v); 179 } 180 181 static void 182 attach(Ether*) 183 { 184 } 185 186 static void 187 detach(Ether* ether) 188 { 189 Ctlr *ctlr; 190 191 ctlr = ether->ctlr; 192 ctlr->iow(ctlr, Rdp, Iena|Stop); 193 } 194 195 static void 196 ringinit(Ctlr* ctlr) 197 { 198 Dre *dre; 199 200 /* 201 * Initialise the receive and transmit buffer rings. 202 * The ring entries must be aligned on 16-byte boundaries. 203 * 204 * This routine is protected by ctlr->init. 205 */ 206 if(ctlr->rdr == 0){ 207 ctlr->rdr = ialloc(Nrdre*sizeof(Dre), 0x10); 208 for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){ 209 dre->data = malloc(Rbsize); 210 dre->addr = PADDR(dre->data); 211 dre->md2 = 0; 212 dre->md1 = Own|(-Rbsize & 0xFFFF); 213 } 214 } 215 ctlr->rdrx = 0; 216 217 if(ctlr->tdr == 0) 218 ctlr->tdr = ialloc(Ntdre*sizeof(Dre), 0x10); 219 memset(ctlr->tdr, 0, Ntdre*sizeof(Dre)); 220 ctlr->tdrh = ctlr->tdri = 0; 221 } 222 223 static void 224 transmit(Ether* ether) 225 { 226 Ctlr *ctlr; 227 Block *bp; 228 Dre *dre; 229 RingBuf *tb; 230 231 ctlr = ether->ctlr; 232 233 if(ctlr->init) 234 return; 235 236 while(ctlr->ntq < (Ntdre-1)){ 237 tb = ðer->tb[ether->ti]; 238 if(tb->owner != Interface) 239 break; 240 241 bp = allocb(tb->len); 242 memmove(bp->wp, tb->pkt, tb->len); 243 memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); 244 bp->wp += tb->len; 245 246 /* 247 * Give ownership of the descriptor to the chip, 248 * increment the software ring descriptor pointer 249 * and tell the chip to poll. 250 * There's no need to pad to ETHERMINTU 251 * here as ApadXmt is set in CSR4. 252 */ 253 dre = &ctlr->tdr[ctlr->tdrh]; 254 dre->data = bp; 255 dre->addr = PADDR(bp->rp); 256 dre->md2 = 0; 257 dre->md1 = Own|Stp|Enp|Oflo|(-BLEN(bp) & 0xFFFF); 258 ctlr->ntq++; 259 ctlr->iow(ctlr, Rap, 0); 260 ctlr->iow(ctlr, Rdp, Iena|Tdmd); 261 ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre); 262 263 tb->owner = Host; 264 ether->ti = NEXT(ether->ti, ether->ntb); 265 } 266 } 267 268 static void 269 interrupt(Ureg*, void* arg) 270 { 271 Ctlr *ctlr; 272 Ether *ether; 273 int csr0; 274 Dre *dre; 275 RingBuf *rb; 276 277 ether = arg; 278 ctlr = ether->ctlr; 279 280 /* 281 * Acknowledge all interrupts and whine about those that shouldn't 282 * happen. 283 */ 284 intrloop: 285 csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF; 286 ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena); 287 if(csr0 & Merr) 288 ctlr->merr++; 289 if(csr0 & Miss) 290 ctlr->miss++; 291 if(csr0 & Babl) 292 ctlr->babl++; 293 //if(csr0 & (Babl|Miss|Merr)) 294 // print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0); 295 if(!(csr0 & (Rint|Tint))) 296 return; 297 298 /* 299 * Receiver interrupt: run round the descriptor ring logging 300 * errors and passing valid receive data up to the higher levels 301 * until a descriptor is encountered still owned by the chip. 302 */ 303 if(csr0 & Rint){ 304 dre = &ctlr->rdr[ctlr->rdrx]; 305 while(!(dre->md1 & Own)){ 306 rb = ðer->rb[ether->ri]; 307 if(dre->md1 & RxErr){ 308 if(dre->md1 & RxBuff) 309 ctlr->rxbuff++; 310 if(dre->md1 & Crc) 311 ctlr->crc++; 312 if(dre->md1 & Oflo) 313 ctlr->oflo++; 314 if(dre->md1 & Fram) 315 ctlr->fram++; 316 } 317 else if(rb->owner == Interface){ 318 rb->owner = Host; 319 rb->len = (dre->md2 & 0x0FFF)-4; 320 memmove(rb->pkt, dre->data, rb->len); 321 ether->ri = NEXT(ether->ri, ether->nrb); 322 } 323 324 /* 325 * Finished with this descriptor, reinitialise it, 326 * give it back to the chip, then on to the next... 327 */ 328 dre->md2 = 0; 329 dre->md1 = Own|(-Rbsize & 0xFFFF); 330 331 ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre); 332 dre = &ctlr->rdr[ctlr->rdrx]; 333 } 334 } 335 336 /* 337 * Transmitter interrupt: wakeup anyone waiting for a free descriptor. 338 */ 339 if(csr0 & Tint){ 340 lock(ctlr); 341 while(ctlr->ntq){ 342 dre = &ctlr->tdr[ctlr->tdri]; 343 if(dre->md1 & Own) 344 break; 345 346 if(dre->md1 & TxErr){ 347 if(dre->md2 & Rtry) 348 ctlr->rtry++; 349 if(dre->md2 & Lcar) 350 ctlr->lcar++; 351 if(dre->md2 & Lcol) 352 ctlr->lcol++; 353 if(dre->md2 & Uflo) 354 ctlr->uflo++; 355 if(dre->md2 & TxBuff) 356 ctlr->txbuff++; 357 } 358 359 freeb(dre->data); 360 361 ctlr->ntq--; 362 ctlr->tdri = NEXT(ctlr->tdri, Ntdre); 363 } 364 transmit(ether); 365 unlock(ctlr); 366 } 367 goto intrloop; 368 } 369 370 static void 371 amd79c970pci(void) 372 { 373 Ctlr *ctlr; 374 Pcidev *p; 375 376 p = nil; 377 while(p = pcimatch(p, 0x1022, 0x2000)){ 378 ctlr = malloc(sizeof(Ctlr)); 379 ctlr->port = p->mem[0].bar & ~0x01; 380 ctlr->pcidev = p; 381 382 if(ctlrhead != nil) 383 ctlrtail->next = ctlr; 384 else 385 ctlrhead = ctlr; 386 ctlrtail = ctlr; 387 } 388 } 389 390 int 391 amd79c970reset(Ether* ether) 392 { 393 int x; 394 uchar ea[Eaddrlen]; 395 Ctlr *ctlr; 396 397 if(ctlrhead == nil) 398 amd79c970pci(); 399 400 /* 401 * Any adapter matches if no port is supplied, 402 * otherwise the ports must match. 403 */ 404 for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ 405 if(ctlr->active) 406 continue; 407 if(ether->port == 0 || ether->port == ctlr->port){ 408 ctlr->active = 1; 409 break; 410 } 411 } 412 if(ctlr == nil) 413 return -1; 414 415 /* 416 * Allocate a controller structure and start to initialise it. 417 */ 418 ether->ctlr = ctlr; 419 ether->port = ctlr->port; 420 ether->irq = ctlr->pcidev->intl; 421 ether->tbdf = ctlr->pcidev->tbdf; 422 pcisetbme(ctlr->pcidev); 423 ilock(ctlr); 424 ctlr->init = 1; 425 426 io32r(ctlr, Sreset); 427 io16r(ctlr, Sreset); 428 429 if(io16w(ctlr, Rap, 0), io16r(ctlr, Rdp) == 4){ 430 ctlr->ior = io16r; 431 ctlr->iow = io16w; 432 }else if(io32w(ctlr, Rap, 0), io32r(ctlr, Rdp) == 4){ 433 ctlr->ior = io32r; 434 ctlr->iow = io32w; 435 }else{ 436 print("#l%d: card doesn't talk right\n", ether->ctlrno); 437 iunlock(ctlr); 438 return -1; 439 } 440 441 ctlr->iow(ctlr, Rap, 88); 442 x = ctlr->ior(ctlr, Rdp); 443 ctlr->iow(ctlr, Rap, 89); 444 x |= ctlr->ior(ctlr, Rdp)<<16; 445 446 switch(x&0xFFFFFFF){ 447 case 0x2420003: /* PCnet/PCI 79C970 */ 448 case 0x2621003: /* PCnet/PCI II 79C970A */ 449 break; 450 default: 451 print("unknown PCnet card version %.7ux\n", x&0xFFFFFFF); 452 iunlock(ctlr); 453 return -1; 454 } 455 456 /* 457 * Set the software style in BCR20 to be PCnet-PCI to ensure 32-bit access. 458 * Set the auto pad transmit in CSR4. 459 */ 460 ctlr->iow(ctlr, Rap, 20); 461 ctlr->iow(ctlr, Bdp, 0x0002); 462 463 ctlr->iow(ctlr, Rap, 4); 464 x = ctlr->ior(ctlr, Rdp) & 0xFFFF; 465 ctlr->iow(ctlr, Rdp, ApadXmt|x); 466 467 ctlr->iow(ctlr, Rap, 0); 468 469 /* 470 * Check if the adapter's station address is to be overridden. 471 * If not, read it from the I/O-space and set in ether->ea prior to 472 * loading the station address in the initialisation block. 473 */ 474 memset(ea, 0, Eaddrlen); 475 if(!memcmp(ea, ether->ea, Eaddrlen)){ 476 x = ctlr->ior(ctlr, Aprom); 477 ether->ea[0] = x; 478 ether->ea[1] = x>>8; 479 if(ctlr->ior == io16r) 480 x = ctlr->ior(ctlr, Aprom+2); 481 else 482 x >>= 16; 483 ether->ea[2] = x; 484 ether->ea[3] = x>>8; 485 x = ctlr->ior(ctlr, Aprom+4); 486 ether->ea[4] = x; 487 ether->ea[5] = x>>8; 488 } 489 490 /* 491 * Start to fill in the initialisation block 492 * (must be DWORD aligned). 493 */ 494 ctlr->iblock.rlen = Lognrdre<<4; 495 ctlr->iblock.tlen = Logntdre<<4; 496 memmove(ctlr->iblock.padr, ether->ea, sizeof(ctlr->iblock.padr)); 497 498 ringinit(ctlr); 499 ctlr->iblock.rdra = PADDR(ctlr->rdr); 500 ctlr->iblock.tdra = PADDR(ctlr->tdr); 501 502 /* 503 * Point the chip at the initialisation block and tell it to go. 504 * Mask the Idon interrupt and poll for completion. Strt and interrupt 505 * enables will be set later when attaching to the network. 506 */ 507 x = PADDR(&ctlr->iblock); 508 ctlr->iow(ctlr, Rap, 1); 509 ctlr->iow(ctlr, Rdp, x & 0xFFFF); 510 ctlr->iow(ctlr, Rap, 2); 511 ctlr->iow(ctlr, Rdp, (x>>16) & 0xFFFF); 512 ctlr->iow(ctlr, Rap, 3); 513 ctlr->iow(ctlr, Rdp, Idon); 514 ctlr->iow(ctlr, Rap, 0); 515 ctlr->iow(ctlr, Rdp, Init); 516 517 while(!(ctlr->ior(ctlr, Rdp) & Idon)) 518 ; 519 520 /* 521 * We used to set CSR0 to Idon|Stop here, and then 522 * in attach change it to Iena|Strt. Apparently the simulated 523 * 79C970 in VMware never enables after a write of Idon|Stop, 524 * so we enable the device here now. 525 */ 526 ctlr->iow(ctlr, Rdp, Iena|Strt); 527 ctlr->init = 0; 528 iunlock(ctlr); 529 530 /* 531 * Linkage to the generic ethernet driver. 532 */ 533 ether->attach = attach; 534 ether->transmit = transmit; 535 ether->interrupt = interrupt; 536 ether->detach = detach; 537 538 return 0; 539 } 540