|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1998-1999 by Apple Computer, Inc., All rights reserved. ! 27: * ! 28: * Hardware independent (relatively) code for the BMac Ethernet Controller ! 29: * ! 30: * HISTORY ! 31: * ! 32: * dd-mmm-yy ! 33: * Created. ! 34: * ! 35: */ ! 36: ! 37: #import "BMacEnetPrivate.h" ! 38: ! 39: @implementation BMacEnet ! 40: ! 41: /* ! 42: * Public Factory Methods ! 43: */ ! 44: ! 45: + (BOOL)probe:(IOTreeDevice *)devDesc ! 46: { ! 47: BMacEnet *BMacEnetInstance; ! 48: ! 49: BMacEnetInstance = [self alloc]; ! 50: return [BMacEnetInstance initFromDeviceDescription:devDesc] != nil; ! 51: } ! 52: ! 53: /* ! 54: * Public Instance Methods ! 55: */ ! 56: ! 57: /*------------------------------------------------------------------------- ! 58: * ! 59: * ! 60: * ! 61: *-------------------------------------------------------------------------*/ ! 62: ! 63: - initFromDeviceDescription:(IOTreeDevice *)devDesc ! 64: { ! 65: IOTreeDevice *devDescHeathrow; ! 66: IORange *ioRangeBMac; ! 67: IORange *ioRangeHeathrow; ! 68: ! 69: if ([super initFromDeviceDescription:devDesc] == nil) ! 70: { ! 71: IOLog( "Ethernet(BMac): [super initFromDeviceDescription] failed\n"); ! 72: return nil; ! 73: } ! 74: ! 75: if ( [devDesc numMemoryRanges] < 3 ) ! 76: { ! 77: IOLog( "Ethernet(BMac): Incorrect deviceDescription - 1\n\r"); ! 78: return nil; ! 79: } ! 80: ! 81: ioRangeBMac = [devDesc memoryRangeList]; ! 82: ! 83: ioBaseEnet = (IOPPCAddress) ioRangeBMac[0].start; ! 84: ioBaseEnetTxDMA = (IOPPCAddress) ioRangeBMac[1].start; ! 85: ioBaseEnetRxDMA = (IOPPCAddress) ioRangeBMac[2].start; ! 86: ! 87: devDescHeathrow = [[devDesc parent] deviceDescription]; ! 88: ! 89: if ( [devDescHeathrow numMemoryRanges] < 1 ) ! 90: { ! 91: IOLog( "Ethernet(BMac): Incorrect deviceDescription - 2\n\r"); ! 92: return nil; ! 93: } ! 94: ! 95: ioRangeHeathrow = [devDescHeathrow memoryRangeList]; ! 96: ! 97: ioBaseHeathrow = (IOPPCAddress) ioRangeHeathrow[0].start; ! 98: ! 99: sromAddressBits = 6; ! 100: enetAddressOffset = 20; ! 101: phyId = -1; ! 102: phyMIIDelay = MII_DEFAULT_DELAY; ! 103: ! 104: if ( ![self resetAndEnable:NO] ) ! 105: { ! 106: [self free]; ! 107: return nil; ! 108: } ! 109: ! 110: [self _getStationAddress:&myAddress]; ! 111: ! 112: if ([self _allocateMemory] == NO) ! 113: { ! 114: [self free]; ! 115: return nil; ! 116: } ! 117: ! 118: if ( ![self resetAndEnable:YES] ) ! 119: { ! 120: [self free]; ! 121: return nil; ! 122: } ! 123: ! 124: isPromiscuous = NO; ! 125: multicastEnabled = NO; ! 126: ! 127: networkInterface = [super attachToNetworkWithAddress:myAddress]; ! 128: ! 129: [networkInterface getIONetworkIfnet]->if_eflags |= IFEF_DVR_REENTRY_OK; ! 130: ! 131: return self; ! 132: } ! 133: ! 134: /*------------------------------------------------------------------------- ! 135: * ! 136: * ! 137: * ! 138: *-------------------------------------------------------------------------*/ ! 139: ! 140: - free ! 141: { ! 142: int i; ! 143: ! 144: [self clearTimeout]; ! 145: ! 146: [self _resetChip]; ! 147: ! 148: if (networkInterface) ! 149: [networkInterface free]; ! 150: ! 151: for (i = 0; i < rxMaxCommand; i++) ! 152: if (rxNetbuf[i]) nb_free(rxNetbuf[i]); ! 153: ! 154: for (i = 0; i < txMaxCommand; i++) ! 155: if (txNetbuf[i]) nb_free(txNetbuf[i]); ! 156: ! 157: return [super free]; ! 158: } ! 159: ! 160: /*------------------------------------------------------------------------- ! 161: * ! 162: * ! 163: * ! 164: *-------------------------------------------------------------------------*/ ! 165: ! 166: - (void)interruptOccurredAt:(int)irqNum ! 167: { ! 168: ! 169: [self reserveDebuggerLock]; ! 170: ! 171: switch ( irqNum ) ! 172: { ! 173: /* ! 174: * On the transmit side, we use the chipset interrupt. Using the transmit ! 175: * DMA interrupt (or having multiple transmit DMA entries) would allows us to ! 176: * send the next frame to the chipset prior the transmit fifo going empty. ! 177: * However, this aggrevates a BMac chipset bug where the next frame going out ! 178: * gets corrupted (first two bytes lost) if the chipset had to retry the previous ! 179: * frame. ! 180: */ ! 181: case kIRQEnetDev: ! 182: case kIRQEnetTxDMA: ! 183: txWDInterrupts++; ! 184: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 ); ! 185: [self _transmitInterruptOccurred]; ! 186: [self serviceTransmitQueue]; ! 187: KERNEL_DEBUG(DBG_BMAC_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 ); ! 188: break; ! 189: case kIRQEnetRxDMA: ! 190: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 ); ! 191: [self _receiveInterruptOccurred]; ! 192: KERNEL_DEBUG(DBG_BMAC_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 ); ! 193: break; ! 194: } ! 195: ! 196: [self enableAllInterrupts]; ! 197: ! 198: [self releaseDebuggerLock]; ! 199: } ! 200: ! 201: /*------------------------------------------------------------------------- ! 202: * ! 203: * ! 204: * ! 205: *-------------------------------------------------------------------------*/ ! 206: ! 207: - (void) serviceTransmitQueue ! 208: { ! 209: netbuf_t packet; ! 210: u_int32_t i; ! 211: ! 212: while ( 1 ) ! 213: { ! 214: if ( ![transmitQueue count] ) ! 215: { ! 216: break; ! 217: } ! 218: ! 219: i = txCommandTail + 1; ! 220: if ( i >= txMaxCommand ) i = 0; ! 221: if ( i == txCommandHead ) ! 222: { ! 223: break; ! 224: } ! 225: packet = [transmitQueue dequeue]; ! 226: [self _transmitPacket:packet]; ! 227: } ! 228: ! 229: } ! 230: ! 231: /*------------------------------------------------------------------------- ! 232: * ! 233: * ! 234: * ! 235: *-------------------------------------------------------------------------*/ ! 236: ! 237: - (void)transmit:(netbuf_t)pkt ! 238: { ! 239: u_int32_t i; ! 240: u_int32_t n; ! 241: ! 242: KERNEL_DEBUG(DBG_BMAC_TXQUEUE | DBG_FUNC_NONE, (int) pkt, (int) nb_size(pkt), 0, 0, 0 ); ! 243: ! 244: /* ! 245: * Hold the debugger lock so the debugger can't interrupt us ! 246: */ ! 247: [self reserveDebuggerLock]; ! 248: ! 249: do ! 250: { ! 251: /* ! 252: * Preliminary sanity checks ! 253: */ ! 254: if (!pkt) ! 255: { ! 256: IOLog("EtherNet(BMac): transmit received NULL netbuf\n"); ! 257: continue; ! 258: } ! 259: if ( ![self isRunning] ) ! 260: { ! 261: nb_free(pkt); ! 262: continue; ! 263: } ! 264: ! 265: #if 0 ! 266: /* ! 267: * Remove any completed packets from the Tx ring ! 268: */ ! 269: if ( chipId >= kCHIPID_PaddingtonXmitStreaming ) ! 270: { ! 271: [self _transmitInterruptOccurred]; ! 272: } ! 273: #endif ! 274: ! 275: /* ! 276: * Refill the Tx ring from the Transmit waiting list ! 277: */ ! 278: [self serviceTransmitQueue]; ! 279: ! 280: /* ! 281: * If the Transmit waiting list is not empty or the Tx ring is ! 282: * full, add the new packet to the waiting list. ! 283: */ ! 284: n = [transmitQueue count]; ! 285: if ( n > 0 ) ! 286: { ! 287: if ( n >= [transmitQueue maxCount] ) ! 288: { ! 289: IOLog("Ethernet(BMac): Transmit queue overflow\n"); ! 290: } ! 291: ! 292: [transmitQueue enqueue:pkt]; ! 293: continue; ! 294: } ! 295: i = txCommandTail + 1; ! 296: if ( i >= txMaxCommand ) i = 0; ! 297: if ( i == txCommandHead ) ! 298: { ! 299: [transmitQueue enqueue:pkt]; ! 300: continue; ! 301: } ! 302: ! 303: /* ! 304: * If there is space on the Tx ring, add the packet directly to the ! 305: * ring ! 306: */ ! 307: [self _transmitPacket:pkt]; ! 308: } ! 309: while( 0 ); ! 310: ! 311: [self releaseDebuggerLock]; ! 312: } ! 313: ! 314: /*------------------------------------------------------------------------- ! 315: * ! 316: * ! 317: * ! 318: *-------------------------------------------------------------------------*/ ! 319: ! 320: - (int) transmitQueueSize ! 321: { ! 322: return (TRANSMIT_QUEUE_SIZE); ! 323: } ! 324: ! 325: - (int) transmitQueueCount ! 326: { ! 327: return ([transmitQueue count]); ! 328: } ! 329: /*------------------------------------------------------------------------- ! 330: * ! 331: * ! 332: * ! 333: *-------------------------------------------------------------------------*/ ! 334: ! 335: - (BOOL)resetAndEnable:(BOOL)enable ! 336: { ! 337: resetAndEnabled = NO; ! 338: [self clearTimeout]; ! 339: [self disableAllInterrupts]; ! 340: [self _resetChip]; ! 341: ! 342: if (enable) ! 343: { ! 344: if (![self _initRxRing] || ![self _initTxRing]) ! 345: { ! 346: return NO; ! 347: } ! 348: ! 349: if ( phyId != 0xff ) ! 350: { ! 351: [self miiInitializePHY:phyId]; ! 352: } ! 353: ! 354: if ([self _initChip] == NO) ! 355: { ! 356: [self setRunning:NO]; ! 357: return NO; ! 358: } ! 359: ! 360: [self _startChip]; ! 361: ! 362: [self setRelativeTimeout: WATCHDOG_TIMER_MS]; ! 363: ! 364: [self enableAllInterrupts]; ! 365: [self _enableAdapterInterrupts]; ! 366: ! 367: resetAndEnabled = YES; ! 368: ! 369: [self _sendDummyPacket]; ! 370: } ! 371: ! 372: [self setRunning:enable]; ! 373: ! 374: return YES; ! 375: } ! 376: ! 377: /*------------------------------------------------------------------------- ! 378: * ! 379: * ! 380: * ! 381: *-------------------------------------------------------------------------*/ ! 382: ! 383: - (void)timeoutOccurred ! 384: { ! 385: u_int32_t dmaStatus; ! 386: u_int16_t phyStatus; ! 387: u_int16_t linkStatus; ! 388: u_int16_t phyStatusChange; ! 389: BOOL fullDuplex = NO; ! 390: ! 391: if ( ![self isRunning] ) ! 392: { ! 393: return; ! 394: } ! 395: ! 396: [self reserveDebuggerLock]; ! 397: ! 398: /* ! 399: * Check for DMA shutdown on receive channel ! 400: */ ! 401: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); ! 402: if ( !(dmaStatus & kdbdmaActive) ) ! 403: { ! 404: IOLog( "Ethernet(BMac): Checking for timeout - RxHead = %d RxTail = %d\n\r", rxCommandHead, rxCommandTail); ! 405: #if 0 ! 406: IOLog( "Ethernet(BMac): Rx Commands = %08x(p) Rx DMA Ptr = %08x(p)\n\r", rxDMACommandsPhys, IOGetDBDMACommandPtr(ioBaseEnetRxDMA) ); ! 407: [self _dumpDesc:(void *)rxDMACommands Size:rxMaxCommand * sizeof(enet_dma_cmd_t)]; ! 408: #endif ! 409: [self _receiveInterruptOccurred]; ! 410: } ! 411: ! 412: /* ! 413: * If there are pending entries on the Tx ring ! 414: */ ! 415: if ( txCommandHead != txCommandTail ) ! 416: { ! 417: /* ! 418: * If we did not service the Tx ring during the last timeout interval, ! 419: * then force servicing of the Tx ring ! 420: */ ! 421: if ( txWDInterrupts == 0 ) ! 422: { ! 423: if ( txWDCount++ > 0 ) ! 424: { ! 425: if ( [self _transmitInterruptOccurred] == NO ) ! 426: { ! 427: IOLog( "Ethernet(BMac): Checking for timeout - TxHead = %d TxTail = %d\n\r", txCommandHead, txCommandTail); ! 428: [self _restartTransmitter]; ! 429: } ! 430: } ! 431: } ! 432: else ! 433: { ! 434: txWDInterrupts = 0; ! 435: txWDCount = 0; ! 436: } ! 437: } ! 438: else ! 439: { ! 440: txWDInterrupts = 0; ! 441: txWDCount = 0; ! 442: } ! 443: ! 444: if ( phyId != 0xff ) ! 445: { ! 446: if ( [self miiReadWord:&phyStatus reg:MII_STATUS phy:phyId] == YES ) ! 447: { ! 448: phyStatusChange = (phyStatusPrev ^ phyStatus) & (MII_STATUS_LINK_STATUS | MII_STATUS_NEGOTIATION_COMPLETE); ! 449: if ( phyStatusChange ) ! 450: { ! 451: if ( (phyStatus & MII_STATUS_LINK_STATUS) && (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE ) ) ! 452: { ! 453: if ( (phyType & MII_ST10040_MASK) == MII_ST10040_ID ) ! 454: { ! 455: [self miiReadWord:&linkStatus reg:MII_ST10040_CHIPST phy:phyId]; ! 456: ! 457: fullDuplex = (linkStatus & MII_ST10040_CHIPST_DUPLEX) ? YES : NO; ! 458: ! 459: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r", ! 460: (linkStatus & MII_ST10040_CHIPST_SPEED) ? "100" : "10", ! 461: (fullDuplex) ? "Full" : "Half" ); ! 462: } ! 463: else if ( (phyType & MII_DP83843_MASK) == MII_DP83843_ID ) ! 464: { ! 465: [self miiReadWord:&linkStatus reg:MII_DP83843_PHYSTS phy:phyId]; ! 466: ! 467: fullDuplex = (linkStatus & MII_DP83843_PHYSTS_DUPLEX) ? YES : NO; ! 468: ! 469: IOLog( "Ethernet(BMac): Link is up at %sMb - %s Duplex\n\r", ! 470: (linkStatus & MII_DP83843_PHYSTS_SPEED10) ? "10" : "100", ! 471: (fullDuplex) ? "Full" : "Half" ); ! 472: } ! 473: else ! 474: { ! 475: fullDuplex = NO ; ! 476: IOLog( "Ethernet(BMac): Link is up\n\r" ); ! 477: } ! 478: ! 479: if ( fullDuplex != isFullDuplex ) ! 480: { ! 481: [self _setDuplexMode: fullDuplex]; ! 482: } ! 483: } ! 484: else ! 485: { ! 486: IOLog( "Ethernet(BMac): Link is down.\n\r" ); ! 487: } ! 488: phyStatusPrev = phyStatus; ! 489: } ! 490: } ! 491: } ! 492: ! 493: /* ! 494: * Restart the watchdog timer ! 495: */ ! 496: [self setRelativeTimeout: WATCHDOG_TIMER_MS]; ! 497: ! 498: [self releaseDebuggerLock]; ! 499: ! 500: } ! 501: ! 502: /*------------------------------------------------------------------------- ! 503: * ! 504: * ! 505: * ! 506: *-------------------------------------------------------------------------*/ ! 507: ! 508: - (BOOL)enablePromiscuousMode ! 509: { ! 510: u_int16_t rxCFGVal; ! 511: ! 512: isPromiscuous = YES; ! 513: ! 514: [self reserveDebuggerLock]; ! 515: ! 516: /* ! 517: * Turn off the receiver and wait for the chipset to acknowledge ! 518: */ ! 519: rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG); ! 520: WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable ); ! 521: while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable ) ! 522: ; ! 523: ! 524: /* ! 525: * Set promiscuous mode and restore receiver state ! 526: */ ! 527: rxCFGVal |= kRxPromiscEnable; ! 528: WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal ); ! 529: ! 530: [self releaseDebuggerLock]; ! 531: ! 532: return YES; ! 533: } ! 534: ! 535: - (void)disablePromiscuousMode ! 536: { ! 537: u_int16_t rxCFGVal; ! 538: ! 539: isPromiscuous = NO; ! 540: ! 541: [self reserveDebuggerLock]; ! 542: ! 543: /* ! 544: * Turn off the receiver and wait for the chipset to acknowledge ! 545: */ ! 546: rxCFGVal = ReadBigMacRegister(ioBaseEnet, kRXCFG); ! 547: WriteBigMacRegister(ioBaseEnet, kRXCFG, rxCFGVal & ~kRxMACEnable ); ! 548: while( ReadBigMacRegister(ioBaseEnet, kRXCFG) & kRxMACEnable ) ! 549: ; ! 550: ! 551: /* ! 552: * Reset promiscuous mode and restore receiver state ! 553: */ ! 554: rxCFGVal &= ~kRxPromiscEnable; ! 555: WriteBigMacRegister( ioBaseEnet, kRXCFG, rxCFGVal ); ! 556: ! 557: [self releaseDebuggerLock]; ! 558: } ! 559: ! 560: - (BOOL)enableMulticastMode ! 561: { ! 562: multicastEnabled = YES; ! 563: return YES; ! 564: } ! 565: ! 566: - (void)disableMulticastMode ! 567: { ! 568: multicastEnabled = NO; ! 569: } ! 570: ! 571: - (void)addMulticastAddress:(enet_addr_t *)addr ! 572: { ! 573: multicastEnabled = YES; ! 574: [self reserveDebuggerLock]; ! 575: [self _addToHashTableMask:addr->ea_byte]; ! 576: [self _updateBMacHashTableMask]; ! 577: [self releaseDebuggerLock]; ! 578: } ! 579: ! 580: - (void)removeMulticastAddress:(enet_addr_t *)addr ! 581: { ! 582: [self reserveDebuggerLock]; ! 583: [self _removeFromHashTableMask:addr->ea_byte]; ! 584: [self _updateBMacHashTableMask]; ! 585: [self releaseDebuggerLock]; ! 586: } ! 587: ! 588: /* ! 589: * Kernel Debugger Support ! 590: */ ! 591: - (void)sendPacket:(void *)pkt length:(unsigned int)pkt_len ! 592: { ! 593: [self _sendPacket:(void *)pkt length:(unsigned int)pkt_len]; ! 594: } ! 595: ! 596: - (void)receivePacket:(void *)pkt length:(unsigned int *)pkt_len timeout:(unsigned int)timeout ! 597: { ! 598: [self _receivePacket:(void *)pkt length:(unsigned int *)pkt_len timeout:(unsigned int)timeout]; ! 599: } ! 600: ! 601: /* ! 602: * Power management methods. ! 603: */ ! 604: - (IOReturn)getPowerState:(PMPowerState *)state_p ! 605: { ! 606: return IO_R_UNSUPPORTED; ! 607: } ! 608: ! 609: - (IOReturn)setPowerState:(PMPowerState)state ! 610: { ! 611: if (state == PM_OFF) { ! 612: resetAndEnabled = NO; ! 613: [self _resetChip]; ! 614: return IO_R_SUCCESS; ! 615: } ! 616: return IO_R_UNSUPPORTED; ! 617: } ! 618: ! 619: - (IOReturn)getPowerManagement:(PMPowerManagementState *)state_p ! 620: { ! 621: return IO_R_UNSUPPORTED; ! 622: } ! 623: ! 624: - (IOReturn)setPowerManagement:(PMPowerManagementState)state ! 625: { ! 626: return IO_R_UNSUPPORTED; ! 627: } ! 628: ! 629: - (void)reserveDebuggerLock ! 630: { ! 631: if ( debuggerLockCount++ == 0 ) ! 632: { ! 633: [super reserveDebuggerLock]; ! 634: } ! 635: } ! 636: ! 637: - (void)releaseDebuggerLock ! 638: { ! 639: if ( --debuggerLockCount == 0 ) ! 640: { ! 641: [super releaseDebuggerLock]; ! 642: } ! 643: } ! 644: ! 645: ! 646: @end ! 647: ! 648: ! 649: ! 650: ! 651: ! 652: ! 653: ! 654: ! 655: ! 656: ! 657: ! 658: ! 659: ! 660: ! 661:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.