1 /* Copyright (c) 2003-2011 2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved. 3 * This file is released under the MIT license 4 */ 5 #include "device.h" 6 #include "driver.h" 7 #include "debug.h" 8 #include "ether_driver.h" 9 #include "interface.h" 10 #include "wb840.h" 11 12 #include <ByteOrder.h> 13 #include <KernelExport.h> 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1)) 20 21 // MII chip info table 22 #define PHY_ID0_DAVICOM_DM9101 0x0181 23 #define PHY_ID1_DAVICOM_DM9101 0xb800 24 #define MII_HOME 0x0001 25 #define MII_LAN 0x0002 26 27 struct mii_chip_info 28 { 29 const char* name; 30 uint16 id0; 31 uint16 id1; 32 uint8 types; 33 }; 34 35 36 const static struct mii_chip_info 37 gMIIChips[] = { 38 {"DAVICOM_DM9101", PHY_ID0_DAVICOM_DM9101, PHY_ID1_DAVICOM_DM9101, MII_LAN}, 39 {NULL, 0, 0, 0} 40 }; 41 42 43 static int 44 mii_readstatus(wb_device* device) 45 { 46 int i = 0; 47 int status; 48 49 // status bit has to be retrieved 2 times 50 while (i++ < 2) 51 status = wb_miibus_readreg(device, device->phy, MII_STATUS); 52 53 return status; 54 } 55 56 57 static phys_addr_t 58 physicalAddress(volatile void* addr, uint32 length) 59 { 60 physical_entry table; 61 62 get_memory_map((void*)addr, length, &table, 1); 63 64 return table.address; 65 } 66 67 68 // Prepares a RX descriptor to be used by the chip 69 void 70 wb_put_rx_descriptor(volatile wb_desc* descriptor) 71 { 72 descriptor->wb_status = WB_RXSTAT_OWN; 73 descriptor->wb_ctl |= WB_MAX_FRAMELEN | WB_RXCTL_RLINK; 74 } 75 76 77 void 78 wb_enable_interrupts(wb_device* device) 79 { 80 write32(device->reg_base + WB_IMR, WB_INTRS); 81 write32(device->reg_base + WB_ISR, 0xFFFFFFFF); 82 } 83 84 85 void 86 wb_disable_interrupts(wb_device* device) 87 { 88 write32(device->reg_base + WB_IMR, 0L); 89 write32(device->reg_base + WB_ISR, 0L); 90 } 91 92 93 static void 94 wb_selectPHY(wb_device* device) 95 { 96 uint16 status; 97 98 // ToDo: need to be changed, select PHY in relation to the link mode 99 device->currentPHY = device->firstPHY; 100 device->phy = device->currentPHY->address; 101 status = wb_miibus_readreg(device, device->phy, MII_CONTROL); 102 status &= ~MII_CONTROL_ISOLATE; 103 104 wb_miibus_writereg(device, device->phy, MII_CONTROL, status); 105 106 wb_read_mode(device); 107 } 108 109 110 status_t 111 wb_initPHYs(wb_device* device) 112 { 113 uint16 phy; 114 // search for total of 32 possible MII PHY addresses 115 for (phy = 0; phy < 32; phy++) { 116 struct mii_phy* mii; 117 uint16 status; 118 int i = 0; 119 120 status = wb_miibus_readreg(device, phy, MII_STATUS); 121 status = wb_miibus_readreg(device, phy, MII_STATUS); 122 123 if (status == 0xffff || status == 0x0000) 124 // this MII is not accessable 125 continue; 126 127 mii = (struct mii_phy*)calloc(1, sizeof(struct mii_phy)); 128 if (mii == NULL) 129 return B_NO_MEMORY; 130 131 mii->address = phy; 132 mii->id0 = wb_miibus_readreg(device, phy, MII_PHY_ID0); 133 mii->id1 = wb_miibus_readreg(device, phy, MII_PHY_ID1); 134 mii->types = MII_HOME; 135 mii->next = device->firstPHY; 136 device->firstPHY = mii; 137 138 while (gMIIChips[i].name != NULL) { 139 if (gMIIChips[i].id0 == mii->id0 140 && gMIIChips[i].id1 == (mii->id1 & 0xfff0)) { 141 dprintf("Found MII PHY: %s\n", gMIIChips[i].name); 142 mii->types = gMIIChips[i].types; 143 break; 144 } 145 i++; 146 } 147 if (gMIIChips[i].name == NULL) { 148 dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n", 149 mii->id0, mii->id1); 150 } 151 } 152 153 if (device->firstPHY == NULL) { 154 dprintf("No MII PHY transceiver found!\n"); 155 return B_ENTRY_NOT_FOUND; 156 } 157 158 wb_selectPHY(device); 159 device->link = mii_readstatus(device) & MII_STATUS_LINK; 160 161 return B_OK; 162 } 163 164 165 void 166 wb_init(wb_device* device) 167 { 168 LOG((DEVICE_NAME": init()\n")); 169 170 wb_reset(device); 171 172 device->wb_txthresh = WB_TXTHRESH_INIT; 173 174 switch(device->wb_cachesize) { 175 case 32: 176 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_32LONG); 177 break; 178 case 16: 179 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_16LONG); 180 break; 181 case 8: 182 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_8LONG); 183 break; 184 case 0: 185 default: 186 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_CACHEALIGN_NONE); 187 break; 188 } 189 190 write32(device->reg_base + WB_BUSCTL, 191 WB_BUSCTL_MUSTBEONE | WB_BUSCTL_ARBITRATION); 192 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BURSTLEN_16LONG); 193 194 write32(device->reg_base + WB_BUSCTL_SKIPLEN, WB_SKIPLEN_4LONG); 195 196 // Disable early TX/RX interrupt, as we can't take advantage 197 // from them, at least for now. 198 WB_CLRBIT(device->reg_base + WB_NETCFG, 199 (WB_NETCFG_TX_EARLY_ON | WB_NETCFG_RX_EARLY_ON)); 200 201 wb_set_rx_filter(device); 202 } 203 204 205 void 206 wb_reset(wb_device *device) 207 { 208 int i = 0; 209 210 LOG((DEVICE_NAME": reset()\n")); 211 212 write32(device->reg_base + WB_NETCFG, 0L); 213 write32(device->reg_base + WB_BUSCTL, 0L); 214 write32(device->reg_base + WB_TXADDR, 0L); 215 write32(device->reg_base + WB_RXADDR, 0L); 216 217 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); 218 WB_SETBIT(device->reg_base + WB_BUSCTL, WB_BUSCTL_RESET); 219 220 for (i = 0; i < WB_TIMEOUT; i++) { 221 if (!(read32(device->reg_base + WB_BUSCTL) & WB_BUSCTL_RESET)) 222 break; 223 } 224 225 if (i == WB_TIMEOUT) 226 LOG((DEVICE_NAME": reset hasn't completed!!!")); 227 228 /* Wait a bit while the chip reorders his toughts */ 229 snooze(1000); 230 } 231 232 233 status_t 234 wb_stop(wb_device* device) 235 { 236 uint32 cfgAddress = (uint32)device->reg_base + WB_NETCFG; 237 int32 i = 0; 238 239 if (read32(cfgAddress) & (WB_NETCFG_TX_ON | WB_NETCFG_RX_ON)) { 240 WB_CLRBIT(cfgAddress, (WB_NETCFG_TX_ON | WB_NETCFG_RX_ON)); 241 242 for (i = 0; i < WB_TIMEOUT; i++) { 243 if ((read32(device->reg_base + WB_ISR) & WB_ISR_TX_IDLE) && 244 (read32(device->reg_base + WB_ISR) & WB_ISR_RX_IDLE)) 245 break; 246 } 247 } 248 249 if (i < WB_TIMEOUT) 250 return B_OK; 251 252 return B_ERROR; 253 } 254 255 256 static void 257 wb_updateLink(wb_device* device) 258 { 259 if (!device->autoNegotiationComplete) { 260 int32 mode = wb_read_mode(device); 261 if (mode) 262 wb_set_mode(device, mode); 263 264 return; 265 } 266 267 if (device->link) { 268 uint16 status = mii_readstatus(device); 269 270 // Check if link lost 271 if ((status & MII_STATUS_LINK) == 0) 272 device->link = false; 273 } else { 274 uint16 status; 275 wb_selectPHY(device); 276 277 // Check if we have a new link 278 status = mii_readstatus(device); 279 if (status & MII_STATUS_LINK) 280 device->link = true; 281 } 282 } 283 284 285 int32 286 wb_tick(timer* arg) 287 { 288 wb_device* device = (wb_device*)arg; 289 290 wb_updateLink(device); 291 292 return B_HANDLED_INTERRUPT; 293 } 294 295 296 /* 297 * Program the rx filter. 298 */ 299 void 300 wb_set_rx_filter(wb_device* device) 301 { 302 // TODO: Basically we just config the filter to accept broadcasts 303 // packets. We'll need also to configure it to multicast. 304 WB_SETBIT(device->reg_base + WB_NETCFG, WB_NETCFG_RX_BROAD); 305 } 306 307 308 /***************** Interrupt handling ******************************/ 309 static status_t 310 wb_rxok(wb_device* device) 311 { 312 uint32 releaseRxSem = 0; 313 int16 limit; 314 315 acquire_spinlock(&device->rxSpinlock); 316 317 for (limit = device->rxFree; limit > 0; limit--) { 318 if (device->rxDescriptor[device->rxInterruptIndex].wb_status 319 & WB_RXSTAT_OWN) { 320 break; 321 } 322 323 releaseRxSem++; 324 device->rxInterruptIndex = (device->rxInterruptIndex + 1) 325 & WB_RX_CNT_MASK; 326 device->rxFree--; 327 } 328 329 // Re-enable receive queue 330 write32(device->reg_base + WB_RXSTART, 0xFFFFFFFF); 331 332 release_spinlock(&device->rxSpinlock); 333 334 if (releaseRxSem > 0) { 335 release_sem_etc(device->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE); 336 return B_INVOKE_SCHEDULER; 337 } 338 339 return B_HANDLED_INTERRUPT; 340 } 341 342 343 static status_t 344 wb_tx_nobuf(wb_device* info) 345 { 346 int16 releaseTxSem = 0; 347 int16 limit; 348 status_t status; 349 350 acquire_spinlock(&info->txSpinlock); 351 352 for (limit = info->txSent; limit > 0; limit--) { 353 status = info->txDescriptor[info->txInterruptIndex].wb_status; 354 355 LOG(("wb_tx_nobuf, status: %lx\n", status)); 356 if (status & WB_TXSTAT_TXERR) { 357 LOG(("TX_STAT_ERR\n")); 358 break; 359 } else if (status & WB_UNSENT) { 360 LOG(("TX_STAT_UNSENT\n")); 361 break; 362 } else if (status & WB_TXSTAT_OWN) { 363 LOG((DEVICE_NAME": Device still owns the descriptor\n")); 364 break; 365 } else 366 info->txDescriptor[info->txInterruptIndex].wb_status = 0; 367 368 releaseTxSem++; // this many buffers are free 369 info->txInterruptIndex = (info->txInterruptIndex + 1) & WB_TX_CNT_MASK; 370 info->txSent--; 371 372 if (info->txSent < 0 || info->txSent > WB_TX_LIST_CNT) 373 dprintf("ERROR interrupt: txSent = %d\n", info->txSent); 374 } 375 376 release_spinlock(&info->txSpinlock); 377 378 if (releaseTxSem) { 379 release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE); 380 return B_INVOKE_SCHEDULER; 381 } 382 383 return B_HANDLED_INTERRUPT; 384 } 385 386 387 int32 388 wb_interrupt(void* arg) 389 { 390 wb_device* device = (wb_device*)arg; 391 int32 retval = B_UNHANDLED_INTERRUPT; 392 uint32 status; 393 394 // TODO: Handle other interrupts 395 396 acquire_spinlock(&device->intLock); 397 398 status = read32(device->reg_base + WB_ISR); 399 400 // Did this card request the interrupt ? 401 if (status & WB_INTRS) { 402 // Clean all the interrupts bits 403 if (status) 404 write32(device->reg_base + WB_ISR, status); 405 406 if (status & WB_ISR_ABNORMAL) 407 LOG((DEVICE_NAME": *** Abnormal Interrupt received ***\n")); 408 else 409 LOG((DEVICE_NAME": interrupt received: \n")); 410 411 if (status & WB_ISR_RX_EARLY) { 412 LOG(("WB_ISR_RX_EARLY\n")); 413 } 414 415 if (status & WB_ISR_RX_NOBUF) { 416 LOG(("WB_ISR_RX_NOBUF\n")); 417 // Something is screwed 418 } 419 420 if (status & WB_ISR_RX_ERR) { 421 LOG(("WB_ISR_RX_ERR\n")); 422 // TODO: Do something useful 423 } 424 425 if (status & WB_ISR_RX_OK) { 426 LOG(("WB_ISR_RX_OK\n")); 427 retval = wb_rxok(device); 428 } 429 430 if (status & WB_ISR_RX_IDLE) { 431 LOG(("WB_ISR_RX_IDLE\n")); 432 // ??? 433 } 434 435 if (status & WB_ISR_TX_EARLY) { 436 LOG(("WB_ISR_TX_EARLY\n")); 437 438 } 439 440 if (status & WB_ISR_TX_NOBUF) { 441 LOG(("WB_ISR_TX_NOBUF\n")); 442 retval = wb_tx_nobuf(device); 443 } 444 445 if (status & WB_ISR_TX_UNDERRUN) { 446 LOG(("WB_ISR_TX_UNDERRUN\n")); 447 // TODO: Jack up TX Threshold 448 } 449 450 if (status & WB_ISR_TX_IDLE) { 451 LOG(("WB_ISR_TX_IDLE\n")); 452 } 453 454 if (status & WB_ISR_TX_OK) { 455 LOG(("WB_ISR_TX_OK\n")); 456 // So what ? 457 } 458 459 if (status & WB_ISR_BUS_ERR) { 460 LOG(("WB_ISR_BUS_ERROR: %lx\n", (status & WB_ISR_BUSERRTYPE) >> 4)); 461 //wb_reset(device); 462 } 463 464 if (status & WB_ISR_TIMER_EXPIRED) { 465 LOG(("WB_ISR_TIMER_EXPIRED\n")); 466 // ?? 467 } 468 } 469 470 release_spinlock(&device->intLock); 471 472 return retval; 473 } 474 475 476 /* 477 * Print an ethernet address 478 */ 479 void 480 print_address(ether_address_t* addr) 481 { 482 int i; 483 char buf[3 * 6 + 1]; 484 485 for (i = 0; i < 5; i++) { 486 sprintf(&buf[3 * i], "%02x:", addr->ebyte[i]); 487 } 488 sprintf(&buf[3 * 5], "%02x", addr->ebyte[5]); 489 dprintf("%s\n", buf); 490 } 491 492 493 status_t 494 wb_create_semaphores(wb_device* device) 495 { 496 device->rxSem = create_sem(0, "wb840 receive"); 497 if (device->rxSem < B_OK) { 498 LOG(("Couldn't create sem, sem_id %ld\n", device->rxSem)); 499 return device->rxSem; 500 } 501 502 device->txSem = create_sem(WB_TX_LIST_CNT, "wb840 transmit"); 503 if (device->txSem < B_OK) { 504 LOG(("Couldn't create sem, sem_id %ld\n", device->txSem)); 505 delete_sem(device->rxSem); 506 return device->txSem; 507 } 508 509 set_sem_owner(device->rxSem, B_SYSTEM_TEAM); 510 set_sem_owner(device->txSem, B_SYSTEM_TEAM); 511 512 device->rxLock = 0; 513 device->txLock = 0; 514 515 return B_OK; 516 } 517 518 519 void 520 wb_delete_semaphores(wb_device* device) 521 { 522 if (device->rxSem >= 0) 523 delete_sem(device->rxSem); 524 if (device->txSem >= 0) 525 delete_sem(device->txSem); 526 } 527 528 529 status_t 530 wb_create_rings(wb_device* device) 531 { 532 int i; 533 534 device->rxArea = create_area("wb840 rx buffer", 535 (void**)&device->rxBuffer[0], B_ANY_KERNEL_ADDRESS, 536 ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_RX_LIST_CNT), 537 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 538 if (device->rxArea < B_OK) 539 return device->rxArea; 540 541 for (i = 1; i < WB_RX_LIST_CNT; i++) { 542 device->rxBuffer[i] = (void*)(((addr_t)device->rxBuffer[0]) 543 + (i * WB_BUFBYTES)); 544 } 545 546 for (i = 0; i < WB_RX_LIST_CNT; i++) { 547 device->rxDescriptor[i].wb_status = 0; 548 device->rxDescriptor[i].wb_ctl = WB_RXCTL_RLINK; 549 wb_put_rx_descriptor(&device->rxDescriptor[i]); 550 device->rxDescriptor[i].wb_data = physicalAddress( 551 device->rxBuffer[i], WB_BUFBYTES); 552 device->rxDescriptor[i].wb_next = physicalAddress( 553 &device->rxDescriptor[(i + 1) & WB_RX_CNT_MASK], 554 sizeof(struct wb_desc)); 555 } 556 557 device->rxFree = WB_RX_LIST_CNT; 558 559 device->txArea = create_area("wb840 tx buffer", 560 (void**)&device->txBuffer[0], B_ANY_KERNEL_ADDRESS, 561 ROUND_TO_PAGE_SIZE(WB_BUFBYTES * WB_TX_LIST_CNT), 562 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 563 564 if (device->txArea < B_OK) { 565 delete_area(device->rxArea); 566 return device->txArea; 567 } 568 569 for (i = 1; i < WB_TX_LIST_CNT; i++) { 570 device->txBuffer[i] = (void*)(((addr_t)device->txBuffer[0]) 571 + (i * WB_BUFBYTES)); 572 } 573 574 for (i = 0; i < WB_TX_LIST_CNT; i++) { 575 device->txDescriptor[i].wb_status = 0; 576 device->txDescriptor[i].wb_ctl = WB_TXCTL_TLINK; 577 device->txDescriptor[i].wb_data = physicalAddress( 578 device->txBuffer[i], WB_BUFBYTES); 579 device->txDescriptor[i].wb_next = physicalAddress( 580 &device->txDescriptor[(i + 1) & WB_TX_CNT_MASK], 581 sizeof(struct wb_desc)); 582 } 583 584 if (wb_stop(device) == B_OK) { 585 write32(device->reg_base + WB_RXADDR, 586 physicalAddress(&device->rxDescriptor[0], sizeof(struct wb_desc))); 587 write32(device->reg_base + WB_TXADDR, 588 physicalAddress(&device->txDescriptor[0], sizeof(struct wb_desc))); 589 } 590 591 return B_OK; 592 } 593 594 595 void 596 wb_delete_rings(wb_device* device) 597 { 598 delete_area(device->rxArea); 599 delete_area(device->txArea); 600 } 601 602 603 int32 604 wb_read_mode(wb_device* info) 605 { 606 uint16 autoAdv; 607 uint16 autoLinkPartner; 608 int32 speed; 609 int32 duplex; 610 611 uint16 status = mii_readstatus(info); 612 if (!(status & MII_STATUS_LINK)) { 613 LOG((DEVICE_NAME ": no link detected (status = %x)\n", status)); 614 return 0; 615 } 616 617 // auto negotiation completed 618 autoAdv = wb_miibus_readreg(info, info->phy, MII_AUTONEG_ADV); 619 autoLinkPartner = wb_miibus_readreg(info, info->phy, 620 MII_AUTONEG_LINK_PARTNER); 621 status = autoAdv & autoLinkPartner; 622 623 speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) 624 ? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT; 625 duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) 626 ? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX; 627 628 info->autoNegotiationComplete = true; 629 630 LOG((DEVICE_NAME ": linked, 10%s MBit, %s duplex\n", 631 speed == LINK_SPEED_100_MBIT ? "0" : "", 632 duplex == LINK_FULL_DUPLEX ? "full" : "half")); 633 634 return speed | duplex; 635 } 636 637 638 void 639 wb_set_mode(wb_device* info, int mode) 640 { 641 uint32 cfgAddress = (uint32)info->reg_base + WB_NETCFG; 642 643 uint32 configFlags = 0; 644 status_t status; 645 646 info->speed = mode & LINK_SPEED_MASK; 647 info->full_duplex = mode & LINK_DUPLEX_MASK; 648 649 status = wb_stop(info); 650 651 if ((mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX) 652 configFlags |= WB_NETCFG_FULLDUPLEX; 653 654 if (info->speed == LINK_SPEED_100_MBIT) 655 configFlags |= WB_NETCFG_100MBPS; 656 657 write32(cfgAddress, configFlags); 658 659 if (status == B_OK) 660 WB_SETBIT(cfgAddress, WB_NETCFG_TX_ON|WB_NETCFG_RX_ON); 661 } 662