#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 );
}
struct LengthOffset
{
UInt32 setLength, setOffset;
};
LengthOffset gGMACRegisterTemplate[] =
{
{ 0x20, 0x0000 },
{ 0x14, 0x1000 },
{ 0x38, 0x2000 },
{ 0x1C, 0x2100 },
{ 0x14, 0x3000 },
{ 0x2C, 0x4000 },
{ 0x24, 0x4100 },
{ 0x68, 0x6000 },
{ 0xB8, 0x6080 },
{ 0x20, 0x6200 },
{ 0x1C, 0x9000 },
{ 0x10, 0x9050 },
{ 0, 0 }
};
#define super IOEthernetController
OSDefineMetaClassAndStructors( UniNEnet, IOEthernetController ) ;
#if USE_ELG
void UniNEnet::AllocateEventLog( UInt32 size )
{
IOPhysicalAddress phys;
mach_timespec_t time;
fpELG = (elg*)IOMallocContiguous( size, 0x1000, &phys );
if ( !fpELG )
{
kprintf( "AllocateEventLog - UniNEnet evLog allocation failed " );
return;
}
#ifdef OPEN_FIRMWARE
IOSetProcessorCacheMode( kernel_task,
(IOVirtualAddress)fpELG,
size,
kIOMapWriteThruCache );
#endif // OPEN_FIRMWARE
bzero( fpELG, size );
fpELG->evLogBuf = (UInt8*)fpELG + sizeof( struct elg );
fpELG->evLogBufe = (UInt8*)fpELG + kEvLogSize - 0x20; fpELG->evLogBufp = fpELG->evLogBuf;
fpELG->evLogFlag = 0x03330333;
IOGetTime( &time );
fpELG->startTimeSecs = time.tv_sec;
fpELG->physAddr = (UInt32)phys;
IOLog( "\033[32mUniNEnet::AllocateEventLog - buffer=%8x phys=%8lx \033[0m \n",
(unsigned int)fpELG, (UInt32)phys );
return;
}
void UniNEnet::EvLog( UInt32 a, UInt32 b, UInt32 ascii, char* str )
{
register UInt32 *lp;
register elg *pe = fpELG;
mach_timespec_t time;
UInt32 lefty;
if ( pe->evLogFlag == 0 )
return;
IOGetTime( &time );
if ( pe->evLogFlag <= kEvLogSize / 0x10 )
--pe->evLogFlag;
else if ( pe->evLogFlag == 0xDEBEEFED )
{
for ( lp = (UInt32*)pe->evLogBuf; lp < (UInt32*)pe->evLogBufe; lp++ )
*lp = 0xDEBEEFED;
pe->evLogBufp = pe->evLogBuf; pe->evLogFlag = 0x03330333; }
if ( pe->evLogBufp >= pe->evLogBufe )
{
pe->evLogBufp = pe->evLogBuf;
pe->wrapCount++;
if ( pe->evLogFlag != 0xFEEDBEEF ) {
pe->evLogFlag = 0;
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)fpELG, kEvLogSize );
return;
}
pe->startTimeSecs = time.tv_sec;
}
lp = (UInt32*)pe->evLogBufp;
pe->evLogBufp += 0x10;
lefty = time.tv_sec << 24; *lp++ = lefty | (time.tv_nsec >> 10); *lp++ = a;
*lp++ = b;
*lp = ascii;
#ifdef STEPPABLE
if ( pe->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 );
}
#endif // STEPPABLE
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( '****', '****', 'Alrt', "*** 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';
fpELG->alertCount++;
OSSynchronizeIO();
IOFlushProcessorCache( kernel_task, (IOVirtualAddress)fpELG, kEvLogSize );
return 0xDEADBEEF;
}
#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;
fCellClockEnabled = true;
fMediumType = kIOMediumEthernetAuto;
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;
phyId = 0xFF;
fLinkStatus = kLinkStatusUnknown;
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" );
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 ( fMediumDict ) fMediumDict->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;
UInt32 mifStatus;
bool doFlushQueue;
bool doService;
if ( fReady == false )
{
if ( fCellClockEnabled == false )
interruptStatus = 0x8BADF00D;
else interruptStatus = READ_REGISTER( Status );
ALRT( 0, interruptStatus, 'int-', "interruptOccurred - not ready" );
return;
}
lockState = IODebuggerLock( this );
interruptStatus = READ_REGISTER( Status );
ELG( READ_REGISTER( RxCompletion ), interruptStatus, 'Int+', "interruptOccurred - got status" );
#ifdef LOG_RX_BACKUP
{
UInt32 fifoCtr = READ_REGISTER( RxFIFOPacketCounter );
UInt32 rxMACStatus = READ_REGISTER( RxMACStatus ); if ( interruptStatus & kStatus_Rx_Buffer_Not_Available
|| rxMACStatus & kRX_MAC_Status_Rx_Overflow || fifoCtr > 5 )
{
ELG( fifoCtr, rxMACStatus, 'Rx--', "interruptOccurred - Rx overflow" );
fRxMACStatus |= rxMACStatus; }
}
#endif // LOG_RX_BACKUP
fIntStatusForTO |= interruptStatus;
doService = false;
if ( interruptStatus & kStatus_TX_INT_ME )
{
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;
{
KERNEL_DEBUG( DBG_GEM_RXIRQ | DBG_FUNC_START, 0, 0, 0, 0, 0 );
doFlushQueue = receivePackets( false );
KERNEL_DEBUG( DBG_GEM_RXIRQ | DBG_FUNC_END, 0, 0, 0, 0, 0 );
ETHERNET_STAT_ADD( dot3RxExtraEntry.interrupts );
}
if ( interruptStatus & kStatus_MIF_Interrupt )
{
mifStatus = READ_REGISTER( MIFStatus ); ELG( 0, mifStatus, '*MIF', "interruptOccurred - MIF interrupt" );
}
IODebuggerUnlock( lockState );
if ( doFlushQueue )
networkInterface->flushInputQueue();
if ( doService && netifEnabled )
transmitQueue->service();
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, fLinkStatus, 'OutP', "outputPacket" );
if ( fLinkStatus != kLinkStatusUp )
{
ELG( pkt, fLinkStatus, 'Out-', "UniNEnet::outputPacket - link is down" );
freePacket( pkt );
}
else if ( transmitPacket( pkt ) == false )
{ ret = kIOReturnOutputStall;
}
releaseDebuggerLock();
return ret;
}
void UniNEnet::putToSleep( bool sleepCellClockOnly )
{
IOMediumType mediumType = kIOMediumEthernetNone;
IONetworkMedium *medium;
ELG( fCellClockEnabled, sleepCellClockOnly, 'Slep', "UniNEnet::putToSleep" );
if ( fCellClockEnabled == false )
{
if ( sleepCellClockOnly )
return;
ELG( 0, 0, '+Clk', "UniNEnet::putToSleep - turning on cell clock!!!" );
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, (void*)nub, 0, 0 );
OSSynchronizeIO();
IODelay( 3 ); fCellClockEnabled = true;
}
reserveDebuggerLock();
fReady = false;
if ( timerSource )
timerSource->cancelTimeout();
WRITE_REGISTER( InterruptMask, kInterruptMask_None );
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
medium = IONetworkMedium::getMediumWithType( fMediumDict, mediumType );
setLinkStatus( kIONetworkLinkValid, medium, 0 ); if ( sleepCellClockOnly )
{
}
else
{
stopChip(); stopPHY(); }
flushRings( true, false );
currentPowerState = 0;
if ( fBuiltin && (!fWOL || sleepCellClockOnly) )
{
fCellClockEnabled = false;
ELG( 0, 0, '-Clk', "UniNEnet::putToSleep - disabling cell clock!!!" );
OSSynchronizeIO();
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)false, (void*)nub, 0, 0 );
OSSynchronizeIO();
ELG( 0, 0, '-clk', "UniNEnet::putToSleep - disabled ethernet cell clock." );
}
if ( sleepCellClockOnly )
timerSource->setTimeoutMS( WATCHDOG_TIMER_MS );
releaseDebuggerLock();
return;
}
bool UniNEnet::wakeUp( bool wakeCellClockOnly )
{
bool rc = false;
bool regAvail;
UInt32 gemReg = 0;
IOMediumType mediumType = kIOMediumEthernetNone;
IONetworkMedium *medium;
ELG( this, wakeCellClockOnly, 'Wake', "UniNEnet::wakeUp" );
reserveDebuggerLock();
fReady = false;
if ( !wakeCellClockOnly ) phyId = 0xFF;
if ( timerSource )
timerSource->cancelTimeout();
if ( getWorkLoop() )
getWorkLoop()->disableAllInterrupts();
medium = IONetworkMedium::getMediumWithType( fMediumDict, mediumType );
setLinkStatus( kIONetworkLinkValid, medium, 0 );
if ( fBuiltin )
{
ELG( 0, 0, '+Clk', "UniNEnet::wakeUp - turning on cell clock!!!" );
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, (void*)nub, 0, 0 );
IODelay( 3 );
if ( ioMapEnet ) {
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
ALRT( 0, 0, 'wk1-', "UniNEnet::wakeUp - ethernet cell's clock is disabled." );
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)true, (void*)nub, 0, 0 );
IOSleep( 10 );
regAvail = ml_probe_read( (vm_offset_t)&fpRegsPhys->Status,
&(unsigned int)gemReg );
if ( !regAvail ) {
ALRT( 0, 0, 'wk2-', "UniNEnet::wakeUp - ethernet cell's clock is still disabled." );
goto wakeUp_exit;
}
}
}
fCellClockEnabled = true;
}
if ( !wakeCellClockOnly )
{
nub->configWrite32( 0x04, 0x16 );
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 ( !wakeCellClockOnly )
{
if ( fBuiltin )
{
hardwareResetPHY();
if ( phyId == 0xFF )
{
if ( miiFindPHY( &phyId ) == false )
goto wakeUp_exit;
}
}
getPhyType();
if ( !fMediumDict && 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();
fReady = true;
if ( !wakeCellClockOnly )
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 ( (fReady == false) && !wakeUp(false) )
return kIOReturnIOError;
netifEnabled = true;
transmitQueue->setCapacity( TRANSMIT_QUEUE_SIZE );
transmitQueue->start();
return kIOReturnSuccess;
}
IOReturn UniNEnet::disable( IONetworkInterface* )
{
#if USE_ELG
#endif // USE_ELG
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, fReady, 'DbgE', "UniNEnet::enable( IOKernelDebugger* )" );
if ( (fReady == 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;
ELG( txCommandHead << 16 | txCommandTail, fCellClockEnabled, 'Time', "UniNEnet::timeoutOccurred" );
if ( fCellClockEnabled == false )
{
monitorLinkStatus( false );
timerSource->setTimeoutMS( WATCHDOG_TIMER_MS );
return;
}
x = READ_REGISTER( TxMACStatus );
fRxMACStatus |= READ_REGISTER( RxMACStatus );
ELG( x, fRxMACStatus, 'MACS', "timeoutOccurred - Tx and Rx MAC Status regs" );
#ifdef JUST_FOR_TESTING
{
UInt32 interruptStatus, rxKick, rxCompletion;
interruptStatus = READ_REGISTER( StatusAlias );
rxKick = READ_REGISTER( RxKick );
rxCompletion = READ_REGISTER( RxCompletion );
ELG( rxKick<<16 | rxCompletion, interruptStatus, 'rxIS', "timeoutOccurred" );
}
#endif // JUST_FOR_TESTING
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 );
if ( (fIntStatusForTO & (kStatus_TX_DONE | kStatus_RX_DONE)) == 0 )
monitorLinkStatus( false );
if ( fLinkStatus == kLinkStatusDown )
{
putToSleep( true );
timerSource->setTimeoutMS( WATCHDOG_TIMER_MS );
return;
}
if ( (fIntStatusForTO & kStatus_TX_DONE) )
{
txWDCount = 0;
}
else
{
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;
}
}
if ( fIntStatusForTO & kStatus_RX_DONE )
{
rxWDCount = 0; }
else if ( rxWDCount++ >= 2 ) {
if ( (fRxMACStatus & kRX_MAC_Status_Rx_Overflow) || (rxWDCount > (30000 / WATCHDOG_TIMER_MS)) ) {
restartReceiver();
NETWORK_STAT_ADD( inputErrors );
ETHERNET_STAT_ADD( dot3RxExtraEntry.watchdogTimeouts );
fRxMACStatus = 0; rxWDCount = 0; }
}
fIntStatusForTO = 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 ( fCellClockEnabled )
{
fRxMACConfiguration = READ_REGISTER( RxMACConfiguration );
if ( active )
{
fRxMACConfiguration |= kRxMACConfiguration_Promiscuous;
fRxMACConfiguration &= ~kRxMACConfiguration_Strip_FCS;
}
else
{
fRxMACConfiguration &= ~kRxMACConfiguration_Promiscuous;
fRxMACConfiguration |= kRxMACConfiguration_Strip_FCS;
}
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 ( fCellClockEnabled == false )
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;
fMediumDict = OSDictionary::withCapacity( fMediumTableCount );
ELG( 0, fMediumDict, 'MTbl', "createMediumTables" );
if ( fMediumDict == 0 )
return false;
for ( i = 0; i < fMediumTableCount; i++ )
{
medium = IONetworkMedium::medium( fpgMediumTable[i].type, fpgMediumTable[i].speed );
IONetworkMedium::addMedium( fMediumDict, medium );
medium->release();
}
if ( publishMediumDictionary( fMediumDict ) != true )
return false;
medium = IONetworkMedium::getMediumWithType( fMediumDict, kIOMediumEthernetAuto );
setCurrentMedium( medium );
return true;
}
IOReturn UniNEnet::selectMedium( const IONetworkMedium *medium )
{
IOMediumType mType = medium->getType();
UInt16 controlReg = 0;
IOReturn ior;
bool gotReg;
if ( fCellClockEnabled == false )
wakeUp( true );
gotReg = miiReadWord( &controlReg, MII_CONTROL, phyId );
ALRT( controlReg, mType, 'sMed', "selectMedium" );
if ( !gotReg || controlReg == 0xFFFF )
{
ALRT( fPHYType, controlReg, 'Pnr-', "UniNEnet::selectMedium - PHY not responding" );
return kIOReturnIOError;
}
if ( (mType & kIOMediumNetworkTypeMask) != kIOMediumEthernet )
{
ALRT( fPHYType, controlReg, 'sMe-', "UniNEnet::selectMedium - not ethernet medium" );
return kIOReturnBadArgument;
}
fMediumType = mType;
ior = negotiateSpeedDuplex( controlReg );
if ( ior != kIOReturnSuccess )
{
ior = forceSpeedDuplex( controlReg );
if ( ior != kIOReturnSuccess )
return ior;
}
setSelectedMedium( medium );
ELG( fXIFConfiguration, controlReg, 'sMe+', "UniNEnet::selectMedium - returning kIOReturnSuccess" );
monitorLinkStatus( true );
return kIOReturnSuccess;
}
IOReturn UniNEnet::negotiateSpeedDuplex( UInt16 controlReg )
{
UInt16 anar; UInt16 gigReg; IOMediumType mType;
bool br;
mType = fMediumType & (kIOMediumNetworkTypeMask | kIOMediumSubTypeMask | kIOMediumCommonOptionsMask);
controlReg |= MII_CONTROL_AUTONEGOTIATION | MII_CONTROL_RESTART_NEGOTIATION;
ELG( mType, controlReg, 'n SD', "UniNEnet::negotiateSpeedDuplex" );
br = miiReadWord( &anar, MII_ADVERTISEMENT, phyId );
anar &= ~( MII_ANAR_100BASET4
| MII_ANAR_100BASETX_FD
| MII_ANAR_100BASETX
| MII_ANAR_10BASET_FD
| MII_ANAR_10BASET );
switch ( mType )
{
case kIOMediumEthernetAuto:
anar |= ( MII_ANAR_100BASETX_FD
| MII_ANAR_100BASETX
| MII_ANAR_10BASET_FD
| MII_ANAR_10BASET );
break;
case kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex: anar |= MII_ANAR_10BASET_FD;
break;
case kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex: anar |= MII_ANAR_10BASET;
break;
case kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex: anar |= MII_ANAR_100BASETX_FD;
break;
case kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex: anar |= MII_ANAR_100BASETX;
break;
case kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex: case kIOMediumEthernet1000BaseTX | kIOMediumOptionHalfDuplex: break;
default:
ELG( 0, 0, ' ?sd', "UniNEnet::negotiateSpeedDuplex - not 10 nor 100 combo." );
break;
}
miiWriteWord( anar, MII_ADVERTISEMENT, phyId );
switch ( fPHYType )
{
case 0x0971: case 0x5201: case 0x5221:
break;
case 0x1011:
br = miiReadWord( &gigReg, MII_MARVELL_PHY_SPECIFIC_CONTROL, phyId );
gigReg |= MII_MARVELL_PHY_SPECIFIC_CONTROL_AUTOL_MDIX;
miiWriteWord( gigReg, MII_1000BASETCONTROL, phyId );
controlReg |= MII_CONTROL_RESET;
case 0x5400: case 0x5401:
case 0x5411:
case 0x5421:
br = miiReadWord( &gigReg, MII_1000BASETCONTROL, phyId );
gigReg &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | MII_1000BASETCONTROL_HALFDUPLEXCAP);
switch ( mType )
{ case kIOMediumEthernetAuto:
case kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex:
gigReg |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
break;
case kIOMediumEthernet1000BaseTX | kIOMediumOptionHalfDuplex:
gigReg |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
break;
}
miiWriteWord( gigReg, MII_1000BASETCONTROL, phyId );
break;
case ' GEM': default:
break;
}
miiWriteWord( controlReg, MII_CONTROL, phyId );
br = miiWaitForAutoNegotiation( phyId );
if ( br )
return kIOReturnSuccess;
return kIOReturnIOError;
}
IOReturn UniNEnet::forceSpeedDuplex( UInt16 controlReg )
{
IOMediumType mType;
UInt16 statusReg;
UInt16 gigReg; bool br;
mType = fMediumType & (kIOMediumNetworkTypeMask | kIOMediumSubTypeMask | kIOMediumCommonOptionsMask);
ELG( mType, controlReg, 'f SD', "UniNEnet::forceSpeedDuplex" );
switch ( mType & (kIOMediumNetworkTypeMask | kIOMediumSubTypeMask) )
{
case kIOMediumEthernetAuto:
return kIOReturnIOError;
case kIOMediumEthernet10BaseT:
break;
case kIOMediumEthernet100BaseTX:
controlReg = MII_CONTROL_SPEED_SELECTION;
break;
case kIOMediumEthernet1000BaseTX:
controlReg = MII_CONTROL_SPEED_SELECTION_2;
break;
}
if ( mType & kIOMediumOptionFullDuplex ) controlReg |= MII_CONTROL_FULLDUPLEX;
if ( mType & kIOMediumOptionLoopback ) controlReg |= MII_CONTROL_LOOPBACK;
switch ( fPHYType )
{
case 0x1011:
br = miiReadWord( &gigReg, MII_MARVELL_PHY_SPECIFIC_CONTROL, phyId );
gigReg &= ~(MII_MARVELL_PHY_SPECIFIC_CONTROL_AUTOL_MDIX
| MII_MARVELL_PHY_SPECIFIC_CONTROL_MANUAL_MDIX);
miiWriteWord( gigReg, MII_1000BASETCONTROL, phyId );
controlReg |= MII_CONTROL_RESET;
break;
case 0x0971: case 0x5201: case 0x5221:
case 0x5400:
case 0x5401:
case 0x5411:
case 0x5421:
case ' GEM':
default: miiWriteWord( MII_CONTROL_RESET, MII_CONTROL, phyId );
IOSleep( 3 );
break;
}
miiWriteWord( controlReg, MII_CONTROL, phyId );
if ( controlReg & MII_CONTROL_SPEED_SELECTION_2 )
fXIFConfiguration |= kXIFConfiguration_GMIIMODE; else fXIFConfiguration &= kXIFConfiguration_GMIIMODE; WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
for ( int i = 0; i < 5000; i+= 10 )
{
miiReadWord( &statusReg, MII_STATUS, phyId );
if ( statusReg & MII_STATUS_LINK_STATUS )
return kIOReturnSuccess; IOSleep( 10 );
}
return kIOReturnIOError;
}
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 ( fCellClockEnabled == false )
{
ALRT( data, pReg, 'Wrg-', "writeRegister: enet clock is disabled" );
return;
}
if ( pReg != &fpRegs->MIFBitBangFrame_Output )
ELG( data, (UInt32)pReg - (UInt32)fpRegs, 'wReg', "writeRegister" );
OSWriteLittleInt32( pReg, 0, data );
return;
}
IOReturn UniNEnet::newUserClient( task_t owningTask,
void*, UInt32 type, IOUserClient **handler ) {
IOReturn ior = kIOReturnSuccess;
UniNEnetUserClient *client = NULL;
ELG( type, type, 'Usr+', "UniNEnet::newUserClient" );
if ( type != 'GMAC' )
{ ELG( 0, type, 'Usr-', "UniNEnet::newUserClient - unlucky." );
return 0x333;
}
client = UniNEnetUserClient::withTask( owningTask );
if ( !client )
{
ELG( 0, 0, 'usr-', "UniNEnet::newUserClient: Can't create user client" );
return 0x334;
}
if ( ior == kIOReturnSuccess )
{ if ( client->attach( this ) == false )
{
ior = 0x335;
ELG( 0, 0, 'USR-', "UniNEnet::newUserClient: Can't attach user client" );
}
}
if ( ior == kIOReturnSuccess )
{ if ( client->start( this ) == false )
{
ior = 0x336;
ELG( 0, 0, 'USR-', "UniNEnet::newUserClient: Can't start user client" );
}
}
if ( client && (ior != kIOReturnSuccess) )
{
client->detach( this );
client->release();
client = 0;
}
*handler = client;
return ior;
}
#undef super
#define super IOUserClient
OSDefineMetaClassAndStructors( UniNEnetUserClient, IOUserClient ) ;
UniNEnetUserClient* UniNEnetUserClient::withTask( task_t owningTask )
{
UniNEnetUserClient* me = new UniNEnetUserClient;
if ( me && me->init() == false )
{
me->release();
return 0;
}
me->fTask = owningTask;
return me;
}
bool UniNEnetUserClient::start( IOService * provider )
{
fProvider = (UniNEnet*)provider;
UC_ELG( 0, 0, 'UC S', "UniNEnetUserClient::start" );
if ( super::start( provider ) == false ) return false;
if ( provider->open( this ) == false ) return false;
fProvider = (UniNEnet*)provider;
fMethods[0].object = this;
fMethods[0].func = (IOMethod)&UniNEnetUserClient::doRequest;
fMethods[0].count0 = 0xFFFFFFFF;
fMethods[0].count1 = 0xFFFFFFFF;
fMethods[0].flags = kIOUCStructIStructO;
return true;
}
IOReturn UniNEnetUserClient::clientClose()
{
if ( fProvider )
{
UC_ELG( 0, 0, 'UC C', "UniNEnetUserClient::clientClose" );
if ( fProvider->isOpen( this ) )
fProvider->close( this );
detach( fProvider );
fProvider = 0;
}
return kIOReturnSuccess;
}
IOReturn UniNEnetUserClient::clientDied()
{
if ( fProvider )
UC_ELG( 0, 0, 'UC D', "UniNEnetUserClient::clientDied" );
return clientClose();
}
IOReturn UniNEnetUserClient::connectClient( IOUserClient *client )
{
UC_ELG( 0, 0, 'uCon', "connectClient - connect client" );
return kIOReturnSuccess;
}
IOReturn UniNEnetUserClient::registerNotificationPort( mach_port_t port, UInt32 type )
{
UC_ELG( 0, 0, 'uRNP', "UniNEnetUserClient - register notification ignored" );
return kIOReturnUnsupported;
}
IOExternalMethod* UniNEnetUserClient::getExternalMethodForIndex( UInt32 index )
{
IOExternalMethod *result = NULL;
UC_ELG( 0, index, 'uXMi', "getExternalMethodForIndex - get external method" );
if ( index == 0 )
result = &fMethods[0];
return result;
}
IOReturn UniNEnetUserClient::doRequest(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
UInt8 *input;
UC_ELG( *pOutPutSize, (UInt32)pIn, 'uReq', "doRequest - get external method" );
if ( pIn && pOut && (inputSize > 0) )
{
input = (UInt8*)pIn;
switch( *input ) {
case kGMACUserCmd_GetLog: return getGMACLog( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_GetRegs: return getGMACRegs( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_GetTxRing: return getGMACTxRing( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_GetRxRing: return getGMACRxRing( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_ReadAllMII:return readAllMII( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_ReadMII: return readMII( pIn, pOut, inputSize, pOutPutSize );
case kGMACUserCmd_WriteMII: return writeMII( pIn, pOut, inputSize, pOutPutSize );
default:
IOLog( "UniNEnetUserClient - Bad command to doRequest, %x\n", *input );
}
}
else IOLog( "UniNEnetUserClient - pin/pout,size error\n" );
return kIOReturnBadArgument;
}
#if USE_ELG
IOReturn UniNEnetUserClient::getGMACLog(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
IOMemoryDescriptor *md; UInt8 *input = (UInt8*)pIn;
vm_address_t bigaddr;
IOByteCount biglen;
IOByteCount bc;
IOReturn ior;
UC_ELG( (UInt32)pIn, inputSize, 'UgLg', "UniNEnetUserClient::getGMACLog" );
UC_ELG( (UInt32)pOut, *pOutPutSize, 'UgL2', "UniNEnetUserClient::getGMACLog" );
bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
biglen = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
UC_ELG( bigaddr, biglen, '=uBf', "UniNEnetUserClient::getGMACLog - user buffer" );
md = IOMemoryDescriptor::withAddress( bigaddr, biglen, kIODirectionOutIn, fTask ); if ( !md ) goto Fail;
ior = md->prepare( kIODirectionNone );
if ( ior ) { UC_ELG( -1, ior, 'prp-', "UniNEnetUserClient::getGMACLog - prepare failed" ); }
#ifdef JUST_FOR_TESTING /// don't execute until Alrt is called.
while( fProvider->fpELG->alertCount == 0 ) IOSleep( 100 );
#endif // JUST_FOR_TESTING
bc = md->writeBytes( 0, fProvider->fpELG, kEvLogSize );
if ( bc != kEvLogSize )
UC_ELG( 0, bc, 'Ubc-', "UniNEnetUserClient::getGMACLog - write failed" );
ior = md->complete( kIODirectionNone );
if ( ior ) { UC_ELG( 0, ior, 'gLg-', "UniNEnetUserClient::getGMACLog - complete failed" ); }
else { UC_ELG( 0, 0, 'gLg+', "UniNEnetUserClient::getGMACLog - complete worked" ); }
md->release(); fProvider->fpELG->evLogFlag = 0xFEEDBEEF;
return kIOReturnSuccess;
Fail:
return kIOReturnBadArgument;
}
#else // no event logging buffer:
IOReturn UniNEnetUserClient::getGMACLog( void *, void *, IOByteCount, IOByteCount* )
{
return kIOReturnBadArgument;
}
#endif // USE_ELG
IOReturn UniNEnetUserClient::getGMACRegs(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
IOMemoryDescriptor *md; UInt8 *input = (UInt8*)pIn;
vm_address_t bigaddr;
IOByteCount biglen;
LengthOffset *pTemplate;
UInt8 *src;
UInt32 dest = 0;
UInt32 len;
IOByteCount bc;
UInt32 lowRegs[ 8 ];
UInt32 *pl; IOReturn ior;
bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
biglen = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
md = IOMemoryDescriptor::withAddress( bigaddr, biglen, kIODirectionOutIn, fTask ); if ( !md ) goto Fail;
ior = md->prepare( kIODirectionNone );
if ( ior ) { UC_ELG( -1, ior, 'prp-', "UniNEnetUserClient::getGMACRegs - prepare failed" ); }
for ( pTemplate = gGMACRegisterTemplate; ; pTemplate++ )
{
bc = md->writeBytes( dest, pTemplate, sizeof( LengthOffset ) );
dest += sizeof( LengthOffset );
len = pTemplate->setLength;
if ( len == 0 )
break;
if ( pTemplate->setOffset == 0 )
{ pl = (UInt32*)fProvider->fpRegs;
lowRegs[ 0 ] = pl[ 0 ];
lowRegs[ 1 ] = pl[ 1 ];
lowRegs[ 2 ] = pl[ 2 ];
lowRegs[ 3 ] = pl[ 7 ];
lowRegs[ 4 ] = pl[ 4 ];
lowRegs[ 5 ] = pl[ 5 ];
lowRegs[ 6 ] = pl[ 6 ];
lowRegs[ 7 ] = pl[ 7 ];
src = (UInt8*)lowRegs;
bc = md->writeBytes( dest, src, len );
}
else
{
src = (UInt8*)fProvider->fpRegs + pTemplate->setOffset;
bc = md->writeBytes( dest, src, len );
}
if ( bc != len )
{
UC_ELG( len, bc, 'Ubc-', "UniNEnetUserClient::getGMACRegs - write failed" );
break;
}
dest += len;
}
ior = md->complete( kIODirectionNone );
if ( ior ) { UC_ELG( 0, ior, 'gLg-', "UniNEnetUserClient::getGMACRegs - complete failed" ); }
else { UC_ELG( 0, 0, 'gLg+', "UniNEnetUserClient::getGMACRegs - complete worked" ); }
md->release(); return kIOReturnSuccess;
Fail:
return kIOReturnBadArgument;
}
IOReturn UniNEnetUserClient::getGMACTxRing(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
IOMemoryDescriptor *md; UInt8 *input = (UInt8*)pIn;
vm_address_t bigaddr;
IOByteCount biglen;
UInt8 *src;
UInt32 dest;
UInt32 len;
IOByteCount bc;
IOReturn ior;
bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
biglen = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
md = IOMemoryDescriptor::withAddress( bigaddr, biglen, kIODirectionOutIn, fTask ); if ( !md ) return kIOReturnBadArgument;
ior = md->prepare( kIODirectionNone );
if ( ior ) { UC_ELG( -1, ior, 'prp-', "UniNEnetUserClient::getGMACTxRing - prepare failed" ); }
dest = 0;
src = (UInt8*)fProvider->fTxDescriptorRing;
len = fProvider->fTxRingElements * sizeof( TxDescriptor );
bc = md->writeBytes( dest, src, len );
ior = md->complete( kIODirectionNone );
if ( ior ) { UC_ELG( 0, ior, 'gLg-', "UniNEnetUserClient::getGMACTxRing - complete failed" ); }
else { UC_ELG( 0, 0, 'gLg+', "UniNEnetUserClient::getGMACTxRing - complete worked" ); }
md->release(); return kIOReturnSuccess;
}
IOReturn UniNEnetUserClient::getGMACRxRing(
void *pIn, void *pOut,
IOByteCount inputSize, IOByteCount *pOutPutSize )
{
IOMemoryDescriptor *md; UInt8 *input = (UInt8*)pIn;
vm_address_t bigaddr;
IOByteCount biglen;
UInt8 *src;
UInt32 dest;
UInt32 len;
IOByteCount bc;
IOReturn ior;
bigaddr = input[1] << 24 | input[2] << 16 | input[3] << 8 | input[4];
biglen = input[5] << 24 | input[6] << 16 | input[7] << 8 | input[8];
md = IOMemoryDescriptor::withAddress( bigaddr, biglen, kIODirectionOutIn, fTask ); if ( !md ) return kIOReturnBadArgument;
ior = md->prepare( kIODirectionNone );
if ( ior ) { UC_ELG( -1, ior, 'prp-', "UniNEnetUserClient::getGMACRxRing - prepare failed" ); }
dest = 0;
src = (UInt8*)fProvider->fRxDescriptorRing;
len = fProvider->fRxRingElements * sizeof( RxDescriptor );
bc = md->writeBytes( dest, src, len );
ior = md->complete( kIODirectionNone );
if ( ior ) { UC_ELG( 0, ior, 'gLg-', "UniNEnetUserClient::getGMACRxRing - complete failed" ); }
else { UC_ELG( 0, 0, 'gLg+', "UniNEnetUserClient::getGMACRxRing - complete worked" ); }
md->release(); return kIOReturnSuccess;
}
IOReturn UniNEnetUserClient::readAllMII( void *pIn,
void *pOut,
IOByteCount inputSize,
IOByteCount *outPutSize )
{
bool result;
UInt16 *reg_value; UInt16 i;
IOLog( "Hello from readAllMII\n" );
if ( pOut && outPutSize && *outPutSize >= (32 * sizeof( UInt16 )) )
{
reg_value = (UInt16*)pOut;
*outPutSize = 0;
for ( i = 0 ; i < 32; i++ )
{
result = fProvider->miiReadWord( reg_value, i, kPHYAddr0 );
if ( result )
{
IOLog( "read mii %d, 0x%x\n", i, *reg_value );
reg_value++; *outPutSize += sizeof( UInt16 ); }
else
{
IOLog( "read of mii %d failed\n", i );
return kIOReturnError; }
}
return kIOReturnSuccess;
}
return kIOReturnBadArgument;
}
IOReturn UniNEnetUserClient::readMII( void *pIn,
void *pOut,
IOByteCount inputSize,
IOByteCount *outPutSize )
{
bool result;
UInt16 *reg_value = (UInt16*)pOut; UInt16 reg_num = *((UInt8*)pIn+1);
IOLog( "hello from readMII\n" );
if ( pIn && inputSize == 2 && pOut && outPutSize && *outPutSize >= (1 * sizeof(UInt16))) {
if ( reg_num < 32 )
{
*outPutSize = 0; result = fProvider->miiReadWord( reg_value, reg_num, kPHYAddr0 );
if ( result )
{
IOLog( "read mii %d, 0x%x\n", reg_num, *reg_value );
*outPutSize += sizeof( UInt16 ); }
else
{
IOLog( "read of mii %d failed\n", reg_num );
return kIOReturnError; }
return kIOReturnSuccess;
}
}
return kIOReturnBadArgument;
}
IOReturn UniNEnetUserClient::writeMII( void *pIn,
void *pOut,
IOByteCount inputSize,
IOByteCount *outPutSize )
{
UInt8 *input_bytes = (UInt8*)pIn;
UInt16 reg_num = input_bytes[1];
UInt16 reg_val = input_bytes[2] << 8 | input_bytes[3];
bool result;
IOLog( "hello from writeMII\n" );
if ( outPutSize )
*outPutSize = 0;
if ( pIn && inputSize == 4 )
{
if ( reg_num < 32 )
{
result = fProvider->miiWriteWord( reg_val, reg_num, kPHYAddr0 );
if ( result )
{
IOLog( "wrote mii %d with 0x%x\n", reg_num, reg_val );
}
else
{
IOLog( "write of mii %d failed\n", reg_num );
return kIOReturnError; }
return kIOReturnSuccess;
}
}
return kIOReturnBadArgument;
}