UniNEnetPrivate.cpp [plain text]
#include "UniNEnet.h"
#include "UniNEnetMII.h"
#include <libkern/OSByteOrder.h>
extern void *kernel_pmap;
bool UniNEnet::allocateMemory()
{
UInt32 rxRingSize, txRingSize;
txRingSize = fTxRingElements * sizeof( TxDescriptor );
fTxDescriptorRing = (TxDescriptor*)IOMallocContiguous( txRingSize,
PAGE_SIZE, 0 );
if ( !fTxDescriptorRing )
{
ALRT( 0, txRingSize, '-Tx-', "UniNEnet::allocateMemory - failed to alloc Tx Ring" );
return false;
}
ELG( txRingSize, fTxDescriptorRing, '=TxR', "UniNEnet::allocateMemory - Tx Ring alloc'd" );
rxRingSize = fRxRingElements * sizeof( RxDescriptor );
fRxDescriptorRing = (RxDescriptor*)IOMallocContiguous( rxRingSize,
PAGE_SIZE, 0 );
if ( !fRxDescriptorRing )
{
ALRT( 0, rxRingSize, '-Rx-', "UniNEnet::allocateMemory - failed to alloc Rx Ring" );
return false;
}
ELG( rxRingSize, fRxDescriptorRing, '=RxR', "UniNEnet::allocateMemory - Rx Ring alloc'd" );
fTxMbuf = (mbuf**)IOMalloc( sizeof( mbuf* ) * fTxRingElements );
if ( !fTxMbuf )
{
ALRT( 0, 0, 'mpT-', "UniNEnet::allocateMemory - alloc Tx mbuf pointers failed" );
return false;
}
bzero( fTxMbuf, sizeof( mbuf* ) * fTxRingElements );
fRxMbuf = (mbuf**)IOMalloc( sizeof( mbuf* ) * fRxRingElements );
if ( !fRxMbuf )
{
ALRT( 0, 0, 'mpR-', "UniNEnet::allocateMemory - alloc Rx mbuf pointers failed" );
return false;
}
bzero( fRxMbuf, sizeof( mbuf* ) * fRxRingElements );
ELG( fTxMbuf, fRxMbuf, 'arys', "UniNEnet::allocateMemory - mbuf pointer arrays" );
return true;
}
bool UniNEnet::initTxRing()
{
UInt32 i;
ELG( this, fTxDescriptorRing, 'ITxR', "initTxRing" );
bzero( (void*)fTxDescriptorRing, sizeof( TxDescriptor ) * fTxRingElements );
txCommandHead = 0;
txCommandTail = 0;
fTxDescriptorRingPhys = pmap_extract( kernel_pmap, (vm_address_t)fTxDescriptorRing );
if ( fTxDescriptorRingPhys == 0 )
{
IOLog( "UniNEnet::initTxRing - Bad dma command buf - %08x\n\r", (int)fTxDescriptorRing );
}
for ( i = 0; i < fTxRingElements; i++ )
{
if ( fTxMbuf[ i ] )
{
ELG( i, fTxMbuf[ i ], 'txpf', "UniNEnet::initTxRing - free the packet" );
freePacket( fTxMbuf[ i ] );
fTxMbuf[ i ] = 0;
}
}
fTxElementsAvail = fTxRingElements - 1;
txIntCnt = 0;
txWDCount = 0;
return true;
}
bool UniNEnet::initRxRing()
{
UInt32 i;
bool status;
ELG( fRxMbuf, fRxDescriptorRing, 'IRxR', "initRxRing" );
bzero( (void*)fRxDescriptorRing, sizeof( RxDescriptor ) * fRxRingElements );
fRxDescriptorRingPhys = pmap_extract( kernel_pmap, (vm_address_t)fRxDescriptorRing );
if ( fRxDescriptorRingPhys == 0 )
{
IOLog( "UniNEnet::initRxRing - Bad dma command buf - %08x\n\r", (int)fRxDescriptorRing );
return false;
}
for ( i = 0; i < fRxRingElements; i++ )
{
if ( fRxMbuf[i] == NULL )
{
fRxMbuf[i] = allocatePacket( NETWORK_BUFSIZE );
if ( fRxMbuf[i] == NULL )
{
IOLog( "UniNEnet::initRxRing - NULL packet\n" );
return false;
}
}
status = genRxDescriptor( i );
if ( status == false )
{
IOLog( "UniNEnet::initRxRing genRxDescriptor error\n" );
return false;
}
}
rxCommandHead = 0;
rxCommandTail = i - 4;
return true;
}
void UniNEnet::flushRings( bool flushTx, bool flushRx )
{
UInt32 i;
ELG( fTxRingElements, fRxRingElements, 'FluR', "flushRings" );
if ( flushTx ) {
for ( i = 0; i < fTxRingElements; i++ )
{
if ( fTxMbuf[ i ] )
{
ELG( i, fTxMbuf[ i ], 'flTx', "UniNEnet::flushRings" );
freePacket( fTxMbuf[ i ] );
fTxMbuf[ i ] = 0;
}
}
}
if ( flushRx ) {
for ( i = 0; i < fRxRingElements; i++ )
{
if ( fRxMbuf[ i ] )
{
ELG( i, fRxMbuf[ i ], 'flRx', "UniNEnet::flushRings" );
freePacket( fRxMbuf[ i ] );
fRxMbuf[i] = 0;
}
}
}
return;
}
void UniNEnet::startChip()
{
UInt32 gemReg;
ELG( this, 0, 'SChp', "startChip" );
gemReg = READ_REGISTER( TxConfiguration ); gemReg |= kTxConfiguration_Tx_DMA_Enable;
WRITE_REGISTER( TxConfiguration, gemReg );
gemReg = READ_REGISTER( RxConfiguration ); gemReg |= kRxConfiguration_Rx_DMA_Enable;
WRITE_REGISTER( RxConfiguration, gemReg );
gemReg = READ_REGISTER( TxMACConfiguration ); gemReg |= kTxMACConfiguration_TxMac_Enable;
WRITE_REGISTER( TxMACConfiguration, gemReg );
fRxMACConfiguration = kRxMACConfiguration_Rx_Mac_Enable | kRxMACConfiguration_Strip_FCS;
if ( fIsPromiscuous )
fRxMACConfiguration |= kRxMACConfiguration_Promiscuous;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
gemReg = ~(kStatus_TX_INT_ME | kStatus_RX_DONE); WRITE_REGISTER( InterruptMask, gemReg );
return;
}
void UniNEnet::stopChip()
{
UInt32 gemReg;
ELG( READ_REGISTER( TxConfiguration ), READ_REGISTER( RxConfiguration ), 'HChp', "stopChip" );
gemReg = READ_REGISTER( TxConfiguration ); gemReg &= ~kTxConfiguration_Tx_DMA_Enable;
WRITE_REGISTER( TxConfiguration, gemReg );
gemReg = READ_REGISTER( RxConfiguration ); gemReg &= ~kRxConfiguration_Rx_DMA_Enable;
WRITE_REGISTER( RxConfiguration, gemReg );
IOSleep( 1 );
gemReg = READ_REGISTER( TxMACConfiguration ); gemReg &= ~kTxMACConfiguration_TxMac_Enable;
WRITE_REGISTER( TxMACConfiguration, gemReg );
fRxMACConfiguration = READ_REGISTER( RxMACConfiguration ); fRxMACConfiguration &= ~kRxMACConfiguration_Rx_Mac_Enable;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
IOSleep( 4 );
return;
}
static MediumTable gMediumTableGEM[] =
{
{ kIOMediumEthernetNone , 0 },
{ kIOMediumEthernetAuto , 0 },
{ kIOMediumEthernet1000BaseSX | kIOMediumOptionFullDuplex, 1000 },
};
static MediumTable gMediumTable100[] =
{
{ kIOMediumEthernetNone , 0 },
{ kIOMediumEthernetAuto , 0 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 },
};
static MediumTable gMediumTableGigabit[] =
{
{ kIOMediumEthernetNone , 0 },
{ kIOMediumEthernetAuto , 0 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex, 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex, 10 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex, 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex, 100 },
{ kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex, 1000 }
};
void UniNEnet::getPhyType()
{
UInt16 *pPhyType;
UInt16 phyWord;
ELG( this, phyId, 'gPhT', "getPhyType" );
if ( fBuiltin )
{
miiResetPHY( phyId );
pPhyType = (UInt16 *)&phyType;
miiReadWord( pPhyType, MII_ID0, phyId );
miiReadWord( pPhyType+1, MII_ID1, phyId );
setProperty( "PHY ID", phyType, sizeof( phyType ) * 8 );
ELG( phyId, phyType, '=FyT', "UniNEnet::getPhyType" );
}
if ( !fBuiltin )
{
fPHYType = ' GEM';
fpgMediumTable = gMediumTableGEM;
fMediumTableCount = sizeof( gMediumTableGEM ) / sizeof( MediumTable ) ;
setProperty( "PHY type", "GEM integrated" );
}
else if ( (phyType & MII_BCM5400_MASK) == MII_BCM5400_ID )
{
fPHYType = 0x5400;
ELG( this, phyId, '5400', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Broadcom 5400" );
miiReadWord( &phyWord, MII_BCM5400_AUXCONTROL, phyId );
phyWord |= MII_BCM5400_AUXCONTROL_PWR10BASET;
miiWriteWord( phyWord, MII_BCM5400_AUXCONTROL, phyId );
miiReadWord( &phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
phyWord |= MII_BCM5400_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
IODelay(100);
miiResetPHY( 0x1F );
miiReadWord( &phyWord, MII_BCM5201_MULTIPHY, 0x1F );
phyWord |= MII_BCM5201_MULTIPHY_SERIALMODE;
miiWriteWord( phyWord, MII_BCM5201_MULTIPHY, 0x1F );
miiReadWord( &phyWord, MII_BCM5400_AUXCONTROL, phyId );
phyWord &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
miiWriteWord( phyWord, MII_BCM5400_AUXCONTROL, phyId );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_BCM5400_MASK) == MII_BCM5401_ID )
{
fPHYType = 0x5401;
ELG( this, phyId, '5401', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Broadcom 5401" );
miiReadWord( &phyWord, MII_ID1, phyId );
phyWord &= 0x000F ;
if ( (phyWord == 0x0001 ) || (phyWord == 0x0003) )
{
miiWriteWord( 0x0C20, 0x018, phyId );
miiWriteWord( 0x0012, 0x017, phyId );
miiWriteWord( 0x1804, 0x015, phyId );
miiWriteWord( 0x0013, 0x017, phyId );
miiWriteWord( 0x1204, 0x015, phyId );
miiWriteWord( 0x8006, 0x017, phyId );
miiWriteWord( 0x0132, 0x015, phyId );
miiWriteWord( 0x8006, 0x017, phyId );
miiWriteWord( 0x0232, 0x015, phyId );
miiWriteWord( 0x201F, 0x017, phyId );
miiWriteWord( 0x0A20, 0x015, phyId );
}
miiReadWord( &phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
phyWord |= MII_BCM5400_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
IODelay( 10 );
miiResetPHY( 0x1F );
miiReadWord( &phyWord, MII_BCM5201_MULTIPHY, 0x1F );
phyWord |= MII_BCM5201_MULTIPHY_SERIALMODE;
miiWriteWord( phyWord, MII_BCM5201_MULTIPHY, 0x1F );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_BCM5400_MASK) == MII_BCM5411_ID ) {
fPHYType = 0x5411;
ELG( this, phyId, '5411', "UniNEnet::getPhyType - Broadcom 5411" );
setProperty( "PHY type", "Broadcom 5411" );
miiWriteWord( 0x8C23, 0x01C, phyId ); miiWriteWord( 0x8CA3, 0x01C, phyId );
miiWriteWord( 0x8C23, 0x01C, phyId );
miiWriteWord( 0x8000, 0x000, phyId );
miiWriteWord( 0x1340, 0x000, phyId );
miiReadWord( &phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
phyWord |= MII_BCM5400_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_BCM5400_1000BASETCONTROL, phyId );
IODelay( 10 );
miiResetPHY( 0x1F );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable ) ;
}
else if ( ((phyType & MII_MARVELL_MASK) == MII_MARVELL_ID) || ((phyType & MII_MARVELL_MASK) == MII_MARVELL_ID_1) ) {
fPHYType = 0x1011;
ELG( this, phyId, '1011', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Marvell" );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_BCM5201_MASK) == MII_BCM5201_ID )
{
fPHYType = 0x5201;
ELG( this, phyId, '5201', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Broadcom 5201" );
fpgMediumTable = gMediumTable100;
fMediumTableCount = sizeof( gMediumTable100 ) / sizeof( MediumTable ) ;
}
else
{
fPHYType = 0;
ELG( this, phyType, 'phy?', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Unknown" );
fpgMediumTable = gMediumTable100;
fMediumTableCount = sizeof( gMediumTable100 ) / sizeof( MediumTable ) ;
}
return;
}
bool UniNEnet::initChip()
{
UInt32 i, temp;
mach_timespec_t timeStamp;
UInt32 rxFifoSize;
UInt32 rxOff;
UInt32 rxOn;
u_int16_t *p16;
ELG( 0, phyId, 'ChpI', "initChip" );
if ( fBuiltin == false )
{
WRITE_REGISTER( DatapathMode, kDatapathMode_ExtSERDESMode );
WRITE_REGISTER( SerialinkControl, kSerialinkControl_DisableLoopback
| kSerialinkControl_EnableSyncDet );
WRITE_REGISTER( Advertisement, kAdvertisement_Full_Duplex
| kAdvertisement_PAUSE );
WRITE_REGISTER( PCSMIIControl, kPCSMIIControl_Auto_Negotiation_Enable
| kPCSMIIControl_Restart_Auto_Negotiation );
WRITE_REGISTER( PCSConfiguration, kPCSConfiguration_Enable );
fXIFConfiguration = kXIFConfiguration_Tx_MII_OE
| kXIFConfiguration_GMIIMODE
| kXIFConfiguration_FDPLXLED;
}
else
{
WRITE_REGISTER( DatapathMode, kDatapathMode_GMIIMode );
fXIFConfiguration = kXIFConfiguration_Tx_MII_OE;
}
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
WRITE_REGISTER( SendPauseCommand, kSendPauseCommand_default );
WRITE_REGISTER( MACControlConfiguration, 0 );
WRITE_REGISTER( InterruptMask, kInterruptMask_None );
WRITE_REGISTER( TxMACMask, kTxMACMask_default );
WRITE_REGISTER( RxMACMask, kRxMACMask_default );
WRITE_REGISTER( MACControlMask, kMACControlMask_default );
WRITE_REGISTER( Configuration, kConfiguration_TX_DMA_Limit
| kConfiguration_RX_DMA_Limit
| kConfiguration_Infinite_Burst );
WRITE_REGISTER( InterPacketGap0, kInterPacketGap0_default );
WRITE_REGISTER( InterPacketGap1, kInterPacketGap1_default );
WRITE_REGISTER( InterPacketGap2, kInterPacketGap2_default );
WRITE_REGISTER( SlotTime, kSlotTime_default );
WRITE_REGISTER( MinFrameSize, kMinFrameSize_default );
WRITE_REGISTER( MaxFrameSize, kMaxFrameSize_default );
WRITE_REGISTER( PASize, kPASize_default );
WRITE_REGISTER( JamSize, kJamSize_default );
WRITE_REGISTER( AttemptLimit, kAttemptLimit_default );
WRITE_REGISTER( MACControlType, kMACControlType_default );
p16 = (u_int16_t *) myAddress.bytes;
for ( i=0; i < sizeof(IOEthernetAddress) / 2; i++ )
WRITE_REGISTER( MACAddress[ i ], p16[ 2 - i ] );
for ( i=0; i < 3; i ++ )
{
WRITE_REGISTER( MACAddress[ i + 3 ], 0 );
WRITE_REGISTER( AddressFilter[ i ], 0 );
}
WRITE_REGISTER( MACAddress[ 6 ], kMACAddress_default_6 );
WRITE_REGISTER( MACAddress[ 7 ], kMACAddress_default_7 );
WRITE_REGISTER( MACAddress[ 8 ], kMACAddress_default_8 );
WRITE_REGISTER( AddressFilter2_1Mask, 0 );
WRITE_REGISTER( AddressFilter0Mask, 0 );
for ( i=0; i < 16; i++ )
WRITE_REGISTER( HashTable[ i ], 0 );
WRITE_REGISTER( NormalCollisionCounter, 0 );
WRITE_REGISTER( FirstAttemptSuccessfulCollisionCounter, 0 );
WRITE_REGISTER( ExcessiveCollisionCounter, 0 );
WRITE_REGISTER( LateCollisionCounter, 0 );
WRITE_REGISTER( DeferTimer, 0 );
WRITE_REGISTER( PeakAttempts, 0 );
WRITE_REGISTER( ReceiveFrameCounter, 0 );
WRITE_REGISTER( LengthErrorCounter, 0 );
WRITE_REGISTER( AlignmentErrorCounter, 0 );
WRITE_REGISTER( FCSErrorCounter, 0 );
WRITE_REGISTER( RxCodeViolationErrorCounter, 0 );
IOGetTime(&timeStamp);
WRITE_REGISTER( RandomNumberSeed, timeStamp.tv_nsec & 0xFFFF );
WRITE_REGISTER( TxDescriptorBaseLow, fTxDescriptorRingPhys );
WRITE_REGISTER( TxDescriptorBaseHigh, 0 );
temp = kTxConfiguration_TxFIFO_Threshold
| fTxRingLengthFactor << kTxConfiguration_Tx_Desc_Ring_Size_Shift;
WRITE_REGISTER( TxConfiguration, temp );
WRITE_REGISTER( TxMACConfiguration, 0 );
IOSleep( 4 );
setDuplexMode( (phyId == 0xff) ? true : false );
WRITE_REGISTER( RxDescriptorBaseLow, fRxDescriptorRingPhys );
WRITE_REGISTER( RxDescriptorBaseHigh, 0 );
WRITE_REGISTER( RxKick, fRxRingElements - 4 );
temp = kRxConfiguration_RX_DMA_Threshold
| fRxRingLengthFactor << kRxConfiguration_Rx_Desc_Ring_Size_Shift
| kRxConfiguration_Checksum_Start_Offset;
WRITE_REGISTER( RxConfiguration, temp );
fRxMACConfiguration = 0;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
IOSleep( 4 );
rxFifoSize = READ_REGISTER( RxFIFOSize );
rxOff = rxFifoSize - (kMaxFrameSize_default * 2 / kPauseThresholds_Factor);
rxOn = kMaxFrameSize_default / kPauseThresholds_Factor + 1;
WRITE_REGISTER( PauseThresholds,
(rxOff << kPauseThresholds_OFF_Threshold_Shift)
| (rxOn << kPauseThresholds_ON_Threshold_Shift) );
temp = READ_REGISTER( BIFConfiguration );
if ( temp & kBIFConfiguration_M66EN )
temp = kRxBlanking_default_66;
else temp = kRxBlanking_default_33;
WRITE_REGISTER( RxBlanking, temp );
if ( fBuiltin )
WRITE_REGISTER( WOLWakeupCSR, 0 );
ELG( READ_REGISTER( TxFIFOSize ), READ_REGISTER( RxFIFOSize ), 'FFsz', "initChip - done" );
return true;
}
void UniNEnet::setDuplexMode( bool duplexMode )
{
UInt32 txMacConfig;
isFullDuplex = duplexMode;
txMacConfig = READ_REGISTER( TxMACConfiguration );
ELG( txMacConfig, duplexMode, 'DupM', "setDuplexMode" );
WRITE_REGISTER( TxMACConfiguration, txMacConfig & ~kTxMACConfiguration_TxMac_Enable );
while ( READ_REGISTER( TxMACConfiguration ) & kTxMACConfiguration_TxMac_Enable )
;
if ( isFullDuplex )
{
txMacConfig |= (kTxMACConfiguration_Ignore_Collisions | kTxMACConfiguration_Ignore_Carrier_Sense);
fXIFConfiguration &= ~kXIFConfiguration_Disable_Echo;
}
else
{
txMacConfig &= ~(kTxMACConfiguration_Ignore_Collisions | kTxMACConfiguration_Ignore_Carrier_Sense);
fXIFConfiguration |= kXIFConfiguration_Disable_Echo;
}
WRITE_REGISTER( TxMACConfiguration, txMacConfig );
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
return;
}
void UniNEnet::restartReceiver()
{
UInt16 i;
UInt16 u16;
ELG( 0, READ_REGISTER( StatusAlias ), 'Alas', "restartReceiver" );
ELG( READ_REGISTER( TxKick ), READ_REGISTER( TxCompletion ), 'TxKC', "restartReceiver" );
ELG( 0, READ_REGISTER( TxConfiguration ), 'TxCf', "restartReceiver" );
ELG( READ_REGISTER( TxFIFOShadowReadPointer ), READ_REGISTER( TxFIFOReadPointer ), 'TxRp', "restartReceiver" );
ELG( READ_REGISTER( TxFIFOSize ), READ_REGISTER( TxFIFOPacketCounter ), 'TxPc', "restartReceiver" );
ELG( READ_REGISTER( RxKick ), READ_REGISTER( RxCompletion ), 'RxKC', "restartReceiver" );
ELG( READ_REGISTER( RxStateMachine ), READ_REGISTER( RxConfiguration ), 'RxCf', "restartReceiver" );
ELG( READ_REGISTER( RxFIFOShadowWritePointer ), READ_REGISTER( RxFIFOWritePointer ), 'RxWp', "restartReceiver" );
ELG( READ_REGISTER( RxFIFOPacketCounter ), READ_REGISTER( RxFIFOPacketCounter ), 'RxPC', "restartReceiver" );
WRITE_REGISTER( RxMACSoftwareResetCommand, kRxMACSoftwareResetCommand_Reset );
for ( i = 0; i < 5000; i++ )
{
if ( ( READ_REGISTER( RxMACSoftwareResetCommand )
& kRxMACSoftwareResetCommand_Reset ) == 0 )
{
break; }
IODelay(1);
}
WRITE_REGISTER( RxMACConfiguration, 0 );
for ( i = 0; i < 5000; i++ )
{
if ( ( READ_REGISTER( RxMACConfiguration )
& kRxMACConfiguration_Rx_Mac_Enable ) == 0 )
{
break; }
IODelay(1);
}
u16 = OSSwapConstInt16( kGEMRxDescFrameSize_Own );
for ( i = 0; i < fRxRingElements; ++i )
fRxDescriptorRing[ i ].frameDataSize |= u16;
WRITE_REGISTER( MACControlConfiguration, fMACControlConfiguration );
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
return;
}
bool UniNEnet::transmitPacket( struct mbuf *packet )
{
TxDescriptor *dp; UInt32 i,j,k;
mbuf *m;
UInt32 dataPhys;
UInt32 demandMask;
UInt16 param0, param1;
for ( m = packet, i=1; m->m_next; m=m->m_next, i++ )
;
ELG( i, packet, ' Tx', "UniNEnet::transmitPacket" );
if ( i > fTxElementsAvail )
return false;
j = txCommandTail;
OSAddAtomic( -i, (SInt32*)&fTxElementsAvail );
m = packet;
do
{
k = j;
dataPhys = (UInt32)mcl_to_paddr( mtod( m, char* ) );
if ( dataPhys == 0 )
dataPhys = pmap_extract( kernel_pmap, mtod( m, vm_offset_t ) );
dp = &fTxDescriptorRing[ j ];
OSWriteLittleInt32( &dp->bufferAddrLo, 0, dataPhys );
OSWriteLittleInt32( &dp->flags0, 0, m->m_len );
dp->flags1 = 0;
txIntCnt++;
j = (j + 1) & (fTxRingElements - 1);
} while ( (m = m->m_next) != 0 );
fTxMbuf[ k ] = packet;
fTxDescriptorRing[ k ].flags0 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags0_EndOfFrame );
fTxDescriptorRing[ txCommandTail ].flags0 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags0_StartOfFrame );
if ( txIntCnt >= TX_DESC_PER_INT )
{
fTxDescriptorRing[ txCommandTail ].flags1 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags1_Int );
txIntCnt = txIntCnt % TX_DESC_PER_INT;
}
getChecksumDemand( packet,
kChecksumFamilyTCPIP,
&demandMask, ¶m0, ¶m1 ); if ( demandMask & kChecksumTCPSum16 )
{
fTxDescriptorRing[ txCommandTail ].flags0
|= OSSwapHostToLittleConstInt32( kGEMTxDescFlags0_ChecksumEnable
| param0 << kGEMTxDescFlags0_ChecksumStart_Shift
| param1 << kGEMTxDescFlags0_ChecksumStuff_Shift );
}
txCommandTail = j;
OSSynchronizeIO(); WRITE_REGISTER( TxKick, j );
return true;
}
void UniNEnet::receivePacket( void *pkt, UInt32 *pkt_len, UInt32 timeout )
{
mach_timespec_t startTime, currentTime;
UInt32 elapsedTimeMS;
*pkt_len = 0;
if ( ready == false )
return;
#if USE_ELG
UInt32 elgFlag = fpELG->evLogFlag; fpELG->evLogFlag = 0;
#endif // USE_ELG
debuggerPkt = pkt;
debuggerPktSize = 0;
IOGetTime( &startTime );
do
{
receivePackets( true );
IOGetTime( ¤tTime );
if ( currentTime.tv_nsec < startTime.tv_nsec )
{
currentTime.tv_nsec += 1000000000; currentTime.tv_sec -= 1;
}
elapsedTimeMS = (currentTime.tv_sec - startTime.tv_sec) * 1000;
elapsedTimeMS += (currentTime.tv_nsec - startTime.tv_nsec) / 1000000;
}
while ( (debuggerPktSize == 0) && (elapsedTimeMS < timeout) );
*pkt_len = debuggerPktSize;
#if USE_ELG
fpELG->evLogFlag = elgFlag;
#endif // USE_ELG
return;
}
void UniNEnet::packetToDebugger( struct mbuf *packet, u_int size )
{
ELG( packet, size, 'ToDb', "packetToDebugger" );
debuggerPktSize = size;
bcopy( mtod(packet, char*), debuggerPkt, size );
return;
}
void UniNEnet::sendPacket( void *pkt, UInt32 pkt_len )
{
mach_timespec_t startTime, currentTime;
UInt32 elapsedTimeMS;
if ( !ready || !pkt || (pkt_len > ETHERMAXPACKET) )
return;
#if USE_ELG
UInt32 elgFlag = fpELG->evLogFlag; fpELG->evLogFlag = 0;
#endif // USE_ELG
IOGetTime( &startTime );
do
{
debugTransmitInterruptOccurred();
IOGetTime( ¤tTime );
if ( currentTime.tv_nsec < startTime.tv_nsec )
{
currentTime.tv_nsec += 1000000000; currentTime.tv_sec -= 1;
}
elapsedTimeMS = (currentTime.tv_sec - startTime.tv_sec) * 1000;
elapsedTimeMS += (currentTime.tv_nsec - startTime.tv_nsec) / 1000000;
}
while ( (txCommandHead != txCommandTail) && (elapsedTimeMS < TX_KDB_TIMEOUT) );
if ( txCommandHead != txCommandTail )
{
IOLog( "UniNEnet::sendPacket - Polled transmit timeout - 1\n\r" );
return;
}
txDebuggerPkt->m_next = 0;
txDebuggerPkt->m_data = (caddr_t)pkt;
txDebuggerPkt->m_pkthdr.len = txDebuggerPkt->m_len = pkt_len;
transmitPacket( txDebuggerPkt );
do
{
debugTransmitInterruptOccurred();
IOGetTime( ¤tTime );
if ( currentTime.tv_nsec < startTime.tv_nsec )
{
currentTime.tv_nsec += 1000000000; currentTime.tv_sec -= 1;
}
elapsedTimeMS = (currentTime.tv_sec - startTime.tv_sec) * 1000;
elapsedTimeMS += (currentTime.tv_nsec - startTime.tv_nsec) / 1000000;
}
while ( (txCommandHead != txCommandTail) && (elapsedTimeMS < TX_KDB_TIMEOUT) );
if ( txCommandHead != txCommandTail )
{
IOLog( "UniNEnet::sendPacket - Polled transmit timeout - 2\n\r" );
}
#if USE_ELG
fpELG->evLogFlag = elgFlag;
#endif // USE_ELG
return;
}
void UniNEnet::sendDummyPacket()
{
union
{
UInt8 bytes[ 64 ];
IOEthernetAddress enet_addr[ 2 ];
} dummyPacket;
ELG( &dummyPacket, sizeof( dummyPacket ), 'SenD', "sendDummyPacket" );
bzero( &dummyPacket, sizeof( dummyPacket ) );
dummyPacket.enet_addr[0] = myAddress;
dummyPacket.enet_addr[1] = myAddress;
sendPacket( (void*)dummyPacket.bytes, (unsigned int)sizeof( dummyPacket ) );
return;
}
bool UniNEnet::receiveInterruptOccurred()
{
return receivePackets( false );
}
bool UniNEnet::receivePackets( bool debuggerParam )
{
mbuf *packet;
UInt32 i, last;
int receivedFrameSize = 0;
UInt16 dmaFlags;
UInt16 checksum;
UInt32 rxPktStatus = 0;
bool passPacketUp;
bool reusePkt;
bool status;
bool useNetif = !debuggerParam && netifEnabled;
bool packetsQueued = false;
bool replaced;
last = (UInt32)-1;
i = rxCommandHead;
while ( 1 )
{
passPacketUp = false;
reusePkt = false;
dmaFlags = OSReadLittleInt16( &fRxDescriptorRing[ i ].frameDataSize, 0 );
checksum = OSReadLittleInt16( &fRxDescriptorRing[ i ].tcpPseudoChecksum, 0 );
if ( dmaFlags & kGEMRxDescFrameSize_Own )
break;
receivedFrameSize = dmaFlags & kGEMRxDescFrameSize_Mask;
rxPktStatus = OSReadLittleInt32( &fRxDescriptorRing[ i ].flags, 0 );
ELG( rxPktStatus, receivedFrameSize, 'Rx P', "UniNEnet::receivePackets - rx'd packet" );
if ( receivedFrameSize < (ETHERMINPACKET - ETHERCRC)
|| receivedFrameSize > (ETHERMAXPACKET + ETHERCRC)
|| rxPktStatus & kGEMRxDescFlags_BadCRC )
{
reusePkt = true;
NETWORK_STAT_ADD( inputErrors );
if ( receivedFrameSize < (ETHERMINPACKET - ETHERCRC) )
ETHERNET_STAT_ADD( dot3RxExtraEntry.frameTooShorts );
else ETHERNET_STAT_ADD( dot3StatsEntry.frameTooLongs );
ELG( rxPktStatus, receivedFrameSize, '-Rx-', "receivePackets - mutant or bad CRC." );
}
else if ( useNetif == false )
{
reusePkt = true;
if ( debuggerParam )
packetToDebugger( fRxMbuf[ i ], receivedFrameSize );
}
packet = 0;
if ( reusePkt == false )
{
packet = replaceOrCopyPacket( &fRxMbuf[i], receivedFrameSize, &replaced );
reusePkt = true;
if ( packet && replaced )
{
status = genRxDescriptor( i );
if ( status )
{
reusePkt = false;
}
else
{
ELG( packet, fRxMbuf[i], 'upd-', "UniNEnet::receivePackets" );
freePacket( fRxMbuf[i] ); fRxMbuf[i] = packet; packet = 0; IOLog( "UniNEnet::receivePackets - genRxDescriptor error\n" );
}
}
if ( packet == 0 )
NETWORK_STAT_ADD( inputErrors );
}
if ( reusePkt == true )
{
fRxDescriptorRing[i].flags = 0;
fRxDescriptorRing[i].frameDataSize = OSSwapHostToLittleConstInt16( NETWORK_BUFSIZE | kGEMRxDescFrameSize_Own );
}
last = i;
i = (i + 1) & (fRxRingElements - 1);
if ( (i & 3) == 0 ) WRITE_REGISTER( RxKick, (i - 4) & (fRxRingElements - 1) );
if ( debuggerParam )
break;
if ( packet )
{
KERNEL_DEBUG( DBG_UniN_RXCOMPLETE | DBG_FUNC_NONE,
(int)packet, (int)receivedFrameSize, 0, 0, 0 );
if ( (receivedFrameSize > 64) && (checksum != 0) )
setChecksumResult( packet,
kChecksumFamilyTCPIP,
kChecksumTCPSum16,
0, checksum, kRxHwCksumStartOffset );
ELG( packet, receivedFrameSize, 'RxP+', "UniNEnet::receivePackets - packet up." );
networkInterface->inputPacket( packet, receivedFrameSize, true );
NETWORK_STAT_ADD( inputPackets );
packetsQueued = true;
}
}
if ( last != (UInt32)-1 )
{
rxCommandTail = last;
rxCommandHead = i;
}
return packetsQueued;
}
bool UniNEnet::transmitInterruptOccurred()
{
UInt32 i, elemCnt = 0;
bool serviced = false;
i = READ_REGISTER( TxCompletion );
ELG( txCommandHead, i, ' Tx+', "transmitInterruptOccurred" );
while ( i != txCommandHead ) {
do
{
KERNEL_DEBUG( DBG_UniN_TXCOMPLETE | DBG_FUNC_NONE,
fTxMbuf[ txCommandHead ], 0, 0, 0, 0 );
elemCnt++;
if ( fTxMbuf[ txCommandHead ] )
{
freePacket( fTxMbuf[ txCommandHead ], kDelayFree );
fTxMbuf[ txCommandHead ] = 0;
NETWORK_STAT_ADD( outputPackets ); }
txCommandHead = (txCommandHead + 1) & (fTxRingElements - 1);
} while ( i != txCommandHead );
serviced = true;
i = READ_REGISTER( TxCompletion ); }
OSAddAtomic( elemCnt, (SInt32*)&fTxElementsAvail );
fpNetStats->outputPackets += releaseFreePackets();
return serviced;
}
void UniNEnet::debugTransmitInterruptOccurred()
{
UInt32 i;
debugTxPoll = true;
i = READ_REGISTER( TxCompletion );
while ( i != txCommandHead )
{
OSIncrementAtomic( (SInt32*)&fTxElementsAvail );
KERNEL_DEBUG( DBG_UniN_TXCOMPLETE | DBG_FUNC_NONE,
(int)fTxMbuf[ txCommandHead ],
(int)fTxMbuf[ txCommandHead ]->m_pkthdr.len, 0, 0, 0 );
if ( fTxMbuf[ txCommandHead ] )
{
if ( fTxMbuf[ txCommandHead ] != txDebuggerPkt )
debugQueue->enqueue( fTxMbuf[ txCommandHead ] );
fTxMbuf[ txCommandHead ] = 0;
}
txCommandHead = (txCommandHead + 1) & (fTxRingElements - 1);
}
return;
}
void UniNEnet::debugTransmitCleanup()
{
debugQueue->flush();
transmitQueue->start();
return;
}
bool UniNEnet::genRxDescriptor( UInt32 i )
{
IOPhysicalSegment segVector[ 2 ];
UInt32 segments;
segments = mbufCursor->getPhysicalSegmentsWithCoalesce( fRxMbuf[i], segVector );
if ( segments != 1 )
{
ALRT( fRxMbuf[i], segments, 'seg-', "UniNEnet::genRxDescriptor - segments != 1" );
return false;
}
OSWriteLittleInt32( &fRxDescriptorRing[i].bufferAddrLo, 0, segVector[0].location );
OSWriteLittleInt16( &fRxDescriptorRing[i].frameDataSize, 0, segVector[0].length | kGEMRxDescFrameSize_Own );
fRxDescriptorRing[ i ].flags = 0;
return true;
}
void UniNEnet::monitorLinkStatus( bool firstPoll )
{
UInt16 phyStatus;
UInt16 linkStatus;
UInt16 linkMode;
UInt16 lpAbility;
UInt16 phyStatusChange;
bool fullDuplex = false;
bool clockWasOff = false;
UInt32 linkSpeed = 0;
IOMediumType mediumType = kIOMediumEthernetNone;
IONetworkMedium *medium;
ELG( phyId, firstPoll, ' MLS', "monitorLinkStatus" );
if ( firstPoll )
{
phyStatusPrev = 0;
linkStatusPrev = kLinkStatusUnknown;
}
if(enetClockOff)
{
OSSynchronizeIO();
callPlatformFunction("EnableUniNEthernetClock", true, (void*)true, 0, 0, 0);
OSSynchronizeIO();
enetClockOff = false;
clockWasOff = true;
}
if ( phyId == 0xff )
{
phyStatus = READ_REGISTER( PCSMIIStatus ) & 0x0000FFFF;
lpAbility = READ_REGISTER( PCSMIILinkPartnerAbility ) & 0x0000FFFF;
}
else
{
if ( miiReadWord( &phyStatus, MII_STATUS, phyId) != true )
return;
miiReadWord( &lpAbility, MII_LINKPARTNER, phyId );
}
ELG( lpAbility, phyStatus, ' mls', "monitorLinkStatus - LinkPartnerAbility and Status" );
if(clockWasOff)
{
OSSynchronizeIO();
callPlatformFunction( "EnableUniNEthernetClock", true, (void*)false, 0, 0, 0 );
OSSynchronizeIO();
enetClockOff = true;
}
phyStatusChange = (phyStatusPrev ^ phyStatus) &
( MII_STATUS_LINK_STATUS |
MII_STATUS_NEGOTIATION_COMPLETE );
if ( phyStatusChange || firstPoll )
{
if ( firstPoll && fBuiltin )
{
miiWaitForAutoNegotiation( phyId );
miiReadWord(&phyStatus, MII_STATUS, phyId);
miiReadWord(&phyStatus, MII_STATUS, phyId);
}
if(!enetClockOff)
{
fMACControlConfiguration = READ_REGISTER( MACControlConfiguration );
fMACControlConfiguration |= kMACControlConfiguration_Receive_Pause_Enable;
if ( lpAbility & MII_LPAR_PAUSE )
fMACControlConfiguration |= kMACControlConfiguration_Send_Pause_Enable;
else fMACControlConfiguration &= ~kMACControlConfiguration_Send_Pause_Enable;
WRITE_REGISTER( MACControlConfiguration, fMACControlConfiguration );
}
if ( (phyStatus & MII_STATUS_LINK_STATUS) &&
( firstPoll || (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE) ) )
{
wakeUp(true);
if ( phyId == 0xff )
{
linkSpeed = 1000;
fullDuplex = true;
mediumType = kIOMediumEthernet1000BaseSX;
}
else if ( (phyType & MII_LXT971_MASK) == MII_LXT971_ID )
{
miiReadWord( &linkStatus, MII_LXT971_STATUS_2, phyId );
linkSpeed = (linkStatus & MII_LXT971_STATUS_2_SPEED) ?
100 : 10;
fullDuplex = (linkStatus & MII_LXT971_STATUS_2_DUPLEX) ?
true : false;
mediumType = (linkSpeed == 10) ? kIOMediumEthernet10BaseT :
kIOMediumEthernet100BaseTX;
}
else if ( (phyType & MII_BCM5201_MASK) == MII_BCM5201_ID )
{
miiReadWord( &linkStatus, MII_BCM5201_AUXSTATUS, phyId );
linkSpeed = (linkStatus & MII_BCM5201_AUXSTATUS_SPEED) ?
100 : 10;
fullDuplex = (linkStatus & MII_BCM5201_AUXSTATUS_DUPLEX) ?
true : false;
mediumType = (linkSpeed == 10) ? kIOMediumEthernet10BaseT :
kIOMediumEthernet100BaseTX;
}
else if ( ((phyType & MII_BCM5400_MASK) == MII_BCM5400_ID)
|| ((phyType & MII_BCM5400_MASK) == MII_BCM5401_ID) || ((phyType & MII_BCM5400_MASK) == MII_BCM5411_ID) || ((phyType & MII_BCM5400_MASK) == MII_BCM5421_ID) ) {
miiReadWord( &linkStatus, MII_BCM5400_AUXSTATUS, phyId );
linkMode = (linkStatus & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) /
MII_BCM5400_AUXSTATUS_LINKMODE_BIT;
if ( linkMode < 6 )
fXIFConfiguration &= ~kXIFConfiguration_GMIIMODE;
else fXIFConfiguration |= kXIFConfiguration_GMIIMODE;
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
if ( linkMode == 0 )
{
linkSpeed = 0;
}
else if ( linkMode < 3 )
{
linkSpeed = 10;
fullDuplex = ( linkMode < 2 ) ? false : true;
mediumType = kIOMediumEthernet10BaseT;
}
else if ( linkMode < 6 )
{
linkSpeed = 100;
fullDuplex = ( linkMode < 5 ) ? false : true;
mediumType = kIOMediumEthernet100BaseTX;
}
else
{
linkSpeed = 1000;
fullDuplex = true;
mediumType = kIOMediumEthernet1000BaseTX;
}
}
setDuplexMode( fullDuplex );
if ( ready == true )
startChip();
if ( linkSpeed != 0 )
{
mediumType |= (fullDuplex == true) ?
kIOMediumOptionFullDuplex :
kIOMediumOptionHalfDuplex;
}
medium = IONetworkMedium::getMediumWithType( mediumDict,
mediumType );
setLinkStatus( kIONetworkLinkActive | kIONetworkLinkValid,
medium,
linkSpeed * 1000000 );
IOLog( "UniNEnet::monitorLinkStatus - Link is up at %ld Mbps - %s Duplex\n\r",
linkSpeed, fullDuplex ? "Full" : "Half" );
linkStatusPrev = kLinkStatusUp;
}
else
{
if ( (linkStatusPrev == kLinkStatusUp) ||
(linkStatusPrev == kLinkStatusUnknown) )
{
stopChip();
medium = IONetworkMedium::getMediumWithType( mediumDict,
mediumType );
setLinkStatus( kIONetworkLinkValid,
medium,
0 );
if ( linkStatusPrev != kLinkStatusUnknown )
{
IOLog( "Ethernet(UniN): Link is down.\n\r" );
}
txIntCnt = 0;
if ( txCommandHead != txCommandTail )
{
initTxRing();
txCommandHead = READ_REGISTER( TxCompletion );
txCommandTail = txCommandHead;
}
}
linkStatusPrev = kLinkStatusDown;
}
phyStatusPrev = phyStatus;
}
return;
}
IOReturn UniNEnet::getHardwareAddress(IOEthernetAddress *ea)
{
UInt32 i;
OSData *macEntry;
UInt8 *macAddress;
UInt32 len;
macEntry = OSDynamicCast( OSData, nub->getProperty( "local-mac-address" ) );
if ( macEntry == 0 )
{
return kIOReturnError;
}
macAddress = (UInt8 *)macEntry->getBytesNoCopy();
if ( macAddress == 0 )
{
return kIOReturnError;
}
len = macEntry->getLength();
if ( len != 6 )
{
return kIOReturnError;
}
for (i = 0; i < sizeof(*ea); i++)
{
ea->bytes[i] = macAddress[i];
}
return kIOReturnSuccess;
}
#define ENET_CRCPOLY 0x04c11db7
static UInt32 crc416(UInt32 current, UInt16 nxtval )
{
register UInt32 counter;
register int highCRCBitSet, lowDataBitSet;
nxtval = ((nxtval & 0x00FF) << 8) | (nxtval >> 8);
for (counter = 0; counter != 16; ++counter)
{
if ((current & 0x80000000) == 0)
highCRCBitSet = 0;
else
highCRCBitSet = 1;
current = current << 1;
if ((nxtval & 0x0001) == 0)
lowDataBitSet = 0;
else
lowDataBitSet = 1;
nxtval = nxtval >> 1;
if (highCRCBitSet ^ lowDataBitSet)
current = current ^ ENET_CRCPOLY;
}
return current;
}
static UInt32 mace_crc(UInt16 *address)
{
register UInt32 newcrc;
newcrc = crc416(0xffffffff, *address);
newcrc = crc416(newcrc, address[1]);
newcrc = crc416(newcrc, address[2]);
return(newcrc);
}
void UniNEnet::addToHashTableMask(UInt8 *addr)
{
UInt32 i,j;
UInt32 crcBitIndex;
UInt16 mask;
j = mace_crc((UInt16 *)addr) & 0xFF;
for ( crcBitIndex = i = 0; i < 8; i++ )
{
crcBitIndex >>= 1;
crcBitIndex |= (j & 0x80);
j <<= 1;
}
crcBitIndex ^= 0xFF;
if (hashTableUseCount[crcBitIndex]++)
return;
mask = crcBitIndex % 16;
mask = 1 << mask;
hashTableMask[crcBitIndex/16] |= mask;
}
void UniNEnet::resetHashTableMask()
{
bzero(hashTableUseCount, sizeof(hashTableUseCount));
bzero(hashTableMask, sizeof(hashTableMask));
}
void UniNEnet::updateHashTableMask()
{
UInt32 i;
fRxMACConfiguration = READ_REGISTER( RxMACConfiguration );
ELG( this, fRxMACConfiguration, 'updH', "updateHashTableMask" );
WRITE_REGISTER( RxMACConfiguration,
fRxMACConfiguration & ~(kRxMACConfiguration_Rx_Mac_Enable
| kRxMACConfiguration_Hash_Filter_Enable) );
while ( READ_REGISTER( RxMACConfiguration ) & (kRxMACConfiguration_Rx_Mac_Enable
| kRxMACConfiguration_Hash_Filter_Enable) )
;
for ( i= 0; i < 16; i++ )
WRITE_REGISTER( HashTable[ i ], hashTableMask[ 15 - i ] );
fRxMACConfiguration |= kRxMACConfiguration_Hash_Filter_Enable;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
}