|
|
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) 1995-1996 NeXT Software, Inc. ! 24: * ! 25: * Implementation for hardware dependent (relatively) code ! 26: * for the Mace Ethernet controller. ! 27: * ! 28: * HISTORY ! 29: * ! 30: * 10-Sept-97 ! 31: * Created. ! 32: * ! 33: */ ! 34: ! 35: #include <IOKit/assert.h> ! 36: #include <IOKit/system.h> ! 37: #include <IOKit/IOLib.h> ! 38: #include "MaceEnetPrivate.h" ! 39: ! 40: ! 41: /***************************************************************************** ! 42: * ! 43: * Hacks. ! 44: */ ! 45: ! 46: typedef unsigned long long ns_time_t; /* nanoseconds! */ ! 47: ! 48: #define NSEC_PER_SEC 1000000000 ! 49: ! 50: static void ! 51: _IOGetTimestamp(ns_time_t *nsp) ! 52: { ! 53: mach_timespec_t now; ! 54: ! 55: IOGetTime(&now); ! 56: *nsp = ((ns_time_t)now.tv_sec * NSEC_PER_SEC) + now.tv_nsec; ! 57: } ! 58: ! 59: /* ! 60: * Find a physical address (if any) for the specified virtual address. ! 61: * ! 62: * Note: what about vm_offset_t kvtophys(vm_offset_t va) ! 63: */ ! 64: static IOReturn _IOPhysicalFromVirtual( ! 65: vm_address_t virtualAddress, ! 66: unsigned *physicalAddress) ! 67: { ! 68: *physicalAddress = pmap_extract(kernel_pmap, virtualAddress); ! 69: if(*physicalAddress == 0) { ! 70: return kIOReturnBadArgument; ! 71: } ! 72: else { ! 73: return kIOReturnSuccess; ! 74: } ! 75: } ! 76: ! 77: // From osfmk/ppc/pmap.h ! 78: // ! 79: extern "C" { ! 80: extern void invalidate_dcache(vm_offset_t va, unsigned length, boolean_t phys); ! 81: extern void flush_dcache(vm_offset_t va, unsigned length, boolean_t phys); ! 82: } ! 83: ! 84: static inline void ! 85: invalidate_cache_v(vm_offset_t va, unsigned length) ! 86: { ! 87: invalidate_dcache(va, length, 0); ! 88: } ! 89: ! 90: static inline void ! 91: flush_cache_v(vm_offset_t va, unsigned length) ! 92: { ! 93: flush_dcache(va, length, 0); ! 94: } ! 95: ! 96: /****************************************************************************/ ! 97: ! 98: static IODBDMADescriptor dbdmaCmd_Nop; ! 99: static IODBDMADescriptor dbdmaCmd_NopWInt; ! 100: static IODBDMADescriptor dbdmaCmd_LoadXFS; ! 101: static IODBDMADescriptor dbdmaCmd_LoadIntwInt; ! 102: static IODBDMADescriptor dbdmaCmd_Stop; ! 103: static IODBDMADescriptor dbdmaCmd_Branch; ! 104: ! 105: ! 106: static u_int8_t reverseBitOrder(u_int8_t data ) ! 107: { ! 108: u_int8_t val = 0; ! 109: int i; ! 110: ! 111: for ( i=0; i < 8; i++ ) ! 112: { ! 113: val <<= 1; ! 114: if (data & 1) val |= 1; ! 115: data >>= 1; ! 116: } ! 117: return( val ); ! 118: } ! 119: ! 120: /* ! 121: * Function: IOMallocPage ! 122: * ! 123: * Purpose: ! 124: * Returns a pointer to a page-aligned memory block of size >= PAGE_SIZE ! 125: * ! 126: * Return: ! 127: * Actual pointer and size of block returned in actual_ptr and actual_size. ! 128: * Use these as arguments to kfree: kfree(*actual_ptr, *actual_size); ! 129: */ ! 130: static void * ! 131: IOMallocPage(int request_size, void ** actual_ptr, u_int * actual_size) ! 132: { ! 133: void * mem_ptr; ! 134: ! 135: *actual_size = round_page(request_size) + PAGE_SIZE; ! 136: mem_ptr = IOMalloc(*actual_size); ! 137: if (mem_ptr == NULL) ! 138: return NULL; ! 139: *actual_ptr = mem_ptr; ! 140: return ((void *)round_page(mem_ptr)); ! 141: } ! 142: ! 143: /* ! 144: * Private functions ! 145: */ ! 146: bool MaceEnet::_allocateMemory() ! 147: { ! 148: u_int32_t i, n; ! 149: unsigned char * virtAddr; ! 150: u_int32_t physBase; ! 151: u_int32_t physAddr; ! 152: u_int32_t dbdmaSize; ! 153: ! 154: /* ! 155: * Calculate total space for DMA channel commands ! 156: */ ! 157: dbdmaSize = round_page( ! 158: RX_RING_LENGTH * sizeof(enet_dma_cmd_t) + ! 159: TX_RING_LENGTH * sizeof(enet_txdma_cmd_t) + ! 160: 2 * sizeof(IODBDMADescriptor) ); ! 161: ! 162: /* ! 163: * Allocate required memory ! 164: */ ! 165: dmaMemory.size = dbdmaSize; ! 166: dmaMemory.ptr = (void *)IOMallocPage( ! 167: dmaMemory.size, ! 168: &dmaMemory.ptrReal, ! 169: &dmaMemory.sizeReal ! 170: ); ! 171: ! 172: dmaCommands = (unsigned char *) dmaMemory.ptr; ! 173: if (!dmaCommands) { ! 174: IOLog( "Mace: Cant allocate channel DBDMA commands\n\r" ); ! 175: return false; ! 176: } ! 177: ! 178: /* ! 179: * If we needed more than one page, then make sure we received ! 180: * contiguous memory. ! 181: */ ! 182: n = (dbdmaSize - PAGE_SIZE) / PAGE_SIZE; ! 183: _IOPhysicalFromVirtual((vm_address_t) dmaCommands, &physBase ); ! 184: ! 185: virtAddr = (unsigned char *) dmaCommands; ! 186: for( i=0; i < n; i++, virtAddr += PAGE_SIZE ) ! 187: { ! 188: _IOPhysicalFromVirtual( (vm_address_t) virtAddr, &physAddr ); ! 189: if (physAddr != (physBase + i * PAGE_SIZE) ) ! 190: { ! 191: IOLog("Mace: Cannot allocate contiguous memory for DBDMA " ! 192: "commands\n"); ! 193: return false; ! 194: } ! 195: } ! 196: ! 197: /* ! 198: * Setup the receive ring pointers ! 199: */ ! 200: rxDMACommands = (enet_dma_cmd_t *)dmaCommands; ! 201: rxMaxCommand = RX_RING_LENGTH; ! 202: ! 203: /* ! 204: * Setup the transmit ring pointers ! 205: */ ! 206: txDMACommands = (enet_txdma_cmd_t *)( ! 207: dmaCommands + ! 208: RX_RING_LENGTH * sizeof(enet_dma_cmd_t) + ! 209: sizeof(IODBDMADescriptor)); ! 210: ! 211: txMaxCommand = TX_RING_LENGTH; ! 212: ! 213: /* ! 214: * Setup pre-initialized DBDMA commands ! 215: */ ! 216: IOMakeDBDMADescriptor( (&dbdmaCmd_Nop), ! 217: kdbdmaNop, ! 218: kdbdmaKeyStream0, ! 219: kdbdmaIntNever, ! 220: kdbdmaBranchNever, ! 221: kdbdmaWaitNever, ! 222: 0, ! 223: 0 ); ! 224: ! 225: IOMakeDBDMADescriptor( (&dbdmaCmd_NopWInt), ! 226: kdbdmaNop, ! 227: kdbdmaKeyStream0, ! 228: kdbdmaIntAlways, ! 229: kdbdmaBranchNever, ! 230: kdbdmaWaitNever, ! 231: 0, ! 232: 0 ); ! 233: ! 234: UInt32 ioBaseEnetPhys = maps[MEMORY_MAP_ENET_INDEX]->getPhysicalAddress(); ! 235: ! 236: IOMakeDBDMADescriptor( (&dbdmaCmd_LoadXFS), ! 237: kdbdmaLoadQuad, ! 238: kdbdmaKeySystem, ! 239: kdbdmaIntNever, ! 240: kdbdmaBranchNever, ! 241: kdbdmaWaitNever, ! 242: 1, ! 243: ((int)ioBaseEnetPhys + kXmtFS) ); ! 244: ! 245: IOMakeDBDMADescriptor( (&dbdmaCmd_LoadIntwInt), ! 246: kdbdmaLoadQuad, ! 247: kdbdmaKeySystem, ! 248: kdbdmaIntAlways, ! 249: kdbdmaBranchNever, ! 250: kdbdmaWaitNever, ! 251: 1, ! 252: ((int)ioBaseEnetPhys + kIntReg) ); ! 253: ! 254: IOMakeDBDMADescriptor( (&dbdmaCmd_Stop), ! 255: kdbdmaStop, ! 256: kdbdmaKeyStream0, ! 257: kdbdmaIntNever, ! 258: kdbdmaBranchNever, ! 259: kdbdmaWaitNever, ! 260: 0, ! 261: 0 ); ! 262: ! 263: IOMakeDBDMADescriptor( (&dbdmaCmd_Branch), ! 264: kdbdmaNop, ! 265: kdbdmaKeyStream0, ! 266: kdbdmaIntNever, ! 267: kdbdmaBranchAlways, ! 268: kdbdmaWaitNever, ! 269: 0, ! 270: 0 ); ! 271: ! 272: return true; ! 273: } ! 274: ! 275: /*------------------------------------------------------------------------- ! 276: * ! 277: * Setup the Transmit Ring ! 278: * ----------------------- ! 279: * Each transmit ring entry consists of two words to transmit data from buffer ! 280: * segments (possibly) spanning a page boundary. This is followed by two DMA ! 281: * commands which read transmit frame status and interrupt status from the Mace ! 282: * chip. The last DMA command in each transmit ring entry generates a host ! 283: * interrupt. The last entry in the ring is followed by a DMA branch to the ! 284: * first entry. ! 285: *-------------------------------------------------------------------------*/ ! 286: ! 287: bool MaceEnet::_initTxRing() ! 288: { ! 289: bool kr; ! 290: u_int32_t i; ! 291: ! 292: /* ! 293: * Clear the transmit DMA command memory ! 294: */ ! 295: bzero( (void *)txDMACommands, sizeof(enet_txdma_cmd_t) * txMaxCommand); ! 296: txCommandHead = 0; ! 297: txCommandTail = 0; ! 298: ! 299: /* ! 300: * DMA Channel commands 2,3 are the same for all DBDMA entries on transmit. ! 301: * Initialize them now. ! 302: */ ! 303: for( i=0; i < txMaxCommand; i++ ) ! 304: { ! 305: txDMACommands[i].desc_seg[2] = dbdmaCmd_LoadXFS; ! 306: txDMACommands[i].desc_seg[3] = dbdmaCmd_LoadIntwInt; ! 307: } ! 308: ! 309: /* ! 310: * Put a DMA Branch command after the last entry in the transmit ring. ! 311: * Set the branch address to the physical address of the start of the ! 312: * transmit ring. ! 313: */ ! 314: txDMACommands[txMaxCommand].desc_seg[0] = dbdmaCmd_Branch; ! 315: ! 316: kr = _IOPhysicalFromVirtual( (vm_address_t) txDMACommands, ! 317: (u_int32_t *)&txDMACommandsPhys ); ! 318: if ( kr != kIOReturnSuccess ) ! 319: { ! 320: IOLog("Mace: Bad Tx DBDMA command buf - %08x\n\r", ! 321: (u_int32_t)txDMACommands ); ! 322: } ! 323: IOSetCCCmdDep( &txDMACommands[txMaxCommand].desc_seg[0], ! 324: txDMACommandsPhys ); ! 325: ! 326: /* ! 327: * Set the Transmit DMA Channel pointer to the first entry in the ! 328: * transmit ring. ! 329: */ ! 330: IOSetDBDMACommandPtr( ioBaseEnetTxDMA, txDMACommandsPhys ); ! 331: ! 332: /* ! 333: * Push the DMA channel words into physical memory. ! 334: */ ! 335: flush_cache_v( (vm_offset_t)txDMACommands, ! 336: txMaxCommand*sizeof(enet_txdma_cmd_t) + sizeof(IODBDMADescriptor)); ! 337: ! 338: return true; ! 339: } ! 340: ! 341: /*------------------------------------------------------------------------- ! 342: * ! 343: * Setup the Receive ring ! 344: * ---------------------- ! 345: * Each receive ring entry consists of two DMA commands to receive data ! 346: * into a network buffer (possibly) spanning a page boundary. The second ! 347: * DMA command in each entry generates a host interrupt. ! 348: * The last entry in the ring is followed by a DMA branch to the first ! 349: * entry. ! 350: * ! 351: *-------------------------------------------------------------------------*/ ! 352: ! 353: bool MaceEnet::_initRxRing() ! 354: { ! 355: u_int32_t i; ! 356: bool status; ! 357: IOReturn kr; ! 358: ! 359: /* ! 360: * Clear the receive DMA command memory ! 361: */ ! 362: bzero( (void *)rxDMACommands, sizeof(enet_dma_cmd_t) * rxMaxCommand); ! 363: ! 364: kr = _IOPhysicalFromVirtual( (vm_address_t) rxDMACommands, ! 365: (u_int32_t *)&rxDMACommandsPhys ); ! 366: if ( kr != kIOReturnSuccess ) ! 367: { ! 368: IOLog("Mace: Bad Rx DBDMA command buf - %08x\n\r", ! 369: (u_int32_t)rxDMACommands ); ! 370: return false; ! 371: } ! 372: ! 373: /* ! 374: * Allocate a receive buffer for each entry in the Receive ring ! 375: */ ! 376: for (i = 0; i < rxMaxCommand-1; i++) ! 377: { ! 378: if (rxMbuf[i] == 0) ! 379: { ! 380: rxMbuf[i] = allocatePacket(NETWORK_BUFSIZE); ! 381: ! 382: if (!rxMbuf[i]) ! 383: { ! 384: IOLog("Mace: allocatePacket failed in _initRxRing()\n\r"); ! 385: return false; ! 386: } ! 387: } ! 388: ! 389: /* ! 390: * Set the DMA commands for the ring entry to transfer data to the ! 391: * mbuf. ! 392: */ ! 393: status = _updateDescriptorFromMbuf(rxMbuf[i], &rxDMACommands[i], true); ! 394: if (status == false) ! 395: { ! 396: IOLog("Mace: Cant map mbuf to physical memory in _initRxRing\n\r"); ! 397: return false; ! 398: } ! 399: } ! 400: ! 401: /* ! 402: * Set the receive queue head to point to the first entry in the ring. ! 403: * Set the receive queue tail to point to a DMA Stop command after the ! 404: * last ring entry ! 405: */ ! 406: rxCommandHead = 0; ! 407: rxCommandTail = i; ! 408: ! 409: rxDMACommands[i].desc_seg[0] = dbdmaCmd_Stop; ! 410: rxDMACommands[i].desc_seg[1] = dbdmaCmd_Nop; ! 411: ! 412: /* ! 413: * Setup a DMA branch command after the stop command ! 414: */ ! 415: i++; ! 416: rxDMACommands[i].desc_seg[0] = dbdmaCmd_Branch; ! 417: ! 418: IOSetCCCmdDep( &rxDMACommands[i].desc_seg[0], rxDMACommandsPhys ); ! 419: ! 420: /* ! 421: * Set DMA command pointer to first receive entry ! 422: */ ! 423: IOSetDBDMACommandPtr( ioBaseEnetRxDMA, rxDMACommandsPhys ); ! 424: ! 425: /* ! 426: * Push DMA commands to physical memory ! 427: */ ! 428: flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], ! 429: 2 * sizeof(enet_dma_cmd_t) ); ! 430: ! 431: return true; ! 432: } ! 433: ! 434: /*------------------------------------------------------------------------- ! 435: * ! 436: * ! 437: * ! 438: *-------------------------------------------------------------------------*/ ! 439: ! 440: void MaceEnet::_startChip() ! 441: { ! 442: WriteMaceRegister( ioBaseEnet, kMacCC, kMacCCEnXmt | kMacCCEnRcv ); ! 443: ! 444: // enable rx dma channel ! 445: IODBDMAContinue( ioBaseEnetRxDMA ); ! 446: } ! 447: ! 448: /*------------------------------------------------------------------------- ! 449: * ! 450: * ! 451: * ! 452: *-------------------------------------------------------------------------*/ ! 453: ! 454: void MaceEnet::_resetChip() ! 455: { ! 456: u_int8_t regValue; ! 457: ! 458: /* ! 459: * Mace errata - chip reset does not clear pending interrupts ! 460: */ ! 461: ReadMaceRegister( ioBaseEnet, kIntReg ); ! 462: ! 463: IODBDMAReset( ioBaseEnetRxDMA ); ! 464: IODBDMAReset( ioBaseEnetTxDMA ); ! 465: ! 466: IOSetDBDMAWaitSelect( ioBaseEnetTxDMA, ! 467: IOSetDBDMAChannelControlBits( kdbdmaS5 ) ); ! 468: ! 469: IOSetDBDMABranchSelect( ioBaseEnetRxDMA, ! 470: IOSetDBDMAChannelControlBits( kdbdmaS6 ) ); ! 471: ! 472: IOSetDBDMAInterruptSelect( ioBaseEnetRxDMA, ! 473: IOSetDBDMAChannelControlBits( kdbdmaS6 ) ); ! 474: ! 475: WriteMaceRegister( ioBaseEnet, kBIUCC, kBIUCCSWRst ); ! 476: do ! 477: { ! 478: regValue = ReadMaceRegister( ioBaseEnet, kBIUCC ); ! 479: } ! 480: while( regValue & kBIUCCSWRst ); ! 481: } ! 482: ! 483: /*------------------------------------------------------------------------- ! 484: * ! 485: * ! 486: * ! 487: *-------------------------------------------------------------------------*/ ! 488: ! 489: bool MaceEnet::_initChip() ! 490: { ! 491: volatile u_int16_t regValue; ! 492: u_int32_t i; ! 493: ! 494: _disableAdapterInterrupts(); ! 495: ! 496: chipId = ReadMaceRegister( ioBaseEnet, kMaceChipId0 ); ! 497: chipId |= ReadMaceRegister( ioBaseEnet, kMaceChipId1 ) << 8; ! 498: ! 499: /* ! 500: * Turn off ethernet header stripping ! 501: */ ! 502: regValue = ReadMaceRegister( ioBaseEnet, kRcvFC ); ! 503: regValue &= ~kRcvFCAStrpRcv; ! 504: WriteMaceRegister( ioBaseEnet, kRcvFC, regValue ); ! 505: ! 506: /* ! 507: * Set Mace destination address. ! 508: */ ! 509: if ( chipId != kMaceRevisionA2 ) ! 510: { ! 511: WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACPhyAddr ); ! 512: do ! 513: { ! 514: regValue = ReadMaceRegister( ioBaseEnet, kIAC ); ! 515: } ! 516: while( regValue & kIACAddrChg ); ! 517: } ! 518: else ! 519: { ! 520: WriteMaceRegister( ioBaseEnet, kIAC, kIACPhyAddr ); ! 521: } ! 522: ! 523: for (i=0; i < sizeof(enet_addr_t); i++ ) ! 524: { ! 525: WriteMaceRegister( ioBaseEnet, kPADR, ! 526: reverseBitOrder(((unsigned char *)ioBaseEnetROM)[i<<4]) ); ! 527: } ! 528: ! 529: /* ! 530: * Clear logical address (multicast) filter ! 531: */ ! 532: if ( chipId != kMaceRevisionA2 ) ! 533: { ! 534: WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACLogAddr ); ! 535: do ! 536: { ! 537: regValue = ReadMaceRegister( ioBaseEnet, kIAC ); ! 538: } ! 539: while( regValue & kIACAddrChg ); ! 540: } ! 541: else ! 542: { ! 543: WriteMaceRegister( ioBaseEnet, kIAC, kIACLogAddr ); ! 544: } ! 545: ! 546: for (i = 0; i < 8; i++ ) ! 547: { ! 548: WriteMaceRegister( ioBaseEnet, kLADRF, 0 ); ! 549: } ! 550: ! 551: /* ! 552: * Enable ethernet transceiver ! 553: */ ! 554: WriteMaceRegister( ioBaseEnet, kPLSCC, kPLSCCPortSelGPSI | kPLSCCEnSts ); ! 555: ! 556: return true; ! 557: } ! 558: ! 559: ! 560: /*------------------------------------------------------------------------- ! 561: * ! 562: * ! 563: * ! 564: *-------------------------------------------------------------------------*/ ! 565: ! 566: void MaceEnet::_restartChip() ! 567: { ! 568: /* ! 569: * Shutdown DMA channels ! 570: */ ! 571: _stopReceiveDMA(); ! 572: _stopTransmitDMA(); ! 573: ! 574: /* ! 575: * Get the silicon's attention ! 576: */ ! 577: _resetChip(); ! 578: _initChip(); ! 579: ! 580: /* ! 581: * Restore multicast settings ! 582: */ ! 583: _updateHashTableMask(); ! 584: ! 585: if ( isPromiscuous ) ! 586: { ! 587: _setPromiscuousMode(kIOEnetPromiscuousModeOn); ! 588: } ! 589: ! 590: /* ! 591: * Enable receiver and transmitter ! 592: */ ! 593: _startChip(); ! 594: _enableAdapterInterrupts(); ! 595: ! 596: /* ! 597: * Restart transmit DMA ! 598: */ ! 599: IODBDMAContinue( ioBaseEnetTxDMA ); ! 600: } ! 601: ! 602: /*------------------------------------------------------------------------- ! 603: * ! 604: * Orderly stop of receive DMA. ! 605: * ! 606: * ! 607: *-------------------------------------------------------------------------*/ ! 608: ! 609: void MaceEnet::_stopReceiveDMA() ! 610: { ! 611: u_int32_t dmaStatus; ! 612: u_int32_t dmaCmdPtr; ! 613: u_int32_t dmaIndex; ! 614: u_int8_t tmpBuf[16]; ! 615: u_int8_t *p = 0; ! 616: u_int8_t MacCCReg; ! 617: ! 618: /* ! 619: * Stop the receiver and allow any frame receive in progress to complete ! 620: */ ! 621: MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); ! 622: WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnRcv ); ! 623: IODelay( RECEIVE_QUIESCE_uS ); ! 624: ! 625: /* ! 626: * Capture channel status and pause the dma channel. ! 627: */ ! 628: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); ! 629: IODBDMAPause( ioBaseEnetRxDMA ); ! 630: ! 631: /* ! 632: * Read the command pointer and convert it to a byte offset into the ! 633: * DMA program. ! 634: */ ! 635: dmaCmdPtr = IOGetDBDMACommandPtr( ioBaseEnetRxDMA ); ! 636: dmaIndex = (dmaCmdPtr - rxDMACommandsPhys); ! 637: ! 638: /* ! 639: * If the channel status is DEAD, the DMA pointer is pointing to the ! 640: * next command ! 641: */ ! 642: if ( dmaStatus & kdbdmaDead ) ! 643: { ! 644: dmaIndex -= sizeof(IODBDMADescriptor); ! 645: } ! 646: ! 647: /* ! 648: * Convert channel program offset to command index ! 649: */ ! 650: dmaIndex = dmaIndex / sizeof(enet_dma_cmd_t); ! 651: if ( dmaIndex >= rxMaxCommand ) dmaIndex = 0; ! 652: ! 653: /* ! 654: * The DMA controller doesnt like being stopped before transferring any ! 655: * data. ! 656: * ! 657: * When we do so it pollutes up to 16-bytes aligned to the nearest (lower) ! 658: * 16-byte boundary. This corruption can be outside the data transfer area ! 659: * of the mbuf, so we capture and then restore these bytes after stopping ! 660: * the channel. ! 661: * ! 662: */ ! 663: if ( rxMbuf[dmaIndex] ) ! 664: { ! 665: p = mtod(rxMbuf[dmaIndex], u_int8_t *); ! 666: } ! 667: ! 668: (u_int32_t)p &= ~0x0f; ! 669: ! 670: if ( p ) ! 671: { ! 672: bcopy( p, tmpBuf, 16 ); ! 673: } ! 674: ! 675: IODBDMAReset( ioBaseEnetRxDMA ); ! 676: ! 677: if ( p ) ! 678: { ! 679: bcopy( tmpBuf, p, 16 ); ! 680: } ! 681: ! 682: /* ! 683: * Reset the dma channel pointer to the nearest command index ! 684: */ ! 685: dmaCmdPtr = rxDMACommandsPhys + sizeof(enet_dma_cmd_t) * dmaIndex; ! 686: IOSetDBDMACommandPtr( ioBaseEnetRxDMA, dmaCmdPtr); ! 687: } ! 688: ! 689: /*------------------------------------------------------------------------- ! 690: * ! 691: * ! 692: * ! 693: *-------------------------------------------------------------------------*/ ! 694: ! 695: void MaceEnet::_stopTransmitDMA() ! 696: { ! 697: u_int32_t dmaStatus; ! 698: u_int32_t dmaCmdPtr; ! 699: u_int32_t dmaIndex; ! 700: u_int8_t MacCCReg; ! 701: ! 702: /* ! 703: * Stop the transmitter and allow any frame transmit in progress to abort ! 704: */ ! 705: MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); ! 706: WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnXmt ); ! 707: IODelay( TRANSMIT_QUIESCE_uS ); ! 708: ! 709: /* ! 710: * Capture channel status and pause the dma channel. ! 711: */ ! 712: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetTxDMA ); ! 713: IODBDMAPause( ioBaseEnetTxDMA ); ! 714: ! 715: /* ! 716: * Read the command pointer and convert it to a byte offset into the ! 717: * DMA program. ! 718: */ ! 719: dmaCmdPtr = IOGetDBDMACommandPtr( ioBaseEnetTxDMA ); ! 720: dmaIndex = (dmaCmdPtr - txDMACommandsPhys); ! 721: ! 722: /* ! 723: * If the channel status is DEAD, the DMA pointer is pointing to the ! 724: * next command ! 725: */ ! 726: if ( dmaStatus & kdbdmaDead ) ! 727: { ! 728: dmaIndex -= sizeof(IODBDMADescriptor); ! 729: } ! 730: ! 731: /* ! 732: * Convert channel program offset to command index ! 733: */ ! 734: dmaIndex = dmaIndex / sizeof(enet_txdma_cmd_t); ! 735: if ( dmaIndex >= txMaxCommand ) dmaIndex = 0; ! 736: ! 737: IODBDMAReset( ioBaseEnetTxDMA ); ! 738: ! 739: /* ! 740: * Reset the dma channel pointer to the nearest command index ! 741: */ ! 742: dmaCmdPtr = txDMACommandsPhys + sizeof(enet_txdma_cmd_t) * dmaIndex; ! 743: IOSetDBDMACommandPtr( ioBaseEnetTxDMA, dmaCmdPtr ); ! 744: } ! 745: ! 746: /*------------------------------------------------------------------------- ! 747: * ! 748: * ! 749: * ! 750: *-------------------------------------------------------------------------*/ ! 751: ! 752: void MaceEnet::_disableAdapterInterrupts() ! 753: { ! 754: WriteMaceRegister( ioBaseEnet, kIntMask, 0xFF ); ! 755: } ! 756: ! 757: /*------------------------------------------------------------------------- ! 758: * ! 759: * _enableAdapterInterrupts ! 760: * ! 761: * It appears to make the Mace chip work properly with the DBDMA channel ! 762: * we need to leave the transmit interrupt unmasked at the chip. This ! 763: * is weird, but that's what happens when you try to glue a chip that ! 764: * wasn't intended to work with a DMA engine on to a DMA. ! 765: * ! 766: *-------------------------------------------------------------------------*/ ! 767: ! 768: void MaceEnet::_enableAdapterInterrupts() ! 769: { ! 770: u_int8_t regValue; ! 771: ! 772: regValue = ReadMaceRegister( ioBaseEnet, kIntMask ); ! 773: regValue &= ~kIntMaskXmtInt; ! 774: WriteMaceRegister( ioBaseEnet, kIntMask, regValue ); ! 775: IODelay(500); ! 776: ReadMaceRegister( ioBaseEnet, kXmtFS ); ! 777: ReadMaceRegister( ioBaseEnet, kIntReg ); ! 778: } ! 779: ! 780: /*------------------------------------------------------------------------- ! 781: * ! 782: * ! 783: * ! 784: *-------------------------------------------------------------------------*/ ! 785: ! 786: bool MaceEnet::_transmitPacket(struct mbuf * packet) ! 787: { ! 788: enet_dma_cmd_t tmpCommand; ! 789: u_int32_t i; ! 790: ! 791: /* ! 792: * Check for room on the transmit ring. There should always be space ! 793: * since it is the responsibility of the caller to verify this before ! 794: * calling _transmitPacket. ! 795: * ! 796: * Get a copy of the DMA transfer commands in a temporary buffer. ! 797: * The new DMA command is written into the channel program so that the ! 798: * command word for the old Stop command is overwritten last. This prevents ! 799: * the DMA engine from executing a partially written channel command. ! 800: */ ! 801: i = txCommandTail + 1; ! 802: if ( i >= txMaxCommand ) i = 0; ! 803: ! 804: if ( (i == txCommandHead) || ! 805: !_updateDescriptorFromMbuf(packet, &tmpCommand, false)) ! 806: { ! 807: IOLog("Mace: Freeing transmit packet eh?\n\r"); ! 808: if (packet != txDebuggerPkt) ! 809: freePacket(packet); ! 810: return false; ! 811: } ! 812: ! 813: /* ! 814: * txCommandTail points to the current DMA Stop command for the channel. ! 815: * We are now creating a new DMA Stop command in the next slot in the ! 816: * transmit ring. The previous DMA Stop command will be overwritten with ! 817: * the DMA commands to transfer the new mbuf. ! 818: */ ! 819: txDMACommands[i].desc_seg[0] = dbdmaCmd_Stop; ! 820: txDMACommands[i].desc_seg[1] = dbdmaCmd_Nop; ! 821: ! 822: flush_cache_v( (vm_offset_t)&txDMACommands[i], sizeof(enet_dma_cmd_t) ); ! 823: ! 824: bcopy( ((u_int32_t *)&tmpCommand)+1, ! 825: ((u_int32_t *)&txDMACommands[txCommandTail])+1, ! 826: sizeof(enet_dma_cmd_t)-sizeof(u_int32_t) ); ! 827: ! 828: flush_cache_v( (vm_offset_t)&txDMACommands[txCommandTail], ! 829: sizeof(enet_dma_cmd_t) ); ! 830: ! 831: txMbuf[txCommandTail] = packet; ! 832: txDMACommands[txCommandTail].desc_seg[0].operation = ! 833: tmpCommand.desc_seg[0].operation; ! 834: ! 835: flush_cache_v( (vm_offset_t)&txDMACommands[txCommandTail], ! 836: sizeof(enet_dma_cmd_t) ); ! 837: ! 838: /* ! 839: * Set the transmit tail to the new stop command. ! 840: */ ! 841: txCommandTail = i; ! 842: ! 843: /* ! 844: * Tap the DMA channel to wake it up ! 845: */ ! 846: IODBDMAContinue( ioBaseEnetTxDMA ); ! 847: ! 848: return true; ! 849: } ! 850: ! 851: /*------------------------------------------------------------------------- ! 852: * _receivePacket ! 853: * -------------- ! 854: * This routine runs the receiver in polled-mode (yuk!) for the kernel ! 855: * debugger. ! 856: * ! 857: * The _receivePackets allocate mbufs and pass them up the stack. The kernel ! 858: * debugger interface passes a buffer into us. To reconcile the two interfaces, ! 859: * we allow the receive routine to continue to allocate its own buffers and ! 860: * transfer any received data to the passed-in buffer. This is handled by ! 861: * _receivePacket calling _packetToDebugger. ! 862: *-------------------------------------------------------------------------*/ ! 863: ! 864: void MaceEnet::_receivePacket(void *pkt, unsigned int *pkt_len, ! 865: unsigned int timeout) ! 866: { ! 867: ns_time_t startTime; ! 868: ns_time_t currentTime; ! 869: u_int32_t elapsedTimeMS; ! 870: ! 871: if (!ready || !pkt || !pkt_len) ! 872: return; ! 873: ! 874: *pkt_len = 0; ! 875: ! 876: debuggerPkt = pkt; ! 877: debuggerPktSize = 0; ! 878: ! 879: _IOGetTimestamp(&startTime); ! 880: do ! 881: { ! 882: _receivePackets(true); ! 883: _IOGetTimestamp(¤tTime); ! 884: elapsedTimeMS = (currentTime - startTime) / (1000*1000); ! 885: } ! 886: while ( (debuggerPktSize == 0) && (elapsedTimeMS < timeout) ); ! 887: ! 888: *pkt_len = debuggerPktSize; ! 889: ! 890: return; ! 891: } ! 892: ! 893: /*------------------------------------------------------------------------- ! 894: * _packetToDebugger ! 895: * ----------------- ! 896: * This is called by _receivePackets when we are polling for kernel debugger ! 897: * packets. It copies the mbuf contents to the buffer passed by the debugger. ! 898: * It also sets the var debuggerPktSize which will break the polling loop. ! 899: *-------------------------------------------------------------------------*/ ! 900: ! 901: void MaceEnet::_packetToDebugger(struct mbuf * packet, u_int size) ! 902: { ! 903: debuggerPktSize = size; ! 904: bcopy( mtod(packet, char *), debuggerPkt, size ); ! 905: } ! 906: ! 907: /*------------------------------------------------------------------------- ! 908: * _sendPacket ! 909: * ----------- ! 910: * ! 911: * This routine runs the transmitter in polled-mode (yuk!) for the ! 912: * kernel debugger. ! 913: * ! 914: *-------------------------------------------------------------------------*/ ! 915: ! 916: void MaceEnet::_sendPacket(void *pkt, unsigned int pkt_len) ! 917: { ! 918: ns_time_t startTime; ! 919: ns_time_t currentTime; ! 920: u_int32_t elapsedTimeMS; ! 921: ! 922: if ( !ready || !pkt || (pkt_len > ETHERMAXPACKET)) ! 923: return; ! 924: ! 925: /* ! 926: * Wait for the transmit ring to empty ! 927: */ ! 928: _IOGetTimestamp(&startTime); ! 929: do ! 930: { ! 931: _transmitInterruptOccurred(true); ! 932: _IOGetTimestamp(¤tTime); ! 933: elapsedTimeMS = (currentTime - startTime) / (1000*1000); ! 934: } ! 935: while ( (txCommandHead != txCommandTail) && ! 936: (elapsedTimeMS < TX_KDB_TIMEOUT) ); ! 937: ! 938: if ( txCommandHead != txCommandTail ) ! 939: { ! 940: IOLog( "Mace: Polled tranmit timeout - 1\n\r"); ! 941: return; ! 942: } ! 943: ! 944: txDebuggerPkt->m_next = 0; ! 945: txDebuggerPkt->m_data = (caddr_t) pkt; ! 946: txDebuggerPkt->m_pkthdr.len = txDebuggerPkt->m_len = pkt_len; ! 947: ! 948: /* ! 949: * Send the debugger packet. txDebuggerPkt must not be freed by ! 950: * the transmit routine. ! 951: */ ! 952: _transmitPacket(txDebuggerPkt); ! 953: ! 954: /* ! 955: * Poll waiting for the transmit ring to empty again ! 956: */ ! 957: do ! 958: { ! 959: _transmitInterruptOccurred(true); ! 960: _IOGetTimestamp(¤tTime); ! 961: elapsedTimeMS = (currentTime - startTime) / (1000*1000); ! 962: } ! 963: while ( (txCommandHead != txCommandTail) && ! 964: (elapsedTimeMS < TX_KDB_TIMEOUT) ); ! 965: ! 966: if ( txCommandHead != txCommandTail ) ! 967: { ! 968: IOLog("Mace: Polled transmit timeout - 2\n\r"); ! 969: } ! 970: ! 971: return; ! 972: } ! 973: ! 974: /*------------------------------------------------------------------------- ! 975: * ! 976: * ! 977: * ! 978: *-------------------------------------------------------------------------*/ ! 979: ! 980: bool MaceEnet::_receiveInterruptOccurred() ! 981: { ! 982: return _receivePackets(false); ! 983: } ! 984: ! 985: /*------------------------------------------------------------------------- ! 986: * ! 987: * ! 988: * ! 989: *-------------------------------------------------------------------------*/ ! 990: ! 991: bool MaceEnet::_receivePackets(bool fDebugger) ! 992: { ! 993: enet_dma_cmd_t tmpCommand; ! 994: struct mbuf * packet; ! 995: u_int32_t i,j,last; ! 996: u_int32_t dmaChnlStatus; ! 997: int receivedFrameSize = 0; ! 998: u_int32_t dmaCount[2], dmaResid[2], dmaStatus[2]; ! 999: bool reusePkt; ! 1000: bool status; ! 1001: bool useNetif = !fDebugger && netifClient; ! 1002: bool packetsQueued = false; ! 1003: u_int8_t *rxFS = NULL; ! 1004: u_int32_t nextDesc; ! 1005: static const u_int32_t lastResetValue = (u_int32_t)(-1); ! 1006: ! 1007: last = lastResetValue; ! 1008: i = rxCommandHead; ! 1009: ! 1010: while ( 1 ) ! 1011: { ! 1012: reusePkt = false; ! 1013: ! 1014: /* ! 1015: * Purge cache references for the DBDMA entry we are about to look at. ! 1016: */ ! 1017: invalidate_cache_v((vm_offset_t)&rxDMACommands[i], ! 1018: sizeof(enet_dma_cmd_t)); ! 1019: ! 1020: /* ! 1021: * Collect the DMA residual counts/status for the two buffer segments. ! 1022: */ ! 1023: for ( j = 0; j < 2; j++ ) ! 1024: { ! 1025: dmaResid[j] = IOGetCCResult( &rxDMACommands[i].desc_seg[j] ); ! 1026: dmaStatus[j] = dmaResid[j] >> 16; ! 1027: dmaResid[j] &= 0x0000ffff; ! 1028: dmaCount[j] = IOGetCCOperation( &rxDMACommands[i].desc_seg[j] ) & ! 1029: kdbdmaReqCountMask; ! 1030: } ! 1031: ! 1032: #if 0 ! 1033: IOLog("Ethernet(Mace): Rx NetBuf[%2d] = %08x Resid[0] = %04x Status[0] = %04x Resid[1] = %04x Status[1] = %04x\n\r", ! 1034: i, (int)nb_map(rxNetbuf[i]), dmaResid[0], dmaStatus[0], dmaResid[1], dmaStatus[1] ); ! 1035: #endif ! 1036: ! 1037: /* ! 1038: * If the current entry has not been written, then stop at this entry ! 1039: */ ! 1040: if ( !((dmaStatus[0] & kdbdmaBt) || (dmaStatus[1] & kdbdmaActive)) ) ! 1041: { ! 1042: break; ! 1043: } ! 1044: ! 1045: /* ! 1046: * The Mace Ethernet controller appends four bytes to each receive ! 1047: * buffer containing the buffer size and receive frame status. ! 1048: * We locate these bytes by using the DMA residual counts. ! 1049: */ ! 1050: receivedFrameSize = dmaCount[0] - dmaResid[0] + dmaCount[1] - ! 1051: ((dmaStatus[0] & kdbdmaBt) ? dmaCount[1] : dmaResid[1]); ! 1052: ! 1053: if ( ( receivedFrameSize >= 4 ) && ! 1054: ( receivedFrameSize <= NETWORK_BUFSIZE ) ) ! 1055: { ! 1056: /* ! 1057: * Get the receive frame size as reported by the Mace controller ! 1058: */ ! 1059: ! 1060: rxFS = mtod(rxMbuf[i], u_int8_t *) + receivedFrameSize - 4; ! 1061: ! 1062: receivedFrameSize = (u_int16_t) rxFS[0] | ! 1063: (rxFS[1] & kRcvFS1RcvCnt) << 8; ! 1064: } ! 1065: ! 1066: /* ! 1067: * Reject packets that are runts or that have other mutations. ! 1068: */ ! 1069: if ( receivedFrameSize < (ETHERMINPACKET - ETHERCRC) || ! 1070: receivedFrameSize > (ETHERMAXPACKET + ETHERCRC) || ! 1071: (rxFS[1] & (kRcvFS1OFlo | kRcvFS1Clsn | kRcvFS1Fram | kRcvFS1FCS)) ! 1072: ) ! 1073: { ! 1074: if (useNetif) netStats->inputErrors++; ! 1075: reusePkt = true; ! 1076: } ! 1077: else if ( useNetif == false ) ! 1078: { ! 1079: /* ! 1080: * Always reuse packets in debugger mode. ! 1081: */ ! 1082: reusePkt = true; ! 1083: if (fDebugger) ! 1084: _packetToDebugger(rxMbuf[i], receivedFrameSize); ! 1085: } ! 1086: ! 1087: /* ! 1088: * Before we pass this packet up the networking stack. Make sure we ! 1089: * can get a replacement. Otherwise, hold on to the current packet and ! 1090: * increment the input error count. ! 1091: * Thanks Justin! ! 1092: */ ! 1093: ! 1094: packet = 0; ! 1095: ! 1096: if ( reusePkt == false ) ! 1097: { ! 1098: bool replaced; ! 1099: ! 1100: packet = replaceOrCopyPacket(&rxMbuf[i], receivedFrameSize, ! 1101: &replaced); ! 1102: ! 1103: reusePkt = true; ! 1104: ! 1105: if (packet && replaced) ! 1106: { ! 1107: status = _updateDescriptorFromMbuf(rxMbuf[i], ! 1108: &rxDMACommands[i], true); ! 1109: ! 1110: if (status) ! 1111: { ! 1112: reusePkt = false; ! 1113: } ! 1114: else ! 1115: { ! 1116: // Assume descriptor has not been corrupted. ! 1117: freePacket(rxMbuf[i]); // release new packet. ! 1118: rxMbuf[i] = packet; // get the old packet back. ! 1119: packet = 0; // pass up nothing. ! 1120: IOLog("Mace: _updateDescriptorFromMbuf error\n"); ! 1121: } ! 1122: } ! 1123: ! 1124: if (packet == 0) ! 1125: netStats->inputErrors++; ! 1126: } ! 1127: ! 1128: /* ! 1129: * If we are reusing the existing mbuf, then refurbish the existing ! 1130: * DMA command \ descriptors by clearing the status/residual count ! 1131: * fields. ! 1132: */ ! 1133: ! 1134: if ( reusePkt == true ) ! 1135: { ! 1136: for ( j=0; j < sizeof(enet_dma_cmd_t)/sizeof(IODBDMADescriptor); ! 1137: j++ ) ! 1138: { ! 1139: IOSetCCResult( &rxDMACommands[i].desc_seg[j], 0 ); ! 1140: } ! 1141: flush_cache_v( (vm_offset_t)&rxDMACommands[i], ! 1142: sizeof(enet_dma_cmd_t) ); ! 1143: } ! 1144: ! 1145: /* ! 1146: * Keep track of the last receive descriptor processed ! 1147: */ ! 1148: last = i; ! 1149: ! 1150: /* ! 1151: * Implement ring wrap-around ! 1152: */ ! 1153: if (++i >= rxMaxCommand) i = 0; ! 1154: ! 1155: /* ! 1156: * Early exit in debugger mode. ! 1157: */ ! 1158: if (fDebugger) ! 1159: { ! 1160: break; ! 1161: } ! 1162: ! 1163: /* ! 1164: * Transfer received to network stack. ! 1165: */ ! 1166: if (packet) ! 1167: { ! 1168: KERNEL_DEBUG(DBG_MACE_RXCOMPLETE | DBG_FUNC_NONE, (int) packet, ! 1169: (int)receivedFrameSize, 0, 0, 0 ); ! 1170: ! 1171: /* ! 1172: * The KDB lock must be held before calling this function. ! 1173: */ ! 1174: networkInterface->inputPacket(packet, receivedFrameSize, true); ! 1175: netStats->inputPackets++; ! 1176: packetsQueued = true; ! 1177: } ! 1178: } ! 1179: ! 1180: /* ! 1181: * OK...this is a little messy ! 1182: * ! 1183: * We just processed a bunch of DMA receive descriptors. We are going to ! 1184: * exchange the current DMA stop command (rxCommandTail) with the last ! 1185: * receive descriptor we processed (last). This will make these list of ! 1186: * descriptors we just processed available. If we processed no receive ! 1187: * descriptors on this call then skip this exchange. ! 1188: */ ! 1189: ! 1190: #if 0 ! 1191: IOLog("Mace: Prev - Rx Head = %2d Rx Tail = %2d Rx Last = %2d\n\r", ! 1192: rxCommandHead, rxCommandTail, last ); ! 1193: #endif ! 1194: ! 1195: if ( last != lastResetValue ) ! 1196: { ! 1197: /* ! 1198: * Save the contents of the last receive descriptor processed. ! 1199: */ ! 1200: packet = rxMbuf[last]; ! 1201: tmpCommand = rxDMACommands[last]; ! 1202: ! 1203: /* ! 1204: * Write a DMA stop command into this descriptor slot ! 1205: */ ! 1206: rxDMACommands[last].desc_seg[0] = dbdmaCmd_Stop; ! 1207: rxDMACommands[last].desc_seg[1] = dbdmaCmd_Nop; ! 1208: rxMbuf[last] = 0; ! 1209: ! 1210: flush_cache_v( (vm_offset_t)&rxDMACommands[last], ! 1211: sizeof(enet_dma_cmd_t) ); ! 1212: ! 1213: /* ! 1214: * Replace the previous DMA stop command with the last receive ! 1215: * descriptor processed. ! 1216: * ! 1217: * The new DMA command is written into the channel program so that the ! 1218: * command word for the old Stop command is overwritten last. This ! 1219: * prevents the DMA engine from executing a partially written channel ! 1220: * command. ! 1221: * ! 1222: * Note: When relocating the descriptor, we must update its branch ! 1223: * field to reflect its new location. ! 1224: */ ! 1225: nextDesc = rxDMACommandsPhys + (int)&rxDMACommands[rxCommandTail+1] - ! 1226: (int)rxDMACommands; ! 1227: IOSetCCCmdDep( &tmpCommand.desc_seg[0], nextDesc ); ! 1228: ! 1229: bcopy( (u_int32_t *)&tmpCommand+1, ! 1230: (u_int32_t *)&rxDMACommands[rxCommandTail]+1, ! 1231: sizeof(enet_dma_cmd_t)-sizeof(u_int32_t) ); ! 1232: ! 1233: flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], ! 1234: sizeof(enet_dma_cmd_t) ); ! 1235: ! 1236: rxMbuf[rxCommandTail] = packet; ! 1237: ! 1238: rxDMACommands[rxCommandTail].desc_seg[0].operation = ! 1239: tmpCommand.desc_seg[0].operation; ! 1240: ! 1241: flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], ! 1242: sizeof(IODBDMADescriptor) ); ! 1243: ! 1244: /* ! 1245: * Update rxCommmandTail to point to the new Stop command. Update ! 1246: * rxCommandHead to point to the next slot in the ring past the Stop ! 1247: * command ! 1248: */ ! 1249: rxCommandTail = last; ! 1250: rxCommandHead = i; ! 1251: } ! 1252: ! 1253: /* ! 1254: * The DMA channel has a nasty habit of shutting down when there is a ! 1255: * non-recoverable error on receive. We get no interrupt for this since ! 1256: * the channel shuts down before the descriptor that causes the host ! 1257: * interrupt is executed. ! 1258: * ! 1259: * We check if the channel is DEAD by checking the channel status reg. ! 1260: * Also, the watchdog timer can force receiver interrupt servicing based ! 1261: * on detecting that the receive DMA is DEAD. ! 1262: */ ! 1263: dmaChnlStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); ! 1264: if ( dmaChnlStatus & kdbdmaDead ) ! 1265: { ! 1266: /* ! 1267: * Read log error ! 1268: */ ! 1269: if (useNetif) netStats->inputErrors++; ! 1270: IOLog( "Mace: Rx DMA Error - Status = %04x\n", dmaChnlStatus ); ! 1271: ! 1272: /* ! 1273: * Reset and reinitialize chip ! 1274: */ ! 1275: _restartChip(); // This must not block in debugger mode. ! 1276: } ! 1277: else ! 1278: { ! 1279: /* ! 1280: * Tap the DMA to wake it up ! 1281: */ ! 1282: IODBDMAContinue( ioBaseEnetRxDMA ); ! 1283: } ! 1284: ! 1285: #if 0 ! 1286: IOLog( "Mace: New - Rx Head = %2d Rx Tail = %2d\n\r", ! 1287: rxCommandHead, rxCommandTail ); ! 1288: #endif ! 1289: ! 1290: return packetsQueued; ! 1291: } ! 1292: ! 1293: /*------------------------------------------------------------------------- ! 1294: * ! 1295: * ! 1296: * ! 1297: *-------------------------------------------------------------------------*/ ! 1298: ! 1299: bool MaceEnet::_transmitInterruptOccurred(bool fDebugger = false) ! 1300: { ! 1301: u_int32_t dmaStatus; ! 1302: u_int32_t xmtFS; ! 1303: bool fServiced = false; ! 1304: bool useNetif = !fDebugger && netifClient; ! 1305: ! 1306: // Set the debugTxPoll flag to indicate the debugger was active ! 1307: // and some cleanup may be needed when the driver returns to ! 1308: // normal operation. ! 1309: // ! 1310: if (fDebugger) ! 1311: debugTxPoll = true; ! 1312: ! 1313: while ( 1 ) ! 1314: { ! 1315: /* ! 1316: * Purge cache references for the DBDMA entry we are about to look at. ! 1317: */ ! 1318: invalidate_cache_v((vm_offset_t)&txDMACommands[txCommandHead], ! 1319: sizeof(enet_txdma_cmd_t)); ! 1320: ! 1321: /* ! 1322: * Check the status of the last descriptor in this entry to see if ! 1323: * the DMA engine completed this entry. ! 1324: */ ! 1325: dmaStatus = IOGetCCResult( ! 1326: &txDMACommands[txCommandHead].desc_seg[3] ) >> 16; ! 1327: ! 1328: if ( !(dmaStatus & kdbdmaActive) ) ! 1329: { ! 1330: break; ! 1331: } ! 1332: ! 1333: fServiced = true; ! 1334: ! 1335: /* ! 1336: * Reset the status word for the entry we are about to process ! 1337: */ ! 1338: IOSetCCResult( &txDMACommands[txCommandHead].desc_seg[3], 0 ); ! 1339: ! 1340: flush_cache_v( (vm_offset_t) &txDMACommands[txCommandHead].desc_seg[3], ! 1341: sizeof(IODBDMADescriptor) ); ! 1342: ! 1343: /* ! 1344: * This DMA descriptor read the transmit frame status. See what it has ! 1345: * to tell us. ! 1346: */ ! 1347: xmtFS = IOGetCCCmdDep( &txDMACommands[txCommandHead].desc_seg[2] ); ! 1348: if ( useNetif && (xmtFS & kXmtFSXmtSV) ) ! 1349: { ! 1350: if (xmtFS & (kXmtFSUFlo | kXmtFSLCol | kXmtFSRtry | kXmtFSLCar) ) ! 1351: { ! 1352: netStats->outputErrors++; ! 1353: } ! 1354: else ! 1355: { ! 1356: netStats->outputPackets++; ! 1357: } ! 1358: ! 1359: if (xmtFS & (kXmtFSOne | kXmtFSMore) ) ! 1360: { ! 1361: netStats->collisions++; ! 1362: } ! 1363: } ! 1364: ! 1365: /* ! 1366: * Free the mbuf we just transmitted. ! 1367: */ ! 1368: KERNEL_DEBUG(DBG_MACE_TXCOMPLETE | DBG_FUNC_NONE, ! 1369: (int) txMbuf[txCommandHead], ! 1370: (int) txMbuf[txCommandHead]->m_pkthdr.len, 0, 0, 0 ); ! 1371: ! 1372: if (txMbuf[txCommandHead] != txDebuggerPkt) ! 1373: { ! 1374: if ( fDebugger ) ! 1375: { ! 1376: // ! 1377: // While in debugger mode, do not touch the mbuf pool. ! 1378: // Queue any used mbufs to a local queue. This queue ! 1379: // will get flushed after we exit from debugger mode. ! 1380: // ! 1381: // During continuous debugger transmission and ! 1382: // interrupt polling, we expect only the txDebuggerPkt ! 1383: // to show up on the transmit mbuf ring. ! 1384: // ! 1385: debugQueue->enqueue( txMbuf[txCommandHead] ); ! 1386: } ! 1387: else ! 1388: { ! 1389: freePacket( txMbuf[txCommandHead] ); ! 1390: } ! 1391: } ! 1392: ! 1393: txMbuf[txCommandHead] = 0; ! 1394: ! 1395: if ( ++txCommandHead >= txMaxCommand ) txCommandHead = 0; ! 1396: } ! 1397: ! 1398: /* ! 1399: * The DMA channel has a nasty habit of shutting down when there is ! 1400: * non-recoverable error on transmit. We get no interrupt for this since ! 1401: * the channel shuts down before the descriptor that causes the host ! 1402: * interrupt is executed. ! 1403: * ! 1404: * We check if the channel is DEAD by checking the channel status reg. ! 1405: * Also, the watchdog timer can force a transmitter reset if it sees no ! 1406: * interrupt activity for to consecutive timeout intervals. ! 1407: */ ! 1408: ! 1409: dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetTxDMA ); ! 1410: if ( (dmaStatus & kdbdmaDead) || (txWDForceReset == true) ) ! 1411: { ! 1412: /* ! 1413: * Read the transmit frame status and log error ! 1414: */ ! 1415: xmtFS = ReadMaceRegister( ioBaseEnet, kXmtFS ); ! 1416: if (useNetif) netStats->outputErrors++; ! 1417: IOLog( "Mace: Tx DMA Error - Status = %04x FS = %02x\n\r", ! 1418: dmaStatus, xmtFS); ! 1419: ! 1420: /* ! 1421: * Reset and reinitialize chip ! 1422: */ ! 1423: _restartChip(); ! 1424: ! 1425: txWDForceReset = false; ! 1426: fServiced = true; ! 1427: } ! 1428: ! 1429: return fServiced; ! 1430: } ! 1431: ! 1432: /*------------------------------------------------------------------------- ! 1433: * ! 1434: * ! 1435: * ! 1436: *-------------------------------------------------------------------------*/ ! 1437: ! 1438: /* ! 1439: * Breaks up an ethernet data buffer into two physical chunks. We know that ! 1440: * the buffer can't straddle more than two pages. If the content of paddr2 is ! 1441: * zero this means that all of the buffer lies in one physical page. Note ! 1442: * that we use the fact that tx and rx descriptors have the same size and ! 1443: * same layout of relevent fields (data address and count). ! 1444: */ ! 1445: bool ! 1446: MaceEnet::_updateDescriptorFromMbuf(struct mbuf * m, enet_dma_cmd_t *desc, ! 1447: bool isReceive) ! 1448: { ! 1449: u_int32_t nextDesc = 0; ! 1450: int segments; ! 1451: struct IOPhysicalSegment segVector[2]; ! 1452: ! 1453: /* ! 1454: * Although coalescing is always enabled, it cannot occur ! 1455: * while the driver is in debugger mode. ! 1456: */ ! 1457: segments = mbufCursor->getPhysicalSegmentsWithCoalesce(m, segVector); ! 1458: ! 1459: if ((!segments) || (segments > 2)) { ! 1460: IOLog("Mace: _updateDescriptorFromMbuf error, %d segments\n", ! 1461: segments); ! 1462: return false; ! 1463: } ! 1464: ! 1465: if ( segments == 1 ) ! 1466: { ! 1467: IOMakeDBDMADescriptor( (&desc->desc_seg[0]), ! 1468: ((isReceive) ? kdbdmaInputLast : kdbdmaOutputLast), ! 1469: (kdbdmaKeyStream0), ! 1470: (kdbdmaIntNever), ! 1471: (kdbdmaBranchNever), ! 1472: ((isReceive) ? kdbdmaWaitNever : ! 1473: kdbdmaWaitIfFalse), ! 1474: (segVector[0].length), ! 1475: (segVector[0].location) ); ! 1476: ! 1477: desc->desc_seg[1] = (isReceive) ? dbdmaCmd_NopWInt : dbdmaCmd_Nop; ! 1478: } ! 1479: else ! 1480: { ! 1481: if ( isReceive ) ! 1482: { ! 1483: nextDesc = rxDMACommandsPhys + (int)desc - (int)rxDMACommands + ! 1484: sizeof(enet_dma_cmd_t); ! 1485: } ! 1486: ! 1487: IOMakeDBDMADescriptorDep( (&desc->desc_seg[0]), ! 1488: ((isReceive) ? kdbdmaInputMore : kdbdmaOutputMore), ! 1489: (kdbdmaKeyStream0), ! 1490: ((isReceive) ? kdbdmaIntIfTrue : kdbdmaIntNever), ! 1491: ((isReceive) ? kdbdmaBranchIfTrue : ! 1492: kdbdmaBranchNever), ! 1493: (kdbdmaWaitNever), ! 1494: (segVector[0].length), ! 1495: (segVector[0].location), ! 1496: nextDesc ); ! 1497: ! 1498: IOMakeDBDMADescriptor( (&desc->desc_seg[1]), ! 1499: ((isReceive) ? kdbdmaInputLast : kdbdmaOutputLast), ! 1500: (kdbdmaKeyStream0), ! 1501: ((isReceive) ? kdbdmaIntAlways : kdbdmaIntNever), ! 1502: (kdbdmaBranchNever), ! 1503: ((isReceive) ? kdbdmaWaitNever : ! 1504: kdbdmaWaitIfFalse), ! 1505: (segVector[1].length), ! 1506: (segVector[1].location) ); ! 1507: } ! 1508: ! 1509: flush_cache_v( (vm_offset_t)desc, sizeof(enet_dma_cmd_t) ); ! 1510: ! 1511: return true; ! 1512: } ! 1513: ! 1514: ! 1515: #ifdef DEBUG ! 1516: /* ! 1517: * Useful for testing. ! 1518: */ ! 1519: ! 1520: void MaceEnet::_dumpDesc(void * addr, u_int32_t size) ! 1521: { ! 1522: u_int32_t i; ! 1523: unsigned long *p; ! 1524: vm_offset_t paddr; ! 1525: ! 1526: _IOPhysicalFromVirtual( (vm_offset_t) addr, (vm_offset_t *)&paddr ); ! 1527: ! 1528: p = (unsigned long *)addr; ! 1529: ! 1530: for ( i=0; i < size/sizeof(IODBDMADescriptor); i++, p+=4, ! 1531: paddr+=sizeof(IODBDMADescriptor) ) ! 1532: { ! 1533: IOLog("Ethernet(Mace): %08x(v) %08x(p): %08x %08x %08x %08x\n", ! 1534: (int)p, ! 1535: (int)paddr, ! 1536: (int)OSReadSwapInt32(p, 0), (int)OSReadSwapInt32(p, 4), ! 1537: (int)OSReadSwapInt32(p, 8), (int)OSReadSwapInt32(p, 12) ); ! 1538: } ! 1539: IOLog("\n"); ! 1540: } ! 1541: ! 1542: void MaceEnet::_dumpRegisters() ! 1543: { ! 1544: u_int8_t dataValue; ! 1545: ! 1546: IOLog("\nEthernet(Mace): IO Address = %08x", (int)ioBaseEnet ); ! 1547: ! 1548: dataValue = ReadMaceRegister(ioBaseEnet, kXmtFC); ! 1549: IOLog("\nEthernet(Mace): Read Register %04x Transmit Frame Control = %02x", kXmtFC, dataValue ); ! 1550: ! 1551: dataValue = ReadMaceRegister(ioBaseEnet, kXmtFS); ! 1552: IOLog("\nEthernet(Mace): Read Register %04x Transmit Frame Status = %02x", kXmtFS, dataValue ); ! 1553: ! 1554: dataValue = ReadMaceRegister(ioBaseEnet, kXmtRC); ! 1555: IOLog("\nEthernet(Mace): Read Register %04x Transmit Retry Count = %02x", kXmtRC, dataValue ); ! 1556: ! 1557: dataValue = ReadMaceRegister(ioBaseEnet, kRcvFC); ! 1558: IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Control = %02x", kRcvFC, dataValue ); ! 1559: ! 1560: dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS0); ! 1561: IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 0 = %02x", kRcvFS0, dataValue ); ! 1562: dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS1); ! 1563: IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 1 = %02x", kRcvFS1, dataValue ); ! 1564: dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS2); ! 1565: IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 2 = %02x", kRcvFS2, dataValue ); ! 1566: dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS3); ! 1567: IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 3 = %02x", kRcvFS3, dataValue ); ! 1568: ! 1569: dataValue = ReadMaceRegister(ioBaseEnet, kFifoFC); ! 1570: IOLog("\nEthernet(Mace): Read Register %04x FIFO Frame Count = %02x", kFifoFC, dataValue ); ! 1571: ! 1572: dataValue = ReadMaceRegister(ioBaseEnet, kIntReg); ! 1573: IOLog("\nEthernet(Mace): Read Register %04x Interrupt Register = %02x", kIntReg, dataValue ); ! 1574: ! 1575: dataValue = ReadMaceRegister(ioBaseEnet, kIntMask); ! 1576: IOLog("\nEthernet(Mace): Read Register %04x Interrupt Mask Register = %02x", kIntMask, dataValue ); ! 1577: ! 1578: dataValue = ReadMaceRegister(ioBaseEnet, kPollReg); ! 1579: IOLog("\nEthernet(Mace): Read Register %04x Poll Register = %02x", kPollReg, dataValue ); ! 1580: ! 1581: dataValue = ReadMaceRegister(ioBaseEnet, kBIUCC); ! 1582: IOLog("\nEthernet(Mace): Read Register %04x BUI Configuration Control = %02x", kBIUCC, dataValue ); ! 1583: ! 1584: dataValue = ReadMaceRegister(ioBaseEnet, kFifoCC); ! 1585: IOLog("\nEthernet(Mace): Read Register %04x FIFO Configuration Control = %02x", kFifoCC, dataValue ); ! 1586: ! 1587: dataValue = ReadMaceRegister(ioBaseEnet, kMacCC); ! 1588: IOLog("\nEthernet(Mace): Read Register %04x MAC Configuration Control = %02x", kMacCC, dataValue ); ! 1589: ! 1590: dataValue = ReadMaceRegister(ioBaseEnet, kPLSCC); ! 1591: IOLog("\nEthernet(Mace): Read Register %04x PLS Configuration Contro = %02x", kPLSCC, dataValue ); ! 1592: ! 1593: dataValue = ReadMaceRegister(ioBaseEnet, kPHYCC); ! 1594: IOLog("\nEthernet(Mace): Read Register %04x PHY Configuration Control = %02x", kPHYCC, dataValue ); ! 1595: ! 1596: dataValue = ReadMaceRegister(ioBaseEnet, kMaceChipId0); ! 1597: IOLog("\nEthernet(Mace): Read Register %04x MACE ChipID Register 7:0 = %02x", kMaceChipId0, dataValue ); ! 1598: ! 1599: dataValue = ReadMaceRegister(ioBaseEnet, kMaceChipId1); ! 1600: IOLog("\nEthernet(Mace): Read Register %04x MACE ChipID Register 15:8 = %02x", kMaceChipId1, dataValue ); ! 1601: ! 1602: dataValue = ReadMaceRegister(ioBaseEnet, kMPC); ! 1603: IOLog("\nEthernet(Mace): Read Register %04x Missed Packet Count = %02x", kMPC, dataValue ); ! 1604: ! 1605: dataValue = ReadMaceRegister(ioBaseEnet, kUTR); ! 1606: IOLog("\nEthernet(Mace): Read Register %04x User Test Register = %02x", kUTR, dataValue ); ! 1607: IOLog("\nEthernet(Mace): -------------------------------------------------------\n" ); ! 1608: } ! 1609: #endif DEBUG ! 1610: ! 1611: ! 1612: /*------------------------------------------------------------------------- ! 1613: * ! 1614: * ! 1615: * ! 1616: *-------------------------------------------------------------------------*/ ! 1617: ! 1618: IOReturn MaceEnet::getHardwareAddress(enet_addr_t *ea) ! 1619: { ! 1620: unsigned char data; ! 1621: ! 1622: for (UInt i = 0; i < sizeof(*ea); i++) ! 1623: { ! 1624: data = ((unsigned char *)ioBaseEnetROM)[i << 4]; ! 1625: ea->ea_byte[i] = reverseBitOrder(data); ! 1626: } ! 1627: ! 1628: return kIOReturnSuccess; ! 1629: } ! 1630: ! 1631: /*------------------------------------------------------------------------- ! 1632: * ! 1633: * ! 1634: * ! 1635: *-------------------------------------------------------------------------*/ ! 1636: ! 1637: #define ENET_CRCPOLY 0x04c11db7 ! 1638: ! 1639: /* Real fast bit-reversal algorithm, 6-bit values */ ! 1640: static int reverse6[] = ! 1641: { 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, ! 1642: 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, ! 1643: 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, ! 1644: 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, ! 1645: 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, ! 1646: 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, ! 1647: 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, ! 1648: 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f ! 1649: }; ! 1650: ! 1651: static u_int32_t crc416(unsigned int current, unsigned short nxtval ) ! 1652: { ! 1653: register unsigned int counter; ! 1654: register int highCRCBitSet, lowDataBitSet; ! 1655: ! 1656: /* Swap bytes */ ! 1657: nxtval = ((nxtval & 0x00FF) << 8) | (nxtval >> 8); ! 1658: ! 1659: /* Compute bit-by-bit */ ! 1660: for (counter = 0; counter != 16; ++counter) ! 1661: { /* is high CRC bit set? */ ! 1662: if ((current & 0x80000000) == 0) ! 1663: highCRCBitSet = 0; ! 1664: else ! 1665: highCRCBitSet = 1; ! 1666: ! 1667: current = current << 1; ! 1668: ! 1669: if ((nxtval & 0x0001) == 0) ! 1670: lowDataBitSet = 0; ! 1671: else ! 1672: lowDataBitSet = 1; ! 1673: ! 1674: nxtval = nxtval >> 1; ! 1675: ! 1676: /* do the XOR */ ! 1677: if (highCRCBitSet ^ lowDataBitSet) ! 1678: current = current ^ ENET_CRCPOLY; ! 1679: } ! 1680: return current; ! 1681: } ! 1682: ! 1683: /*------------------------------------------------------------------------- ! 1684: * ! 1685: * ! 1686: * ! 1687: *-------------------------------------------------------------------------*/ ! 1688: ! 1689: static u_int32_t mace_crc(unsigned short *address) ! 1690: { ! 1691: register u_int32_t newcrc; ! 1692: ! 1693: newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ ! 1694: newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ ! 1695: newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ ! 1696: ! 1697: return (newcrc); ! 1698: } ! 1699: ! 1700: /* ! 1701: * Clear the hash table filter. ! 1702: * ! 1703: */ ! 1704: void MaceEnet::_resetHashTableMask() ! 1705: { ! 1706: bzero(hashTableUseCount, sizeof(hashTableUseCount)); ! 1707: bzero(hashTableMask, sizeof(hashTableMask)); ! 1708: } ! 1709: ! 1710: /* ! 1711: * Add requested mcast addr to Mace's hash table filter. ! 1712: * ! 1713: */ ! 1714: void MaceEnet::_addToHashTableMask(u_int8_t *addr) ! 1715: { ! 1716: u_int32_t crc; ! 1717: u_int8_t mask; ! 1718: ! 1719: crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ ! 1720: crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ ! 1721: if (hashTableUseCount[crc]++) ! 1722: return; /* This bit is already set */ ! 1723: mask = crc % 8; ! 1724: mask = (unsigned char) 1 << mask; ! 1725: hashTableMask[crc/8] |= mask; ! 1726: } ! 1727: ! 1728: /*------------------------------------------------------------------------- ! 1729: * ! 1730: * ! 1731: * ! 1732: *-------------------------------------------------------------------------*/ ! 1733: ! 1734: void MaceEnet::_removeFromHashTableMask(u_int8_t *addr) ! 1735: { ! 1736: unsigned int crc; ! 1737: unsigned char mask; ! 1738: ! 1739: /* Now, delete the address from the filter copy, as indicated */ ! 1740: crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ ! 1741: crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ ! 1742: if (hashTableUseCount[crc] == 0) ! 1743: return; /* That bit wasn't in use! */ ! 1744: ! 1745: if (--hashTableUseCount[crc]) ! 1746: return; /* That bit is still in use */ ! 1747: ! 1748: mask = crc % 8; ! 1749: mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */ ! 1750: hashTableMask[crc/8] &= mask; ! 1751: } ! 1752: ! 1753: /* ! 1754: * Sync the adapter with the software copy of the multicast mask ! 1755: * (logical address filter). ! 1756: */ ! 1757: void MaceEnet::_updateHashTableMask() ! 1758: { ! 1759: u_int8_t status; ! 1760: u_int32_t i; ! 1761: u_int8_t *p; ! 1762: u_int8_t MacCCReg; ! 1763: ! 1764: // Stop the receiver before changing the filter. ! 1765: // ! 1766: MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); ! 1767: WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnRcv ); ! 1768: IODelay( RECEIVE_QUIESCE_uS ); ! 1769: ! 1770: if ( chipId != kMaceRevisionA2 ) ! 1771: { ! 1772: WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACLogAddr ); ! 1773: do ! 1774: { ! 1775: status = ReadMaceRegister( ioBaseEnet, kIAC ); ! 1776: } ! 1777: while( status & kIACAddrChg ); ! 1778: } ! 1779: else ! 1780: { ! 1781: WriteMaceRegister( ioBaseEnet, kIAC, kIACLogAddr ); ! 1782: } ! 1783: ! 1784: p = (u_int8_t *) hashTableMask; ! 1785: for (i = 0; i < 8; i++, p++ ) ! 1786: { ! 1787: WriteMaceRegister( ioBaseEnet, kLADRF, *p ); ! 1788: } ! 1789: ! 1790: // Restore the engine's state. ! 1791: // ! 1792: WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg ); ! 1793: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.