1/* SiS 900 chip specific functions 2 * 3 * Copyright © 2001-2005 pinc Software. All Rights Reserved. 4 * Distributed under the terms of the MIT license. 5 */ 6 7 8#include <OS.h> 9#include <KernelExport.h> 10#include <Drivers.h> 11#include <PCI.h> 12#include <SupportDefs.h> 13 14#include <stdlib.h> 15#include <string.h> 16 17#include "ether_driver.h" 18#include "driver.h" 19#include "device.h" 20#include "interface.h" 21#include "sis900.h" 22 23 24// prototypes 25 26uint16 sis900_resetPHY(struct sis_info *info); 27void sis900_selectPHY(struct sis_info *info); 28void sis900_setMode(struct sis_info *info, int32 mode); 29int32 sis900_readMode(struct sis_info *info); 30 31 32// MII chip info table 33 34#define PHY_ID0_SiS900_INTERNAL 0x001d 35#define PHY_ID1_SiS900_INTERNAL 0x8000 36#define PHY_ID0_ICS_1893 0x0015 37#define PHY_ID1_ICS_1893 0xff40 38#define PHY_ID0_REALTEK_8201 0x0000 39#define PHY_ID1_REALTEK_8201 0x8200 40#define PHY_ID0_VIA_6103 0x0101 41#define PHY_ID1_VIA_6103 0x8f20 42 43#define MII_HOME 0x0001 44#define MII_LAN 0x0002 45 46const static struct mii_chip_info { 47 const char *name; 48 uint16 id0, id1; 49 uint8 types; 50} gMIIChips[] = { 51 {"SiS 900 Internal MII PHY", 52 PHY_ID0_SiS900_INTERNAL, PHY_ID1_SiS900_INTERNAL, MII_LAN}, 53 {"SiS 7014 Physical Layer Solution", 54 0x0016, 0xf830, MII_LAN}, 55 {"AMD 79C901 10BASE-T PHY", 56 0x0000, 0x6B70, MII_LAN}, 57 {"AMD 79C901 HomePNA PHY", 58 0x0000, 0x6B90, MII_HOME}, 59 {"ICS 1893 LAN PHY", 60 PHY_ID0_ICS_1893, PHY_ID1_ICS_1893, MII_LAN}, 61 {"NS 83851 PHY", 62 0x2000, 0x5C20, MII_LAN | MII_HOME}, 63 {"Realtek RTL8201 PHY", 64 PHY_ID0_REALTEK_8201, PHY_ID1_REALTEK_8201, MII_LAN}, 65 {"VIA 6103 PHY", 66 PHY_ID0_VIA_6103, PHY_ID1_VIA_6103, MII_LAN}, 67 {NULL, 0, 0, 0} 68}; 69 70 71/***************************** helper functions *****************************/ 72 73 74static phys_addr_t 75physicalAddress(volatile void *address, uint32 length) 76{ 77 physical_entry table; 78 79 get_memory_map((void *)address, length, &table, 1); 80 return table.address; 81} 82 83 84/***************************** interrupt handling *****************************/ 85// #pragma mark - 86int32 intrCounter = 0; 87int32 lastIntr[100]; 88 89 90static int32 91sis900_rxInterrupt(struct sis_info *info) 92{ 93 int32 handled = B_UNHANDLED_INTERRUPT; 94 int16 releaseRxSem = 0; 95 int16 limit; 96 97 acquire_spinlock(&info->rxSpinlock); 98 99 HACK(spin(10000)); 100 101 // check for packet ownership 102 for (limit = info->rxFree; limit > 0; limit--) { 103 if (!(info->rxDescriptor[info->rxInterruptIndex].status & SiS900_DESCR_OWN)) { 104// if (limit == info->rxFree) 105// { 106 //dprintf("here!\n"); 107// limit++; 108// continue; 109// } 110 break; 111 } 112 //dprintf("received frame %d!\n",info->rxInterruptIndex); 113 114 releaseRxSem++; 115 info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK; 116 info->rxFree--; 117 } 118 release_spinlock(&info->rxSpinlock); 119 120 // reenable rx queue 121 write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE); 122 123 if (releaseRxSem) { 124 release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE); 125 return B_INVOKE_SCHEDULER; 126 } 127 128 return handled; 129} 130 131 132static int32 133sis900_txInterrupt(struct sis_info *info) 134{ 135 int16 releaseTxSem = 0; 136 uint32 status; 137 int16 limit; 138 139 acquire_spinlock(&info->txSpinlock); 140 141 HACK(spin(10000)); 142 143 for (limit = info->txSent; limit > 0; limit--) { 144 status = info->txDescriptor[info->txInterruptIndex].status; 145 146//dprintf("txIntr: %d: mem = %lx : hardware = %lx\n",info->txInterruptIndex, 147// physicalAddress(&info->txDescriptor[info->txInterruptIndex],sizeof(struct buffer_desc)), 148// read32(info->registers + SiS900_MAC_Tx_DESCR)); 149 150 /* Does the device generate extra interrupts? */ 151 if (status & SiS900_DESCR_OWN) { 152 uint32 descriptor = read32(info->registers + SiS900_MAC_Tx_DESCR); 153 int16 that; 154 for (that = 0; 155 that < NUM_Tx_DESCR 156 && physicalAddress(&info->txDescriptor[that], 157 sizeof(struct buffer_desc)) != descriptor; 158 that++) { 159 } 160 if (that == NUM_Tx_DESCR) 161 that = 0; 162 163//dprintf("tx busy %d: %lx (hardware status %d = %lx)!\n",info->txInterruptIndex,status,that,info->txDescriptor[that].status); 164// if (limit == info->txSent) 165// { 166//dprintf("oh no!\n"); 167// limit++; 168// continue; 169// } 170 break; 171 } 172 173 if (status & (SiS900_DESCR_Tx_ABORT | SiS900_DESCR_Tx_UNDERRUN 174 | SiS900_DESCR_Tx_OOW_COLLISION)) { 175 dprintf("tx error: %" B_PRIx32 "\n", status); 176 } else 177 info->txDescriptor[info->txInterruptIndex].status = 0; 178 179 releaseTxSem++; /* this many buffers are free */ 180 info->txInterruptIndex = (info->txInterruptIndex + 1) & NUM_Tx_MASK; 181 info->txSent--; 182 183 if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR) 184 dprintf("ERROR interrupt: txSent = %d\n", info->txSent); 185 } 186 release_spinlock(&info->txSpinlock); 187 188 if (releaseTxSem) { 189 release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE); 190 return B_INVOKE_SCHEDULER; 191 } 192 193 return B_HANDLED_INTERRUPT; 194} 195 196 197int32 198sis900_interrupt(void *data) 199{ 200 struct sis_info *info = data; 201 int32 handled = B_UNHANDLED_INTERRUPT; 202 int16 worklimit = 20; 203 uint32 intr; 204 cpu_status former; 205 206 former = disable_interrupts(); 207 acquire_spinlock(&info->lock); 208 209 while (worklimit-- > 0) { 210 // reading the interrupt status register clears all interrupts 211 intr = read32(info->registers + SiS900_MAC_INTR_STATUS); 212 if (!intr) 213 break; 214 215 TRACE(("************ interrupt received: %08lx **************\n", intr)); 216 intrCounter = (intrCounter + 1) % 100; 217 lastIntr[intrCounter] = intr; 218 219 // wake-up event interrupt 220 if (intr & SiS900_INTR_WAKEUP_EVENT) { 221 TRACE(("wake-up event received: %ld\n", 222 read32(info->registers + SiS900_MAC_WAKEUP_EVENT))); 223 224 // clear PM event register 225 write32(info->registers + SiS900_MAC_WAKEUP_EVENT, 226 SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS); 227 handled = B_HANDLED_INTERRUPT; 228 } 229 230 // receive packet interrupts 231 if (intr & (/*SiS900_INTR_Rx_STATUS_OVERRUN |*/ SiS900_INTR_Rx_OVERRUN | 232 SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK)) 233 handled = sis900_rxInterrupt(info); 234 235 // transmit packet interrupts 236 if (intr & (SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR | 237 SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK)) 238 handled = sis900_txInterrupt(info); 239 } 240 241 release_spinlock(&info->lock); 242 restore_interrupts(former); 243 244 return handled; 245} 246 247 248void 249sis900_disableInterrupts(struct sis_info *info) 250{ 251 write32(info->registers + SiS900_MAC_INTR_MASK, 0); 252 write32(info->registers + SiS900_MAC_INTR_ENABLE, 0); 253} 254 255 256void 257sis900_enableInterrupts(struct sis_info *info) 258{ 259 write32(info->registers + SiS900_MAC_INTR_ENABLE, 0); 260 261 // enable link detection 262 write32(info->registers + SiS900_MAC_WAKEUP_CONTROL, 263 SiS900_WAKEUP_LINK_ON | SiS900_WAKEUP_LINK_LOSS); 264 265 // set interrupt mask 266 write32(info->registers + SiS900_MAC_INTR_MASK, 267 //SiS900_INTR_WAKEUP_EVENT | 268 SiS900_INTR_Tx_UNDERRUN | SiS900_INTR_Tx_ERROR | SiS900_INTR_Tx_IDLE | SiS900_INTR_Tx_OK | 269 SiS900_INTR_Rx_STATUS_OVERRUN | SiS900_INTR_Rx_OVERRUN | 270 SiS900_INTR_Rx_ERROR | SiS900_INTR_Rx_OK); 271 272 write32(info->registers + SiS900_MAC_INTR_ENABLE,1); 273} 274 275 276/***************************** PHY and link mode *****************************/ 277// #pragma mark - 278 279 280int32 281sis900_timer(timer *t) 282{ 283 struct sis_info *info = (struct sis_info *)t; 284 285 if (!info->autoNegotiationComplete) { 286 int32 mode = sis900_readMode(info); 287 if (mode) 288 sis900_setMode(info, mode); 289 290 return 0; 291 } 292 293 if (info->link) { // link lost 294 uint16 status = mdio_status(info); 295 296 if ((status & MII_STATUS_LINK) == 0) { 297 info->link = false; 298 dprintf(DEVICE_NAME ": link lost\n"); 299 300 // if it's the internal SiS900 MII PHY, reset it 301 if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL 302 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) 303 sis900_resetPHY(info); 304 } 305 } 306 if (!info->link) { // new link established 307 uint16 status; 308 309 sis900_selectPHY(info); 310 311 status = mdio_status(info); 312 if (status & MII_STATUS_LINK) { 313 sis900_checkMode(info); 314 info->link = true; 315 } 316 } 317 318// revision = info->pciInfo->revision; 319// if (!(revision == SiS900_REVISION_SiS630E || revision == SiS900_REVISION_SiS630EA1 320// || revision == SiS900_REVISION_SiS630A || revision == SiS900_REVISION_SiS630ET)) 321// bug(DEVICE_NAME ": set_eq() not needed!\n"); 322// else 323// bug("********* set_eq() would be needed! ********\n"); 324 325 return 0; 326} 327 328 329uint16 330sis900_resetPHY(struct sis_info *info) 331{ 332 uint16 status = mdio_status(info); 333 334 mdio_write(info, MII_CONTROL, MII_CONTROL_RESET); 335 return status; 336} 337 338 339status_t 340sis900_initPHYs(struct sis_info *info) 341{ 342 uint16 phy; 343 344 // search for total of 32 possible MII PHY addresses 345 for (phy = 0; phy < 32; phy++) { 346 struct mii_phy *mii; 347 uint16 status; 348 int32 i; 349 350 status = mdio_statusFromPHY(info, phy); 351 if (status == 0xffff || status == 0x0000) 352 // this MII is not accessable 353 continue; 354 355 mii = (struct mii_phy *)malloc(sizeof(struct mii_phy)); 356 if (mii == NULL) 357 return B_NO_MEMORY; 358 359 mii->address = phy; 360 mii->id0 = mdio_readFromPHY(info, phy, MII_PHY_ID0); 361 mii->id1 = mdio_readFromPHY(info, phy, MII_PHY_ID1); 362 mii->types = MII_HOME; 363 mii->next = info->firstPHY; 364 info->firstPHY = mii; 365 366 for (i = 0; gMIIChips[i].name; i++) { 367 if (gMIIChips[i].id0 != mii->id0 368 || gMIIChips[i].id1 != (mii->id1 & 0xfff0)) 369 continue; 370 371 dprintf("Found MII PHY: %s\n", gMIIChips[i].name); 372 373 mii->types = gMIIChips[i].types; 374 break; 375 } 376 if (gMIIChips[i].name == NULL) 377 dprintf("Unknown MII PHY transceiver: id = (%x, %x).\n", mii->id0, mii->id1); 378 } 379 380 if (info->firstPHY == NULL) { 381 dprintf("No MII PHY transceiver found!\n"); 382 return B_ENTRY_NOT_FOUND; 383 } 384 385 sis900_selectPHY(info); 386 387 // if the internal PHY is selected, reset it 388 if (info->currentPHY->id0 == PHY_ID0_SiS900_INTERNAL 389 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_SiS900_INTERNAL) { 390 if (sis900_resetPHY(info) & MII_STATUS_LINK) { 391 uint16 poll = MII_STATUS_LINK; 392 while (poll) { 393 poll ^= mdio_read(info, MII_STATUS) & poll; 394 } 395 } 396 } 397 398 // workaround for ICS1893 PHY 399 if (info->currentPHY->id0 == PHY_ID0_ICS_1893 400 && (info->currentPHY->id1 & 0xfff0) == PHY_ID1_ICS_1893) 401 mdio_write(info, 0x0018, 0xD200); 402 403 // SiS 630E has some bugs on default value of PHY registers 404 if (info->pciInfo->revision == SiS900_REVISION_SiS630E) { 405 mdio_write(info, MII_AUTONEG_ADV, 0x05e1); 406 mdio_write(info, MII_CONFIG1, 0x22); 407 mdio_write(info, MII_CONFIG2, 0xff00); 408 mdio_write(info, MII_MASK, 0xffc0); 409 } 410 411 info->link = mdio_status(info) & MII_STATUS_LINK; 412 413 return B_OK; 414} 415 416 417void 418sis900_selectPHY(struct sis_info *info) 419{ 420 uint16 status; 421 422 // ToDo: need to be changed, select PHY in relation to the link mode 423 info->currentPHY = info->firstPHY; 424 info->phy = info->currentPHY->address; 425 426 status = mdio_read(info, MII_CONTROL); 427 status &= ~MII_CONTROL_ISOLATE; 428 429 mdio_write(info, MII_CONTROL, status); 430} 431 432 433void 434sis900_setMode(struct sis_info *info, int32 mode) 435{ 436 uint32 address = info->registers + SiS900_MAC_CONFIG; 437 uint32 txFlags = SiS900_Tx_AUTO_PADDING | SiS900_Tx_FILL_THRES; 438 uint32 rxFlags = 0; 439 440 info->speed = mode & LINK_SPEED_MASK; 441 info->full_duplex = (mode & LINK_DUPLEX_MASK) == LINK_FULL_DUPLEX; 442 443 if (read32(address) & SiS900_MAC_CONFIG_EDB_MASTER) { 444 TRACE((DEVICE_NAME ": EDB master is set!\n")); 445 txFlags |= 5 << SiS900_DMA_SHIFT; 446 rxFlags = 5 << SiS900_DMA_SHIFT; 447 } 448 449 // link speed FIFO thresholds 450 451 if (info->speed == LINK_SPEED_HOME || info->speed == LINK_SPEED_10_MBIT) { 452 rxFlags |= SiS900_Rx_10_MBIT_DRAIN_THRES; 453 txFlags |= SiS900_Tx_10_MBIT_DRAIN_THRES; 454 } else { 455 rxFlags |= SiS900_Rx_100_MBIT_DRAIN_THRES; 456 txFlags |= SiS900_Tx_100_MBIT_DRAIN_THRES; 457 } 458 459 // duplex mode 460 461 if (info->full_duplex) { 462 txFlags |= SiS900_Tx_CS_IGNORE | SiS900_Tx_HB_IGNORE; 463 rxFlags |= SiS900_Rx_ACCEPT_Tx_PACKETS; 464 } 465 466 write32(info->registers + SiS900_MAC_Tx_CONFIG, txFlags); 467 write32(info->registers + SiS900_MAC_Rx_CONFIG, rxFlags); 468} 469 470 471int32 472sis900_readMode(struct sis_info *info) 473{ 474 struct mii_phy *phy = info->currentPHY; 475 uint16 autoAdv, autoLinkPartner; 476 int32 speed, duplex; 477 478 uint16 status = mdio_status(info); 479 if (!(status & MII_STATUS_LINK)) { 480 dprintf(DEVICE_NAME ": no link detected (status = %x)\n", status); 481 return 0; 482 } 483 484 // auto negotiation completed 485 autoAdv = mdio_read(info, MII_AUTONEG_ADV); 486 autoLinkPartner = mdio_read(info, MII_AUTONEG_LINK_PARTNER); 487 status = autoAdv & autoLinkPartner; 488 489 speed = status & (MII_NWAY_TX | MII_NWAY_TX_FDX) ? LINK_SPEED_100_MBIT : LINK_SPEED_10_MBIT; 490 duplex = status & (MII_NWAY_TX_FDX | MII_NWAY_T_FDX) ? LINK_FULL_DUPLEX : LINK_HALF_DUPLEX; 491 492 info->autoNegotiationComplete = true; 493 494 // workaround for Realtek RTL8201 PHY issue 495 if (phy->id0 == PHY_ID0_REALTEK_8201 && (phy->id1 & 0xFFF0) == PHY_ID1_REALTEK_8201) { 496 if (mdio_read(info, MII_CONTROL) & MII_CONTROL_FULL_DUPLEX) 497 duplex = LINK_FULL_DUPLEX; 498 if (mdio_read(info, 0x0019) & 0x01) 499 speed = LINK_SPEED_100_MBIT; 500 } 501 502 dprintf(DEVICE_NAME ": linked, 10%s MBit, %s duplex\n", 503 speed == LINK_SPEED_100_MBIT ? "0" : "", 504 duplex == LINK_FULL_DUPLEX ? "full" : "half"); 505 506 return speed | duplex; 507} 508 509 510static void 511sis900_setAutoNegotiationCapabilities(struct sis_info *info) 512{ 513 uint16 status = mdio_status(info); 514 uint16 capabilities = MII_NWAY_CSMA_CD 515 | (status & MII_STATUS_CAN_TX_FDX ? MII_NWAY_TX_FDX : 0) 516 | (status & MII_STATUS_CAN_TX ? MII_NWAY_TX : 0) 517 | (status & MII_STATUS_CAN_T_FDX ? MII_NWAY_T_FDX : 0) 518 | (status & MII_STATUS_CAN_T ? MII_NWAY_T : 0); 519 520 TRACE((DEVICE_NAME ": write capabilities %d\n", capabilities)); 521 mdio_write(info, MII_AUTONEG_ADV, capabilities); 522} 523 524 525static void 526sis900_autoNegotiate(struct sis_info *info) 527{ 528 uint16 status = mdio_status(info); 529 530 if ((status & MII_STATUS_LINK) == 0) 531 { 532 TRACE((DEVICE_NAME ": media link off\n")); 533 info->autoNegotiationComplete = true; 534 return; 535 } 536 TRACE((DEVICE_NAME ": auto negotiation started...\n")); 537 538 // reset auto negotiation 539 mdio_write(info, MII_CONTROL, MII_CONTROL_AUTO | MII_CONTROL_RESET_AUTONEG); 540 info->autoNegotiationComplete = false; 541} 542 543 544void 545sis900_checkMode(struct sis_info *info) 546{ 547 uint32 address = info->registers + SiS900_MAC_CONFIG; 548 549 if (info->fixedMode != 0) { 550 TRACE((DEVICE_NAME ": link mode set via settings\n")); 551 552 // ToDo: what about the excessive deferral timer? 553 554 sis900_setMode(info, info->fixedMode); 555 info->autoNegotiationComplete = true; 556 } else if (info->currentPHY->types == MII_LAN) { 557 TRACE((DEVICE_NAME ": PHY type is LAN\n")); 558 559 // enable excessive deferral timer 560 write32(address, ~SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL & read32(address)); 561 562 sis900_setAutoNegotiationCapabilities(info); 563 sis900_autoNegotiate(info); 564 } else { 565 TRACE((DEVICE_NAME ": PHY type is not LAN\n")); 566 567 // disable excessive deferral timer 568 write32(address, SiS900_MAC_CONFIG_EXCESSIVE_DEFERRAL | read32(address)); 569 570 sis900_setMode(info, LINK_SPEED_HOME | LINK_HALF_DUPLEX); 571 info->autoNegotiationComplete = true; 572 } 573} 574 575 576/***************************** MACs, rings & config *****************************/ 577// #pragma mark - 578 579 580bool 581sis900_getMACAddress(struct sis_info *info) 582{ 583 if (info->pciInfo->revision >= SiS900_REVISION_SiS96x) { 584 // SiS 962 & 963 are using a different method to access the EEPROM 585 // than the standard SiS 630 586 addr_t eepromAccess = info->registers + SiS900_MAC_EEPROM_ACCESS; 587 uint32 tries = 0; 588 589 write32(eepromAccess, SiS96x_EEPROM_CMD_REQ); 590 591 while (tries < 1000) { 592 if (read32(eepromAccess) & SiS96x_EEPROM_CMD_GRANT) { 593 int i; 594 595 /* get MAC address from EEPROM */ 596 for (i = 0; i < 3; i++) { 597 uint16 id; 598 599 id = eeprom_read(info, SiS900_EEPROM_MAC_ADDRESS + i); 600 info->address.ebyte[i*2 + 1] = id >> 8; 601 info->address.ebyte[i*2] = id & 0xff; 602 } 603 604 write32(eepromAccess, SiS96x_EEPROM_CMD_DONE); 605 return true; 606 } else { 607 spin(2); 608 tries++; 609 } 610 } 611 write32(eepromAccess, SiS96x_EEPROM_CMD_DONE); 612 return false; 613 } else if (info->pciInfo->revision >= SiS900_REVISION_SiS630E) { 614 /* SiS630E and above are using CMOS RAM to store MAC address */ 615 pci_info isa; 616 int32 index; 617 618 for (index = 0; pci->get_nth_pci_info(index, &isa) == B_OK; index++) { 619 if (isa.vendor_id == VENDOR_ID_SiS 620 && isa.device_id == DEVICE_ID_SiS_ISA_BRIDGE) { 621 uint8 reg,i; 622 addr_t registers = isa.u.h0.base_registers[0]; 623 624 reg = pci->read_pci_config(isa.bus,isa.device,isa.function,0x48,1); 625 pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg | 0x40); 626 627 for (i = 0; i < 6; i++) { 628 write8(registers + 0x70,0x09 + i); 629 info->address.ebyte[i] = read8(registers + 0x71); 630 } 631 632 pci->write_pci_config(isa.bus,isa.device,isa.function,0x48,1,reg & ~0x40); 633 return true; 634 } 635 } 636 return false; 637 } else { 638 /* SiS630 stores the MAC in an eeprom */ 639 uint16 signature; 640 int i; 641 642 /* check to see if we have sane EEPROM */ 643 signature = eeprom_read(info,SiS900_EEPROM_SIGNATURE); 644 if (signature == 0xffff || signature == 0x0000) { 645 dprintf(DEVICE_NAME ": cannot read EEPROM signature\n"); 646 return false; 647 } 648 649 /* get MAC address from EEPROM */ 650 for (i = 0; i < 3; i++) { 651 uint16 id; 652 653 id = eeprom_read(info,SiS900_EEPROM_MAC_ADDRESS + i); 654 info->address.ebyte[i*2 + 1] = id >> 8; 655 info->address.ebyte[i*2] = id & 0xff; 656 } 657 658 return true; 659 } 660 return false; 661} 662 663 664status_t 665sis900_reset(struct sis_info *info) 666{ 667 addr_t address = info->registers + SiS900_MAC_COMMAND; 668 int16 tries = 1000; 669 670 TRACE(("sis900 reset\n")); 671 672 write32(address, SiS900_MAC_CMD_RESET); 673 674 write32(info->registers + SiS900_MAC_Rx_FILTER_CONTROL, SiS900_RxF_ENABLE | 675 SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST); 676 677 // wait until the chip leaves reset state 678 while ((read32(address) & SiS900_MAC_CMD_RESET) && tries-- > 0) 679 snooze(2); 680 681 write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE); 682 683 return B_OK; 684} 685 686 687void 688sis900_setPromiscuous(struct sis_info *info, bool on) 689{ 690 addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL; 691 int32 filter = read32(filterControl); 692 693 // accept all incoming packets (or not) 694 if (on) { 695 write32(filterControl, SiS900_RxF_ENABLE | 696 SiS900_RxF_ACCEPT_ALL_BROADCAST | SiS900_RxF_ACCEPT_ALL_MULTICAST); 697 } else 698 write32(filterControl, filter | ~SiS900_RxF_ACCEPT_ALL_ADDRESSES); 699} 700 701 702void 703sis900_setRxFilter(struct sis_info *info) 704{ 705 addr_t filterControl = info->registers + SiS900_MAC_Rx_FILTER_CONTROL; 706 addr_t filterData = info->registers + SiS900_MAC_Rx_FILTER_DATA; 707 int32 i; 708 709 // set MAC address as receive filter 710 for (i = 0; i < 3; i++) { 711 write32(filterControl, i << SiS900_Rx_FILTER_ADDRESS_SHIFT); 712 write32(filterData, info->address.ebyte[i*2] | (info->address.ebyte[i*2 + 1] << 8)); 713 } 714 write32(filterControl, SiS900_RxF_ENABLE 715 | SiS900_RxF_ACCEPT_ALL_BROADCAST 716 | SiS900_RxF_ACCEPT_ALL_MULTICAST /*| SiS900_RxF_ACCEPT_ALL_ADDRESSES*/); 717} 718 719 720void 721sis900_deleteRings(struct sis_info *info) 722{ 723 delete_area(info->txArea); 724 delete_area(info->rxArea); 725} 726 727 728status_t 729sis900_createRings(struct sis_info *info) 730{ 731 uint16 i; 732 733 // create transmit buffer area 734 info->txArea = create_area("sis900 tx buffer", (void **)&info->txBuffer[0], 735 B_ANY_KERNEL_ADDRESS, 736 ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Tx_DESCR), 737 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 738 if (info->txArea < B_OK) 739 return info->txArea; 740 741 // initialize transmit buffer descriptors 742 for (i = 1; i < NUM_Tx_DESCR; i++) 743 info->txBuffer[i] = (void *)(((addr_t)info->txBuffer[0]) + (i * BUFFER_SIZE)); 744 745 for (i = 0; i < NUM_Tx_DESCR; i++) { 746 info->txDescriptor[i].status = 0; 747 info->txDescriptor[i].buffer = physicalAddress(info->txBuffer[i], BUFFER_SIZE); 748 info->txDescriptor[i].link = 749#if (NUM_Tx_DESCR == 1) 750 0; 751#else 752 physicalAddress(&info->txDescriptor[(i + 1) & NUM_Tx_MASK], sizeof(struct buffer_desc)); 753#endif 754 } 755 756 // create receive buffer area 757 info->rxArea = create_area("sis900 rx buffer", (void **)&info->rxBuffer[0], 758 B_ANY_KERNEL_ADDRESS, 759 ROUND_TO_PAGE_SIZE(BUFFER_SIZE * NUM_Rx_DESCR), 760 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA); 761 if (info->rxArea < B_OK) { 762 delete_area(info->txArea); 763 return info->rxArea; 764 } 765 766 // initialize receive buffer descriptors 767 for (i = 1; i < NUM_Rx_DESCR; i++) 768 info->rxBuffer[i] = (void *)(((addr_t)info->rxBuffer[0]) + (i * BUFFER_SIZE)); 769 770 for (i = 0; i < NUM_Rx_DESCR; i++) { 771 info->rxDescriptor[i].status = MAX_FRAME_SIZE; 772 info->rxDescriptor[i].buffer = physicalAddress(info->rxBuffer[i], BUFFER_SIZE); 773 info->rxDescriptor[i].link = physicalAddress(&info->rxDescriptor[(i + 1) & NUM_Rx_MASK], 774 sizeof(struct buffer_desc)); 775 } 776 info->rxFree = NUM_Rx_DESCR; 777 778 // set descriptor pointer registers 779 write32(info->registers + SiS900_MAC_Tx_DESCR, 780 physicalAddress(&info->txDescriptor[0], sizeof(struct buffer_desc))); 781 write32(info->registers + SiS900_MAC_Rx_DESCR, 782 physicalAddress(&info->rxDescriptor[0], sizeof(struct buffer_desc))); 783 784 return B_OK; 785} 786 787