RTL8139Private.cpp [plain text]
#include "RTL8139.h"
void RTL8139::transmitterInterrupt( bool * reclaimed )
{
UInt32 tx_status;
UInt8 collisions;
UInt32 tcr;
while ( tx_send_count )
{
tx_status = csrRead32( RTL_TSD0 + tx_ack_index * 4 );
if ( (tx_status & (R_TSD_TABT | R_TSD_TOK | R_TSD_TUN)) == 0 )
break;
collisions = ( tx_status & R_TSD_NCC ) >> 24;
if ( tx_status & R_TSD_TABT ) {
BUMP_NET_COUNTER( outputErrors );
tcr = csrRead32( RTL_TCR );
tcr |= R_TCR_CLRABT; csrWrite32( RTL_TCR, tcr );
if ( collisions == 0xF )
BUMP_ETHER_COUNTER( excessiveCollisions );
if ( tx_status & R_TSD_OWC )
BUMP_ETHER_COUNTER( lateCollisions );
if ( tx_status & R_TSD_CRS )
BUMP_ETHER_COUNTER( carrierSenseErrors );
break; }
if ( tx_status & R_TSD_TUN )
{
BUMP_ETHER_TX_COUNTER( underruns );
}
if ( collisions )
{
netStats->collisions += collisions;
if ( collisions > 1 )
BUMP_ETHER_COUNTER( multipleCollisionFrames );
else
BUMP_ETHER_COUNTER( singleCollisionFrames );
}
tx_send_count--;
tx_buf_ownership[tx_ack_index] = kOwnedByHost;
if ( 4 == ++tx_ack_index ) tx_ack_index = 0;
*reclaimed = true;
}
BUMP_ETHER_TX_COUNTER( interrupts );
}
void RTL8139::receiverInterrupt( bool * queued )
{
rbuf_hdr_t rbh; UInt16 offset;
UInt16 tmp_capr;
mbuf_t pkt;
UInt16 pkt_len;
while ( ( csrRead8( RTL_CM ) & R_CM_BUFE ) == 0 )
{
*((UInt32 *)&rbh) = OSReadLittleInt32( rx_buf_ptr, 0 );
pkt_len = rbh.rb_count;
if ( rbh.rb_status & (R_RSR_FAE | R_RSR_CRC | R_RSR_LONG |
R_RSR_RUNT | R_RSR_ISE) )
{
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 )
{
restartReceiver();
BUMP_ETHER_RX_COUNTER( resets );
DEBUG_LOG("%s: restarted receiver\n", getName());
break;
}
if ( (pkt_len < MINPACK + 4) || (pkt_len > MAXPACK + 4) )
{
DEBUG_LOG("%s: bad packet length (%d)\n", getName(), pkt_len);
BUMP_NET_COUNTER( inputErrors );
if ( pkt_len < MINPACK + 4 )
BUMP_ETHER_RX_COUNTER( frameTooShorts );
else
BUMP_ETHER_COUNTER( frameTooLongs );
}
else
{
pkt = allocatePacket( pkt_len );
if ( 0 == pkt )
{
BUMP_ETHER_RX_COUNTER( resourceErrors );
}
else
{
assert ( netif );
bcopy( rx_buf_ptr + sizeof(rbh), mbuf_data(pkt), pkt_len );
netif->inputPacket( pkt, pkt_len, IONetworkInterface::
kInputOptionQueuePacket );
BUMP_NET_COUNTER( inputPackets );
*queued = true;
}
}
offset = IORound(pkt_len, 4) + sizeof(rbh);
rx_buf_ptr += offset;
if (rx_buf_ptr >= (rx_buf_end - 1))
rx_buf_ptr -= RX_BUF_SIZE;
tmp_capr = csrRead16( RTL_CAPR );
tmp_capr += offset;
csrWrite16Slow( RTL_CAPR, tmp_capr );
}
BUMP_ETHER_RX_COUNTER( interrupts );
}
void RTL8139::restartReceiver( void )
{
UInt8 tmp_cm = csrRead8( RTL_CM );
tmp_cm &= ~R_CM_RE;
csrWrite8( RTL_CM, tmp_cm );
IOSleep(10);
rx_buf_ptr = rx_buf_start;
csrWrite32( RTL_RBSTART, rx_buf_phys );
tmp_cm |= R_CM_RE;
csrWrite8( RTL_CM, tmp_cm );
csrWrite32( RTL_RCR, reg_rcr );
}
void RTL8139::enableHardwareInterrupts( void )
{
csrWrite16( RTL_IMR, R_ISR_ALL );
interruptEnabled = true;
}
void RTL8139::disableHardwareInterrupts( void )
{
csrWrite16( RTL_IMR, R_ISR_NONE );
interruptEnabled = false;
}
bool RTL8139::allocateDescriptorMemory( void )
{
IOByteCount len;
rx_md = IOBufferMemoryDescriptor::withOptions(
kIOMemoryPhysicallyContiguous,
RX_BUF_SIZE + (4 * 1024),
PAGE_SIZE );
if ( 0 == rx_md || rx_md->prepare() != kIOReturnSuccess )
{
IOLog("%s: Can't allocate %d contiguous bytes\n",
getName(), RX_BUF_SIZE + (4 * 1024));
return false;
}
rx_buf_start = (UInt8 *) rx_md->getBytesNoCopy();
rx_buf_end = rx_buf_start + RX_BUF_SIZE;
rx_buf_phys = rx_md->getPhysicalSegment( 0, &len );
DEBUG_LOG("Rx Buffer len = %d virt = %p phys = 0x%lx\n",
rx_md->getCapacity(), rx_buf_start, rx_buf_phys);
for ( int i = 0; i < kTxBufferCount; i++ )
{
tx_md[i] = IOBufferMemoryDescriptor::withOptions(
0,
PAGE_SIZE,
PAGE_SIZE );
if ( 0 == tx_md[i] || tx_md[i]->prepare() != kIOReturnSuccess )
{
IOLog("%s: Can't allocate %dth Tx buffer\n", getName(), i);
return false;
}
tx_buf_ptr[i] = (UInt8 *) tx_md[i]->getBytesNoCopy();
tx_buf_phys[i] = tx_md[i]->getPhysicalSegment( 0, &len );
DEBUG_LOG("Tx Buffer %d len = %d virt = %p phys = 0x%lx\n",
i, PAGE_SIZE, tx_buf_ptr[i], tx_buf_phys[i]);
}
return true;
}
bool RTL8139::initAdapter( IOOptionBits options )
{
DEBUG_LOG("initAdapter() ===>\n");
disableHardwareInterrupts();
csrWrite8( RTL_CM, R_CM_RST );
disableHardwareInterrupts();
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 );
rx_buf_ptr = rx_buf_start;
rx_buf_ptr[0x1001] = 0x9f;
csrWrite32( RTL_RBSTART, rx_buf_phys );
for ( int i = 0; i < kTxBufferCount; i++ )
{
csrWrite32( RTL_TSAD0 + i * 4, tx_buf_phys[i] );
tx_buf_ownership[i] = kOwnedByHost;
}
tx_send_index = 0;
tx_send_count = 0;
tx_ack_index = 0;
csrWrite8( RTL_CM, R_CM_RE | R_CM_TE );
csrWrite32( RTL_TCR, R_TCR_MXDMA | R_TCR_IFG );
reg_rcr = R_RCR_RBLEN_16K | R_RCR_AB | R_RCR_APM | R_RCR_AM |
R_RCR_ERTH + R_RCR_RXFTH + R_RCR_MXDMA + R_RCR_WRAP;
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 ( false == interruptEnabled ) return;
lockState = IODebuggerLock( this );
while ( 1 )
{
isr = csrRead16( RTL_ISR );
if ( ( isr & R_ISR_ALL ) == 0 )
{
break; }
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) )
{
transmitterInterrupt( &serviceOutputQ );
}
#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 ( isr & (R_ISR_ROK | R_ISR_RER | R_ISR_RXOVW | R_ISR_FOVW) )
{
receiverInterrupt( &flushInputQ );
}
}
if ( tx_buf_reclaimed )
{
serviceOutputQ = true;
tx_buf_reclaimed = false;
}
IODebuggerUnlock( lockState );
assert( netif );
if ( flushInputQ ) netif->flushInputQueue();
if ( serviceOutputQ ) transmitQueue->service();
}
UInt32 RTL8139::outputPacket( mbuf_t pkt, void * param )
{
UInt8 * des_ptr_ub;
long pkt_len;
mbuf_t mn;
IODebuggerLockState lockState;
DEBUG_LOG("outputPacket() ===>\n");
lockState = IODebuggerLock( this );
if ( kOwnedByChip == tx_buf_ownership[tx_send_index] )
{
DEBUG_LOG("outputPacket() <===\n");
IODebuggerUnlock( lockState );
return kIOReturnOutputStall;
}
des_ptr_ub = tx_buf_ptr[tx_send_index];
pkt_len = mbuf_pkthdr_len(pkt);
for ( mn = pkt; mn; mn = mbuf_next(mn) )
{
bcopy( mbuf_data(mn), des_ptr_ub, mbuf_len(mn) );
des_ptr_ub += mbuf_len(mn);
}
if ( pkt_len < MINPACK )
{
memset( des_ptr_ub, 0x55, MINPACK - pkt_len );
pkt_len = MINPACK;
}
csrWrite32( RTL_TSD0 + (4 * tx_send_index), pkt_len | R_TSD_ERTXTH );
tx_send_count++;
tx_buf_ownership[tx_send_index] = kOwnedByChip;
if ( 4 == ++tx_send_index ) tx_send_index = 0;
IODebuggerUnlock( lockState );
freePacket( pkt );
BUMP_NET_COUNTER( outputPackets );
DEBUG_LOG("outputPacket() <===\n");
return kIOReturnOutputSuccess;
}
void RTL8139::sendPacket( void * pkt, UInt32 pkt_len )
{
UInt8 * dest_ptr;
if ( pkt_len > MAXPACK ) return;
while ( kOwnedByChip == tx_buf_ownership[tx_send_index] )
{
reclaimTransmitBuffer();
}
dest_ptr = tx_buf_ptr[ tx_send_index ];
bcopy( pkt, dest_ptr, pkt_len );
if ( pkt_len < MINPACK )
{
memset( dest_ptr + pkt_len, 0x55, MINPACK - pkt_len );
pkt_len = MINPACK;
}
csrWrite32( RTL_TSD0 + (4 * tx_send_index), pkt_len | R_TSD_ERTXTH );
tx_send_count++;
tx_buf_ownership[tx_send_index] = kOwnedByChip;
if ( 4 == ++tx_send_index ) tx_send_index = 0;
}
void RTL8139::reclaimTransmitBuffer( void )
{
UInt32 tx_status;
UInt32 tmp_ul;
tx_buf_reclaimed = true;
while ( tx_send_count )
{
tx_status = csrRead32( RTL_TSD0 + tx_ack_index * 4 );
if ( (tx_status & (R_TSD_TABT | R_TSD_TOK | R_TSD_TUN)) == 0 )
break;
if ( tx_status & R_TSD_TABT ) {
tmp_ul = csrRead32( RTL_TCR );
tmp_ul |= R_TCR_CLRABT; csrWrite32( RTL_TCR, tmp_ul );
break; }
tx_send_count--;
tx_buf_ownership[tx_ack_index] = kOwnedByHost;
if ( 4 == ++tx_ack_index ) tx_ack_index = 0;
}
}
void RTL8139::receivePacket( void * pkt, UInt32 * pkt_len, UInt32 timeout )
{
rbuf_hdr_t rbh; UInt16 offset;
UInt16 capr;
UInt16 rcv_len;
*pkt_len = 0;
timeout *= 1000;
while ( timeout && *pkt_len == 0 )
{
if ( (csrRead8( RTL_CM ) & R_CM_BUFE) == R_CM_BUFE )
{
IODelay( 50 );
timeout -= 50;
continue;
}
*((UInt32 *)&rbh) = OSReadLittleInt32( rx_buf_ptr, 0 );
rcv_len = rbh.rb_count;
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 ( (rcv_len >= MINPACK + 4) && (rcv_len <= MAXPACK + 4) )
{
bcopy( rx_buf_ptr + sizeof(rbh), pkt, rcv_len );
*pkt_len = rcv_len;
}
offset = IORound(rcv_len, 4) + sizeof(rbh);
rx_buf_ptr += offset;
if (rx_buf_ptr >= (rx_buf_end - 1))
rx_buf_ptr -= RX_BUF_SIZE;
capr = csrRead16( RTL_CAPR );
capr += offset;
csrWrite16Slow( RTL_CAPR, capr );
}
}