#include "UniNEnet.h"
#include "UniNEnetMII.h"
#include <libkern/OSByteOrder.h>
extern "C"
{
extern boolean_t ml_probe_read( vm_offset_t physAddr, unsigned int *val );
}
#define super IOEthernetController
OSDefineMetaClassAndStructors( UniNEnet, IOEthernetController ) ;
#if USE_ELG
void UniNEnet::AllocateEventLog( UInt32 size )
{
IOPhysicalAddress phys;
fpELG = (elg*)IOMallocContiguous( size, 0x1000, &phys );
if ( !fpELG )
{
kprintf( "AllocateEventLog - UniNEnet evLog allocation failed " );
return;
}
bzero( fpELG, size );
fpELG->evLogBuf = (UInt8*)fpELG + sizeof( struct elg );
fpELG->evLogBufp = fpELG->evLogBuf;
fpELG->evLogBufe = fpELG->evLogBufp + kEvLogSize - 0x20; fpELG->evLogFlag = 0xFEEDBEEF;
IOLog( "UniNEnet - AllocateEventLog - buffer=%8x phys=%8x\n",
(unsigned int)fpELG, (UInt32)phys );
return;
}
void UniNEnet::EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
register UInt32 *lp;
mach_timespec_t time;
if ( fpELG->evLogFlag == 0 )
return;
IOGetTime( &time );
if ( fpELG->evLogFlag == 0xDEBEEFED )
{
for ( lp = (UInt32*)fpELG->evLogBuf; lp < (UInt32*)fpELG->evLogBufe; lp++ )
*lp = 0xDEBEEFED;
fpELG->evLogBufp = fpELG->evLogBuf; fpELG->evLogFlag = 0x333; }
lp = (UInt32*)fpELG->evLogBufp;
fpELG->evLogBufp += 0x10;
if ( fpELG->evLogBufp >= fpELG->evLogBufe )
{ fpELG->evLogBufp = fpELG->evLogBuf;
if ( fpELG->evLogFlag != 0xFEEDBEEF ) {
fpELG->evLogFlag = 0;
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)fpELG->evLogBuf, kEvLogSize );
}
}
*lp++ = (time.tv_nsec >> 10); *lp++ = a;
*lp++ = b;
*lp = ascii;
if ( fpELG->evLogFlag == 'step' )
{ static char code[ 5 ] = {0,0,0,0,0};
*(UInt32*)&code = ascii;
IOLog( "%8x UniNEnet: %8x %8x\t%s\n",
time.tv_nsec>>10, (unsigned int)a, (unsigned int)b, code );
IOSleep( 2 );
}
return;
}
UInt32 UniNEnet::Alrt( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
char work [ 256 ];
char name[] = "UniNEnet: ";
char *bp = work;
UInt8 x;
int i;
EvLog( a, b, ascii, str );
EvLog( '****', '** A', 'lert', "*** Alrt" );
bcopy( name, bp, sizeof( name ) );
bp += sizeof( name ) - 1;
*bp++ = '{'; for ( i = 7; i >= 0; --i )
{
x = a & 0x0F;
if ( x < 10 )
x += '0';
else x += 'A' - 10;
bp[ i ] = x;
a >>= 4;
}
bp += 8;
*bp++ = ' ';
for ( i = 7; i >= 0; --i )
{
x = b & 0x0F;
if ( x < 10 )
x += '0';
else x += 'A' - 10;
bp[ i ] = x;
b >>= 4;
}
bp += 8;
*bp++ = '}';
*bp++ = ' ';
for ( i = sizeof( work ) - (int)(bp - work) - 1; i && (*bp++ = *str++); --i ) ;
*bp++ = '\n';
OSSynchronizeIO();
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)fpELG, kEvLogSize );
return 1;
}
#endif // USE_ELG
bool UniNEnet::init( OSDictionary *properties )
{
#if USE_ELG
AllocateEventLog( kEvLogSize );
ELG( 0, 0, 'eNet', "UniNEnet::init - event logging set up." );
#endif
if ( super::init( properties ) == false )
return false;
phyId = 0xFF;
linkStatusPrev = kLinkStatusUnknown;
enetClockOff = false;
return true;
}
bool UniNEnet::start( IOService *provider )
{
OSString *matchEntry;
OSNumber *numObj;
IOWorkLoop *myWorkLoop = getWorkLoop();
UInt32 x, xFactor;
ELG( IOThreadSelf(), provider, 'Strt', "UniNEnet::start - this, provider." );
matchEntry = OSDynamicCast( OSString, getProperty( gIONameMatchedKey ) );
if ( matchEntry == 0 )
{
ALRT( 0, 0, 'Mat-', "UniNEnet::start: Cannot obtain matching property." );
return false;
}
fBuiltin = matchEntry->isEqualTo( "gmac" );
nub = OSDynamicCast( IOPCIDevice, provider );
if ( !nub || !super::start( provider ) )
return false;
if ( fBuiltin )
{
keyLargo = waitForService( serviceMatching( "KeyLargo" ) );
if ( keyLargo == 0 ) return false;
keyLargo_resetUniNEthernetPhy = OSSymbol::withCString( "keyLargo_resetUniNEthernetPhy" );
ELG( IOThreadSelf(), keyLargo, 'KeyL', "UniNEnet::start - KeyLargo" );
}
else
{
keyLargo = 0;
}
transmitQueue = (IOGatedOutputQueue*)getOutputQueue();
if ( !transmitQueue )
{
IOLog( "UniNEnet::start - Output queue initialization failed\n" );
return false;
}
transmitQueue->retain();
debugQueue = IOPacketQueue::withCapacity( (UInt)-1 );
if ( !debugQueue )
return false;
mbufCursor = IOMbufBigMemoryCursor::withSpecification( NETWORK_BUFSIZE, 1 );
if ( !mbufCursor )
{
IOLog( "UniNEnet::start - IOMbufBigMemoryCursor allocation failure\n" );
return false;
}
phyId = 0xFF;
myWorkLoop = getWorkLoop();
interruptSource = IOInterruptEventSource::interruptEventSource(
(OSObject*)this,
(IOInterruptEventAction)&UniNEnet::interruptOccurred,
(IOService*)provider,
(int)0 );
if ( interruptSource == NULL )
{ IOLog( "UniNEnet::start: Couldn't allocate Interrupt event source\n" );
return false;
}
if ( myWorkLoop->addEventSource( interruptSource ) != kIOReturnSuccess )
{ IOLog( "UniNEnet::start - Couldn't add Interrupt event source\n" );
return false;
}
timerSource = IOTimerEventSource::timerEventSource(
this,
(IOTimerEventSource::Action)&UniNEnet::timeoutOccurred );
if ( timerSource == NULL )
{
IOLog( "UniNEnet::start - Couldn't allocate timer event source\n" );
return false;
}
if ( myWorkLoop->addEventSource( timerSource ) != kIOReturnSuccess )
{
IOLog( "UniNEnet::start - Couldn't add timer event source\n" );
return false;
}
MGETHDR( txDebuggerPkt, M_DONTWAIT, MT_DATA );
if ( !txDebuggerPkt )
{ IOLog( "UniNEnet::start - Couldn't allocate KDB buffer\n" );
return false;
}
if ( getHardwareAddress( &myAddress ) != kIOReturnSuccess )
{ ALRT( 0, 0, 'gha-', "UniNEnet::start - getHardwareAddress failed" );
return false;
}
fTxQueueSize = TRANSMIT_QUEUE_SIZE;
fTxRingElements = TX_RING_LENGTH; fTxRingLengthFactor = TX_RING_LENGTH_FACTOR;
fRxRingElements = RX_RING_LENGTH; fRxRingLengthFactor = RX_RING_LENGTH_FACTOR;
numObj = OSDynamicCast( OSNumber, getProperty( kTxQueueSize ) );
if ( numObj )
{
x = numObj->unsigned32BitValue();
if ( x >= 32 && x <= 9999 )
fTxQueueSize = x;
ELG( x, fTxQueueSize, '=txq', "UniNEnet::start - TxQueueSize" );
}
numObj = OSDynamicCast( OSNumber, getProperty( kTxRingElements ) );
if ( numObj )
{
xFactor = 0;
x = numObj->unsigned32BitValue();
switch ( x )
{
case 8192: ++xFactor;
case 4096: ++xFactor;
case 2048: ++xFactor;
case 1024: ++xFactor;
case 512: ++xFactor;
case 256: ++xFactor;
case 128: ++xFactor;
case 64: ++xFactor;
case 32:
fTxRingElements = x;
fTxRingLengthFactor = xFactor;
}
ELG( x, fTxRingElements, '=txe', "UniNEnet::start - TxRingElements" );
}
numObj = OSDynamicCast( OSNumber, getProperty( kRxRingElements ) );
if ( numObj )
{
xFactor = 0;
x = numObj->unsigned32BitValue();
switch ( x )
{
case 8192: ++xFactor;
case 4096: ++xFactor;
case 2048: ++xFactor;
case 1024: ++xFactor;
case 512: ++xFactor;
case 256: ++xFactor;
case 128: ++xFactor;
case 64: ++xFactor;
case 32:
fRxRingElements = x;
fRxRingLengthFactor = xFactor;
}
ELG( x, fRxRingElements, '=rxe', "UniNEnet::start - TxRingElements" );
}
ELG( fTxQueueSize, fTxRingElements << 16 | fRxRingElements, 'parm', "UniNEnet::start - config parms" );
if ( allocateMemory() == false )
{ ALRT( 0, 0, 'alo-', "UniNEnet::start - allocateMemory failed" );
return false;
}
ELG( IOThreadSelf(), 0, 'AttI', "UniNEnet::start - attach interface" );
if ( !attachInterface( (IONetworkInterface**)&networkInterface, false ) )
{ ALRT( 0, 0, 'Att-', "UniNEnet::start - attachInterface failed" );
return false;
}
if ( fBuiltin )
{
ELG( IOThreadSelf(), 0, 'AttD', "UniNEnet::start - attach debugger" );
attachDebuggerClient( &debugger );
}
if ( fBuiltin )
{ ELG( IOThreadSelf(), currentPowerState, 'powr', "UniNEnet::start - more power!" );
}
else
{
currentPowerState = 1; }
ELG( IOThreadSelf(), 0, 'RegS', "UniNEnet::start - networkInterface->registerService" );
networkInterface->registerService();
ELG( IOThreadSelf(), 0, 'Exit', "UniNEnet::start - exiting" );
return true;
}
bool UniNEnet::configureInterface( IONetworkInterface *netif )
{
IONetworkData *nd;
ELG( IOThreadSelf(), netif, 'cfig', "configureInterface" );
if ( super::configureInterface( netif ) == false )
return false;
nd = netif->getNetworkData( kIONetworkStatsKey );
if (!nd || !(fpNetStats = (IONetworkStats *) nd->getBuffer()))
{
IOLog("EtherNet(UniN): invalid network statistics\n");
return false;
}
nd = netif->getParameter( kIOEthernetStatsKey );
if ( !nd || !(fpEtherStats = (IOEthernetStats*)nd->getBuffer()) )
{
IOLog( "UniNEnet::configureInterface - invalid ethernet statistics\n" );
return false;
}
return true;
}
void UniNEnet::free()
{
ELG( this, 0, 'Free', "UniNEnet::free" );
putToSleep(false);
flushRings( true, true );
if ( debugger ) debugger->release();
if ( getWorkLoop() ) getWorkLoop()->disableAllEventSources();
if ( timerSource ) timerSource->release();
if ( interruptSource ) interruptSource->release();
if ( txDebuggerPkt ) freePacket( txDebuggerPkt );
if ( transmitQueue ) transmitQueue->release();
if ( debugQueue ) debugQueue->release();
if ( networkInterface ) networkInterface->release();
if ( mbufCursor ) mbufCursor->release();
if ( mediumDict ) mediumDict->release();
if ( ioMapEnet ) ioMapEnet->release();
if ( fTxDescriptorRing )IOFreeContiguous( (void*)fTxDescriptorRing, fTxRingElements * sizeof( TxDescriptor ) );
if ( fRxDescriptorRing )IOFreeContiguous( (void*)fRxDescriptorRing, fRxRingElements * sizeof( RxDescriptor ) );
if ( fTxMbuf ) IOFree( fTxMbuf, sizeof( mbuf* ) * fTxRingElements );
if ( fRxMbuf ) IOFree( fRxMbuf, sizeof( mbuf* ) * fRxRingElements );
if ( workLoop ) workLoop->release();
if ( keyLargo_resetUniNEthernetPhy )
{
keyLargo_resetUniNEthernetPhy->release();
keyLargo_resetUniNEthernetPhy = 0;
}
super::free();
return;
}
bool UniNEnet::createWorkLoop()
{
workLoop = IOWorkLoop::workLoop();
return ( workLoop != 0 );
}
IOWorkLoop* UniNEnet::getWorkLoop() const
{
return workLoop;
}
void UniNEnet::interruptOccurred( IOInterruptEventSource *src, int )
{
IODebuggerLockState lockState;
UInt32 interruptStatus;
bool doFlushQueue;
bool doService;
if ( ready == false )
{
ALRT( 0, READ_REGISTER( Status ), 'int-', "interruptOccurred - not ready" );
return;
}
do
{
lockState = IODebuggerLock( this );
interruptStatus = READ_REGISTER( Status )
& ( kStatus_TX_INT_ME | kStatus_RX_DONE );
ELG( READ_REGISTER( RxCompletion ), interruptStatus, 'Int+', "interruptOccurred - got status" );
doService = false;
if ( interruptStatus & kStatus_TX_INT_ME )
{
txWDInterrupts++;
KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
doService = transmitInterruptOccurred();
KERNEL_DEBUG(DBG_GEM_TXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
ETHERNET_STAT_ADD( dot3TxExtraEntry.interrupts );
}
doFlushQueue = false;
if ( interruptStatus & kStatus_RX_DONE )
{
rxWDInterrupts++;
KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
doFlushQueue = receiveInterruptOccurred();
KERNEL_DEBUG(DBG_GEM_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
ETHERNET_STAT_ADD( dot3RxExtraEntry.interrupts );
}
IODebuggerUnlock( lockState );
if ( doFlushQueue )
networkInterface->flushInputQueue();
if ( doService && netifEnabled )
transmitQueue->service();
} while ( interruptStatus );
return;
}
UInt32 UniNEnet::outputPacket(struct mbuf * pkt, void * param)
{
UInt32 ret = kIOReturnOutputSuccess;
KERNEL_DEBUG( DBG_GEM_TXQUEUE | DBG_FUNC_NONE,
(int) pkt, (int) pkt->m_pkthdr.len, 0, 0, 0 );
reserveDebuggerLock();
ELG( pkt, linkStatusPrev, 'OutP', "outputPacket" );
if ( linkStatusPrev != kLinkStatusUp )
{
ELG( pkt, linkStatusPrev, 'Out-', "UniNEnet::outputPacket - link is down" );
freePacket( pkt );
}
else if ( transmitPacket( pkt ) == false )
{
ret = kIOReturnOutputStall;
}
releaseDebuggerLock();
return ret;
}
void UniNEnet::putToSleep(bool pangeaClockOnly)
{
ELG( this, 0, 'Slep', "UniNEnet::putToSleep" );
if(enetClockOff)
{
if(!pangeaClockOnly)
{
OSSynchronizeIO();
callPlatformFunction("EnableUniNEthernetClock", true, (void*)true, 0, 0, 0);
OSSynchronizeIO();
enetClockOff = false;
} else return; }
reserveDebuggerLock();
ready = false;
if ( timerSource )
timerSource->cancelTimeout();
WRITE_REGISTER( InterruptMask, kInterruptMask_None );
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
if(pangeaClockOnly)
setLinkStatus(kIONetworkLinkValid);
else
setLinkStatus( 0, 0 );
if(!pangeaClockOnly)
stopChip(); flushRings( true, false );
if(!pangeaClockOnly)
stopPHY();
currentPowerState = 0;
if ( fBuiltin && (!fWOL || pangeaClockOnly) )
{
ALRT( 0, 0, '-Clk', "UniNEnet::putToSleep - turning off cell clock!!!" );
OSSynchronizeIO();
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)false, 0, 0, 0 );
OSSynchronizeIO();
}
if(pangeaClockOnly)
{
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
enetClockOff = true;
ready = true;
}
releaseDebuggerLock();
return;
}
bool UniNEnet::wakeUp(bool pangeaClockOnly)
{
bool rc = false;
bool regAvail;
UInt32 gemReg = 0;
ELG( this, 0, 'Wake', "UniNEnet::wakeUp" );
reserveDebuggerLock();
ready = false;
if(!pangeaClockOnly)
phyId = 0xFF;
if ( timerSource )
timerSource->cancelTimeout();
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
setLinkStatus( 0, 0 );
if ( fBuiltin )
{
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, 0, 0, 0 );
if ( ioMapEnet ) {
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
IOLog( "UniNEnet::wakeUp - ethernet cell's clock is disabled.\n" );
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, 0, 0, 0 );
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
IOLog( "UniNEnet::wakeUp - ethernet cell's clock is still disabled.\n" );
goto wakeUp_exit;
}
}
}
}
if(pangeaClockOnly)
enetClockOff = false;
else
{
nub->configWrite32( 0x04, 0x16 );
nub->configWrite32( 0x0C, ((2 + (kGEMBurstSize * (0+1)))<< 8) | (CACHE_LINE_SIZE >> 2) );
if ( ioMapEnet == NULL )
{
ioMapEnet = nub->mapDeviceMemoryWithRegister( 0x10 );
if ( ioMapEnet == NULL )
goto wakeUp_exit;
fpRegs = (GMAC_Registers*)ioMapEnet->getVirtualAddress();
ELG( ioMapEnet, fpRegs, 'Adrs', "start - base eNet addr" );
fpRegsPhys = (GMAC_Registers*)ioMapEnet->getPhysicalAddress();
}
}
if ( !initRxRing() || !initTxRing() )
goto wakeUp_exit;
currentPowerState = 1;
WRITE_REGISTER( SoftwareReset, kSoftwareReset_TX | kSoftwareReset_RX );
do
{ gemReg = READ_REGISTER( SoftwareReset );
}
while( gemReg & (kSoftwareReset_TX | kSoftwareReset_RX) );
initChip();
if(!pangeaClockOnly)
{
if ( fBuiltin )
{
hardwareResetPHY();
if ( phyId == 0xFF)
{
if ( miiFindPHY( &phyId ) == false )
goto wakeUp_exit;
}
}
getPhyType();
if ( !mediumDict && createMediumTables() == false )
{
ALRT( 0, 0, 'cmt-', "UniNEnet::start - createMediumTables failed" );
goto wakeUp_exit;
}
startPHY();
if ( fBuiltin )
miiInitializePHY( phyId );
}
timerSource->setTimeoutMS( WATCHDOG_TIMER_MS );
if ( getWorkLoop() )
getWorkLoop()->enableAllInterrupts();
ready = true;
if(!pangeaClockOnly)
monitorLinkStatus( true );
rc = true;
wakeUp_exit:
releaseDebuggerLock();
return rc;
}
IOReturn UniNEnet::enable(IONetworkInterface * netif)
{
ELG( this, netif, 'NetE', "UniNEnet::enable( netInterface* )" );
if ( netifEnabled )
{
IOLog("EtherNet(UniN): already enabled\n");
return kIOReturnSuccess;
}
if ( (ready == false) && !wakeUp(false) )
return kIOReturnIOError;
netifEnabled = true;
transmitQueue->setCapacity( TRANSMIT_QUEUE_SIZE );
transmitQueue->start();
return kIOReturnSuccess;
}
IOReturn UniNEnet::disable(IONetworkInterface * )
{
ELG( this, debugEnabled, 'NetD', "disable( IONetworkInterface* )" );
transmitQueue->stop();
transmitQueue->setCapacity(0);
transmitQueue->flush();
if ( debugEnabled == false )
putToSleep(false);
netifEnabled = false;
return kIOReturnSuccess;
}
IOReturn UniNEnet::enable(IOKernelDebugger * )
{
ELG( this, ready, 'DbgE', "UniNEnet::enable( IOKernelDebugger* )" );
if ( (ready == false) && !wakeUp(false) )
return kIOReturnIOError;
debugEnabled = true;
return kIOReturnSuccess;
}
IOReturn UniNEnet::disable(IOKernelDebugger * )
{
ELG( this, netifEnabled, 'DbgD', "UniNEnet::disable( IOKernelDebugger* )" );
debugEnabled = false;
if ( netifEnabled == false )
putToSleep(false);
return kIOReturnSuccess;
}
IOReturn UniNEnet::getPacketFilters( const OSSymbol *group, UInt32 *filters ) const
{
if ( group == gIOEthernetWakeOnLANFilterGroup )
{
if ( fBuiltin )
*filters = kIOEthernetWakeOnMagicPacket;
else *filters = 0;
return kIOReturnSuccess;
}
return super::getPacketFilters( group, filters );
}
IOReturn UniNEnet::setWakeOnMagicPacket( bool active )
{
ELG( this, active, 'WoMP', "UniNEnet::setWakeOnMagicPacket" );
fWOL = active;
return kIOReturnSuccess;
}
void UniNEnet::timeoutOccurred(IOTimerEventSource * )
{
IODebuggerLockState lockState;
bool doService = false;
UInt32 txRingIndex;
UInt32 x;
UInt32 txMACStatus, rxMACStatus, macControlStatus;
ELG( txCommandHead, txCommandTail, 'Time', "UniNEnet::timeoutOccurred" );
if(enetClockOff)
{
monitorLinkStatus(false);
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
return;
}
if ( ready == false )
{
ALRT( txCommandHead, txCommandTail, 'TIM-', "UniNEnet::timeoutOccurred - spurious" );
return;
}
txMACStatus = READ_REGISTER( TxMACStatus );
rxMACStatus = READ_REGISTER( RxMACStatus );
ELG( txMACStatus, rxMACStatus, 'MACS', "timeoutOccurred - Tx and Rx MAC Status regs" );
#ifdef NOT_NOW
{
UInt32 interruptStatus, rxKick;
interruptStatus = READ_REGISTER( StatusAlias );
rxKick = READ_REGISTER( RxKick );
ELG( rxKick, interruptStatus, 'rxIS', "timeoutOccurred" );
}
#endif // NOT_NOW
x = READ_REGISTER( LengthErrorCounter );
if ( x ) WRITE_REGISTER( LengthErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.frameTooLongs += x;
x = READ_REGISTER( AlignmentErrorCounter );
if ( x ) WRITE_REGISTER( AlignmentErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.alignmentErrors += x;
x = READ_REGISTER( FCSErrorCounter );
if ( x ) WRITE_REGISTER( FCSErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.fcsErrors += x;
x = READ_REGISTER( RxCodeViolationErrorCounter );
if ( x ) WRITE_REGISTER( RxCodeViolationErrorCounter, 0 );
fpEtherStats->dot3StatsEntry.internalMacTransmitErrors += x;
x = READ_REGISTER( FirstAttemptSuccessfulCollisionCounter );
if ( x ) WRITE_REGISTER( FirstAttemptSuccessfulCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.singleCollisionFrames += x;
x = READ_REGISTER( ExcessiveCollisionCounter );
if ( x ) WRITE_REGISTER( ExcessiveCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.excessiveCollisions += x;
x = READ_REGISTER( LateCollisionCounter );
if ( x ) WRITE_REGISTER( LateCollisionCounter, 0 );
fpEtherStats->dot3StatsEntry.lateCollisions += x;
lockState = IODebuggerLock( this );
monitorLinkStatus( false );
if(linkStatusPrev == kLinkStatusDown)
{
putToSleep(true);
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
return;
}
if ( txCommandHead != txCommandTail )
{
txRingIndex = READ_REGISTER( TxCompletion );
if ( txRingIndex == txRingIndexLast )
{
txWDCount++;
}
else
{
txWDCount = 0;
txRingIndexLast = txRingIndex;
}
if ( txWDCount > 2 )
{
if ( txRingIndex != txCommandTail )
{
UInt32 intStatus, compReg, kickReg;
intStatus = READ_REGISTER( StatusAlias );
compReg = READ_REGISTER( TxCompletion );
kickReg = READ_REGISTER( TxKick );
ALRT( intStatus, kickReg << 16 | compReg, 'Tx--', "UniNEnet::timeoutOccurred - Tx Int Timeout" );
}
transmitInterruptOccurred();
doService = true;
txRingIndexLast = txRingIndex;
txWDCount = 0;
}
}
else
{
txWDCount = 0;
}
if ( rxWDInterrupts == 0 )
{
switch ( rxWDCount )
{
case 0:
case 1:
rxWDCount++; break;
default:
if ( rxMACStatus & kRX_MAC_Status_Rx_Overflow )
{
restartReceiver();
NETWORK_STAT_ADD( inputErrors );
ETHERNET_STAT_ADD( dot3RxExtraEntry.watchdogTimeouts );
}
rxWDCount = 0;
break;
}
}
else
{
rxWDCount = 0;
rxWDInterrupts = 0;
}
if ( debugTxPoll )
{
debugQueue->flush();
debugTxPoll = false;
doService = true;
}
IODebuggerUnlock( lockState );
if (doService && netifEnabled)
{
transmitQueue->service();
}
timerSource->setTimeoutMS(WATCHDOG_TIMER_MS);
return;
}
const OSString * UniNEnet::newVendorString() const
{
return OSString::withCString("Apple");
}
const OSString * UniNEnet::newModelString() const
{
return OSString::withCString("gmac+");
}
const OSString * UniNEnet::newRevisionString() const
{
return OSString::withCString("");
}
IOReturn UniNEnet::setPromiscuousMode( bool active )
{
ELG( 0, active, 'SetP', "setPromiscuousMode" );
reserveDebuggerLock();
fIsPromiscuous = active;
if ( enetClockOff == false )
{
fRxMACConfiguration = READ_REGISTER( RxMACConfiguration );
if ( active )
fRxMACConfiguration |= kRxMACConfiguration_Promiscuous;
else fRxMACConfiguration &= ~kRxMACConfiguration_Promiscuous;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
}
releaseDebuggerLock();
return kIOReturnSuccess;
}
IOReturn UniNEnet::setMulticastMode( bool active )
{
ELG( this, active, 'SetM', "setMulticastMode" );
multicastEnabled = active;
return kIOReturnSuccess;
}
IOReturn UniNEnet::setMulticastList(IOEthernetAddress *addrs, UInt32 count)
{
ELG( addrs, count, 'SetL', "setMulticastList" );
if(enetClockOff)
return kIOReturnSuccess;
reserveDebuggerLock();
resetHashTableMask();
for (UInt32 i = 0; i < count; i++)
{
addToHashTableMask(addrs->bytes);
addrs++;
}
updateHashTableMask();
releaseDebuggerLock();
return kIOReturnSuccess;
}
IOOutputQueue* UniNEnet::createOutputQueue()
{
return IOBasicOutputQueue::withTarget( this, TRANSMIT_QUEUE_SIZE );
}
bool UniNEnet::createMediumTables()
{
IONetworkMedium *medium;
UInt32 i;
mediumDict = OSDictionary::withCapacity( fMediumTableCount );
ELG( 0, mediumDict, 'MTbl', "createMediumTables" );
if ( mediumDict == 0 )
return false;
for ( i = 0; i < fMediumTableCount; i++ )
{
medium = IONetworkMedium::medium( fpgMediumTable[i].type, fpgMediumTable[i].speed );
IONetworkMedium::addMedium( mediumDict, medium );
medium->release();
}
if ( publishMediumDictionary( mediumDict ) != true )
return false;
medium = IONetworkMedium::getMediumWithType( mediumDict, kIOMediumEthernetAuto );
setCurrentMedium( medium );
return true;
}
IOReturn UniNEnet::getChecksumSupport( UInt32 *checksumMask,
UInt32 checksumFamily,
bool )
{
if ( checksumFamily != kChecksumFamilyTCPIP )
return kIOReturnUnsupported;
*checksumMask = kChecksumTCPSum16;
return kIOReturnSuccess;
}
void UniNEnet::writeRegister( volatile UInt32 *pReg, UInt32 data )
{
if(enetClockOff)
{
ALRT(0, 0, 'Wrg-', "writeRegister: enet clock is off");
return;
}
if ( pReg != &fpRegs->MIFBitBangFrame_Output )
ELG( data, (UInt32)pReg - (UInt32)fpRegs, 'wReg', "writeRegister" );
OSWriteLittleInt32( pReg, 0, data );
return;
}