1/* 2 * SiS 190/191 NIC Driver. 3 * Copyright (c) 2009 S.Zharski <imker@gmx.li> 4 * Distributed under the terms of the MIT license. 5 * 6 */ 7 8 9#include "Device.h" 10 11#include <net/if_media.h> 12#include <lock.h> 13#include <stdio.h> 14 15#include "Driver.h" 16#include "Settings.h" 17#include "Registers.h" 18 19 20Device::Device(Device::Info &DeviceInfo, pci_info &PCIInfo) 21 : 22 fStatus(B_ERROR), 23 fPCIInfo(PCIInfo), 24 fInfo(DeviceInfo), 25 fIOBase(0), 26 fHWSpinlock(0), 27 fInterruptsNest(0), 28 fFrameSize(MaxFrameSize), 29 fMII(this), 30 fOpen(false), 31 fBlockFlag(0), 32 fLinkStateChangeSem(-1), 33 fHasConnection(false), 34 fTxDataRing(this, true), 35 fRxDataRing(this, false) 36{ 37 memset((struct timer*)this, 0, sizeof(struct timer)); 38 39 uint32 cmdRegister = gPCIModule->read_pci_config(PCIInfo.bus, 40 PCIInfo.device, PCIInfo.function, PCI_command, 2); 41 TRACE_ALWAYS("cmdRegister:%#010x\n", cmdRegister); 42 cmdRegister |= PCI_command_io | PCI_command_memory | PCI_command_master; 43 gPCIModule->write_pci_config(PCIInfo.bus, PCIInfo.device, 44 PCIInfo.function, PCI_command, 2, cmdRegister); 45 46 fIOBase = PCIInfo.u.h0.base_registers[1]; 47 TRACE_ALWAYS("fIOBase:%#010x\n", fIOBase); 48 49 fStatus = B_OK; 50} 51 52 53Device::~Device() 54{ 55} 56 57 58status_t 59Device::Open(uint32 flags) 60{ 61 TRACE("flags:%x\n", flags); 62 if (fOpen) { 63 TRACE_ALWAYS("An attempt to re-open device ignored.\n"); 64 return B_BUSY; 65 } 66 67 status_t result = fMII.Init(); 68 if (result != B_OK) { 69 TRACE_ALWAYS("MII initialization failed: %#010x.\n", result); 70 return result; 71 } 72 73 _Reset(); 74 75 if ((fMII.LinkState().media & IFM_ACTIVE) == 0/*fNegotiationComplete*/) { 76 fMII.UpdateLinkState(); 77 } 78 79 fMII.SetMedia(); 80 81 WritePCI32(RxMACAddress, 0); 82 _InitRxFilter(); 83 84 fRxDataRing.Open(); 85 fTxDataRing.Open(); 86 87 if (atomic_add(&fInterruptsNest, 1) == 0) { 88 install_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 89 InterruptHandler, this, 0); 90 TRACE("Interrupt handler installed at line %d.\n", 91 fPCIInfo.u.h0.interrupt_line); 92 } 93 94 _SetRxMode(); 95 96 // enable al known interrupts 97 WritePCI32(IntMask, knownInterruptsMask); 98 99 // enable Rx and Tx 100 uint32 control = ReadPCI32(RxControl); 101 control |= RxControlEnable | RxControlPoll; 102 WritePCI32(RxControl, control); 103 104 control = ReadPCI32(TxControl); 105 control |= TxControlEnable /*| TxControlPoll*/; 106 WritePCI32(TxControl, control); 107 108 add_timer((timer*)this, _TimerHandler, 1000000LL, B_PERIODIC_TIMER); 109 110 //fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK; 111 fOpen = true; 112 return B_OK; 113} 114 115 116status_t 117Device::Close() 118{ 119 TRACE("closed!\n"); 120 121 // disable interrupts 122 WritePCI32(IntMask, 0); 123 spin(2000); 124 125 // Stop Tx / Rx status machine 126 uint32 status = ReadPCI32(IntControl); 127 status |= 0x00008000; 128 WritePCI32(IntControl, status); 129 spin(50); 130 status &= ~0x00008000; 131 WritePCI32(IntControl, status); 132 133 if (atomic_add(&fInterruptsNest, -1) == 1) { 134 remove_io_interrupt_handler(fPCIInfo.u.h0.interrupt_line, 135 InterruptHandler, this); 136 TRACE("Interrupt handler at line %d uninstalled.\n", 137 fPCIInfo.u.h0.interrupt_line); 138 } 139 140 fRxDataRing.Close(); 141 fTxDataRing.Close(); 142 143 cancel_timer((timer*)this); 144 145 TRACE("timer cancelled\n"); 146 147 fOpen = false; 148 149 return B_OK; 150} 151 152 153status_t 154Device::Free() 155{ 156 // fRxDataRing.Free(); 157 // fTxDataRing.Free(); 158 159 TRACE("freed\n"); 160 return B_OK; 161} 162 163 164status_t 165Device::Read(uint8 *buffer, size_t *numBytes) 166{ 167 return fRxDataRing.Read(buffer, numBytes); 168} 169 170 171status_t 172Device::Write(const uint8 *buffer, size_t *numBytes) 173{ 174 if ((fMII.LinkState().media & IFM_ACTIVE) == 0) { 175 TRACE_ALWAYS("Write failed. link is inactive!\n"); 176 return B_OK; // return OK because of well-known DHCP "moustreap"! 177 } 178 179 return fTxDataRing.Write(buffer, numBytes); 180} 181 182 183status_t 184Device::Control(uint32 op, void *buffer, size_t length) 185{ 186 switch (op) { 187 case ETHER_INIT: 188 TRACE("ETHER_INIT\n"); 189 return B_OK; 190 191 case ETHER_GETADDR: 192 memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); 193 TRACE("ETHER_GETADDR %#02x:%#02x:%#02x:%#02x:%#02x:%#02x\n", 194 fMACAddress.ebyte[0], fMACAddress.ebyte[1], 195 fMACAddress.ebyte[2], fMACAddress.ebyte[3], 196 fMACAddress.ebyte[4], fMACAddress.ebyte[5]); 197 return B_OK; 198 199 case ETHER_GETFRAMESIZE: 200 *(uint32 *)buffer = fFrameSize; 201 TRACE("ETHER_ETHER_GETFRAMESIZE:%d\n",fFrameSize); 202 return B_OK; 203 204 case ETHER_NONBLOCK: 205 TRACE("ETHER_NONBLOCK\n"); 206 fBlockFlag = *((uint32*)buffer) ? B_TIMEOUT : 0; 207 return B_OK; 208 209 case ETHER_SETPROMISC: 210 return _SetRxMode((uint8*)buffer); 211 212 case ETHER_ADDMULTI: 213 return _ModifyMulticastTable(true, (ether_address_t*)buffer); 214 215 case ETHER_REMMULTI: 216 return _ModifyMulticastTable(false, (ether_address_t*)buffer); 217 218 case ETHER_SET_LINK_STATE_SEM: 219 fLinkStateChangeSem = *(sem_id *)buffer; 220 TRACE_ALWAYS("ETHER_SET_LINK_STATE_SEM\n"); 221 return B_OK; 222 223 case ETHER_GET_LINK_STATE: 224 return GetLinkState((ether_link_state *)buffer); 225 226 default: 227 TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op); 228 } 229 230 return B_DEV_INVALID_IOCTL; 231} 232 233 234status_t 235Device::SetupDevice() 236{ 237 ether_address address; 238 status_t result = ReadMACAddress(address); 239 if (result != B_OK) { 240 TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result); 241 return result; 242 } 243 244 TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n", 245 address.ebyte[0], address.ebyte[1], address.ebyte[2], 246 address.ebyte[3], address.ebyte[4], address.ebyte[5]); 247 248 fMACAddress = address; 249 250 uint16 info = _ReadEEPROM(EEPROMInfo); 251 fMII.SetRGMII((info & 0x0080) != 0); 252 253 TRACE("RGMII is '%s'. EEPROM info word:%#06x.\n", 254 fMII.HasRGMII() ? "on" : "off", info); 255 256 fMII.SetGigagbitCapable(fInfo.Id() == SiS191); 257 258 return B_OK; 259} 260 261 262void 263Device::TeardownDevice() 264{ 265 266} 267 268 269uint8 270Device::ReadPCI8(int offset) 271{ 272 return gPCIModule->read_io_8(fIOBase + offset); 273} 274 275 276uint16 277Device::ReadPCI16(int offset) 278{ 279 return gPCIModule->read_io_16(fIOBase + offset); 280} 281 282 283uint32 284Device::ReadPCI32(int offset) 285{ 286 return gPCIModule->read_io_32(fIOBase + offset); 287} 288 289 290void 291Device::WritePCI8(int offset, uint8 value) 292{ 293 gPCIModule->write_io_8(fIOBase + offset, value); 294} 295 296 297void 298Device::WritePCI16(int offset, uint16 value) 299{ 300 gPCIModule->write_io_16(fIOBase + offset, value); 301} 302 303 304void 305Device::WritePCI32(int offset, uint32 value) 306{ 307 gPCIModule->write_io_32(fIOBase + offset, value); 308} 309 310/* 311 cpu_status 312 Device::Lock() 313 { 314 cpu_status st = disable_interrupts(); 315 acquire_spinlock(&fHWSpinlock); 316 return st; 317 } 318 319 320 void 321 Device::Unlock(cpu_status st) 322 { 323 release_spinlock(&fHWSpinlock); 324 restore_interrupts(st); 325 } 326 */ 327 328int32 329Device::InterruptHandler(void *InterruptParam) 330{ 331 Device *device = (Device*)InterruptParam; 332 if(device == 0) { 333 TRACE_ALWAYS("Invalid parameter in the interrupt handler.\n"); 334 return B_HANDLED_INTERRUPT; 335 } 336 337 int32 result = B_UNHANDLED_INTERRUPT; 338 339 acquire_spinlock(&device->fHWSpinlock); 340 341 // disable interrupts... 342 device->WritePCI32(IntMask, 0); 343 344 //int maxWorks = 40; 345 346 //do { 347 uint32 status = device->ReadPCI32(IntSource); 348 349#if STATISTICS 350 device->fStatistics.PutStatus(status); 351#endif 352 device->WritePCI32(IntSource, status); 353 354 if ((status & knownInterruptsMask) != 0) { 355 //break; 356 //} 357 358 // XXX: ???? 359 result = B_HANDLED_INTERRUPT; 360 361 if ((status & (/*INT_TXIDLE |*/ INT_TXDONE)) != 0 ) { 362 result = device->fTxDataRing.InterruptHandler(); 363 } 364 365 if ((status & (/*INT_RXIDLE |*/ INT_RXDONE)) != 0 ) { 366 result = device->fRxDataRing.InterruptHandler(); 367 } 368 369 /*if ((status & (INT_LINK)) != 0 ) { 370 //if (!device->fMII.isLinkUp()) { 371 device->fTxDataRing.CleanUp(); 372 //} 373 }*/ 374 } 375 376 //} while (--maxWorks > 0); 377 378 // enable interrupts... 379 device->WritePCI32(IntMask, knownInterruptsMask); 380 381 release_spinlock(&device->fHWSpinlock); 382 383 return result; 384} 385 386 387status_t 388Device::GetLinkState(ether_link_state *linkState) 389{ 390 status_t result = user_memcpy(linkState, &fMII.LinkState(), 391 sizeof(ether_link_state)); 392 393#if STATISTICS 394 fStatistics.Trace(); 395 fRxDataRing.Trace(); 396 fTxDataRing.Trace(); 397 uint32 rxControl = ReadPCI32(RxControl); 398 uint32 txControl = ReadPCI32(TxControl); 399 TRACE_ALWAYS("RxControl:%#010x;TxControl:%#010x\n", rxControl, txControl); 400#endif 401 402 TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", 403 (linkState->media & IFM_ACTIVE) ? "active" : "inactive", 404 linkState->speed / 1000, 405 (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); 406 407 return result; 408} 409 410 411status_t 412Device::_SetRxMode(uint8* setPromiscuousOn) 413{ 414 uint16 rxMode = ReadPCI16(RxMACControl); 415 416 // clean the Rx MAC Control register 417 WritePCI16(RxMACControl, rxMode & ~RXM_Mask); 418 419 rxMode &= RXM_Mask; 420 421 if (setPromiscuousOn != NULL) { 422 if (*setPromiscuousOn != 0) 423 rxMode |= RXM_AllPhysical; 424 else 425 rxMode &= ~RXM_AllPhysical; 426 } 427 428 uint32 multicastFilter[2] = { 0 }; 429 if ((rxMode & RXM_AllPhysical) == 0 && fMulticastHashes.Count() <= 128) { 430 431 for (int32 i = 0; i < fMulticastHashes.Count(); i++) { 432 uint32 hash = fMulticastHashes[i]; 433 multicastFilter[hash >> 31] |= 1 << ((hash >> 26) & 0x1f); 434 } 435 436 } else 437 multicastFilter[0] = multicastFilter[1] = 0xffffffff; 438 439 rxMode |= RXM_Broadcast | RXM_Multicast | RXM_Physical; 440 441 // set multicast filters 442 WritePCI32(RxHashTable, multicastFilter[0]); 443 WritePCI32(RxHashTable + 4, multicastFilter[1]); 444 445 // update rx mode 446 WritePCI16(RxMACControl, ReadPCI16(RxMACControl) | rxMode); 447 448 return B_OK; 449} 450 451 452int32 453Device::_TimerHandler(struct timer* timer) 454{ 455 Device* device = (Device*)timer; 456 457 bool linkChanged = false; 458 int32 result = device->fMII.TimerHandler(&linkChanged); 459 460 if (linkChanged) { 461 if (device->fMII.IsLinkUp()) { 462 device->fTxDataRing.CleanUp(); 463 //device->WritePCI32(IntControl, 0x8000); 464 //device->ReadPCI32(IntControl); 465 //spin(100); 466 //device->WritePCI32(IntControl, 0x0); 467 } 468 } 469 470 if (linkChanged && device->fLinkStateChangeSem > B_OK) { 471 release_sem_etc(device->fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 472 } 473 474 return result; 475} 476 477 478status_t 479Device::_Reset() 480{ 481 // disable interrupts 482 WritePCI32(IntMask, 0); 483 WritePCI32(IntSource, 0xffffffff); 484 485 // reset Rx & Tx 486 WritePCI32(TxControl, 0x00001c00); 487 WritePCI32(RxControl, 0x001e1c00); 488 489 WritePCI32(IntControl, 0x8000); 490 ReadPCI32(IntControl); 491 spin(100); 492 WritePCI32(IntControl, 0x0); 493 494 WritePCI32(IntMask, 0); 495 WritePCI32(IntSource, 0xffffffff); 496 497 // initial values for all MAC registers 498 WritePCI32(TxBase, 0x0); 499 WritePCI32(TxReserved, 0x0); 500 WritePCI32(RxBase, 0x0); 501 WritePCI32(RxReserved, 0x0); 502 503 WritePCI32(PowControl, 0xffc00000); 504 WritePCI32(Reserved0, 0x0); 505 506 WritePCI32(StationControl, fMII.HasRGMII() ? 0x04008001 : 0x04000001); 507 WritePCI32(GIoCR, 0x0); 508 WritePCI32(GIoControl, 0x0); 509 510 WritePCI32(TxMACControl, 0x00002364); 511 WritePCI32(TxLimit, 0x0000000f); 512 513 WritePCI32(RGDelay, 0x0); 514 WritePCI32(Reserved1, 0x0); 515 WritePCI32(RxMACControl, 0x00000252); 516 517 WritePCI32(RxHashTable, 0x0); 518 WritePCI32(RxHashTable + 4, 0x0); 519 520 WritePCI32(RxWOLControl, 0x80ff0000); 521 WritePCI32(RxWOLData, 0x80ff0000); 522 WritePCI32(RxMPSControl, 0x0); 523 WritePCI32(Reserved2, 0x0); 524 525 return B_OK; 526} 527 528 529void 530Device::_InitRxFilter() 531{ 532 // store filter value 533 uint16 filter = ReadPCI16(RxMACControl); 534 535 // disable disable packet filtering before address is set 536 WritePCI32(RxMACControl, (filter & ~RXM_Mask)); 537 538 for (size_t i = 0; i < _countof(fMACAddress.ebyte); i++) { 539 WritePCI8(RxMACAddress + i, fMACAddress.ebyte[i]); 540 } 541 542 // clear promiscuous bit on initialization 543 filter &= ~RXM_AllPhysical; 544 545 // enable packet filtering 546 WritePCI16(RxMACControl, filter); 547} 548 549 550uint16 551Device::_ReadEEPROM(uint32 address) 552{ 553 if (address > EIOffset) { 554 TRACE_ALWAYS("EEPROM address %#08x is invalid.\n", address); 555 return EIInvalid; 556 } 557 558 WritePCI32(EEPROMInterface, EIReq | EIOpRead | (address << EIOffsetShift)); 559 560 spin(500); // 500 ms? 561 562 for (size_t i = 0; i < 1000; i++) { 563 uint32 data = ReadPCI32(EEPROMInterface); 564 if ((data & EIReq) == 0) { 565 return (data & EIData) >> EIDataShift; 566 } 567 spin(100); // 100 ms? 568 } 569 570 TRACE_ALWAYS("timeout reading EEPROM.\n"); 571 572 return EIInvalid; 573} 574 575 576status_t 577Device::ReadMACAddress(ether_address_t& address) 578{ 579 uint16 signature = _ReadEEPROM(EEPROMSignature); 580 TRACE("EEPROM Signature: %#06x\n", signature); 581 582 if (signature != 0x0000 && signature != EIInvalid) { 583 for (size_t i = 0; i < _countof(address.ebyte) / 2; i++) { 584 uint16 addr = _ReadEEPROM(EEPROMAddress + i); 585 address.ebyte[i * 2 + 0] = (uint8)addr; 586 address.ebyte[i * 2 + 1] = (uint8)(addr >> 8); 587 } 588 589 return B_OK; 590 } 591 592 // SiS96x can use APC CMOS RAM to store MAC address, 593 // this is accessed through ISA bridge. 594 uint32 register73 = gPCIModule->read_pci_config(fPCIInfo.bus, 595 fPCIInfo.device, fPCIInfo.function, 0x73, 1); 596 TRACE_ALWAYS("Config register x73:%#010x\n", register73); 597 598 if ((register73 & 0x00000001) == 0) 599 return B_ERROR; 600 601 // look for PCI-ISA bridge 602 uint16 ids[] = { 0x0965, 0x0966, 0x0968 }; 603 604 pci_info pciInfo = {0}; 605 for (long i = 0; B_OK == (*gPCIModule->get_nth_pci_info)(i, &pciInfo); i++) { 606 if (pciInfo.vendor_id != 0x1039) 607 continue; 608 609 for (size_t idx = 0; idx < _countof(ids); idx++) { 610 if (pciInfo.device_id == ids[idx]) { 611 612 // enable ports 0x78 0x79 to access APC registers 613 uint32 reg = gPCIModule->read_pci_config(pciInfo.bus, 614 pciInfo.device, pciInfo.function, 0x48, 1); 615 reg &= ~0x02; 616 gPCIModule->write_pci_config(pciInfo.bus, 617 pciInfo.device, pciInfo.function, 0x48, 1, reg); 618 snooze(50); 619 reg = gPCIModule->read_pci_config(pciInfo.bus, 620 pciInfo.device, pciInfo.function, 0x48, 1); 621 622 // read factory MAC address 623 for (size_t i = 0; i < _countof(address.ebyte); i++) { 624 gPCIModule->write_io_8(0x78, 0x09 + i); 625 address.ebyte[i] = gPCIModule->read_io_8(0x79); 626 } 627 628 // check MII/RGMII 629 gPCIModule->write_io_8(0x78, 0x12); 630 uint8 u8 = gPCIModule->read_io_8(0x79); 631 // TODO: set RGMII in fMII correctly! 632 // bool bRGMII = (u8 & 0x80) != 0; 633 TRACE_ALWAYS("RGMII: %#04x\n", u8); 634 635 // close access to APC registers 636 gPCIModule->write_pci_config(pciInfo.bus, 637 pciInfo.device, pciInfo.function, 0x48, 1, reg); 638 639 return B_OK; 640 } 641 } 642 } 643 644 TRACE_ALWAYS("ISA bridge was not found.\n"); 645 return B_ERROR; 646} 647 648 649uint32 650Device::_EthernetCRC32(const uint8* buffer, size_t length) 651{ 652 uint32 result = 0xffffffff; 653 for (size_t i = 0; i < length; i++) { 654 uint8 data = *buffer++; 655 for (int bit = 0; bit < 8; bit++, data >>= 1) { 656 uint32 carry = ((result & 0x80000000) ? 1 : 0) ^ (data & 0x01); 657 result <<= 1; 658 if (carry != 0) 659 result = (result ^ 0x04c11db6) | carry; 660 } 661 } 662 return result; 663} 664 665 666status_t 667Device::_ModifyMulticastTable(bool join, ether_address_t* group) 668{ 669 char groupName[6 * 3 + 1] = { 0 }; 670 sprintf(groupName, "%02x:%02x:%02x:%02x:%02x:%02x", 671 group->ebyte[0], group->ebyte[1], group->ebyte[2], 672 group->ebyte[3], group->ebyte[4], group->ebyte[5]); 673 TRACE("%s multicast group %s\n", join ? "Joining" : "Leaving", groupName); 674 675 uint32 hash = _EthernetCRC32(group->ebyte, 6); 676 bool isInTable = fMulticastHashes.Find(hash) != fMulticastHashes.End(); 677 678 if (isInTable && join) 679 return B_OK; // already listed - nothing to do 680 681 if (!isInTable && !join) { 682 TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", groupName); 683 return B_ERROR; 684 } 685 686 if (join) 687 fMulticastHashes.PushBack(hash); 688 else 689 fMulticastHashes.Remove(hash); 690 691 return _SetRxMode(); 692} 693 694 695void 696Device::DumpRegisters() 697{ 698 struct RegisterEntry { 699 uint32 Base; 700 const char* Name; 701 bool writeBack; 702 } RegisterEntries[] = { 703 { TxControl, "TxControl", false }, 704 { TxBase, "TxBase\t", false }, 705 { TxStatus, "TxStatus", false }, 706 { TxReserved, "TxReserved", false }, 707 { RxControl, "RxControl", false }, 708 { RxBase, "RxBase\t", false }, 709 { RxStatus, "RxStatus", false }, 710 { RxReserved, "RxReserved", false }, 711 { IntSource, "IntSource", true }, 712 { IntMask, "IntMask", false }, 713 { IntControl, "IntControl", false }, 714 { IntTimer, "IntTimer", false }, 715 { PowControl, "PowControl", false }, 716 { Reserved0, "Reserved0", false }, 717 { EEPROMControl, "EEPROMCntl", false }, 718 { EEPROMInterface, "EEPROMIface", false }, 719 { StationControl, "StationCntl", false }, 720 { SMInterface, "SMInterface", false }, 721 { GIoCR, "GIoCR\t", false }, 722 { GIoControl, "GIoControl", false }, 723 { TxMACControl, "TxMACCntl", false }, 724 { TxLimit, "TxLimit", false }, 725 { RGDelay, "RGDelay", false }, 726 { Reserved1, "Reserved1", false }, 727 { RxMACControl, "RxMACCntlEtc", false }, 728 { RxMACAddress + 2, "RxMACAddr2", false }, 729 { RxHashTable, "RxHashTable1", false }, 730 { RxHashTable + 4, "RxHashTable2", false }, 731 { RxWOLControl, "RxWOLControl", false }, 732 { RxWOLData, "RxWOLData", false }, 733 { RxMPSControl, "RxMPSControl", false }, 734 { Reserved2, "Reserved2", false } 735 }; 736 737 for (size_t i = 0; i < _countof(RegisterEntries); i++) { 738 uint32 registerContents = ReadPCI32(RegisterEntries[i].Base); 739 kprintf("%s:\t%08" B_PRIx32 "\n", RegisterEntries[i].Name, 740 registerContents); 741 if (RegisterEntries[i].writeBack) { 742 WritePCI32(RegisterEntries[i].Base, registerContents); 743 } 744 } 745} 746 747