1 /* 2 * VIA Velocity gigabit ethernet. 3 * Register info has been stolen from FreeBSD driver. 4 * 5 * Has been tested on: 6 * - VIA8237 (ABIT AV8): 100Mpbs Full duplex only. 7 * It works enough to run replica/pull, vncv, ... 8 * 9 * To do: 10 * - 64/48 bits 11 * - autonegotiation 12 * - thresholds 13 * - dynamic ring sizing ?? 14 * - link status change 15 * - shutdown 16 * - promiscuous 17 * - report error 18 * - Rx/Tx Csum 19 * - Jumbo frames 20 * 21 * Philippe Anel, xigh@free.fr 22 */ 23 24 #include "u.h" 25 #include "../port/lib.h" 26 #include "mem.h" 27 #include "dat.h" 28 #include "fns.h" 29 #include "io.h" 30 #include "../port/error.h" 31 #include "../port/netif.h" 32 33 #include "etherif.h" 34 #include "ethermii.h" 35 36 #define DEBUG 37 38 enum 39 { 40 DumpIntr = (1<<0), 41 DumpRx = (1<<1), 42 DumpTx = (1<<2), 43 }; 44 45 #define htole16(x) (x) 46 #define htole32(x) (x) 47 #define le32toh(x) (x) 48 49 enum 50 { 51 Timeout = 50000, 52 RxCount = 256, 53 TxCount = 256, 54 RxSize = 2048, 55 56 EthAddr = 0x00, 57 58 /* Command registers. */ 59 Cr0S = 0x08, /* Global command 0 (Set) */ 60 Cr0C = 0x0c, /* Global command 0 (Clear) */ 61 Cr0_Start = 0x01, /* - start MAC */ 62 Cr0_Stop = 0x02, /* - stop MAC */ 63 Cr0_EnableRx = 0x04, /* - turn on Rx engine */ 64 Cr0_EnableTx = 0x08, /* - turn on Tx engine */ 65 66 Cr1S = 0x09, /* Global command 1 (Set) */ 67 Cr1C = 0x0d, /* Global command 1 (Clear) */ 68 Cr1_NoPool = 0x08, /* - disable Rx/Tx desc pool */ 69 Cr1_reset = 0x80, /* - software reset */ 70 71 Cr2S = 0x0a, /* Global command 2 (Set) */ 72 Cr2_XonEnable = 0x80, /* - 802.3x XON/XOFF flow control */ 73 74 Cr3S = 0x0b, /* Global command 3 (Set) */ 75 Cr3C = 0x0f, /* Global command 3 (Set) */ 76 Cr3_IntMask = 0x02, /* - Mask all interrupts */ 77 78 /* Eeprom registers. */ 79 Eecsr = 0x93, /* EEPROM control/status */ 80 Eecsr_Autold = 0x20, /* - trigger reload from EEPROM */ 81 82 /* Mii registers. */ 83 MiiStatus = 0x6D, /* MII port status */ 84 MiiStatus_idle = 0x80, /* - idle */ 85 86 MiiCmd = 0x70, /* MII command */ 87 MiiCmd_write = 0x20, /* - write */ 88 MiiCmd_read = 0x40, /* - read */ 89 MiiCmd_auto = 0x80, /* - enable autopolling */ 90 91 MiiAddr = 0x71, /* MII address */ 92 MiiData = 0x72, /* MII data */ 93 94 /* 64 bits related registers. */ 95 TxDescHi = 0x18, 96 DataBufHi = 0x1d, 97 98 /* Rx engine registers. */ 99 RxDescLo = 0x38, /* Rx descriptor base address (lo 32 bits) */ 100 RxCsrS = 0x32, /* Rx descriptor queue control/status (Set) */ 101 RxCsrC = 0x36, /* Rx descriptor queue control/status (Clear) */ 102 RxCsr_RunQueue = 0x01, /* - enable queue */ 103 RxCsr_Active = 0x02, /* - queue active indicator */ 104 RxCsr_Wakeup = 0x04, /* - wake up queue */ 105 RxCsr_Dead = 0x08, /* - queue dead indicator */ 106 RxNum = 0x50, /* Size of Rx desc ring */ 107 RxDscIdx = 0x3c, /* Current Rx descriptor index */ 108 RxResCnt = 0x5e, /* Rx descriptor residue count */ 109 RxHostErr = 0x23, /* Rx host error status */ 110 RxTimer = 0x3e, /* Rx queue timer pend */ 111 RxControl = 0x06, /* MAC Rx control */ 112 RxControl_BadFrame = 0x01, /* - accept CRC error frames */ 113 RxControl_Runt = 0x02, /* - accept runts */ 114 RxControl_MultiCast = 0x04, /* - accept multicasts */ 115 RxControl_BroadCast = 0x08, /* - accept broadcasts */ 116 RxControl_Promisc = 0x10, /* - promisc mode */ 117 RxControl_Giant = 0x20, /* - accept VLAN tagged frames */ 118 RxControl_UniCast = 0x40, /* - use perfect filtering */ 119 RxControl_SymbolErr = 0x80, /* - accept symbol err packet */ 120 RxConfig = 0x7e, /* MAC Rx config */ 121 RxConfig_VlanFilter = 0x01, /* - filter VLAN ID mismatches */ 122 RxConfig_VlanOpt0 = (0<<1), /* - TX: no tag insert, RX: all, no extr */ 123 RxConfig_VlanOpt1 = (1<<1), /* - TX: no tag insert, RX: tagged pkts, no extr */ 124 RxConfig_VlanOpt2 = (2<<1), /* - TX: tag insert, RX: all, extract tags */ 125 RxConfig_VlanOpt3 = (3<<1), /* - TX: tag insert, RX: tagged pkts, with extr */ 126 RxConfig_FifoLowWat = 0x08, /* - RX FIFO low watermark (7QW/15QW) */ 127 RxConfig_FifoTh128 = (0<<4), /* - RX FIFO threshold 128 bytes */ 128 RxConfig_FifoTh512 = (1<<4), /* - RX FIFO threshold 512 bytes */ 129 RxConfig_FifoTh1024 = (2<<4), /* - RX FIFO threshold 1024 bytes */ 130 RxConfig_FifoThFwd = (3<<4), /* - RX FIFO threshold ??? */ 131 RxConfig_ArbPrio = 0x80, /* - arbitration priority */ 132 133 /* Tx engine registers. */ 134 TxDescLo = 0x40, /* Tx descriptor base address (lo 32 bits) */ 135 TxCsrS = 0x30, /* Tx descriptor queue control/status (Set) */ 136 TxCsrC = 0x38, /* Tx descriptor queue control/status (Clear) */ 137 TxCsr_RunQueue = 0x01, /* - enable queue */ 138 TxCsr_Active = 0x02, /* - queue active indicator */ 139 TxCsr_Wakeup = 0x04, /* - wake up queue */ 140 TxCsr_Dead = 0x08, /* - queue dead indicator */ 141 TxNum = 0x52, /* Size of Tx desc ring */ 142 TxDscIdx = 0x54, /* Current Tx descriptor index */ 143 TxHostErr = 0x22, /* Tx host error status */ 144 TxTimer = 0x3f, /* Tx queue timer pend */ 145 TxControl = 0x07, /* MAC Rx control */ 146 TxControl_LC_Off = (0<<0), /* - loopback control off */ 147 TxControl_LC_Mac = (1<<0), /* - loopback control MAC internal */ 148 TxControl_LC_Ext = (2<<0), /* - loopback control external */ 149 TxControl_Coll16 = (0<<2), /* - one set of 16 retries */ 150 TxControl_Coll32 = (1<<2), /* - two sets of 16 retries */ 151 TxControl_Coll48 = (2<<2), /* - three sets of 16 retries */ 152 TxControl_CollInf = (3<<2), /* - retry forever */ 153 154 TxConfig = 0x7f, /* MAC Tx config */ 155 TxConfig_SnapOpt = 0x01, /* - 1 == insert VLAN tag at 13th byte, */ 156 /* 0 == insert VLAN tag after SNAP header (21st byte) */ 157 TxConfig_NonBlk = 0x02, /* - priority TX/non-blocking mode */ 158 TxConfig_Blk64 = (0<<3), /* - non-blocking threshold 64 packets */ 159 TxConfig_Blk32 = (1<<3), /* - non-blocking threshold 32 packets */ 160 TxConfig_Blk128 = (2<<3), /* - non-blocking threshold 128 packets */ 161 TxConfig_Blk8 = (3<<3), /* - non-blocking threshold 8 packets */ 162 TxConfig_ArbPrio = 0x80, /* - arbitration priority */ 163 164 /* Timer registers. */ 165 Timer0 = 0x74, /* single-shot timer */ 166 Timer1 = 0x76, /* periodic timer */ 167 168 /* Chip config registers. */ 169 ChipCfgA = 0x78, /* chip config A */ 170 ChipCfgB = 0x79, /* chip config B */ 171 ChipCfgC = 0x7a, /* chip config C */ 172 ChipCfgD = 0x7b, /* chip config D */ 173 174 /* DMA config registers. */ 175 DmaCfg0 = 0x7C, /* DMA config 0 */ 176 DmaCfg1 = 0x7D, /* DMA config 1 */ 177 178 /* Interrupt registers. */ 179 IntCtl = 0x20, /* Interrupt control */ 180 Imr = 0x28, /* Interrupt mask */ 181 Isr = 0x24, /* Interrupt status */ 182 Isr_RxHiPrio = (1<<0), /* - hi prio Rx int */ 183 Isr_TxHiPrio = (1<<1), /* - hi prio Tx int */ 184 Isr_RxComplete = (1<<2), /* - Rx queue completed */ 185 Isr_TxComplete = (1<<3), /* - One of Tx queues completed */ 186 187 Isr_TxComplete0 = (1<<4), /* - Tx queue 0 completed */ 188 Isr_TxComplete1 = (1<<5), /* - Tx queue 1 completed */ 189 Isr_TxComplete2 = (1<<6), /* - Tx queue 2 completed */ 190 Isr_TxComplete3 = (1<<7), /* - Tx queue 3 completed */ 191 192 Isr_Reserved8 = (1<<8), /* - reserved */ 193 Isr_Reserver9 = (1<<9), /* - reserved */ 194 Isr_RxCountOvflow = (1<<10), /* - Rx packet count overflow */ 195 Isr_RxPause = (1<<11), /* - pause frame Rx */ 196 197 Isr_RxFifoOvflow = (1<<12), /* - RX FIFO overflow */ 198 Isr_RxNoDesc = (1<<13), /* - ran out of Rx descriptors */ 199 Isr_RxNoDescWar = (1<<14), /* - running out of Rx descriptors */ 200 Isr_LinkStatus = (1<<15), /* - link status change */ 201 202 Isr_Timer0 = (1<<16), /* - one shot timer expired */ 203 Isr_Timer1 = (1<<17), /* - periodic timer expired */ 204 Isr_Power = (1<<18), /* - wake up power event */ 205 Isr_PhyIntr = (1<<19), /* - PHY interrupt */ 206 207 Isr_Stopped = (1<<20), /* - software shutdown complete */ 208 Isr_MibOvflow = (1<<21), /* - MIB counter overflow warning */ 209 Isr_SoftIntr = (1<<22), /* - software interrupt */ 210 Isr_HoldOffReload = (1<<23), /* - reload hold timer */ 211 212 Isr_RxDmaStall = (1<<24), /* - Rx DMA stall */ 213 Isr_TxDmaStall = (1<<25), /* - Tx DMA stall */ 214 Isr_Reserved26 = (1<<26), /* - reserved */ 215 Isr_Reserved27 = (1<<27), /* - reserved */ 216 217 Isr_Source0 = (1<<28), /* - interrupt source indication */ 218 Isr_Source1 = (1<<29), /* - interrupt source indication */ 219 Isr_Source2 = (1<<30), /* - interrupt source indication */ 220 Isr_Source3 = (1<<31), /* - interrupt source indication */ 221 222 Isr_Mask = Isr_TxComplete0|Isr_RxComplete|Isr_Stopped| 223 Isr_RxFifoOvflow|Isr_PhyIntr|Isr_LinkStatus| 224 Isr_RxNoDesc|Isr_RxDmaStall|Isr_TxDmaStall 225 }; 226 227 typedef struct Frag Frag; 228 struct Frag 229 { 230 ulong addr_lo; 231 ushort addr_hi; 232 ushort length; 233 }; 234 235 typedef struct RxDesc RxDesc; 236 struct RxDesc 237 { 238 ulong status; 239 ulong control; 240 Frag; 241 }; 242 243 typedef struct TxDesc TxDesc; 244 struct TxDesc 245 { 246 ulong status; 247 ulong control; 248 Frag frags[7]; 249 }; 250 251 enum 252 { 253 RxDesc_Status_VidMiss = (1<<0), /* VLAN tag filter miss */ 254 RxDesc_Status_CrcErr = (1<<1), /* bad CRC error */ 255 RxDesc_Status_FrAlErr = (1<<3), /* frame alignment error */ 256 RxDesc_Status_CsumErr = (1<<3), /* bad TCP/IP checksum */ 257 RxDesc_Status_RxLenErr = (1<<4), /* Rx length error */ 258 RxDesc_Status_SymErr = (1<<5), /* PCS symbol error */ 259 RxDesc_Status_SnTag = (1<<6), /* RX'ed tagged SNAP pkt */ 260 RxDesc_Status_DeTag = (1<<7), /* VLAN tag extracted */ 261 262 RxDesc_Status_OneFrag = (0<<8), /* only one fragment */ 263 RxDesc_Status_FirstFrag = (1<<8), /* first frag in frame */ 264 RxDesc_Status_LastFrag = (2<<8), /* last frag in frame */ 265 RxDesc_Status_MidFrag = (3<<8), /* intermediate frag */ 266 267 RxDesc_Status_Vtag = (1<<10), /* VLAN tag indicator */ 268 RxDesc_Status_UniCast = (1<<11), /* unicast frame */ 269 RxDesc_Status_BroadCast = (1<<12), /* broadcast frame */ 270 RxDesc_Status_MultiCast = (1<<13), /* multicast frame */ 271 RxDesc_Status_Perfect = (1<<14), /* perfect filter hit */ 272 RxDesc_Status_Goodframe = (1<<15), /* frame is good. */ 273 274 RxDesc_Status_SizShift = 16, /* received frame len shift */ 275 RxDesc_Status_SizMask = 0x3FFF, /* received frame len mask */ 276 277 RxDesc_Status_Shutdown = (1<<30), /* shutdown during RX */ 278 RxDesc_Status_Own = (1<<31), /* own bit */ 279 280 /* ... */ 281 TxDesc_Status_Own = (1<<31), /* own bit */ 282 283 /* ... */ 284 TxDesc_Control_Intr = (1<<23), /* Tx intr request */ 285 TxDesc_Control_Normal = (3<<24), /* normal frame */ 286 }; 287 288 typedef struct Stats Stats; 289 struct Stats 290 { 291 ulong rx; 292 ulong tx; 293 ulong txe; 294 ulong intr; 295 }; 296 297 typedef struct Ctlr Ctlr; 298 struct Ctlr 299 { 300 Ctlr* link; 301 Pcidev* pdev; 302 int port; 303 304 int inited; 305 Lock init_lock; 306 307 ulong debugflags; 308 ulong debugcount; 309 310 Mii* mii; 311 int active; 312 uchar ea[6]; 313 314 RxDesc* rx_ring; 315 Block* rx_blocks[RxCount]; 316 317 Lock tx_lock; 318 TxDesc* tx_ring; 319 Block* tx_blocks[TxCount]; 320 ulong tx_count; 321 322 Stats stats; 323 }; 324 325 static Ctlr* vgbehead; 326 static Ctlr* vgbetail; 327 328 #define riob(c, r) inb(c->port + r) 329 #define riow(c, r) ins(c->port + r) 330 #define riol(c, r) inl(c->port + r) 331 #define wiob(c, r, d) outb(c->port + r, d) 332 #define wiow(c, r, d) outs(c->port + r, d) 333 #define wiol(c, r, d) outl(c->port + r, d) 334 335 #define siob(c, r, b) wiob(c, r, riob(c, r) | b) 336 #define siow(c, r, b) wiow(c, r, riob(c, r) | b) 337 #define siol(c, r, b) wiol(c, r, riob(c, r) | b) 338 #define ciob(c, r, b) wiob(c, r, riob(c, r) & ~b) 339 #define ciow(c, r, b) wiow(c, r, riob(c, r) & ~b) 340 #define ciol(c, r, b) wiol(c, r, riob(c, r) & ~b) 341 342 static int 343 vgbemiiw(Mii* mii, int phy, int addr, int data) 344 { 345 Ctlr* ctlr; 346 int i; 347 348 if(phy != 1) 349 return -1; 350 351 ctlr = mii->ctlr; 352 353 wiob(ctlr, MiiAddr, addr); 354 wiow(ctlr, MiiData, (ushort) data); 355 wiob(ctlr, MiiCmd, MiiCmd_write); 356 357 for(i = 0; i < Timeout; i++) 358 if((riob(ctlr, MiiCmd) & MiiCmd_write) == 0) 359 break; 360 361 if(i >= Timeout){ 362 print("vgbe: miiw timeout\n"); 363 return -1; 364 } 365 366 return 0; 367 } 368 369 static int 370 vgbemiir(Mii* mii, int phy, int addr) 371 { 372 Ctlr* ctlr; 373 int i; 374 375 if(phy != 1) 376 return -1; 377 378 ctlr = mii->ctlr; 379 380 wiob(ctlr, MiiAddr, addr); 381 wiob(ctlr, MiiCmd, MiiCmd_read); 382 383 for(i = 0; i < Timeout; i++) 384 if((riob(ctlr, MiiCmd) & MiiCmd_read) == 0) 385 break; 386 387 if(i >= Timeout){ 388 print("vgbe: miir timeout\n"); 389 return -1; 390 } 391 392 return riow(ctlr, MiiData); 393 } 394 395 static long 396 vgbeifstat(Ether* edev, void* a, long n, ulong offset) 397 { 398 char* p; 399 Ctlr* ctlr; 400 int l; 401 402 ctlr = edev->ctlr; 403 404 p = malloc(READSTR); 405 l = 0; 406 l += snprint(p+l, READSTR-l, "tx: %uld\n", ctlr->stats.tx); 407 l += snprint(p+l, READSTR-l, "tx [errs]: %uld\n", ctlr->stats.txe); 408 l += snprint(p+l, READSTR-l, "rx: %uld\n", ctlr->stats.rx); 409 l += snprint(p+l, READSTR-l, "intr: %uld\n", ctlr->stats.intr); 410 snprint(p+l, READSTR-l, "\n"); 411 412 n = readstr(offset, a, n, p); 413 free(p); 414 415 return n; 416 } 417 418 static char* vgbeisr_info[] = { 419 "hi prio Rx int", 420 "hi prio Tx int", 421 "Rx queue completed", 422 "One of Tx queues completed", 423 "Tx queue 0 completed", 424 "Tx queue 1 completed", 425 "Tx queue 2 completed", 426 "Tx queue 3 completed", 427 "reserved", 428 "reserved", 429 "Rx packet count overflow", 430 "pause frame Rx'ed", 431 "RX FIFO overflow", 432 "ran out of Rx descriptors", 433 "running out of Rx descriptors", 434 "link status change", 435 "one shot timer expired", 436 "periodic timer expired", 437 "wake up power event", 438 "PHY interrupt", 439 "software shutdown complete", 440 "MIB counter overflow warning", 441 "software interrupt", 442 "reload hold timer", 443 "Rx DMA stall", 444 "Tx DMA stall", 445 "reserved", 446 "reserved", 447 "interrupt source indication 0", 448 "interrupt source indication 1", 449 "interrupt source indication 2", 450 "interrupt source indication 3", 451 }; 452 453 static void 454 vgbedumpisr(ulong isr) 455 { 456 int i; 457 458 for(i = 0; i < 32; i++){ 459 ulong mask; 460 461 mask = 1<<i; 462 if(isr & mask) 463 print("vgbe: irq: - %02d : %c %s\n", i, 464 Isr_Mask & mask ? '*' : '-', vgbeisr_info[i]); 465 } 466 } 467 468 static int 469 vgbenewrx(Ctlr* ctlr, int i) 470 { 471 Block* block; 472 RxDesc* desc; 473 474 /* Allocate Rx block. (TODO: Alignment ?) */ 475 block = allocb(RxSize); 476 477 /* Remember that block. */ 478 ctlr->rx_blocks[i] = block; 479 480 /* Initialize Rx descriptor. (TODO: 48/64 bits support ?) */ 481 desc = &ctlr->rx_ring[i]; 482 desc->status = htole32(RxDesc_Status_Own); 483 desc->control = htole32(0); 484 485 desc->addr_lo = htole32((ulong)PCIWADDR(block->rp)); 486 desc->addr_hi = htole16(0); 487 desc->length = htole16(RxSize | 0x8000); 488 489 return 0; 490 } 491 492 static void 493 vgberxeof(Ether* edev) 494 { 495 Ctlr* ctlr; 496 int i; 497 Block* block; 498 ulong length, status; 499 RxDesc* desc; 500 501 ctlr = edev->ctlr; 502 503 if(ctlr->debugflags & DumpRx) 504 print("vgbe: rx_eof\n"); 505 506 for(i = 0; i < RxCount; i++){ 507 /* Remember that block. */ 508 desc = &ctlr->rx_ring[i]; 509 510 status = le32toh(desc->status); 511 512 if(status & RxDesc_Status_Own) 513 continue; 514 515 if(status & RxDesc_Status_Goodframe){ 516 length = status >> RxDesc_Status_SizShift; 517 length &= RxDesc_Status_SizMask; 518 519 if(ctlr->debugflags & DumpRx) 520 print("vgbe: Rx-desc[%03d] status=%#08ulx ctl=%#08ulx len=%uld bytes\n", 521 i, status, desc->control, length); 522 523 block = ctlr->rx_blocks[i]; 524 block->wp = block->rp + length; 525 526 ctlr->stats.rx++; 527 /* 528 * the packet actually *is* from the wire, but 529 * we're maintaining a private array of Blocks, 530 * so can't have etheriq free block. 531 */ 532 etheriq(edev, block, 0); 533 } 534 else 535 print("vgbe: Rx-desc[%#02x] *BAD FRAME* status=%#08ulx ctl=%#08ulx\n", 536 i, status, desc->control); 537 538 /* reset packet ... */ 539 desc->status = htole32(RxDesc_Status_Own); 540 desc->control = htole32(0); 541 } 542 543 if(ctlr->debugflags & DumpRx) 544 print("vgbe: rx_eof: done\n"); 545 546 wiow(ctlr, RxResCnt, RxCount); 547 wiob(ctlr, RxCsrS, RxCsr_Wakeup); 548 } 549 550 static void 551 vgbetxeof(Ether* edev) 552 { 553 Ctlr* ctlr; 554 int i, count; 555 Block* block; 556 ulong status; 557 558 ctlr = edev->ctlr; 559 560 ilock(&ctlr->tx_lock); 561 562 if(ctlr->debugflags & DumpTx) 563 print("vgbe: tx_eof\n"); 564 565 for(count = 0, i = 0; i < TxCount; i++){ 566 block = ctlr->tx_blocks[i]; 567 if(block == nil) 568 continue; 569 570 status = le32toh(ctlr->tx_ring[i].status); 571 if(status & TxDesc_Status_Own) 572 continue; 573 574 /* Todo add info if it failed */ 575 ctlr->stats.tx++; 576 577 if(ctlr->debugflags & DumpTx) 578 print("vgbe: Block[%03d]:%#p has been sent\n", i, block); 579 580 count++; 581 ctlr->tx_blocks[i] = nil; 582 freeb(block); 583 584 if(ctlr->debugflags & DumpTx) 585 print("vgbe: Block[%03d]:%#p has been freed\n", i, block); 586 } 587 ctlr->tx_count -= count; 588 589 if(ctlr->debugflags & DumpTx) 590 print("vgbe: tx_eof: done [count=%d]\n", count); 591 592 iunlock(&ctlr->tx_lock); 593 594 if(ctlr->tx_count) 595 wiob(ctlr, TxCsrS, TxCsr_Wakeup); 596 } 597 598 static void 599 vgbeinterrupt(Ureg *, void* arg) 600 { 601 Ether* edev; 602 Ctlr* ctlr; 603 ulong status; 604 605 edev = (Ether *) arg; 606 if(edev == nil) 607 return; 608 609 ctlr = edev->ctlr; 610 if(ctlr == nil) 611 return; 612 613 /* Mask interrupts. */ 614 wiol(ctlr, Imr, 0); 615 616 status = riol(ctlr, Isr); 617 if(status == 0xffff) 618 goto end; 619 620 /* acknowledge */ 621 if(status) 622 wiol(ctlr, Isr, status); 623 624 if((status & Isr_Mask) == 0) 625 goto end; 626 627 ctlr->stats.intr++; 628 629 if(ctlr->debugflags & DumpIntr) 630 if(ctlr->debugcount){ 631 print("vgbe: irq: status = %#08ulx\n", status); 632 vgbedumpisr(status); 633 ctlr->debugcount--; 634 } 635 636 if(status & Isr_RxComplete) 637 vgberxeof(edev); 638 639 if(status & Isr_TxComplete0) 640 vgbetxeof(edev); 641 642 if(status & Isr_Stopped) 643 print("vgbe: irq: software shutdown complete\n"); 644 645 if(status & Isr_RxFifoOvflow) 646 print("vgbe: irq: RX FIFO overflow\n"); 647 648 if(status & Isr_PhyIntr) 649 print("vgbe: irq: PHY interrupt\n"); 650 651 if(status & Isr_LinkStatus) 652 print("vgbe: irq: link status change\n"); 653 654 if(status & Isr_RxNoDesc) 655 print("vgbe: irq: ran out of Rx descriptors\n"); 656 657 if(status & Isr_RxDmaStall){ 658 print("vgbe: irq: Rx DMA stall\n"); 659 wiol(ctlr, Cr3C, Cr3_IntMask); 660 return; 661 } 662 663 if(status & Isr_TxDmaStall){ 664 print("vgbe: irq: Tx DMA stall\n"); 665 wiol(ctlr, Cr3C, Cr3_IntMask); 666 return; 667 } 668 669 end: 670 /* Unmask interrupts. */ 671 wiol(ctlr, Imr, ~0); 672 } 673 674 static void 675 vgbetransmit(Ether* edev) 676 { 677 Block* block; 678 Ctlr* ctlr; 679 int i, index, start, count; 680 TxDesc* desc; 681 ulong status, length; 682 683 ctlr = edev->ctlr; 684 685 ilock(&ctlr->tx_lock); 686 687 start = riow(ctlr, TxDscIdx); 688 689 if(ctlr->debugflags & DumpTx) 690 print("vgbe: transmit (start=%d)\n", start); 691 692 /* find empty slot */ 693 for(count = 0, i = 0; i < TxCount; i++){ 694 index = (i + start) % TxCount; 695 696 if(ctlr->tx_blocks[index]) 697 continue; 698 699 desc = &ctlr->tx_ring[index]; 700 701 status = le32toh(desc->status); 702 if(status & TxDesc_Status_Own) 703 continue; 704 705 block = qget(edev->oq); 706 if(block == nil) 707 break; 708 709 count++; 710 711 length = BLEN(block); 712 713 if(ctlr->debugflags & DumpTx) 714 print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block, 715 PCIWADDR(block->rp), length); 716 717 ctlr->tx_blocks[index] = block; 718 719 /* Initialize Tx descriptor. */ 720 desc->status = htole32((length<<16)|TxDesc_Status_Own); 721 desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28)); 722 723 desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp)); 724 desc->frags[0].addr_hi = htole16(0); 725 desc->frags[0].length = htole16(length); 726 } 727 ctlr->tx_count += count; 728 729 if(ctlr->debugflags & DumpTx) 730 print("vgbe: transmit: done [count=%d]\n", count); 731 732 iunlock(&ctlr->tx_lock); 733 734 if(ctlr->tx_count) 735 wiob(ctlr, TxCsrS, TxCsr_Wakeup); 736 737 if(count == 0) 738 print("vgbe: transmit: no Tx entry available\n"); 739 } 740 741 static void 742 vgbeattach(Ether* edev) 743 { 744 Ctlr* ctlr; 745 RxDesc* rxdesc; 746 TxDesc* txdesc; 747 int i; 748 749 ctlr = edev->ctlr; 750 751 lock(&ctlr->init_lock); 752 if(ctlr->inited){ 753 unlock(&ctlr->init_lock); 754 return; 755 } 756 757 // print("vgbe: attach\n"); 758 759 /* Allocate Rx ring. (TODO: Alignment ?) */ 760 rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0); 761 if(rxdesc == nil){ 762 print("vgbe: unable to alloc Rx ring\n"); 763 unlock(&ctlr->init_lock); 764 return; 765 } 766 ctlr->rx_ring = rxdesc; 767 768 /* Allocate Rx blocks, initialize Rx ring. */ 769 for(i = 0; i < RxCount; i++) 770 vgbenewrx(ctlr, i); 771 772 /* Init Rx MAC. */ 773 wiob(ctlr, RxControl, 774 RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast); 775 wiob(ctlr, RxConfig, RxConfig_VlanOpt0); 776 777 /* Load Rx ring. */ 778 wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc)); 779 wiow(ctlr, RxNum, RxCount - 1); 780 wiow(ctlr, RxDscIdx, 0); 781 wiow(ctlr, RxResCnt, RxCount); 782 783 /* Allocate Tx ring. */ 784 txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0); 785 if(txdesc == nil){ 786 print("vgbe: unable to alloc Tx ring\n"); 787 unlock(&ctlr->init_lock); 788 return; 789 } 790 ctlr->tx_ring = txdesc; 791 792 /* Init DMAs */ 793 wiob(ctlr, DmaCfg0, 4); 794 795 /* Init Tx MAC. */ 796 wiob(ctlr, TxControl, 0); 797 wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio); 798 799 /* Load Tx ring. */ 800 wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc)); 801 wiow(ctlr, TxNum, TxCount - 1); 802 wiow(ctlr, TxDscIdx, 0); 803 804 /* Enable Xon/Xoff */ 805 wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable); 806 807 /* Enable Rx queue */ 808 wiob(ctlr, RxCsrS, RxCsr_RunQueue); 809 810 /* Enable Tx queue */ 811 wiob(ctlr, TxCsrS, TxCsr_RunQueue); 812 813 /* Done */ 814 ctlr->inited = 1; 815 unlock(&ctlr->init_lock); 816 817 /* Enable interrupts */ 818 wiol(ctlr, Isr, 0xffffffff); 819 wiob(ctlr, Cr3S, Cr3_IntMask); 820 821 /* Wake up Rx queue */ 822 wiob(ctlr, RxCsrS, RxCsr_Wakeup); 823 } 824 825 static void 826 vgbereset(Ctlr* ctlr) 827 { 828 // MiiPhy* phy; 829 int timeo, i; 830 831 // print("vgbe: reset\n"); 832 833 /* Soft reset the controller. */ 834 wiob(ctlr, Cr1S, Cr1_reset); 835 836 for(timeo = 0; timeo < Timeout; timeo++) 837 if((riob(ctlr, Cr1S) & Cr1_reset) == 0) 838 break; 839 840 if(timeo >= Timeout){ 841 print("vgbe: softreset timeout\n"); 842 return; 843 } 844 845 /* Reload eeprom. */ 846 siob(ctlr, Eecsr, Eecsr_Autold); 847 848 for(timeo = 0; timeo < Timeout; timeo++) 849 if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0) 850 break; 851 852 if(timeo >= Timeout){ 853 print("vgbe: eeprom reload timeout\n"); 854 return; 855 } 856 857 /* Load the MAC address. */ 858 for(i = 0; i < Eaddrlen; i++) 859 ctlr->ea[i] = riob(ctlr, EthAddr+i); 860 861 /* Initialize interrupts. */ 862 wiol(ctlr, Isr, 0xffffffff); 863 wiol(ctlr, Imr, 0xffffffff); 864 865 /* Disable interrupts. */ 866 wiol(ctlr, Cr3C, Cr3_IntMask); 867 868 /* 32 bits addresses only. (TODO: 64 bits ?) */ 869 wiol(ctlr, TxDescHi, 0); 870 wiow(ctlr, DataBufHi, 0); 871 872 /* Enable MAC (turning off Rx/Tx engines for the moment). */ 873 wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx); 874 wiob(ctlr, Cr0S, Cr0_Start); 875 876 /* Initialize Rx engine. */ 877 wiow(ctlr, RxCsrC, RxCsr_RunQueue); 878 879 /* Initialize Tx engine. */ 880 wiow(ctlr, TxCsrC, TxCsr_RunQueue); 881 882 /* Enable Rx/Tx engines. */ 883 wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx); 884 885 /* Initialize link management. */ 886 ctlr->mii = malloc(sizeof(Mii)); 887 if(ctlr->mii == nil){ 888 print("vgbe: unable to alloc Mii\n"); 889 return; 890 } 891 892 ctlr->mii->mir = vgbemiir; 893 ctlr->mii->miw = vgbemiiw; 894 ctlr->mii->ctlr = ctlr; 895 896 if(mii(ctlr->mii, 1<<1) == 0){ 897 print("vgbe: no phy found\n"); 898 return; 899 } 900 901 // phy = ctlr->mii->curphy; 902 // print("vgbe: phy:oui %#x\n", phy->oui); 903 } 904 905 static void 906 vgbepci(void) 907 { 908 Pcidev* pdev; 909 910 // print("vgbe: pci\n"); 911 912 pdev = nil; 913 while(pdev = pcimatch(pdev, 0, 0)){ 914 Ctlr* ctlr; 915 int port, size; 916 917 if(pdev->ccrb != 0x02 || pdev->ccru != 0) 918 continue; 919 920 switch((pdev->did<<16) | pdev->vid){ 921 default: 922 continue; 923 924 case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */ 925 break; 926 } 927 928 if((pdev->pcr & 1) == 0){ 929 print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr); 930 continue; 931 } 932 933 pcisetbme(pdev); 934 pcisetpms(pdev, 0); 935 936 port = pdev->mem[0].bar; 937 size = pdev->mem[0].size; 938 939 if((port & 1) == 0){ 940 print("vgbe: bar[0]=%#x is not io\n", port); 941 continue; 942 } 943 944 if(port > 0xff00){ 945 print("vgbe: invalid port %#ux\n", port); 946 continue; 947 } 948 949 port &= 0xfffe; 950 951 if(size != 256){ 952 print("vgbe: invalid io size: %d\n", size); 953 continue; 954 } 955 956 if(ioalloc(port, size, 0, "vge") < 0){ 957 print("vgbe: port %#ux already in use\n", port); 958 continue; 959 } 960 961 ctlr = malloc(sizeof(Ctlr)); 962 if(ctlr == nil){ 963 print("vgbe: unable to alloc Ctlr\n"); 964 iofree(port); 965 continue; 966 } 967 968 ctlr->pdev = pdev; 969 ctlr->port = port; 970 ctlr->inited = 0; 971 972 if(vgbehead != nil) 973 vgbetail->link = ctlr; 974 else 975 vgbehead = ctlr; 976 vgbetail = ctlr; 977 } 978 } 979 980 static long 981 vgbectl(Ether* edev, void* buf, long n) 982 { 983 Cmdbuf* cb; 984 Ctlr* ctlr; 985 ulong index; 986 char* rptr; 987 RxDesc* rd; 988 TxDesc* td; 989 uchar* p; 990 991 ctlr = edev->ctlr; 992 993 cb = parsecmd(buf, n); 994 if(waserror()){ 995 free(cb); 996 nexterror(); 997 } 998 999 if(cistrcmp(cb->f[0], "reset") == 0){ 1000 vgbereset(ctlr); 1001 wiob(ctlr, Cr3S, Cr3_IntMask); 1002 wiob(ctlr, RxCsrS, RxCsr_RunQueue); 1003 wiob(ctlr, RxCsrS, RxCsr_Wakeup); 1004 } 1005 else if(cistrcmp(cb->f[0], "dumpintr") == 0){ 1006 if(cb->nf < 2) 1007 error(Ecmdargs); 1008 1009 if(cistrcmp(cb->f[1], "on") == 0){ 1010 ctlr->debugflags |= DumpIntr; 1011 ctlr->debugcount = ~0; 1012 } 1013 else if(cistrcmp(cb->f[1], "off") == 0) 1014 ctlr->debugflags &= ~DumpIntr; 1015 else{ 1016 ulong count; 1017 char* rptr; 1018 1019 count = strtoul(cb->f[1], &rptr, 0); 1020 if(rptr == cb->f[1]) 1021 error("invalid control request"); 1022 1023 ctlr->debugflags |= DumpIntr; 1024 ctlr->debugcount = count; 1025 1026 print("vgbe: debugcount set to %uld\n", count); 1027 } 1028 } 1029 else if(cistrcmp(cb->f[0], "dumprx") == 0){ 1030 if(cb->nf < 2) 1031 error(Ecmdargs); 1032 1033 if(cistrcmp(cb->f[1], "on") == 0) 1034 ctlr->debugflags |= DumpRx; 1035 else if(cistrcmp(cb->f[1], "off") == 0) 1036 ctlr->debugflags &= ~DumpRx; 1037 else{ 1038 index = strtoul(cb->f[1], &rptr, 0); 1039 if((rptr == cb->f[1]) || (index >= RxCount)) 1040 error("invalid control request"); 1041 1042 rd = &ctlr->rx_ring[index]; 1043 print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n", 1044 index, rd->status, rd->control, rd->length); 1045 } 1046 } 1047 else if(cistrcmp(cb->f[0], "dumptx") == 0){ 1048 if(cb->nf < 2) 1049 error(Ecmdargs); 1050 1051 if(cistrcmp(cb->f[1], "on") == 0) 1052 ctlr->debugflags |= DumpTx; 1053 else if(cistrcmp(cb->f[1], "off") == 0) 1054 ctlr->debugflags &= ~DumpTx; 1055 else{ 1056 index = strtoul(cb->f[1], &rptr, 0); 1057 if((rptr == cb->f[1]) || (index >= TxCount)) 1058 error("invalid control request"); 1059 1060 td = &ctlr->tx_ring[index]; 1061 print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes", 1062 index, td->status, td->control, td->frags[0].length); 1063 1064 p = (uchar*)td; 1065 for(index = 0; index < sizeof(TxDesc); index++){ 1066 if((index % 16) == 0) 1067 print("\nvgbe: "); 1068 else 1069 print(" "); 1070 print("%#02x", p[index]); 1071 } 1072 } 1073 } 1074 else if(cistrcmp(cb->f[0], "dumpall") == 0){ 1075 if(cb->nf < 2) 1076 error(Ecmdargs); 1077 1078 if(cistrcmp(cb->f[1], "on") == 0){ 1079 ctlr->debugflags = ~0; 1080 ctlr->debugcount = ~0; 1081 } 1082 else if(cistrcmp(cb->f[1], "off") == 0) 1083 ctlr->debugflags = 0; 1084 else error("invalid control request"); 1085 } 1086 else 1087 error(Ebadctl); 1088 1089 free(cb); 1090 poperror(); 1091 1092 return n; 1093 } 1094 1095 static void 1096 vgbepromiscuous(void* arg, int on) 1097 { 1098 USED(arg, on); 1099 } 1100 1101 /* multicast already on, don't need to do anything */ 1102 static void 1103 vgbemulticast(void*, uchar*, int) 1104 { 1105 } 1106 1107 static int 1108 vgbepnp(Ether* edev) 1109 { 1110 Ctlr* ctlr; 1111 1112 // print("vgbe: pnp\n"); 1113 1114 if(vgbehead == nil) 1115 vgbepci(); 1116 1117 for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){ 1118 if(ctlr->active) 1119 continue; 1120 1121 if(edev->port == 0 || edev->port == ctlr->port){ 1122 ctlr->active = 1; 1123 break; 1124 } 1125 } 1126 1127 if(ctlr == nil) 1128 return -1; 1129 1130 vgbereset(ctlr); 1131 1132 edev->ctlr = ctlr; 1133 edev->port = ctlr->port; 1134 edev->irq = ctlr->pdev->intl; 1135 edev->tbdf = ctlr->pdev->tbdf; 1136 edev->mbps = 1000; 1137 memmove(edev->ea, ctlr->ea, Eaddrlen); 1138 edev->attach = vgbeattach; 1139 edev->transmit = vgbetransmit; 1140 edev->interrupt = vgbeinterrupt; 1141 edev->ifstat = vgbeifstat; 1142 // edev->promiscuous = vgbepromiscuous; 1143 edev->multicast = vgbemulticast; 1144 // edev->shutdown = vgbeshutdown; 1145 edev->ctl = vgbectl; 1146 1147 edev->arg = edev; 1148 return 0; 1149 } 1150 1151 void 1152 ethervgbelink(void) 1153 { 1154 addethercard("vgbe", vgbepnp); 1155 } 1156