|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1998-1999 by Apple Computer, Inc., All rights reserved. ! 24: * ! 25: * Hardware independent (relatively) code for the BMac Ethernet Controller ! 26: * ! 27: * HISTORY ! 28: * ! 29: * dd-mmm-yy ! 30: * Created. ! 31: * ! 32: * Dec 10, 1998 jliu ! 33: * Converted to IOKit/C++. ! 34: */ ! 35: ! 36: #include "BMacEnet.h" ! 37: #include "BMacEnetPrivate.h" ! 38: ! 39: #include <IOKit/IORegistryEntry.h> ! 40: #include <IOKit/IODeviceTreeSupport.h> ! 41: #include <IOKit/platform/AppleMacIODevice.h> ! 42: #include <IOKit/assert.h> ! 43: ! 44: // #define DEBUG_JOE 1 ! 45: ! 46: //------------------------------------------------------------------------ ! 47: ! 48: #define super IOEthernetController ! 49: ! 50: OSDefineMetaClassAndStructors( BMacEnet, IOEthernetController ) ! 51: ! 52: //------------------------------------------------------------------------ ! 53: ! 54: #define PROVIDER_DEV 0 ! 55: #define PROVIDER_DMA_TX 1 ! 56: #define PROVIDER_DMA_RX 2 ! 57: ! 58: /* ! 59: * Public Instance Methods ! 60: */ ! 61: ! 62: /*------------------------------------------------------------------------- ! 63: * ! 64: * ! 65: * ! 66: *-------------------------------------------------------------------------*/ ! 67: ! 68: bool BMacEnet::init(OSDictionary * properties = 0) ! 69: { ! 70: /* ! 71: * Initialize my ivars. ! 72: */ ! 73: networkInterface = 0; ! 74: transmitQueue = 0; ! 75: debugQueue = 0; ! 76: debugger = 0; ! 77: rxIntSrc = 0; ! 78: txDebuggerPkt = 0; ! 79: phyId = 0xff; ! 80: phyMIIDelay = MII_DEFAULT_DELAY; ! 81: sromAddressBits = 6; ! 82: enetAddressOffset = 20; ! 83: phyStatusPrev = 0; ! 84: ready = false; ! 85: debugClient = false; ! 86: debugTxPoll = false; ! 87: netifClient = false; ! 88: isPromiscuous = false; ! 89: multicastEnabled = false; ! 90: ! 91: if (!super::init(properties)) ! 92: return false; ! 93: ! 94: /* ! 95: * Clear the mbuf rings. ! 96: */ ! 97: for (int i = 0; i < TX_RING_LENGTH; i++) ! 98: txMbuf[i] = 0; ! 99: for (int i = 0; i < RX_RING_LENGTH; i++) ! 100: rxMbuf[i] = 0; ! 101: ! 102: /* ! 103: * Clear the memory map objects. ! 104: */ ! 105: for (int i = 0; i < MEMORY_MAP_COUNT; i++) ! 106: maps[i] = 0; ! 107: ! 108: return true; ! 109: } ! 110: ! 111: bool BMacEnet::start(IOService * provider) ! 112: { ! 113: AppleMacIODevice *nub = OSDynamicCast(AppleMacIODevice, provider); ! 114: IOInterruptEventSource *intES; ! 115: ! 116: if (!nub || !super::start(provider)) ! 117: return false; ! 118: ! 119: transmitQueue = OSDynamicCast(IOOQGateFIFOQueue, getOutputQueue()); ! 120: if (!transmitQueue) { ! 121: IOLog("BMac: output queue initialization failed\n"); ! 122: return false; ! 123: } ! 124: transmitQueue->retain(); ! 125: ! 126: // Allocate debug queue. This stores packets retired from the TX ring ! 127: // by the polling routine. We cannot call freePacket() or m_free() within ! 128: // the debugger context. ! 129: // ! 130: // The capacity of the queue is set at maximum to prevent the queue from ! 131: // calling m_free() due to over-capacity. But we don't expect the size ! 132: // of the queue to grow too large. ! 133: // ! 134: debugQueue = IOPacketQueue::withCapacity((UInt) -1); ! 135: if (!debugQueue) ! 136: return false; ! 137: ! 138: // Allocate a IOMBufDBDMAMemoryCursor instance. Currently, the maximum ! 139: // number of segments is set to 2. The maximum length for each segment ! 140: // is set to the maximum ethernet frame size (plus padding). ! 141: ! 142: mbufCursor = IOMBufBigMemoryCursor::withSpecification(NETWORK_BUFSIZE, 2); ! 143: if (!mbufCursor) { ! 144: IOLog("Ethernet(BMac): IOMBufDBDMAMemoryCursor allocation failure\n"); ! 145: return false; ! 146: } ! 147: ! 148: // ! 149: // Our provider is the nub representing the BMacEnet hardware ! 150: // controller. We will query it for our resource information. ! 151: // ! 152: ! 153: for (int i = 0; i < MEMORY_MAP_HEATHROW_INDEX; i++) { ! 154: IOMemoryMap * map; ! 155: ! 156: map = provider->mapDeviceMemoryWithIndex(i); ! 157: if (!map) ! 158: return false; ! 159: #ifdef DEBUG_JOE ! 160: IOLog("map %d: Phys:%08x Virt:%08x len:%d\n", ! 161: i, ! 162: (unsigned) map->getPhysicalAddress(), ! 163: (unsigned) map->getVirtualAddress(), ! 164: (unsigned) map->getLength()); ! 165: #endif DEBUG_JOE ! 166: ! 167: switch (i) { ! 168: case MEMORY_MAP_ENET_INDEX: ! 169: ioBaseEnet = (IOPPCAddress) map->getVirtualAddress(); ! 170: break; ! 171: ! 172: case MEMORY_MAP_TXDMA_INDEX: ! 173: ioBaseEnetTxDMA = (IODBDMAChannelRegisters *) ! 174: map->getVirtualAddress(); ! 175: break; ! 176: ! 177: case MEMORY_MAP_RXDMA_INDEX: ! 178: ioBaseEnetRxDMA = (IODBDMAChannelRegisters *) ! 179: map->getVirtualAddress(); ! 180: break; ! 181: } ! 182: ! 183: maps[i] = map; ! 184: } ! 185: ! 186: #ifdef DEBUG_JOE ! 187: IOLog("ioBaseEnet: 0x%08x\n", ioBaseEnet); ! 188: IOLog("ioBaseEnetTxDMA: 0x%08x\n", ioBaseEnetTxDMA); ! 189: IOLog("ioBaseEnetRxDMA: 0x%08x\n", ioBaseEnetRxDMA); ! 190: #endif DEBUG_JOE ! 191: ! 192: // ! 193: // We need to get the I/O address for the Heathrow controller. ! 194: // We ask the provider (bmac) for its device tree parent. ! 195: // ! 196: IOService *heathrow; ! 197: if (!(heathrow = OSDynamicCast(IOService, ! 198: provider->getParentEntry( gIODTPlane )))) ! 199: return false; ! 200: ! 201: // Check whether the hardware is susceptible to the broken unicast ! 202: // filter problem. ! 203: // ! 204: OSData * devIDData; ! 205: devIDData = OSDynamicCast(OSData, heathrow->getProperty("device-id")); ! 206: ! 207: if (devIDData) { ! 208: useUnicastFilter = ( *((UInt32 *) devIDData->getBytesNoCopy()) == ! 209: 0x10 ); ! 210: if (useUnicastFilter) ! 211: IOLog("%s: Enabling workaround for broken unicast filter\n", ! 212: getName()); ! 213: } ! 214: ! 215: IOMemoryMap * map = heathrow->mapDeviceMemoryWithIndex(0); ! 216: if (map) ! 217: { ! 218: #ifdef DEBUG_JOE ! 219: IOLog("Heathrow: Phys:%08x Virt:%08x len:%d\n", ! 220: (unsigned) map->getPhysicalAddress(), ! 221: (unsigned) map->getVirtualAddress(), ! 222: (unsigned) map->getLength()); ! 223: #endif DEBUG_JOE ! 224: ioBaseHeathrow = (IOPPCAddress) map->getVirtualAddress(); ! 225: ! 226: maps[MEMORY_MAP_HEATHROW_INDEX] = map; ! 227: } ! 228: else { ! 229: return false; ! 230: } ! 231: ! 232: // ! 233: // Get a reference to the IOWorkLoop in our superclass. ! 234: // ! 235: IOWorkLoop * myWorkLoop = getWorkLoop(); ! 236: assert(myWorkLoop); ! 237: ! 238: // ! 239: // Allocate three IOInterruptEventSources. ! 240: // ! 241: rxIntSrc = IOInterruptEventSource::interruptEventSource ! 242: (this, ! 243: (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource, ! 244: provider, PROVIDER_DMA_RX); ! 245: if (!rxIntSrc ! 246: || (myWorkLoop->addEventSource(rxIntSrc) != kIOReturnSuccess)) { ! 247: IOLog("Ethernet(BMac): rxIntSrc init failure\n"); ! 248: return false; ! 249: } ! 250: ! 251: intES = IOInterruptEventSource::interruptEventSource ! 252: (this, ! 253: (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource, ! 254: provider, PROVIDER_DMA_TX); ! 255: if (intES) { ! 256: bool res = (myWorkLoop->addEventSource(intES) != kIOReturnSuccess); ! 257: intES->release(); ! 258: if (res) { ! 259: IOLog("Ethernet(BMac): PROVIDER_DMA_TX add failure\n"); ! 260: return false; ! 261: } ! 262: } ! 263: else { ! 264: IOLog("Mace: PROVIDER_DMA_TX init failure\n"); ! 265: return false; ! 266: } ! 267: ! 268: intES = IOInterruptEventSource::interruptEventSource ! 269: (this, ! 270: (IOInterruptEventAction) &BMacEnet::interruptOccurredForSource, ! 271: provider, PROVIDER_DEV); ! 272: if (intES) { ! 273: bool res = (myWorkLoop->addEventSource(intES) != kIOReturnSuccess); ! 274: intES->release(); ! 275: if (res) { ! 276: IOLog("Ethernet(BMac): PROVIDER_DEV add failure\n"); ! 277: return false; ! 278: } ! 279: } ! 280: else { ! 281: IOLog("Ethernet(BMac): PROVIDER_DEV init failure\n"); ! 282: return false; ! 283: } ! 284: ! 285: timerSrc = IOTimerEventSource::timerEventSource ! 286: (this, (IOTimerEventSource::Action) &BMacEnet::timeoutOccurred); ! 287: if (!timerSrc ! 288: || (myWorkLoop->addEventSource(timerSrc) != kIOReturnSuccess)) { ! 289: IOLog("Ethernet(BMac): timerSrc init failure\n"); ! 290: return false; ! 291: } ! 292: ! 293: MGETHDR(txDebuggerPkt, M_DONTWAIT, MT_DATA); ! 294: if (!txDebuggerPkt) { ! 295: IOLog("Ethernet(BMac): Couldn't allocate KDB buffer\n"); ! 296: return false; ! 297: } ! 298: ! 299: #if 0 ! 300: // Enable the interrupt event sources. The hardware interrupts ! 301: // sources remain disabled until _resetAndEnable(true) is called. ! 302: // ! 303: // myWorkLoop->enableAllInterrupts(); ! 304: #endif ! 305: ! 306: // ! 307: // Perform a hardware reset. ! 308: // ! 309: if ( !_resetAndEnable(false) ) ! 310: { ! 311: return false; ! 312: } ! 313: ! 314: // ! 315: // Cache my MAC address. ! 316: // ! 317: getHardwareAddress(&myAddress); ! 318: ! 319: // ! 320: // Allocate memory for ring buffers. ! 321: // ! 322: if (_allocateMemory() == false) ! 323: { ! 324: return false; ! 325: } ! 326: ! 327: // ! 328: // Attach a kernel debugger client. ! 329: // ! 330: attachDebuggerClient(&debugger); ! 331: ! 332: // ! 333: // Attach an IOEthernetInterface client. ! 334: // ! 335: if (!attachNetworkInterface((IONetworkInterface **) &networkInterface)) ! 336: return false; ! 337: ! 338: return true; ! 339: } ! 340: ! 341: /*------------------------------------------------------------------------- ! 342: * ! 343: * ! 344: * ! 345: *-------------------------------------------------------------------------*/ ! 346: ! 347: void BMacEnet::free() ! 348: { ! 349: UInt i; ! 350: ! 351: _resetAndEnable(false); ! 352: ! 353: if (debugger) ! 354: debugger->release(); ! 355: ! 356: if (getWorkLoop()) ! 357: getWorkLoop()->disableAllEventSources(); ! 358: ! 359: if (timerSrc) ! 360: timerSrc->release(); ! 361: ! 362: if (rxIntSrc) ! 363: rxIntSrc->release(); ! 364: ! 365: if (txDebuggerPkt) ! 366: freePacket(txDebuggerPkt); ! 367: ! 368: if (transmitQueue) ! 369: transmitQueue->release(); ! 370: ! 371: if (debugQueue) ! 372: debugQueue->release(); ! 373: ! 374: if (networkInterface) ! 375: networkInterface->release(); ! 376: ! 377: if (mbufCursor) ! 378: mbufCursor->release(); ! 379: ! 380: for (i = 0; i < rxMaxCommand; i++) ! 381: if (rxMbuf[i]) freePacket(rxMbuf[i]); ! 382: ! 383: for (i = 0; i < txMaxCommand; i++) ! 384: if (txMbuf[i]) freePacket(txMbuf[i]); ! 385: ! 386: for (i = 0; i < MEMORY_MAP_COUNT; i++) ! 387: if (maps[i]) maps[i]->release(); ! 388: ! 389: if (dmaMemory.ptr) ! 390: { ! 391: IOFree(dmaMemory.ptrReal, dmaMemory.sizeReal); ! 392: dmaMemory.ptr = 0; ! 393: } ! 394: ! 395: super::free(); ! 396: } ! 397: ! 398: /*------------------------------------------------------------------------- ! 399: * ! 400: * ! 401: * ! 402: *-------------------------------------------------------------------------*/ ! 403: ! 404: void BMacEnet::interruptOccurredForSource(IOInterruptEventSource *src, ! 405: int /*count*/) ! 406: { ! 407: bool doFlushQueue = false; ! 408: bool doService = false; ! 409: ! 410: reserveDebuggerLock(); ! 411: ! 412: statReg = ReadBigMacRegister( ioBaseEnet, kSTAT ); ! 413: ! 414: if (src == rxIntSrc) { ! 415: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 ); ! 416: doFlushQueue = _receiveInterruptOccurred(); ! 417: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 ); ! 418: } ! 419: else { ! 420: /* ! 421: * On the transmit side, we use the chipset interrupt. Using the ! 422: * transmit DMA interrupt (or having multiple transmit DMA entries) ! 423: * would allows us to send the next frame to the chipset prior the ! 424: * transmit fifo going empty. ! 425: * However, this aggrevates a BMac chipset bug where the next frame going ! 426: * out gets corrupted (first two bytes lost) if the chipset had to retry ! 427: * the previous frame. ! 428: */ ! 429: txWDInterrupts++; ! 430: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 ); ! 431: doService = _transmitInterruptOccurred(); ! 432: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 ); ! 433: } ! 434: ! 435: releaseDebuggerLock(); ! 436: ! 437: /* ! 438: * Submit all received packets queued up by _receiveInterruptOccurred() ! 439: * to the network stack. The up call is performed without holding the ! 440: * debugger lock. ! 441: */ ! 442: if (doFlushQueue) ! 443: networkInterface->flushInputQueue(); ! 444: ! 445: /* ! 446: * Unstall the output queue if some space was made available. ! 447: */ ! 448: if (doService && netifClient) ! 449: transmitQueue->service(); ! 450: } ! 451: ! 452: /*------------------------------------------------------------------------- ! 453: * ! 454: * ! 455: * ! 456: *-------------------------------------------------------------------------*/ ! 457: ! 458: UInt32 BMacEnet::outputPacket(struct mbuf * pkt) ! 459: { ! 460: u_int32_t i; ! 461: UInt32 ret = kIOOQReturnSuccess; ! 462: ! 463: KERNEL_DEBUG(DBG_BMAC_TXQUEUE | DBG_FUNC_NONE, (int) pkt, ! 464: (int) pkt->m_pkthdr.len, 0, 0, 0 ); ! 465: ! 466: /* ! 467: * Hold the debugger lock so the debugger can't interrupt us ! 468: */ ! 469: reserveDebuggerLock(); ! 470: ! 471: do ! 472: { ! 473: /* ! 474: * Preliminary sanity checks ! 475: */ ! 476: assert(pkt && netifClient); ! 477: ! 478: #if 0 ! 479: /* ! 480: * Remove any completed packets from the Tx ring ! 481: */ ! 482: if ( chipId >= kCHIPID_PaddingtonXmitStreaming ) ! 483: { ! 484: _transmitInterruptOccurred(); ! 485: } ! 486: #endif ! 487: ! 488: i = txCommandTail + 1; ! 489: if ( i >= txMaxCommand ) i = 0; ! 490: if ( i == txCommandHead ) ! 491: { ! 492: /* ! 493: * Ring buffer is full. Disable the dequeueing process. ! 494: * We reenable it when an entry is made available by the ! 495: * transmit interrupt handler, or if a timeout occurs. ! 496: */ ! 497: ret = kIOOQReturnStall; ! 498: continue; ! 499: } ! 500: ! 501: /* ! 502: * If there is space on the Tx ring, add the packet directly to the ! 503: * ring. ! 504: */ ! 505: _transmitPacket(pkt); ! 506: } ! 507: while ( 0 ); ! 508: ! 509: releaseDebuggerLock(); ! 510: ! 511: return ret; ! 512: } ! 513: ! 514: /*------------------------------------------------------------------------- ! 515: * ! 516: * ! 517: * ! 518: *-------------------------------------------------------------------------*/ ! 519: ! 520: bool BMacEnet::_resetAndEnable(bool enable) ! 521: { ! 522: bool ret = true; ! 523: ! 524: // reserveDebuggerLock(); ! 525: ! 526: ready = false; ! 527: ! 528: if (timerSrc) timerSrc->cancelTimeout(); ! 529: ! 530: _disableAdapterInterrupts(); ! 531: if (getWorkLoop()) getWorkLoop()->disableAllInterrupts(); ! 532: ! 533: _resetChip(); ! 534: ! 535: while (enable) ! 536: { ! 537: if (!_initRxRing() || !_initTxRing()) ! 538: { ! 539: ret = false; ! 540: break; ! 541: } ! 542: ! 543: if ( phyId != 0xff ) ! 544: { ! 545: miiInitializePHY(phyId); ! 546: } ! 547: ! 548: if (_initChip() == false) ! 549: { ! 550: ret = false; ! 551: break; ! 552: } ! 553: ! 554: _startChip(); ! 555: ! 556: timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS); ! 557: ! 558: if (getWorkLoop()) getWorkLoop()->enableAllInterrupts(); ! 559: _enableAdapterInterrupts(); ! 560: ! 561: ready = true; ! 562: ! 563: _sendDummyPacket(); ! 564: ! 565: break; ! 566: } ! 567: ! 568: // releaseDebuggerLock(); ! 569: ! 570: return ret; ! 571: } ! 572: ! 573: /*------------------------------------------------------------------------- ! 574: * Called by IOEthernetInterface client to enable the controller. ! 575: * This method is always called while running on the default workloop ! 576: * thread. ! 577: *-------------------------------------------------------------------------*/ ! 578: ! 579: IOReturn BMacEnet::enable(IONetworkInterface * netif) ! 580: { ! 581: IONetworkParameter * param; ! 582: ! 583: // If an interface client has previously enabled us, ! 584: // and we know there can only be one interface client ! 585: // for this driver, then simply return true. ! 586: // ! 587: if (netifClient) { ! 588: IOLog("EtherNet(BMac): already enabled\n"); ! 589: return kIOReturnSuccess; ! 590: } ! 591: ! 592: // Grab a pointer to the statistics structure in the interface. ! 593: // ! 594: param = netif->getParameter(kIONetworkStatsKey); ! 595: if (!param || !(netStats = (IONetworkStats *) param->getBuffer())) ! 596: { ! 597: IOLog("EtherNet(BMac): invalid network statistics\n"); ! 598: return kIOReturnError; ! 599: } ! 600: ! 601: if ((ready == false) && !_resetAndEnable(true)) ! 602: return kIOReturnIOError; ! 603: ! 604: // Record the interface as an active client. ! 605: // ! 606: netifClient = true; ! 607: ! 608: // Start our IOOutputQueue object. ! 609: // ! 610: transmitQueue->setCapacity(TRANSMIT_QUEUE_SIZE); ! 611: transmitQueue->start(); ! 612: ! 613: return kIOReturnSuccess; ! 614: } ! 615: ! 616: /*------------------------------------------------------------------------- ! 617: * Called by IOEthernetInterface client to disable the controller. ! 618: * This method is always called while running on the default workloop ! 619: * thread. ! 620: *-------------------------------------------------------------------------*/ ! 621: ! 622: IOReturn BMacEnet::disable(IONetworkInterface * /*netif*/) ! 623: { ! 624: // If we have no active clients, then disable the controller. ! 625: // ! 626: if (debugClient == false) ! 627: _resetAndEnable(false); ! 628: ! 629: // Disable our IOOutputQueue object. This will prevent the ! 630: // outputPacket() method from being called. ! 631: // ! 632: transmitQueue->stop(); ! 633: ! 634: // Flush all packets currently in the output queue. ! 635: // ! 636: transmitQueue->setCapacity(0); ! 637: transmitQueue->flush(); ! 638: ! 639: netifClient = false; ! 640: ! 641: return kIOReturnSuccess; ! 642: } ! 643: ! 644: /*------------------------------------------------------------------------- ! 645: * This method is called by our debugger client to bring up the controller ! 646: * just before the controller is registered as the debugger device. The ! 647: * debugger client is attached in response to the attachDebuggerClient() ! 648: * call. ! 649: * ! 650: * This method is always called while running on the default workloop ! 651: * thread. ! 652: *-------------------------------------------------------------------------*/ ! 653: ! 654: IOReturn BMacEnet::handleDebuggerOpen(IOKernelDebugger * /*debugger*/) ! 655: { ! 656: // Enable hardware and make it ready to support the debugger client. ! 657: // ! 658: if ((ready == false) && !_resetAndEnable(true)) ! 659: return kIOReturnIOError; ! 660: ! 661: // Record the debugger as an active client of ours. ! 662: // ! 663: debugClient = true; ! 664: ! 665: // Returning true will allow the kdp registration to continue. ! 666: // If we return false, then we will not be registered as the ! 667: // debugger device, and the attachDebuggerClient() call will ! 668: // return NULL. ! 669: // ! 670: return kIOReturnSuccess; ! 671: } ! 672: ! 673: /*------------------------------------------------------------------------- ! 674: * This method is called by our debugger client to stop the controller. ! 675: * The debugger will call this method when we issue a detachDebuggerClient(). ! 676: * ! 677: * This method is always called while running on the default workloop ! 678: * thread. ! 679: *-------------------------------------------------------------------------*/ ! 680: ! 681: IOReturn BMacEnet::handleDebuggerClose(IOKernelDebugger * /*debugger*/) ! 682: { ! 683: debugClient = false; ! 684: ! 685: // If we have no active clients, then disable the controller. ! 686: // ! 687: if (netifClient == false) ! 688: _resetAndEnable(false); ! 689: ! 690: return kIOReturnSuccess; ! 691: } ! 692: ! 693: /*------------------------------------------------------------------------- ! 694: * ! 695: * ! 696: * ! 697: *-------------------------------------------------------------------------*/ ! 698: ! 699: void BMacEnet::timeoutOccurred(IOTimerEventSource * /*timer*/) ! 700: { ! 701: u_int32_t dmaStatus; ! 702: u_int16_t phyStatus; ! 703: u_int16_t linkStatus; ! 704: u_int16_t phyStatusChange; ! 705: bool fullDuplex = false; ! 706: bool doFlushQueue = false; ! 707: bool doService = false; ! 708: ! 709: // IOLog("Ethernet(BMac): watchdog timer\n"); ! 710: ! 711: reserveDebuggerLock(); ! 712: ! 713: /* ! 714: * Check for DMA shutdown on receive channel ! 715: */ ! 716: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); ! 717: if ( !(dmaStatus & kdbdmaActive) ) ! 718: { ! 719: #if 0 ! 720: IOLog( "Ethernet(BMac): Timeout check - RxHead = %d RxTail = %d\n", ! 721: rxCommandHead, rxCommandTail); ! 722: ! 723: IOLog( "Ethernet(BMac): Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys, IOGetDBDMACommandPtr(ioBaseEnetRxDMA) ); ! 724: [self _dumpDesc:(void *)rxDMACommands Size:rxMaxCommand * sizeof(enet_dma_cmd_t)]; ! 725: #endif ! 726: ! 727: doFlushQueue = _receiveInterruptOccurred(); ! 728: } ! 729: ! 730: /* ! 731: * If there are pending entries on the Tx ring ! 732: */ ! 733: if ( txCommandHead != txCommandTail ) ! 734: { ! 735: /* ! 736: * If we did not service the Tx ring during the last timeout interval, ! 737: * then force servicing of the Tx ring ! 738: */ ! 739: if ( txWDInterrupts == 0 ) ! 740: { ! 741: if ( txWDCount++ > 0 ) ! 742: { ! 743: if (_transmitInterruptOccurred() == false) ! 744: { ! 745: #if 0 ! 746: IOLog( "Ethernet(BMac): Timeout check - TxHead = %d TxTail = %d\n", ! 747: txCommandHead, txCommandTail); ! 748: #endif ! 749: _restartTransmitter(); ! 750: } ! 751: doService = true; ! 752: } ! 753: } ! 754: else ! 755: { ! 756: txWDInterrupts = 0; ! 757: txWDCount = 0; ! 758: } ! 759: } ! 760: else ! 761: { ! 762: txWDInterrupts = 0; ! 763: txWDCount = 0; ! 764: } ! 765: ! 766: if ( phyId != 0xff ) ! 767: { ! 768: if ( miiReadWord(&phyStatus, MII_STATUS, phyId) == true ) ! 769: { ! 770: phyStatusChange = (phyStatusPrev ^ phyStatus) & ! 771: (MII_STATUS_LINK_STATUS | MII_STATUS_NEGOTIATION_COMPLETE); ! 772: if ( phyStatusChange ) ! 773: { ! 774: if ( (phyStatus & MII_STATUS_LINK_STATUS) && ! 775: (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE ) ) ! 776: { ! 777: if ( (phyType & MII_ST10040_MASK) == MII_ST10040_ID ) ! 778: { ! 779: miiReadWord(&linkStatus, MII_ST10040_CHIPST, phyId); ! 780: ! 781: fullDuplex = (linkStatus & MII_ST10040_CHIPST_DUPLEX) ? true : false; ! 782: ! 783: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r", ! 784: (linkStatus & MII_ST10040_CHIPST_SPEED) ? "100" : "10", ! 785: (fullDuplex) ? "Full" : "Half" ); ! 786: } ! 787: else if ( (phyType & MII_DP83843_MASK) == MII_DP83843_ID ) ! 788: { ! 789: miiReadWord(&linkStatus, MII_DP83843_PHYSTS, phyId); ! 790: ! 791: fullDuplex = (linkStatus & MII_DP83843_PHYSTS_DUPLEX) ? true : false; ! 792: ! 793: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r", ! 794: (linkStatus & MII_DP83843_PHYSTS_SPEED10) ? "10" : "100", ! 795: (fullDuplex) ? "Full" : "Half" ); ! 796: } ! 797: else ! 798: { ! 799: fullDuplex = false ; ! 800: IOLog( "Ethernet(BMac): Link is up\n\r" ); ! 801: } ! 802: ! 803: if ( fullDuplex != isFullDuplex ) ! 804: { ! 805: _setDuplexMode(fullDuplex); ! 806: } ! 807: } ! 808: else ! 809: { ! 810: IOLog( "Ethernet(BMac): Link is down.\n\r" ); ! 811: } ! 812: phyStatusPrev = phyStatus; ! 813: } ! 814: } ! 815: } ! 816: ! 817: // Clean-up after the debugger if the debugger was active. ! 818: // ! 819: if (debugTxPoll) ! 820: { ! 821: debugQueue->flush(); ! 822: debugTxPoll = false; ! 823: releaseDebuggerLock(); ! 824: doService = true; ! 825: } ! 826: else ! 827: { ! 828: releaseDebuggerLock(); ! 829: } ! 830: ! 831: /* ! 832: * Submit all received packets queued up by _receiveInterruptOccurred() ! 833: * to the network stack. The up call is performed without holding the ! 834: * debugger lock. ! 835: */ ! 836: if (doFlushQueue) ! 837: { ! 838: networkInterface->flushInputQueue(); ! 839: } ! 840: ! 841: /* ! 842: * Make sure the output queue is not stalled. ! 843: */ ! 844: if (doService && netifClient) ! 845: { ! 846: transmitQueue->service(); ! 847: } ! 848: ! 849: /* ! 850: * Restart the watchdog timer ! 851: */ ! 852: timerSrc->setTimeoutMS(WATCHDOG_TIMER_MS); ! 853: } ! 854: ! 855: /*------------------------------------------------------------------------- ! 856: * ! 857: * ! 858: * ! 859: *-------------------------------------------------------------------------*/ ! 860: ! 861: const char * BMacEnet::getVendorString() const ! 862: { ! 863: return ("Apple"); ! 864: } ! 865: ! 866: const char * BMacEnet::getModelString() const ! 867: { ! 868: return ("BMac"); ! 869: } ! 870: ! 871: const char * BMacEnet::getRevisionString() const ! 872: { ! 873: return (""); ! 874: } ! 875: ! 876: /*------------------------------------------------------------------------- ! 877: * ! 878: * ! 879: * ! 880: *-------------------------------------------------------------------------*/ ! 881: ! 882: IOReturn BMacEnet::setPromiscuousMode(IOEnetPromiscuousMode mode) ! 883: { ! 884: u_int16_t rxCFGVal; ! 885: ! 886: reserveDebuggerLock(); ! 887: ! 888: /* ! 889: * Turn off the receiver and wait for the chipset to acknowledge ! 890: */ ! 891: rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG); ! 892: WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable ); ! 893: while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable ) ! 894: ; ! 895: ! 896: /* ! 897: * Set or reset promiscuous mode and restore receiver state ! 898: */ ! 899: if (mode == kIOEnetPromiscuousModeOff) { ! 900: rxCFGVal &= ~kRxPromiscEnable; ! 901: isPromiscuous = false; ! 902: } ! 903: else { ! 904: rxCFGVal |= kRxPromiscEnable; ! 905: isPromiscuous = true; ! 906: } ! 907: ! 908: WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal ); ! 909: ! 910: releaseDebuggerLock(); ! 911: ! 912: return kIOReturnSuccess; ! 913: } ! 914: ! 915: IOReturn BMacEnet::setMulticastMode(IOEnetMulticastMode mode) ! 916: { ! 917: multicastEnabled = (mode == kIOEnetMulticastModeOff) ? false : true; ! 918: ! 919: return kIOReturnSuccess; ! 920: } ! 921: ! 922: IOReturn BMacEnet::setMulticastList(enet_addr_t *addrs, UInt count) ! 923: { ! 924: reserveDebuggerLock(); ! 925: _resetHashTableMask(); ! 926: for (UInt i = 0; i < count; i++) { ! 927: _addToHashTableMask(addrs->ea_byte); ! 928: addrs++; ! 929: } ! 930: _updateBMacHashTableMask(); ! 931: releaseDebuggerLock(); ! 932: return kIOReturnSuccess; ! 933: } ! 934: ! 935: /* ! 936: * Kernel Debugger Support ! 937: */ ! 938: void BMacEnet::sendPacket(void *pkt, unsigned int pkt_len) ! 939: { ! 940: _sendPacket(pkt, pkt_len); ! 941: } ! 942: ! 943: void BMacEnet::receivePacket(void *pkt, unsigned int *pkt_len, ! 944: unsigned int timeout) ! 945: { ! 946: _receivePacket(pkt, pkt_len, timeout); ! 947: } ! 948: ! 949: /* ! 950: * Allocate a WorkLoop serialized output queue object. ! 951: */ ! 952: IOOutputQueue * BMacEnet::allocateOutputQueue() ! 953: { ! 954: return IOOQGateFIFOQueue::withTarget( this, ! 955: getWorkLoop(), ! 956: TRANSMIT_QUEUE_SIZE ); ! 957: } ! 958: ! 959: #ifdef PM_SUPPORT ! 960: /* ! 961: * Power management methods. ! 962: */ ! 963: - (IOReturn)getPowerState:(PMPowerState *)state_p ! 964: { ! 965: return kIOReturnUnsupported; ! 966: } ! 967: ! 968: - (IOReturn)setPowerState:(PMPowerState)state ! 969: { ! 970: if (state == PM_OFF) { ! 971: resetAndEnabled = NO; ! 972: [self _resetChip]; ! 973: return kIOReturnSuccess; ! 974: } ! 975: return kIOReturnUnsupported; ! 976: } ! 977: ! 978: - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p ! 979: { ! 980: return kIOReturnUnsupported; ! 981: } ! 982: ! 983: - (IOReturn)setPowerManagement:(PMPowerManagementState)state ! 984: { ! 985: return kIOReturnUnsupported; ! 986: } ! 987: #endif PM_SUPPORT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.