RTL8139Private.cpp [plain text]
#include "RTL8139.h"
void RTL8139::transmitterInterrupt( bool *reclaimed )
{
UInt32 txStatus;
UInt8 collisions;
UInt32 tcr;
while ( fTxSendCount )
{
txStatus = csrRead32( RTL_TSD0 + fTxAckIndex * sizeof( UInt32 ) );
if ( (txStatus & (R_TSD_TABT | R_TSD_TOK | R_TSD_TUN)) == 0 )
break;
ELG( fTxAckIndex, txStatus, ' Tx+', "RTL8139::transmitterInterrupt" );
collisions = (txStatus & R_TSD_NCC) >> 24;
if ( txStatus & R_TSD_TABT ) {
ALRT( fTxAckIndex, txStatus, 'TxA-', "RTL8139::transmitterInterrupt - transmit abort" );
BUMP_NET_COUNTER( outputErrors );
tcr = csrRead32( RTL_TCR );
tcr |= R_TCR_CLRABT; csrWrite32( RTL_TCR, tcr );
if ( collisions == 0xF ) BUMP_ETHER_COUNTER( excessiveCollisions );
if ( txStatus & R_TSD_OWC ) BUMP_ETHER_COUNTER( lateCollisions );
if ( txStatus & R_TSD_CRS ) BUMP_ETHER_COUNTER( carrierSenseErrors );
break; }
if ( txStatus & R_TSD_TUN )
{
ALRT( fTxAckIndex, txStatus, 'TxU-', "RTL8139::transmitterInterrupt - transmit underrun" );
BUMP_ETHER_TX_COUNTER( underruns );
}
if ( collisions )
{
ALRT( fTxAckIndex, txStatus, 'TxC-', "RTL8139::transmitterInterrupt - transmit collisions" );
netStats->collisions += collisions;
if ( collisions > 1 )
BUMP_ETHER_COUNTER( multipleCollisionFrames );
else BUMP_ETHER_COUNTER( singleCollisionFrames );
}
fTxSendCount--;
fTxBufOwnership[ fTxAckIndex ] = kOwnedByHost;
if ( ++fTxAckIndex >= kTxBufferCount )
fTxAckIndex = 0;
*reclaimed = true;
}
BUMP_ETHER_TX_COUNTER( interrupts );
return;
}
void RTL8139::receiverInterrupt( bool *queued )
{
rbuf_hdr_t rbh; mbuf_t pkt;
UInt16 pktLen;
UInt32 totalBytes = 0;
while ( (csrRead8( RTL_CM ) & R_CM_BUFE) == 0 )
{
if ( totalBytes > 0x10000 ) {
ELG( 0, totalBytes, 'RxLm', "RTL8139::receiverInterrupt - reached loop limit." );
break;
}
*(UInt32*)&rbh = OSReadLittleInt32( fpRxBuffer, fRxOffset );
pktLen = rbh.rb_count - 4; fRxOffset += sizeof( rbh );
totalBytes += pktLen;
if ( rbh.rb_status & (R_RSR_FAE | R_RSR_CRC | R_RSR_LONG | R_RSR_RUNT | R_RSR_ISE) )
{
ALRT( fRxOffset, *(UInt32*)&rbh, ' Rx-', "RTL8139::receiverInterrupt" );
BUMP_NET_COUNTER( inputErrors );
if ( rbh.rb_status & R_RSR_FAE ) BUMP_ETHER_COUNTER( alignmentErrors );
if ( rbh.rb_status & R_RSR_CRC ) BUMP_ETHER_COUNTER( fcsErrors );
if ( rbh.rb_status & R_RSR_LONG ) BUMP_ETHER_COUNTER( frameTooLongs );
if ( rbh.rb_status & R_RSR_RUNT ) BUMP_ETHER_RX_COUNTER( frameTooShorts );
if ( rbh.rb_status & R_RSR_ISE ) BUMP_ETHER_RX_COUNTER( phyErrors );
rbh.rb_status &= ~R_RSR_ROK;
}
if ( (rbh.rb_status & R_RSR_ROK) == 0 )
{
ALRT( fRxOffset, *(UInt32*)&rbh, 'Rok-', "RTL8139::receiverInterrupt - not OK" );
restartReceiver();
BUMP_ETHER_RX_COUNTER( resets );
DEBUG_LOG( "%s: restarted receiver\n", getName() );
break;
}
if ( (pktLen < MINPACK - 4) || (pktLen > MAXPACK - 4) )
{
ALRT( fRxOffset, *(UInt32*)&rbh, 'RxL-', "RTL8139::receiverInterrupt - length bad" );
DEBUG_LOG( "%s: bad packet length (%d)\n", getName(), pktLen );
BUMP_NET_COUNTER( inputErrors );
if ( pktLen < MINPACK )
BUMP_ETHER_RX_COUNTER( frameTooShorts );
else BUMP_ETHER_COUNTER( frameTooLongs );
}
else
{
pkt = allocatePacket( pktLen );
if ( !pkt )
{
ALRT( 0, pktLen, 'RxP-', "RTL8139::receiverInterrupt - packet not allocated" );
BUMP_ETHER_RX_COUNTER( resourceErrors );
}
else
{
ELG( fRxOffset, pktLen, 'RxP+', "RTL8139::receiverInterrupt - goodness" );
assert ( netif );
if ( fRxOffset < RX_BUF_SIZE - pktLen )
{
bcopy( fpRxBuffer + fRxOffset, mbuf_data( pkt ), pktLen );
}
else
{
ELG( fRxOffset, pktLen, 'Wrap', "RTL8139::receiverInterrupt - Rx buffer wrapped" );
bcopy( fpRxBuffer + fRxOffset, mbuf_data( pkt ), RX_BUF_SIZE - fRxOffset );
bcopy( fpRxBuffer, (UInt8*)(mbuf_data( pkt )) + (RX_BUF_SIZE - fRxOffset), pktLen - (RX_BUF_SIZE - fRxOffset) );
}
netif->inputPacket( pkt, pktLen, IONetworkInterface:: kInputOptionQueuePacket );
BUMP_NET_COUNTER( inputPackets );
*queued = true;
}
}
fRxOffset += IORound( pktLen + 4, 4 ); csrWrite16( RTL_CAPR, fRxOffset - 0x10 ); }
BUMP_ETHER_RX_COUNTER( interrupts );
return;
}
void RTL8139::restartReceiver()
{
UInt8 tmp_cm;
tmp_cm = csrRead8( RTL_CM );
ELG( 0000, tmp_cm, 'ReRx', "RTL8139::restartReceiver" );
tmp_cm &= ~R_CM_RE;
csrWrite8( RTL_CM, tmp_cm );
IOSleep( 10 );
fRxOffset = 0;
csrWrite32( RTL_RBSTART, fRxBufferPhys );
tmp_cm |= R_CM_RE;
csrWrite8( RTL_CM, tmp_cm );
csrWrite32( RTL_RCR, reg_rcr );
return;
}
void RTL8139::enableHardwareInterrupts()
{
UInt16 imr;
ELG( 0, fSpeed100, 'eHWI', "RTL8139::enableHardwareInterrupts" );
if ( fSpeed100 )
{ csrWrite32( RTL_TIMER_INT, 32768 ); csrWrite32( RTL_TCTR, 0 ); imr = R_ISR_TMOUT | R_ISR_TOK | R_ISR_TER;
}
else {
imr = R_ISR_ALL;
csrWrite32( RTL_TIMER_INT, 0 ); }
csrWrite16( RTL_IMR, imr );
interruptEnabled = true;
return;
}
void RTL8139::disableHardwareInterrupts()
{
ELG( 0, 0, 'dHWI', "RTL8139::disableHardwareInterrupts" );
csrWrite16( RTL_IMR, R_ISR_NONE );
interruptEnabled = false;
return;
}
bool RTL8139::allocateDescriptorMemory()
{
IOByteCount len;
int size;
size = (TX_BUF_SIZE * kTxBufferCount) + (RX_BUF_SIZE + PAGE_SIZE);
ELG( 0, size, 'AlDM', "RTL8139::allocateDescriptorMemory" );
fpTxRxMD = IOBufferMemoryDescriptor::withOptions(
kIOMemoryPhysicallyContiguous,
size,
PAGE_SIZE );
if ( !fpTxRxMD || fpTxRxMD->prepare() != kIOReturnSuccess )
{
IOLog("%s: Can't allocate %d contiguous bytes\n", getName(), size );
return false;
}
fpTxRxBuffers = (UInt8*)fpTxRxMD->getBytesNoCopy();
fTxRxPhysical = fpTxRxMD->getPhysicalSegment( 0, &len );
ELG( fTxRxPhysical, fpTxRxBuffers, 'TxRx', "allocateDescriptorMemory - Tx and Rx buffers" );
fpRxBuffer = fpTxRxBuffers + TX_BUF_SIZE * kTxBufferCount;
fRxBufferPhys = fTxRxPhysical + TX_BUF_SIZE * kTxBufferCount;
return true;
}
bool RTL8139::initAdapter( IOOptionBits options )
{
ELG( 0, options, 'i Ad', "RTL8139::initAdapter" );
DEBUG_LOG( "initAdapter() ===>\n");
csrWrite8( RTL_CM, R_CM_RST );
IOSleep(10);
if ( csrRead8( RTL_CM ) & R_CM_RST )
{
IOLog( "%s: chip reset timed out\n", getName() );
return false;
}
if ( options & kResetChip )
return true;
reg_mar0 = reg_mar4 = 0;
csrWrite32( RTL_MAR0, reg_mar0 );
csrWrite32( RTL_MAR4, reg_mar4 );
reg_config1 = csrRead8( RTL_CONFIG1 );
csrWrite32( RTL_RBSTART, fRxBufferPhys );
fRxOffset = 0;
for ( int i = 0; i < kTxBufferCount; i++ )
{
csrWrite32( RTL_TSAD0 + i * sizeof( UInt32 ), fTxRxPhysical + i * TX_BUF_SIZE );
fTxBufOwnership[i] = kOwnedByHost;
}
fTxSendIndex = fTxSendCount = fTxAckIndex = 0;
csrWrite8( RTL_CM, R_CM_RE | R_CM_TE );
csrWrite32( RTL_TCR, R_TCR_MXDMA | R_TCR_IFG );
reg_rcr = R_RCR_RBLEN_64K | R_RCR_AB | R_RCR_APM | R_RCR_AM
| R_RCR_ERTH | R_RCR_RXFTH | R_RCR_MXDMA;
csrWrite32( RTL_RCR, reg_rcr );
DEBUG_LOG( "initAdapter() <===\n");
return true;
}
void RTL8139::interruptOccurred( IOInterruptEventSource *src, int count )
{
bool flushInputQ = false;
bool serviceOutputQ = false;
UInt16 isr;
IODebuggerLockState lockState;
if ( !interruptEnabled )
{
ELG( 0, 0, 'Int-', "RTL8139::interruptOccurred - not ready" );
return;
}
lockState = IODebuggerLock( this );
isr = csrRead16( RTL_ISR );
ELG( 0, isr, 'Int+', "RTL8139::interruptOccurred" );
if ( isr )
{
if ( isr & R_ISR_TMOUT )
csrWrite32( RTL_TCTR, 0 );
if ( isr & (R_ISR_FOVW | R_ISR_RXOVW) ) isr |= (R_ISR_FOVW | R_ISR_RXOVW);
csrWrite16( RTL_ISR, isr );
if ( isr & (R_ISR_TOK | R_ISR_TER) )
{
BUMP_ETHER_TX_COUNTER( interrupts );
transmitterInterrupt( &serviceOutputQ );
}
}
receiverInterrupt( &flushInputQ );
#if NOT_YET
if ( isr & R_ISR_PUN )
{
UInt16 tmp_rtl74 = csrRead16( RTL_74 );
if ( tmp_rtl74 & SIZE16_BIT11 ) {
if ( tmp_rtl74 & SIZE16_BIT10 ) {
}
else {
}
}
else
{
}
}
#endif
if ( fTxBufReclaimed )
{
serviceOutputQ = true;
fTxBufReclaimed = false;
}
IODebuggerUnlock( lockState );
assert( netif );
if ( flushInputQ )
{
BUMP_ETHER_RX_COUNTER( interrupts );
netif->flushInputQueue();
}
if ( serviceOutputQ )
fTransmitQueue->service();
return;
}
UInt32 RTL8139::outputPacket( mbuf_t pkt, void *param )
{
mbuf_t mn;
long pktLen;
UInt32 tsd; UInt8 *pDest;
IODebuggerLockState lockState;
DEBUG_LOG( "outputPacket() ===>\n" );
lockState = IODebuggerLock( this );
tsd = csrRead32( RTL_TSD0 + fTxSendIndex * sizeof( UInt32 ) );
if ( kOwnedByChip == fTxBufOwnership[ fTxSendIndex ] )
{
ELG( fTxSendIndex, tsd, 'Stal', "RTL8139::outputPacket - Tx stall" );
DEBUG_LOG( "outputPacket() <===\n" );
IODebuggerUnlock( lockState );
return kIOReturnOutputStall;
}
ELG( fTxSendIndex, mbuf_pkthdr_len( pkt ), 'outP', "RTL8139::outputPacket" );
if ( tsd & (R_TSD_CRS | R_TSD_TABT | R_TSD_OWC | R_TSD_TUN) )
{
BUMP_NET_COUNTER( outputErrors );
ALRT( fTxSendIndex, tsd, ' Tx-', "RTL8139::outputPacket - Tx Error" );
}
pDest = fpTxRxBuffers + TX_BUF_SIZE * fTxSendIndex;
pktLen = mbuf_pkthdr_len( pkt );
for ( mn = pkt; mn; mn = mbuf_next( mn ) )
{
bcopy( mbuf_data( mn ), pDest, mbuf_len( mn ) );
pDest += mbuf_len( mn );
}
if ( pktLen < MINPACK - 4 ) {
memset( pDest, 0x55, MINPACK - 4 - pktLen );
pktLen = MINPACK - 4;
}
csrWrite32( RTL_TSD0 + fTxSendIndex * sizeof( UInt32 ), pktLen | fTSD_ERTXTH );
fTxSendCount++;
fTxBufOwnership[ fTxSendIndex ] = kOwnedByChip;
if ( ++fTxSendIndex >= kTxBufferCount )
fTxSendIndex = 0;
IODebuggerUnlock( lockState );
freePacket( pkt );
BUMP_NET_COUNTER( outputPackets );
DEBUG_LOG( "outputPacket() <===\n" );
return kIOReturnOutputSuccess;
}
void RTL8139::sendPacket( void *pkt, UInt32 pktLen ) {
UInt8 *pDest;
if ( pktLen > MAXPACK - 4 ) return;
while ( kOwnedByChip == fTxBufOwnership[ fTxSendIndex ] )
reclaimTransmitBuffer();
pDest = fpTxRxBuffers + fTxSendIndex * TX_BUF_SIZE;
bcopy( pkt, pDest, pktLen );
if ( pktLen < MINPACK - 4 ) {
memset( pDest + pktLen, 0x55, MINPACK - 4 - pktLen );
pktLen = MINPACK - 4;
}
csrWrite32( RTL_TSD0 + fTxSendIndex * sizeof( UInt32 ), pktLen | fTSD_ERTXTH );
fTxSendCount++;
fTxBufOwnership[ fTxSendIndex ] = kOwnedByChip;
if ( ++fTxSendIndex >= kTxBufferCount )
fTxSendIndex = 0;
return;
}
void RTL8139::reclaimTransmitBuffer() {
UInt32 txStatus;
UInt32 u32;
fTxBufReclaimed = true;
while ( fTxSendCount )
{
txStatus = csrRead32( RTL_TSD0 + fTxAckIndex * sizeof( UInt32 ) );
if ( (txStatus & (R_TSD_TABT | R_TSD_TOK | R_TSD_TUN)) == 0 )
break;
if ( txStatus & R_TSD_TABT ) {
ALRT( fTxAckIndex, txStatus, 'TxA-', "RTL8139::reclaimTransmitBuffer - abort" );
u32 = csrRead32( RTL_TCR );
u32 |= R_TCR_CLRABT; csrWrite32( RTL_TCR, u32 );
break; }
fTxSendCount--;
fTxBufOwnership[ fTxAckIndex ] = kOwnedByHost;
if ( ++fTxAckIndex >= kTxBufferCount )
fTxAckIndex = 0;
}
return;
}
void RTL8139::receivePacket( void *pkt, UInt32 *pktLen, UInt32 timeout ) {
rbuf_hdr_t rbh; UInt16 rxLen;
*pktLen = 0;
timeout *= 1000;
while ( timeout && *pktLen == 0 )
{
if ( (csrRead8( RTL_CM ) & R_CM_BUFE) == R_CM_BUFE )
{ IODelay( 50 );
timeout -= 50;
continue;
}
*(UInt32*)&rbh = OSReadLittleInt32( fpRxBuffer, fRxOffset );
rxLen = rbh.rb_count; fRxOffset += sizeof( rbh );
if ( rbh.rb_status & (R_RSR_FAE | R_RSR_CRC | R_RSR_LONG | R_RSR_RUNT | R_RSR_ISE) )
rbh.rb_status &= ~R_RSR_ROK;
if ( (rbh.rb_status & R_RSR_ROK) == 0 )
{
restartReceiver();
continue;
}
if ( rxLen >= MINPACK && rxLen <= MAXPACK )
{
bcopy( fpRxBuffer + fRxOffset, pkt, rxLen );
*pktLen = rxLen;
}
fRxOffset += IORound( rxLen, 4 );
csrWrite16( RTL_CAPR, fRxOffset - 0x10 ); }
return;
}
#pragma mark -
#pragma mark еее Put EEPROM contents in IORegistry еее
#pragma mark -
#define RTL_9346CR_PROGRAM 0x80
#define RTL_9346CR_EECS 0x08
#define RTL_9346CR_EESK 0x04
#define RTL_9346CR_EEDI 0x02
#define RTL_9346CR_EEDO 0x01
#define OP_9346_EWDS 0x100 // Erase/Write Disable
#define OP_9346_EWEN 0x130 // Erase/Write ENable
#define OP_9346_WRITE 0x140
#define OP_9346_READ 0x180
#define OP_9346_ERASE 0x1C0
#define kEEPROM_SIZE 0X80
void RTL8139::registerEEPROM()
{
OSArray *arrayStrings;
OSString *tmpString;
char printBuffer[ 100 ];
UInt16 contents[ kEEPROM_SIZE / sizeof( UInt16 ) ];
UInt16 i, x, checksum;
ELG( 0, 0, 'PROM', "RTL8139::registerEEPROM" );
#if USE_ELG
UInt32 flag = fpELG->evLogFlag; fpELG->evLogFlag = 0; #endif // USE_ELG
checksum = 0;
for ( i = 0; i < kEEPROM_SIZE / sizeof( UInt16 ); ++i ) {
x = inEEPROM16( i );
checksum += x;
contents[ i ] = x;
}
if ( (contents[ 6 ] & 0x0002) != 0 ) IOLog( "RTL8139::fixEnetFlowControl - Flow Control is disabled\n" );
arrayStrings = OSArray::withCapacity( kEEPROM_SIZE / 0x10 );
for ( i = 0 ; i < (kEEPROM_SIZE / sizeof( UInt16 )); i += 8 ) {
sprintf( printBuffer, "%04x %04x %04x %04x %04x %04x %04x %04x",
contents[ i+0 ], contents[i+1], contents[i+2], contents[i+3],
contents[ i+4 ], contents[i+5], contents[i+6], contents[i+7] );
tmpString = OSString::withCString( printBuffer );
arrayStrings->setObject( tmpString );
tmpString->release();
}
setProperty( "EEPROM words", arrayStrings );
arrayStrings->release();
#ifdef CRAP
contents[ 6 ] &= ~0x0002; contents[ 0x32 / 2 ] = 0; checksum = 0;
for ( i = 0; i < kEEPROM_SIZE / 2; ++i ) checksum += contents[ i ];
outEEPROM16( 6, contents[ 6 ] ); outEEPROM16( 0x32 / 2, 0x10000 - checksum );
IOLog( "RTL8139::fixEnetFlowControl - Ethernet Flow Control is now enabled.\n" );
#endif // CRAP
#if USE_ELG
fpELG->evLogFlag = flag; #endif // USE_ELG
return;
}
void RTL8139::write9346CR( UInt8 value )
{
csrWrite8( RTL_9346CR, value );
IOSleep( 1 );
return;
}
#ifdef CRAP
void RTL8139::outEEPROM16( int location, UInt16 value )
{
int i;
UInt16 outData16 = value;
write9346CR( RTL_9346CR_PROGRAM );
outCommand( OP_9346_EWEN );
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); write9346CR( RTL_9346CR_PROGRAM );
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); outCommand( OP_9346_ERASE | location );
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); write9346CR( RTL_9346CR_PROGRAM );
outCommand( OP_9346_WRITE | location );
for ( i = 16; i > 0; i-- )
{
outBit( outData16 );
outData16 <<= 1;
}
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); write9346CR( RTL_9346CR_PROGRAM );
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); write9346CR( RTL_9346CR_PROGRAM );
outCommand( OP_9346_EWDS );
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); write9346CR( RTL_9346CR_PROGRAM );
return;
}
#endif // CRAP
int RTL8139::inEEPROM16( int location )
{
int i;
UInt16 inData16 = 0;
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS );
outCommand( OP_9346_READ | location );
for ( i = 16; i > 0; i-- )
{
inData16 <<= 1;
inData16 |= inBit();
}
write9346CR( RTL_9346CR_PROGRAM );
return inData16;
}
void RTL8139::outCommand( UInt16 cmd )
{
int i;
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS );
cmd <<= 6;
for ( i = 10; i > 0; --i )
{
outBit( cmd );
cmd <<= 1;
}
write9346CR( RTL_9346CR_PROGRAM | RTL_9346CR_EECS ); return;
}
void RTL8139::outBit( UInt16 bit )
{
UInt8 u8 = RTL_9346CR_PROGRAM | RTL_9346CR_EECS;
u8 |= (bit & 0x8000) ? RTL_9346CR_EEDI : 0;
write9346CR( u8 ); write9346CR( u8 | RTL_9346CR_EESK ); return;
}
int RTL8139::inBit()
{
UInt8 u8 = RTL_9346CR_PROGRAM | RTL_9346CR_EECS;
write9346CR( u8 | RTL_9346CR_EESK ); write9346CR( u8 );
u8 = csrRead8( RTL_9346CR );
return (u8 & RTL_9346CR_EEDO) ? 1 : 0;
}