/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1995-1996 NeXT Software, Inc. * * Implementation for hardware dependent (relatively) code * for the Mace Ethernet controller. * * HISTORY * * 10-Sept-97 * Created. * */ #include #include #include #include "MaceEnetPrivate.h" /***************************************************************************** * * Hacks. */ typedef unsigned long long ns_time_t; /* nanoseconds! */ #define NSEC_PER_SEC 1000000000 static void _IOGetTimestamp(ns_time_t *nsp) { mach_timespec_t now; IOGetTime(&now); *nsp = ((ns_time_t)now.tv_sec * NSEC_PER_SEC) + now.tv_nsec; } /* * Find a physical address (if any) for the specified virtual address. * * Note: what about vm_offset_t kvtophys(vm_offset_t va) */ static IOReturn _IOPhysicalFromVirtual( vm_address_t virtualAddress, unsigned *physicalAddress) { *physicalAddress = pmap_extract(kernel_pmap, virtualAddress); if(*physicalAddress == 0) { return kIOReturnBadArgument; } else { return kIOReturnSuccess; } } // From osfmk/ppc/pmap.h // extern "C" { extern void invalidate_dcache(vm_offset_t va, unsigned length, boolean_t phys); extern void flush_dcache(vm_offset_t va, unsigned length, boolean_t phys); } static inline void invalidate_cache_v(vm_offset_t va, unsigned length) { invalidate_dcache(va, length, 0); } static inline void flush_cache_v(vm_offset_t va, unsigned length) { flush_dcache(va, length, 0); } /****************************************************************************/ static IODBDMADescriptor dbdmaCmd_Nop; static IODBDMADescriptor dbdmaCmd_NopWInt; static IODBDMADescriptor dbdmaCmd_LoadXFS; static IODBDMADescriptor dbdmaCmd_LoadIntwInt; static IODBDMADescriptor dbdmaCmd_Stop; static IODBDMADescriptor dbdmaCmd_Branch; static u_int8_t reverseBitOrder(u_int8_t data ) { u_int8_t val = 0; int i; for ( i=0; i < 8; i++ ) { val <<= 1; if (data & 1) val |= 1; data >>= 1; } return( val ); } /* * Function: IOMallocPage * * Purpose: * Returns a pointer to a page-aligned memory block of size >= PAGE_SIZE * * Return: * Actual pointer and size of block returned in actual_ptr and actual_size. * Use these as arguments to kfree: kfree(*actual_ptr, *actual_size); */ static void * IOMallocPage(int request_size, void ** actual_ptr, u_int * actual_size) { void * mem_ptr; *actual_size = round_page(request_size) + PAGE_SIZE; mem_ptr = IOMalloc(*actual_size); if (mem_ptr == NULL) return NULL; *actual_ptr = mem_ptr; return ((void *)round_page(mem_ptr)); } /* * Private functions */ bool MaceEnet::_allocateMemory() { u_int32_t i, n; unsigned char * virtAddr; u_int32_t physBase; u_int32_t physAddr; u_int32_t dbdmaSize; /* * Calculate total space for DMA channel commands */ dbdmaSize = round_page( RX_RING_LENGTH * sizeof(enet_dma_cmd_t) + TX_RING_LENGTH * sizeof(enet_txdma_cmd_t) + 2 * sizeof(IODBDMADescriptor) ); /* * Allocate required memory */ dmaMemory.size = dbdmaSize; dmaMemory.ptr = (void *)IOMallocPage( dmaMemory.size, &dmaMemory.ptrReal, &dmaMemory.sizeReal ); dmaCommands = (unsigned char *) dmaMemory.ptr; if (!dmaCommands) { IOLog( "Mace: Cant allocate channel DBDMA commands\n\r" ); return false; } /* * If we needed more than one page, then make sure we received * contiguous memory. */ n = (dbdmaSize - PAGE_SIZE) / PAGE_SIZE; _IOPhysicalFromVirtual((vm_address_t) dmaCommands, &physBase ); virtAddr = (unsigned char *) dmaCommands; for( i=0; i < n; i++, virtAddr += PAGE_SIZE ) { _IOPhysicalFromVirtual( (vm_address_t) virtAddr, &physAddr ); if (physAddr != (physBase + i * PAGE_SIZE) ) { IOLog("Mace: Cannot allocate contiguous memory for DBDMA " "commands\n"); return false; } } /* * Setup the receive ring pointers */ rxDMACommands = (enet_dma_cmd_t *)dmaCommands; rxMaxCommand = RX_RING_LENGTH; /* * Setup the transmit ring pointers */ txDMACommands = (enet_txdma_cmd_t *)( dmaCommands + RX_RING_LENGTH * sizeof(enet_dma_cmd_t) + sizeof(IODBDMADescriptor)); txMaxCommand = TX_RING_LENGTH; /* * Setup pre-initialized DBDMA commands */ IOMakeDBDMADescriptor( (&dbdmaCmd_Nop), kdbdmaNop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0 ); IOMakeDBDMADescriptor( (&dbdmaCmd_NopWInt), kdbdmaNop, kdbdmaKeyStream0, kdbdmaIntAlways, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0 ); UInt32 ioBaseEnetPhys = maps[MEMORY_MAP_ENET_INDEX]->getPhysicalAddress(); IOMakeDBDMADescriptor( (&dbdmaCmd_LoadXFS), kdbdmaLoadQuad, kdbdmaKeySystem, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 1, ((int)ioBaseEnetPhys + kXmtFS) ); IOMakeDBDMADescriptor( (&dbdmaCmd_LoadIntwInt), kdbdmaLoadQuad, kdbdmaKeySystem, kdbdmaIntAlways, kdbdmaBranchNever, kdbdmaWaitNever, 1, ((int)ioBaseEnetPhys + kIntReg) ); IOMakeDBDMADescriptor( (&dbdmaCmd_Stop), kdbdmaStop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0 ); IOMakeDBDMADescriptor( (&dbdmaCmd_Branch), kdbdmaNop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchAlways, kdbdmaWaitNever, 0, 0 ); return true; } /*------------------------------------------------------------------------- * * Setup the Transmit Ring * ----------------------- * Each transmit ring entry consists of two words to transmit data from buffer * segments (possibly) spanning a page boundary. This is followed by two DMA * commands which read transmit frame status and interrupt status from the Mace * chip. The last DMA command in each transmit ring entry generates a host * interrupt. The last entry in the ring is followed by a DMA branch to the * first entry. *-------------------------------------------------------------------------*/ bool MaceEnet::_initTxRing() { bool kr; u_int32_t i; /* * Clear the transmit DMA command memory */ bzero( (void *)txDMACommands, sizeof(enet_txdma_cmd_t) * txMaxCommand); txCommandHead = 0; txCommandTail = 0; /* * DMA Channel commands 2,3 are the same for all DBDMA entries on transmit. * Initialize them now. */ for( i=0; i < txMaxCommand; i++ ) { txDMACommands[i].desc_seg[2] = dbdmaCmd_LoadXFS; txDMACommands[i].desc_seg[3] = dbdmaCmd_LoadIntwInt; } /* * Put a DMA Branch command after the last entry in the transmit ring. * Set the branch address to the physical address of the start of the * transmit ring. */ txDMACommands[txMaxCommand].desc_seg[0] = dbdmaCmd_Branch; kr = _IOPhysicalFromVirtual( (vm_address_t) txDMACommands, (u_int32_t *)&txDMACommandsPhys ); if ( kr != kIOReturnSuccess ) { IOLog("Mace: Bad Tx DBDMA command buf - %08x\n\r", (u_int32_t)txDMACommands ); } IOSetCCCmdDep( &txDMACommands[txMaxCommand].desc_seg[0], txDMACommandsPhys ); /* * Set the Transmit DMA Channel pointer to the first entry in the * transmit ring. */ IOSetDBDMACommandPtr( ioBaseEnetTxDMA, txDMACommandsPhys ); /* * Push the DMA channel words into physical memory. */ flush_cache_v( (vm_offset_t)txDMACommands, txMaxCommand*sizeof(enet_txdma_cmd_t) + sizeof(IODBDMADescriptor)); return true; } /*------------------------------------------------------------------------- * * Setup the Receive ring * ---------------------- * Each receive ring entry consists of two DMA commands to receive data * into a network buffer (possibly) spanning a page boundary. The second * DMA command in each entry generates a host interrupt. * The last entry in the ring is followed by a DMA branch to the first * entry. * *-------------------------------------------------------------------------*/ bool MaceEnet::_initRxRing() { u_int32_t i; bool status; IOReturn kr; /* * Clear the receive DMA command memory */ bzero( (void *)rxDMACommands, sizeof(enet_dma_cmd_t) * rxMaxCommand); kr = _IOPhysicalFromVirtual( (vm_address_t) rxDMACommands, (u_int32_t *)&rxDMACommandsPhys ); if ( kr != kIOReturnSuccess ) { IOLog("Mace: Bad Rx DBDMA command buf - %08x\n\r", (u_int32_t)rxDMACommands ); return false; } /* * Allocate a receive buffer for each entry in the Receive ring */ for (i = 0; i < rxMaxCommand-1; i++) { if (rxMbuf[i] == 0) { rxMbuf[i] = allocatePacket(NETWORK_BUFSIZE); if (!rxMbuf[i]) { IOLog("Mace: allocatePacket failed in _initRxRing()\n\r"); return false; } } /* * Set the DMA commands for the ring entry to transfer data to the * mbuf. */ status = _updateDescriptorFromMbuf(rxMbuf[i], &rxDMACommands[i], true); if (status == false) { IOLog("Mace: Cant map mbuf to physical memory in _initRxRing\n\r"); return false; } } /* * Set the receive queue head to point to the first entry in the ring. * Set the receive queue tail to point to a DMA Stop command after the * last ring entry */ rxCommandHead = 0; rxCommandTail = i; rxDMACommands[i].desc_seg[0] = dbdmaCmd_Stop; rxDMACommands[i].desc_seg[1] = dbdmaCmd_Nop; /* * Setup a DMA branch command after the stop command */ i++; rxDMACommands[i].desc_seg[0] = dbdmaCmd_Branch; IOSetCCCmdDep( &rxDMACommands[i].desc_seg[0], rxDMACommandsPhys ); /* * Set DMA command pointer to first receive entry */ IOSetDBDMACommandPtr( ioBaseEnetRxDMA, rxDMACommandsPhys ); /* * Push DMA commands to physical memory */ flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], 2 * sizeof(enet_dma_cmd_t) ); return true; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_startChip() { WriteMaceRegister( ioBaseEnet, kMacCC, kMacCCEnXmt | kMacCCEnRcv ); // enable rx dma channel IODBDMAContinue( ioBaseEnetRxDMA ); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_resetChip() { u_int8_t regValue; /* * Mace errata - chip reset does not clear pending interrupts */ ReadMaceRegister( ioBaseEnet, kIntReg ); IODBDMAReset( ioBaseEnetRxDMA ); IODBDMAReset( ioBaseEnetTxDMA ); IOSetDBDMAWaitSelect( ioBaseEnetTxDMA, IOSetDBDMAChannelControlBits( kdbdmaS5 ) ); IOSetDBDMABranchSelect( ioBaseEnetRxDMA, IOSetDBDMAChannelControlBits( kdbdmaS6 ) ); IOSetDBDMAInterruptSelect( ioBaseEnetRxDMA, IOSetDBDMAChannelControlBits( kdbdmaS6 ) ); WriteMaceRegister( ioBaseEnet, kBIUCC, kBIUCCSWRst ); do { regValue = ReadMaceRegister( ioBaseEnet, kBIUCC ); } while( regValue & kBIUCCSWRst ); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ bool MaceEnet::_initChip() { volatile u_int16_t regValue; u_int32_t i; _disableAdapterInterrupts(); chipId = ReadMaceRegister( ioBaseEnet, kMaceChipId0 ); chipId |= ReadMaceRegister( ioBaseEnet, kMaceChipId1 ) << 8; /* * Turn off ethernet header stripping */ regValue = ReadMaceRegister( ioBaseEnet, kRcvFC ); regValue &= ~kRcvFCAStrpRcv; WriteMaceRegister( ioBaseEnet, kRcvFC, regValue ); /* * Set Mace destination address. */ if ( chipId != kMaceRevisionA2 ) { WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACPhyAddr ); do { regValue = ReadMaceRegister( ioBaseEnet, kIAC ); } while( regValue & kIACAddrChg ); } else { WriteMaceRegister( ioBaseEnet, kIAC, kIACPhyAddr ); } for (i=0; i < sizeof(IOEthernetAddress); i++ ) { WriteMaceRegister( ioBaseEnet, kPADR, reverseBitOrder(((unsigned char *)ioBaseEnetROM)[i<<4]) ); } /* * Clear logical address (multicast) filter */ if ( chipId != kMaceRevisionA2 ) { WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACLogAddr ); do { regValue = ReadMaceRegister( ioBaseEnet, kIAC ); } while( regValue & kIACAddrChg ); } else { WriteMaceRegister( ioBaseEnet, kIAC, kIACLogAddr ); } for (i = 0; i < 8; i++ ) { WriteMaceRegister( ioBaseEnet, kLADRF, 0 ); } /* * Enable ethernet transceiver */ WriteMaceRegister( ioBaseEnet, kPLSCC, kPLSCCPortSelGPSI | kPLSCCEnSts ); return true; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_restartChip() { /* * Shutdown DMA channels */ _stopReceiveDMA(); _stopTransmitDMA(); /* * Get the silicon's attention */ _resetChip(); _initChip(); /* * Restore multicast settings */ _updateHashTableMask(); if ( isPromiscuous ) { _setPromiscuousMode(kIOEnetPromiscuousModeOn); } /* * Enable receiver and transmitter */ _startChip(); _enableAdapterInterrupts(); /* * Restart transmit DMA */ IODBDMAContinue( ioBaseEnetTxDMA ); } /*------------------------------------------------------------------------- * * Orderly stop of receive DMA. * * *-------------------------------------------------------------------------*/ void MaceEnet::_stopReceiveDMA() { u_int32_t dmaStatus; u_int32_t dmaCmdPtr; u_int32_t dmaIndex; u_int8_t tmpBuf[16]; u_int8_t *p = 0; u_int8_t MacCCReg; /* * Stop the receiver and allow any frame receive in progress to complete */ MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnRcv ); IODelay( RECEIVE_QUIESCE_uS ); /* * Capture channel status and pause the dma channel. */ dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); IODBDMAPause( ioBaseEnetRxDMA ); /* * Read the command pointer and convert it to a byte offset into the * DMA program. */ dmaCmdPtr = IOGetDBDMACommandPtr( ioBaseEnetRxDMA ); dmaIndex = (dmaCmdPtr - rxDMACommandsPhys); /* * If the channel status is DEAD, the DMA pointer is pointing to the * next command */ if ( dmaStatus & kdbdmaDead ) { dmaIndex -= sizeof(IODBDMADescriptor); } /* * Convert channel program offset to command index */ dmaIndex = dmaIndex / sizeof(enet_dma_cmd_t); if ( dmaIndex >= rxMaxCommand ) dmaIndex = 0; /* * The DMA controller doesnt like being stopped before transferring any * data. * * When we do so it pollutes up to 16-bytes aligned to the nearest (lower) * 16-byte boundary. This corruption can be outside the data transfer area * of the mbuf, so we capture and then restore these bytes after stopping * the channel. * */ if ( rxMbuf[dmaIndex] ) { p = mtod(rxMbuf[dmaIndex], u_int8_t *); } (u_int32_t)p &= ~0x0f; if ( p ) { bcopy( p, tmpBuf, 16 ); } IODBDMAReset( ioBaseEnetRxDMA ); if ( p ) { bcopy( tmpBuf, p, 16 ); } /* * Reset the dma channel pointer to the nearest command index */ dmaCmdPtr = rxDMACommandsPhys + sizeof(enet_dma_cmd_t) * dmaIndex; IOSetDBDMACommandPtr( ioBaseEnetRxDMA, dmaCmdPtr); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_stopTransmitDMA() { u_int32_t dmaStatus; u_int32_t dmaCmdPtr; u_int32_t dmaIndex; u_int8_t MacCCReg; /* * Stop the transmitter and allow any frame transmit in progress to abort */ MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnXmt ); IODelay( TRANSMIT_QUIESCE_uS ); /* * Capture channel status and pause the dma channel. */ dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetTxDMA ); IODBDMAPause( ioBaseEnetTxDMA ); /* * Read the command pointer and convert it to a byte offset into the * DMA program. */ dmaCmdPtr = IOGetDBDMACommandPtr( ioBaseEnetTxDMA ); dmaIndex = (dmaCmdPtr - txDMACommandsPhys); /* * If the channel status is DEAD, the DMA pointer is pointing to the * next command */ if ( dmaStatus & kdbdmaDead ) { dmaIndex -= sizeof(IODBDMADescriptor); } /* * Convert channel program offset to command index */ dmaIndex = dmaIndex / sizeof(enet_txdma_cmd_t); if ( dmaIndex >= txMaxCommand ) dmaIndex = 0; IODBDMAReset( ioBaseEnetTxDMA ); /* * Reset the dma channel pointer to the nearest command index */ dmaCmdPtr = txDMACommandsPhys + sizeof(enet_txdma_cmd_t) * dmaIndex; IOSetDBDMACommandPtr( ioBaseEnetTxDMA, dmaCmdPtr ); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_disableAdapterInterrupts() { WriteMaceRegister( ioBaseEnet, kIntMask, 0xFF ); } /*------------------------------------------------------------------------- * * _enableAdapterInterrupts * * It appears to make the Mace chip work properly with the DBDMA channel * we need to leave the transmit interrupt unmasked at the chip. This * is weird, but that's what happens when you try to glue a chip that * wasn't intended to work with a DMA engine on to a DMA. * *-------------------------------------------------------------------------*/ void MaceEnet::_enableAdapterInterrupts() { u_int8_t regValue; regValue = ReadMaceRegister( ioBaseEnet, kIntMask ); regValue &= ~kIntMaskXmtInt; WriteMaceRegister( ioBaseEnet, kIntMask, regValue ); IODelay(500); ReadMaceRegister( ioBaseEnet, kXmtFS ); ReadMaceRegister( ioBaseEnet, kIntReg ); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ bool MaceEnet::_transmitPacket(struct mbuf * packet) { enet_dma_cmd_t tmpCommand; u_int32_t i; /* * Check for room on the transmit ring. There should always be space * since it is the responsibility of the caller to verify this before * calling _transmitPacket. * * Get a copy of the DMA transfer commands in a temporary buffer. * The new DMA command is written into the channel program so that the * command word for the old Stop command is overwritten last. This prevents * the DMA engine from executing a partially written channel command. */ i = txCommandTail + 1; if ( i >= txMaxCommand ) i = 0; if ( (i == txCommandHead) || !_updateDescriptorFromMbuf(packet, &tmpCommand, false)) { IOLog("Mace: Freeing transmit packet eh?\n\r"); if (packet != txDebuggerPkt) freePacket(packet); return false; } /* * txCommandTail points to the current DMA Stop command for the channel. * We are now creating a new DMA Stop command in the next slot in the * transmit ring. The previous DMA Stop command will be overwritten with * the DMA commands to transfer the new mbuf. */ txDMACommands[i].desc_seg[0] = dbdmaCmd_Stop; txDMACommands[i].desc_seg[1] = dbdmaCmd_Nop; flush_cache_v( (vm_offset_t)&txDMACommands[i], sizeof(enet_dma_cmd_t) ); bcopy( ((u_int32_t *)&tmpCommand)+1, ((u_int32_t *)&txDMACommands[txCommandTail])+1, sizeof(enet_dma_cmd_t)-sizeof(u_int32_t) ); flush_cache_v( (vm_offset_t)&txDMACommands[txCommandTail], sizeof(enet_dma_cmd_t) ); txMbuf[txCommandTail] = packet; txDMACommands[txCommandTail].desc_seg[0].operation = tmpCommand.desc_seg[0].operation; flush_cache_v( (vm_offset_t)&txDMACommands[txCommandTail], sizeof(enet_dma_cmd_t) ); /* * Set the transmit tail to the new stop command. */ txCommandTail = i; /* * Tap the DMA channel to wake it up */ IODBDMAContinue( ioBaseEnetTxDMA ); return true; } /*------------------------------------------------------------------------- * _receivePacket * -------------- * This routine runs the receiver in polled-mode (yuk!) for the kernel * debugger. * * The _receivePackets allocate mbufs and pass them up the stack. The kernel * debugger interface passes a buffer into us. To reconcile the two interfaces, * we allow the receive routine to continue to allocate its own buffers and * transfer any received data to the passed-in buffer. This is handled by * _receivePacket calling _packetToDebugger. *-------------------------------------------------------------------------*/ void MaceEnet::_receivePacket(void *pkt, unsigned int *pkt_len, unsigned int timeout) { ns_time_t startTime; ns_time_t currentTime; u_int32_t elapsedTimeMS; if (!ready || !pkt || !pkt_len) return; *pkt_len = 0; debuggerPkt = pkt; debuggerPktSize = 0; _IOGetTimestamp(&startTime); do { _receivePackets(true); _IOGetTimestamp(¤tTime); elapsedTimeMS = (currentTime - startTime) / (1000*1000); } while ( (debuggerPktSize == 0) && (elapsedTimeMS < timeout) ); *pkt_len = debuggerPktSize; return; } /*------------------------------------------------------------------------- * _packetToDebugger * ----------------- * This is called by _receivePackets when we are polling for kernel debugger * packets. It copies the mbuf contents to the buffer passed by the debugger. * It also sets the var debuggerPktSize which will break the polling loop. *-------------------------------------------------------------------------*/ void MaceEnet::_packetToDebugger(struct mbuf * packet, u_int size) { debuggerPktSize = size; bcopy( mtod(packet, char *), debuggerPkt, size ); } /*------------------------------------------------------------------------- * _sendPacket * ----------- * * This routine runs the transmitter in polled-mode (yuk!) for the * kernel debugger. * *-------------------------------------------------------------------------*/ void MaceEnet::_sendPacket(void *pkt, unsigned int pkt_len) { ns_time_t startTime; ns_time_t currentTime; u_int32_t elapsedTimeMS; if ( !ready || !pkt || (pkt_len > ETHERMAXPACKET)) return; /* * Wait for the transmit ring to empty */ _IOGetTimestamp(&startTime); do { _transmitInterruptOccurred(true); _IOGetTimestamp(¤tTime); elapsedTimeMS = (currentTime - startTime) / (1000*1000); } while ( (txCommandHead != txCommandTail) && (elapsedTimeMS < TX_KDB_TIMEOUT) ); if ( txCommandHead != txCommandTail ) { IOLog( "Mace: Polled tranmit timeout - 1\n\r"); return; } txDebuggerPkt->m_next = 0; txDebuggerPkt->m_data = (caddr_t) pkt; txDebuggerPkt->m_pkthdr.len = txDebuggerPkt->m_len = pkt_len; /* * Send the debugger packet. txDebuggerPkt must not be freed by * the transmit routine. */ _transmitPacket(txDebuggerPkt); /* * Poll waiting for the transmit ring to empty again */ do { _transmitInterruptOccurred(true); _IOGetTimestamp(¤tTime); elapsedTimeMS = (currentTime - startTime) / (1000*1000); } while ( (txCommandHead != txCommandTail) && (elapsedTimeMS < TX_KDB_TIMEOUT) ); if ( txCommandHead != txCommandTail ) { IOLog("Mace: Polled transmit timeout - 2\n\r"); } return; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ bool MaceEnet::_receiveInterruptOccurred() { return _receivePackets(false); } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ bool MaceEnet::_receivePackets(bool fDebugger) { enet_dma_cmd_t tmpCommand; struct mbuf * packet; u_int32_t i,j,last; u_int32_t dmaChnlStatus; int receivedFrameSize = 0; u_int32_t dmaCount[2], dmaResid[2], dmaStatus[2]; bool reusePkt; bool status; bool useNetif = !fDebugger && netifClient; bool packetsQueued = false; u_int8_t *rxFS = NULL; u_int32_t nextDesc; static const u_int32_t lastResetValue = (u_int32_t)(-1); last = lastResetValue; i = rxCommandHead; while ( 1 ) { reusePkt = false; /* * Purge cache references for the DBDMA entry we are about to look at. */ invalidate_cache_v((vm_offset_t)&rxDMACommands[i], sizeof(enet_dma_cmd_t)); /* * Collect the DMA residual counts/status for the two buffer segments. */ for ( j = 0; j < 2; j++ ) { dmaResid[j] = IOGetCCResult( &rxDMACommands[i].desc_seg[j] ); dmaStatus[j] = dmaResid[j] >> 16; dmaResid[j] &= 0x0000ffff; dmaCount[j] = IOGetCCOperation( &rxDMACommands[i].desc_seg[j] ) & kdbdmaReqCountMask; } #if 0 IOLog("Ethernet(Mace): Rx NetBuf[%2d] = %08x Resid[0] = %04x Status[0] = %04x Resid[1] = %04x Status[1] = %04x\n\r", i, (int)nb_map(rxNetbuf[i]), dmaResid[0], dmaStatus[0], dmaResid[1], dmaStatus[1] ); #endif /* * If the current entry has not been written, then stop at this entry */ if ( !((dmaStatus[0] & kdbdmaBt) || (dmaStatus[1] & kdbdmaActive)) ) { break; } /* * The Mace Ethernet controller appends four bytes to each receive * buffer containing the buffer size and receive frame status. * We locate these bytes by using the DMA residual counts. */ receivedFrameSize = dmaCount[0] - dmaResid[0] + dmaCount[1] - ((dmaStatus[0] & kdbdmaBt) ? dmaCount[1] : dmaResid[1]); if ( ( receivedFrameSize >= 4 ) && ( receivedFrameSize <= NETWORK_BUFSIZE ) ) { /* * Get the receive frame size as reported by the Mace controller */ rxFS = mtod(rxMbuf[i], u_int8_t *) + receivedFrameSize - 4; receivedFrameSize = (u_int16_t) rxFS[0] | (rxFS[1] & kRcvFS1RcvCnt) << 8; } /* * Reject packets that are runts or that have other mutations. */ if ( receivedFrameSize < (ETHERMINPACKET - ETHERCRC) || receivedFrameSize > (ETHERMAXPACKET + ETHERCRC) || (rxFS[1] & (kRcvFS1OFlo | kRcvFS1Clsn | kRcvFS1Fram | kRcvFS1FCS)) ) { if (useNetif) netStats->inputErrors++; reusePkt = true; } else if ( useNetif == false ) { /* * Always reuse packets in debugger mode. */ reusePkt = true; if (fDebugger) _packetToDebugger(rxMbuf[i], receivedFrameSize); } /* * Before we pass this packet up the networking stack. Make sure we * can get a replacement. Otherwise, hold on to the current packet and * increment the input error count. * Thanks Justin! */ packet = 0; if ( reusePkt == false ) { bool replaced; packet = replaceOrCopyPacket(&rxMbuf[i], receivedFrameSize, &replaced); reusePkt = true; if (packet && replaced) { status = _updateDescriptorFromMbuf(rxMbuf[i], &rxDMACommands[i], true); if (status) { reusePkt = false; } else { // Assume descriptor has not been corrupted. freePacket(rxMbuf[i]); // release new packet. rxMbuf[i] = packet; // get the old packet back. packet = 0; // pass up nothing. IOLog("Mace: _updateDescriptorFromMbuf error\n"); } } if (packet == 0) netStats->inputErrors++; } /* * If we are reusing the existing mbuf, then refurbish the existing * DMA command \ descriptors by clearing the status/residual count * fields. */ if ( reusePkt == true ) { for ( j=0; j < sizeof(enet_dma_cmd_t)/sizeof(IODBDMADescriptor); j++ ) { IOSetCCResult( &rxDMACommands[i].desc_seg[j], 0 ); } flush_cache_v( (vm_offset_t)&rxDMACommands[i], sizeof(enet_dma_cmd_t) ); } /* * Keep track of the last receive descriptor processed */ last = i; /* * Implement ring wrap-around */ if (++i >= rxMaxCommand) i = 0; /* * Early exit in debugger mode. */ if (fDebugger) { break; } /* * Transfer received to network stack. */ if (packet) { KERNEL_DEBUG(DBG_MACE_RXCOMPLETE | DBG_FUNC_NONE, (int) packet, (int)receivedFrameSize, 0, 0, 0 ); /* * The KDB lock must be held before calling this function. */ networkInterface->inputPacket(packet, receivedFrameSize, true); netStats->inputPackets++; packetsQueued = true; } } /* * OK...this is a little messy * * We just processed a bunch of DMA receive descriptors. We are going to * exchange the current DMA stop command (rxCommandTail) with the last * receive descriptor we processed (last). This will make these list of * descriptors we just processed available. If we processed no receive * descriptors on this call then skip this exchange. */ #if 0 IOLog("Mace: Prev - Rx Head = %2d Rx Tail = %2d Rx Last = %2d\n\r", rxCommandHead, rxCommandTail, last ); #endif if ( last != lastResetValue ) { /* * Save the contents of the last receive descriptor processed. */ packet = rxMbuf[last]; tmpCommand = rxDMACommands[last]; /* * Write a DMA stop command into this descriptor slot */ rxDMACommands[last].desc_seg[0] = dbdmaCmd_Stop; rxDMACommands[last].desc_seg[1] = dbdmaCmd_Nop; rxMbuf[last] = 0; flush_cache_v( (vm_offset_t)&rxDMACommands[last], sizeof(enet_dma_cmd_t) ); /* * Replace the previous DMA stop command with the last receive * descriptor processed. * * The new DMA command is written into the channel program so that the * command word for the old Stop command is overwritten last. This * prevents the DMA engine from executing a partially written channel * command. * * Note: When relocating the descriptor, we must update its branch * field to reflect its new location. */ nextDesc = rxDMACommandsPhys + (int)&rxDMACommands[rxCommandTail+1] - (int)rxDMACommands; IOSetCCCmdDep( &tmpCommand.desc_seg[0], nextDesc ); bcopy( (u_int32_t *)&tmpCommand+1, (u_int32_t *)&rxDMACommands[rxCommandTail]+1, sizeof(enet_dma_cmd_t)-sizeof(u_int32_t) ); flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], sizeof(enet_dma_cmd_t) ); rxMbuf[rxCommandTail] = packet; rxDMACommands[rxCommandTail].desc_seg[0].operation = tmpCommand.desc_seg[0].operation; flush_cache_v( (vm_offset_t)&rxDMACommands[rxCommandTail], sizeof(IODBDMADescriptor) ); /* * Update rxCommmandTail to point to the new Stop command. Update * rxCommandHead to point to the next slot in the ring past the Stop * command */ rxCommandTail = last; rxCommandHead = i; } /* * The DMA channel has a nasty habit of shutting down when there is a * non-recoverable error on receive. We get no interrupt for this since * the channel shuts down before the descriptor that causes the host * interrupt is executed. * * We check if the channel is DEAD by checking the channel status reg. * Also, the watchdog timer can force receiver interrupt servicing based * on detecting that the receive DMA is DEAD. */ dmaChnlStatus = IOGetDBDMAChannelStatus( ioBaseEnetRxDMA ); if ( dmaChnlStatus & kdbdmaDead ) { /* * Read log error */ if (useNetif) netStats->inputErrors++; IOLog( "Mace: Rx DMA Error - Status = %04x\n", dmaChnlStatus ); /* * Reset and reinitialize chip */ _restartChip(); // This must not block in debugger mode. } else { /* * Tap the DMA to wake it up */ IODBDMAContinue( ioBaseEnetRxDMA ); } #if 0 IOLog( "Mace: New - Rx Head = %2d Rx Tail = %2d\n\r", rxCommandHead, rxCommandTail ); #endif return packetsQueued; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ bool MaceEnet::_transmitInterruptOccurred(bool fDebugger = false) { u_int32_t dmaStatus; u_int32_t xmtFS; bool fServiced = false; bool useNetif = !fDebugger && netifClient; // Set the debugTxPoll flag to indicate the debugger was active // and some cleanup may be needed when the driver returns to // normal operation. // if (fDebugger) debugTxPoll = true; while ( 1 ) { /* * Purge cache references for the DBDMA entry we are about to look at. */ invalidate_cache_v((vm_offset_t)&txDMACommands[txCommandHead], sizeof(enet_txdma_cmd_t)); /* * Check the status of the last descriptor in this entry to see if * the DMA engine completed this entry. */ dmaStatus = IOGetCCResult( &txDMACommands[txCommandHead].desc_seg[3] ) >> 16; if ( !(dmaStatus & kdbdmaActive) ) { break; } fServiced = true; /* * Reset the status word for the entry we are about to process */ IOSetCCResult( &txDMACommands[txCommandHead].desc_seg[3], 0 ); flush_cache_v( (vm_offset_t) &txDMACommands[txCommandHead].desc_seg[3], sizeof(IODBDMADescriptor) ); /* * This DMA descriptor read the transmit frame status. See what it has * to tell us. */ xmtFS = IOGetCCCmdDep( &txDMACommands[txCommandHead].desc_seg[2] ); if ( useNetif && (xmtFS & kXmtFSXmtSV) ) { if (xmtFS & (kXmtFSUFlo | kXmtFSLCol | kXmtFSRtry | kXmtFSLCar) ) { netStats->outputErrors++; } else { netStats->outputPackets++; } if (xmtFS & (kXmtFSOne | kXmtFSMore) ) { netStats->collisions++; } } /* * Free the mbuf we just transmitted. */ KERNEL_DEBUG(DBG_MACE_TXCOMPLETE | DBG_FUNC_NONE, (int) txMbuf[txCommandHead], (int) txMbuf[txCommandHead]->m_pkthdr.len, 0, 0, 0 ); if (txMbuf[txCommandHead] != txDebuggerPkt) { if ( fDebugger ) { // // While in debugger mode, do not touch the mbuf pool. // Queue any used mbufs to a local queue. This queue // will get flushed after we exit from debugger mode. // // During continuous debugger transmission and // interrupt polling, we expect only the txDebuggerPkt // to show up on the transmit mbuf ring. // debugQueue->enqueue( txMbuf[txCommandHead] ); } else { freePacket( txMbuf[txCommandHead] ); } } txMbuf[txCommandHead] = 0; if ( ++txCommandHead >= txMaxCommand ) txCommandHead = 0; } /* * The DMA channel has a nasty habit of shutting down when there is * non-recoverable error on transmit. We get no interrupt for this since * the channel shuts down before the descriptor that causes the host * interrupt is executed. * * We check if the channel is DEAD by checking the channel status reg. * Also, the watchdog timer can force a transmitter reset if it sees no * interrupt activity for to consecutive timeout intervals. */ dmaStatus = IOGetDBDMAChannelStatus( ioBaseEnetTxDMA ); if ( (dmaStatus & kdbdmaDead) || (txWDForceReset == true) ) { /* * Read the transmit frame status and log error */ xmtFS = ReadMaceRegister( ioBaseEnet, kXmtFS ); if (useNetif) netStats->outputErrors++; IOLog( "Mace: Tx DMA Error - Status = %04x FS = %02x\n\r", dmaStatus, xmtFS); /* * Reset and reinitialize chip */ _restartChip(); txWDForceReset = false; fServiced = true; } return fServiced; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ /* * Breaks up an ethernet data buffer into two physical chunks. We know that * the buffer can't straddle more than two pages. If the content of paddr2 is * zero this means that all of the buffer lies in one physical page. Note * that we use the fact that tx and rx descriptors have the same size and * same layout of relevent fields (data address and count). */ bool MaceEnet::_updateDescriptorFromMbuf(struct mbuf * m, enet_dma_cmd_t *desc, bool isReceive) { u_int32_t nextDesc = 0; int segments; struct IOPhysicalSegment segVector[2]; /* * Although coalescing is always enabled, it cannot occur * while the driver is in debugger mode. */ segments = mbufCursor->getPhysicalSegmentsWithCoalesce(m, segVector); if ((!segments) || (segments > 2)) { IOLog("Mace: _updateDescriptorFromMbuf error, %d segments\n", segments); return false; } if ( segments == 1 ) { IOMakeDBDMADescriptor( (&desc->desc_seg[0]), ((isReceive) ? kdbdmaInputLast : kdbdmaOutputLast), (kdbdmaKeyStream0), (kdbdmaIntNever), (kdbdmaBranchNever), ((isReceive) ? kdbdmaWaitNever : kdbdmaWaitIfFalse), (segVector[0].length), (segVector[0].location) ); desc->desc_seg[1] = (isReceive) ? dbdmaCmd_NopWInt : dbdmaCmd_Nop; } else { if ( isReceive ) { nextDesc = rxDMACommandsPhys + (int)desc - (int)rxDMACommands + sizeof(enet_dma_cmd_t); } IOMakeDBDMADescriptorDep( (&desc->desc_seg[0]), ((isReceive) ? kdbdmaInputMore : kdbdmaOutputMore), (kdbdmaKeyStream0), ((isReceive) ? kdbdmaIntIfTrue : kdbdmaIntNever), ((isReceive) ? kdbdmaBranchIfTrue : kdbdmaBranchNever), (kdbdmaWaitNever), (segVector[0].length), (segVector[0].location), nextDesc ); IOMakeDBDMADescriptor( (&desc->desc_seg[1]), ((isReceive) ? kdbdmaInputLast : kdbdmaOutputLast), (kdbdmaKeyStream0), ((isReceive) ? kdbdmaIntAlways : kdbdmaIntNever), (kdbdmaBranchNever), ((isReceive) ? kdbdmaWaitNever : kdbdmaWaitIfFalse), (segVector[1].length), (segVector[1].location) ); } flush_cache_v( (vm_offset_t)desc, sizeof(enet_dma_cmd_t) ); return true; } #ifdef DEBUG /* * Useful for testing. */ void MaceEnet::_dumpDesc(void * addr, u_int32_t size) { u_int32_t i; unsigned long *p; vm_offset_t paddr; _IOPhysicalFromVirtual( (vm_offset_t) addr, (vm_offset_t *)&paddr ); p = (unsigned long *)addr; for ( i=0; i < size/sizeof(IODBDMADescriptor); i++, p+=4, paddr+=sizeof(IODBDMADescriptor) ) { IOLog("Ethernet(Mace): %08x(v) %08x(p): %08x %08x %08x %08x\n", (int)p, (int)paddr, (int)OSReadSwapInt32(p, 0), (int)OSReadSwapInt32(p, 4), (int)OSReadSwapInt32(p, 8), (int)OSReadSwapInt32(p, 12) ); } IOLog("\n"); } void MaceEnet::_dumpRegisters() { u_int8_t dataValue; IOLog("\nEthernet(Mace): IO Address = %08x", (int)ioBaseEnet ); dataValue = ReadMaceRegister(ioBaseEnet, kXmtFC); IOLog("\nEthernet(Mace): Read Register %04x Transmit Frame Control = %02x", kXmtFC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kXmtFS); IOLog("\nEthernet(Mace): Read Register %04x Transmit Frame Status = %02x", kXmtFS, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kXmtRC); IOLog("\nEthernet(Mace): Read Register %04x Transmit Retry Count = %02x", kXmtRC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kRcvFC); IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Control = %02x", kRcvFC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS0); IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 0 = %02x", kRcvFS0, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS1); IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 1 = %02x", kRcvFS1, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS2); IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 2 = %02x", kRcvFS2, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kRcvFS3); IOLog("\nEthernet(Mace): Read Register %04x Receive Frame Status 3 = %02x", kRcvFS3, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kFifoFC); IOLog("\nEthernet(Mace): Read Register %04x FIFO Frame Count = %02x", kFifoFC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kIntReg); IOLog("\nEthernet(Mace): Read Register %04x Interrupt Register = %02x", kIntReg, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kIntMask); IOLog("\nEthernet(Mace): Read Register %04x Interrupt Mask Register = %02x", kIntMask, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kPollReg); IOLog("\nEthernet(Mace): Read Register %04x Poll Register = %02x", kPollReg, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kBIUCC); IOLog("\nEthernet(Mace): Read Register %04x BUI Configuration Control = %02x", kBIUCC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kFifoCC); IOLog("\nEthernet(Mace): Read Register %04x FIFO Configuration Control = %02x", kFifoCC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kMacCC); IOLog("\nEthernet(Mace): Read Register %04x MAC Configuration Control = %02x", kMacCC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kPLSCC); IOLog("\nEthernet(Mace): Read Register %04x PLS Configuration Contro = %02x", kPLSCC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kPHYCC); IOLog("\nEthernet(Mace): Read Register %04x PHY Configuration Control = %02x", kPHYCC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kMaceChipId0); IOLog("\nEthernet(Mace): Read Register %04x MACE ChipID Register 7:0 = %02x", kMaceChipId0, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kMaceChipId1); IOLog("\nEthernet(Mace): Read Register %04x MACE ChipID Register 15:8 = %02x", kMaceChipId1, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kMPC); IOLog("\nEthernet(Mace): Read Register %04x Missed Packet Count = %02x", kMPC, dataValue ); dataValue = ReadMaceRegister(ioBaseEnet, kUTR); IOLog("\nEthernet(Mace): Read Register %04x User Test Register = %02x", kUTR, dataValue ); IOLog("\nEthernet(Mace): -------------------------------------------------------\n" ); } #endif DEBUG /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ IOReturn MaceEnet::getHardwareAddress(IOEthernetAddress *ea) { unsigned char data; for (UInt i = 0; i < sizeof(*ea); i++) { data = ((unsigned char *)ioBaseEnetROM)[i << 4]; ea->bytes[i] = reverseBitOrder(data); } return kIOReturnSuccess; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ #define ENET_CRCPOLY 0x04c11db7 /* Real fast bit-reversal algorithm, 6-bit values */ static int reverse6[] = { 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f }; static u_int32_t crc416(unsigned int current, unsigned short nxtval ) { register unsigned int counter; register int highCRCBitSet, lowDataBitSet; /* Swap bytes */ nxtval = ((nxtval & 0x00FF) << 8) | (nxtval >> 8); /* Compute bit-by-bit */ for (counter = 0; counter != 16; ++counter) { /* is high CRC bit set? */ if ((current & 0x80000000) == 0) highCRCBitSet = 0; else highCRCBitSet = 1; current = current << 1; if ((nxtval & 0x0001) == 0) lowDataBitSet = 0; else lowDataBitSet = 1; nxtval = nxtval >> 1; /* do the XOR */ if (highCRCBitSet ^ lowDataBitSet) current = current ^ ENET_CRCPOLY; } return current; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ static u_int32_t mace_crc(unsigned short *address) { register u_int32_t newcrc; newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ return (newcrc); } /* * Clear the hash table filter. * */ void MaceEnet::_resetHashTableMask() { bzero(hashTableUseCount, sizeof(hashTableUseCount)); bzero(hashTableMask, sizeof(hashTableMask)); } /* * Add requested mcast addr to Mace's hash table filter. * */ void MaceEnet::_addToHashTableMask(u_int8_t *addr) { u_int32_t crc; u_int8_t mask; crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (hashTableUseCount[crc]++) return; /* This bit is already set */ mask = crc % 8; mask = (unsigned char) 1 << mask; hashTableMask[crc/8] |= mask; } /*------------------------------------------------------------------------- * * * *-------------------------------------------------------------------------*/ void MaceEnet::_removeFromHashTableMask(u_int8_t *addr) { unsigned int crc; unsigned char mask; /* Now, delete the address from the filter copy, as indicated */ crc = mace_crc((unsigned short *)addr)&0x3f; /* Big-endian alert! */ crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ if (hashTableUseCount[crc] == 0) return; /* That bit wasn't in use! */ if (--hashTableUseCount[crc]) return; /* That bit is still in use */ mask = crc % 8; mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */ hashTableMask[crc/8] &= mask; } /* * Sync the adapter with the software copy of the multicast mask * (logical address filter). */ void MaceEnet::_updateHashTableMask() { u_int8_t status; u_int32_t i; u_int8_t *p; u_int8_t MacCCReg; // Stop the receiver before changing the filter. // MacCCReg = ReadMaceRegister( ioBaseEnet, kMacCC ); WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg & ~kMacCCEnRcv ); IODelay( RECEIVE_QUIESCE_uS ); if ( chipId != kMaceRevisionA2 ) { WriteMaceRegister( ioBaseEnet, kIAC, kIACAddrChg | kIACLogAddr ); do { status = ReadMaceRegister( ioBaseEnet, kIAC ); } while( status & kIACAddrChg ); } else { WriteMaceRegister( ioBaseEnet, kIAC, kIACLogAddr ); } p = (u_int8_t *) hashTableMask; for (i = 0; i < 8; i++, p++ ) { WriteMaceRegister( ioBaseEnet, kLADRF, *p ); } // Restore the engine's state. // WriteMaceRegister( ioBaseEnet, kMacCC, MacCCReg ); }