UniNEnetPrivate.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IORegistryEntry.h>
#include <IOKit/IOKitKeys.h> // kIODeviceTreePlane
#include <IOKit/IOBufferMemoryDescriptor.h>
#include "UniNEnet.h"
#include "UniNEnetMII.h"
bool UniNEnet::allocateMemory()
{
UInt32 rxRingSize, txRingSize;
txRingSize = fTxRingElements * sizeof( TxDescriptor );
fTxRingMemDesc = IOBufferMemoryDescriptor::withOptions( kIOMemoryPhysicallyContiguous,
txRingSize,
PAGE_SIZE );
if ( !fTxRingMemDesc )
{
ALRT( 0, txRingSize, 'TRM-', "UniNEnet::allocateMemory - failed to alloc Tx Ring memory" );
return false;
}
fTxRingMemDesc->prepare( kIODirectionOutIn );
fTxDescriptorRing = (TxDescriptor*)fTxRingMemDesc->getBytesNoCopy(); fTxDescriptorRingPhys = fTxRingMemDesc->getPhysicalAddress();
if ( fTxDescriptorRingPhys == 0 )
{
ALRT( 0, txRingSize, 'TRP-', "UniNEnet::allocateMemory - Bad Tx Ring" );
return false;
}
ELG( txRingSize, fTxDescriptorRing, '=TxR', "UniNEnet::allocateMemory - Tx Ring alloc'd" );
rxRingSize = fRxRingElements * sizeof( RxDescriptor );
fRxRingMemDesc = IOBufferMemoryDescriptor::withOptions( kIOMemoryPhysicallyContiguous,
rxRingSize,
PAGE_SIZE );
if ( !fRxRingMemDesc )
{
ALRT( 0, rxRingSize, 'RRM-', "UniNEnet::allocateMemory - failed to alloc Rx Ring" );
return false;
}
fRxRingMemDesc->prepare( kIODirectionOutIn );
fRxDescriptorRing = (RxDescriptor*)fRxRingMemDesc->getBytesNoCopy(); fRxDescriptorRingPhys = fRxRingMemDesc->getPhysicalAddress();
if ( fRxDescriptorRingPhys == 0 )
{
ALRT( 0, rxRingSize, 'RRP-', "UniNEnet::allocateMemory - Bad Rx Ring" );
return false;
}
ELG( rxRingSize, fRxDescriptorRing, '=RxR', "UniNEnet::allocateMemory - Rx Ring alloc'd" );
fTxMbuf = (mbuf_t*)IOMalloc( sizeof( mbuf_t ) * fTxRingElements );
if ( !fTxMbuf )
{
ALRT( 0, 0, 'mpT-', "UniNEnet::allocateMemory - alloc Tx mbuf pointers failed" );
return false;
}
bzero( fTxMbuf, sizeof( mbuf_t ) * fTxRingElements );
fRxMbuf = (mbuf_t*)IOMalloc( sizeof( mbuf_t ) * fRxRingElements );
if ( !fRxMbuf )
{
ALRT( 0, 0, 'mpR-', "UniNEnet::allocateMemory - alloc Rx mbuf pointers failed" );
return false;
}
bzero( fRxMbuf, sizeof( mbuf_t ) * fRxRingElements );
ELG( fTxMbuf, fRxMbuf, 'arys', "UniNEnet::allocateMemory - mbuf pointer arrays" );
return true;
}
bool UniNEnet::initTxRing()
{
UInt32 i;
ELG( this, fTxDescriptorRing, 'ITxR', "UniNEnet::initTxRing" );
bzero( (void*)fTxDescriptorRing, sizeof( TxDescriptor ) * fTxRingElements );
txCommandHead = 0;
txCommandTail = 0;
for ( i = 0; i < fTxRingElements; i++ )
{
if ( fTxMbuf[ i ] )
{
ELG( i, fTxMbuf[ i ], 'txpf', "UniNEnet::initTxRing - free the packet" );
if ( fTxMbuf[ i ] == txDebuggerPkt )
txDebuggerPktInUse = false;
else
freePacket( fTxMbuf[ i ] );
fTxMbuf[ i ] = 0;
}
}
fTxIntCnt = 0;
txWDCount = 0;
return true;
}
bool UniNEnet::initRxRing()
{
UInt32 i;
bool status;
ELG( fRxMbuf, fRxDescriptorRing, 'IRxR', "UniNEnet::initRxRing" );
bzero( (void*)fRxDescriptorRing, sizeof( RxDescriptor ) * fRxRingElements );
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;
return true;
}
void UniNEnet::flushRings( bool flushTx, bool flushRx )
{
UInt32 i;
ELG( fTxRingElements, fRxRingElements, 'FluR', "UniNEnet::flushRings" );
if ( flushTx ) {
for ( i = 0; i < fTxRingElements; i++ )
{
if ( fTxMbuf[ i ] )
{
ELG( i, fTxMbuf[ i ], 'flTx', "UniNEnet::flushRings - Tx ring" );
if ( fTxMbuf[ i ] == txDebuggerPkt )
txDebuggerPktInUse = false;
else
freePacket( fTxMbuf[ i ] );
fTxMbuf[ i ] = 0;
}
}
}
if ( flushRx ) {
for ( i = 0; i < fRxRingElements; i++ )
{
if ( fRxMbuf[ i ] )
{
ELG( i, fRxMbuf[ i ], 'flRx', "UniNEnet::flushRings - Rx ring" );
freePacket( fRxMbuf[ i ] );
fRxMbuf[i] = 0;
}
}
}
return;
}
void UniNEnet::startChip()
{
ELG( this, 0, 'SChp', "startChip" );
fXIFConfiguration |= kXIFConfiguration_Tx_MII_OE;
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
fTxConfiguration |= kTxConfiguration_Tx_DMA_Enable; WRITE_REGISTER( TxConfiguration, fTxConfiguration );
fRxConfiguration |= kRxConfiguration_Rx_DMA_Enable; WRITE_REGISTER( RxConfiguration, fRxConfiguration );
fTxMACConfiguration |= kTxMACConfiguration_TxMac_Enable;
WRITE_REGISTER( TxMACConfiguration, fTxMACConfiguration );
fRxMACConfiguration = kRxMACConfiguration_Rx_Mac_Enable; if ( fIsPromiscuous )
fRxMACConfiguration |= kRxMACConfiguration_Promiscuous;
else fRxMACConfiguration |= kRxMACConfiguration_Strip_FCS;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
#ifdef LATER
WRITE_REGISTER( InterruptMask, ~(kStatus_TX_ALL | kStatus_TX_INT_ME | kStatus_RX_DONE | kStatus_MIF_Interrupt) );
#else
WRITE_REGISTER( InterruptMask, ~(kStatus_TX_ALL | kStatus_TX_INT_ME | kStatus_RX_DONE) );
#endif // LATER
return;
}
void UniNEnet::stopChip()
{
ELG( READ_REGISTER( TxConfiguration ), READ_REGISTER( RxConfiguration ), 'HChp', "stopChip" );
fTxConfiguration &= ~kTxConfiguration_Tx_DMA_Enable; WRITE_REGISTER( TxConfiguration, fTxConfiguration );
fRxConfiguration &= ~kRxConfiguration_Rx_DMA_Enable; WRITE_REGISTER( RxConfiguration, fRxConfiguration );
IOSleep( 1 );
fTxMACConfiguration &= ~kTxMACConfiguration_TxMac_Enable;
WRITE_REGISTER( TxMACConfiguration, fTxMACConfiguration );
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 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl, 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionLoopback , 10 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex , 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex , 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl, 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex | kIOMediumOptionLoopback , 100 }
};
static MediumTable gMediumTableGigabit[] =
{
{ kIOMediumEthernetNone , 0 },
{ kIOMediumEthernetAuto , 0 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex , 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex , 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl, 10 },
{ kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionLoopback , 10 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex , 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex , 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl, 100 },
{ kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex | kIOMediumOptionLoopback , 100 },
{ kIOMediumEthernet1000BaseT | kIOMediumOptionFullDuplex , 1000 },
{ kIOMediumEthernet1000BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionFlowControl, 1000 },
{ kIOMediumEthernet1000BaseT | kIOMediumOptionFullDuplex | kIOMediumOptionLoopback , 1000 }
};
void UniNEnet::getPhyType()
{
UInt16 *pPhyType;
UInt16 phyWord;
ELG( this, phyId, 'gPhT', "getPhyType" );
if ( !fBuiltin )
{
fPHYType = ' GEM';
fpgMediumTable = gMediumTableGEM;
fMediumTableCount = sizeof( gMediumTableGEM ) / sizeof( MediumTable ) ;
setProperty( "PHY type", "GEM integrated" );
return;
}
pPhyType = (UInt16*)&phyType;
miiReadWord( pPhyType, MII_ID0 );
miiReadWord( pPhyType+1, MII_ID1 );
setProperty( "PHY ID", phyType, sizeof( phyType ) * 8 );
ELG( phyId, phyType, '=FyT', "UniNEnet::getPhyType" );
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 );
phyWord |= MII_BCM5400_AUXCONTROL_PWR10BASET;
miiWriteWord( phyWord, MII_BCM5400_AUXCONTROL );
miiReadWord( &phyWord, MII_1000BASETCONTROL );
phyWord |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_1000BASETCONTROL );
IODelay( 100 );
UInt8 temp = phyId;
phyId = 0x1F;
miiResetPHY();
miiReadWord( &phyWord, MII_BCM5201_MULTIPHY );
phyWord |= MII_BCM5201_MULTIPHY_SERIALMODE;
miiWriteWord( phyWord, MII_BCM5201_MULTIPHY );
phyId = temp;
miiReadWord( &phyWord, MII_BCM5400_AUXCONTROL );
phyWord &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
miiWriteWord( phyWord, MII_BCM5400_AUXCONTROL );
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 );
phyWord &= 0x000F ;
if ( (phyWord == 0x0001 ) || (phyWord == 0x0003) )
{
miiWriteWord( 0x0C20, 0x018 );
miiWriteWord( 0x0012, 0x017 );
miiWriteWord( 0x1804, 0x015 );
miiWriteWord( 0x0013, 0x017 );
miiWriteWord( 0x1204, 0x015 );
miiWriteWord( 0x8006, 0x017 );
miiWriteWord( 0x0132, 0x015 );
miiWriteWord( 0x8006, 0x017 );
miiWriteWord( 0x0232, 0x015 );
miiWriteWord( 0x201F, 0x017 );
miiWriteWord( 0x0A20, 0x015 );
}
miiReadWord( &phyWord, MII_1000BASETCONTROL );
phyWord |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_1000BASETCONTROL );
IODelay( 10 );
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 ); miiWriteWord( 0x8CA3, 0x01C );
miiWriteWord( 0x8C23, 0x01C );
miiWriteWord( 0x8000, 0x000 );
miiWriteWord( 0x1340, 0x000 );
miiReadWord( &phyWord, MII_1000BASETCONTROL );
phyWord |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_1000BASETCONTROL );
IODelay( 10 );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_BCM5400_MASK) == MII_BCM5421_ID || (phyType & MII_BCM5400_MASK) == MII_BCM54K2_ID || (phyType & MII_BCM5400_MASK) == MII_BCM5462_ID ) {
const IORegistryPlane *plane = getPlane( kIODeviceTreePlane );
IORegistryEntry *entry;
OSObject *obj;
bool noAutoLowPower = false;
fPHYType = 0x5421;
ELG( this, phyId, '5421', "UniNEnet::getPhyType - Broadcom 5421" );
setProperty( "PHY type", "Broadcom 5421" );
if ( phyType == MII_BCM5421_ID ) {
miiWriteWord( 0x1007, 0x18 ); miiReadWord( &phyWord, 0x18 );
miiWriteWord( phyWord | 0x0400, 0x18 );
miiWriteWord( 0x0007, 0x18 ); miiReadWord( &phyWord, 0x18 );
miiWriteWord( phyWord | 0x0800, 0x18 );
miiWriteWord( 0x000A, 0x17 );
miiReadWord( &phyWord, 0x15 );
miiWriteWord( phyWord | 0x0200, 0x15 );
}
miiReadWord( &phyWord, MII_1000BASETCONTROL );
phyWord |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
miiWriteWord( phyWord, MII_1000BASETCONTROL );
entry = nub->getChildEntry( plane ); if ( entry )
{ obj = entry->copyProperty( "no-autolowpower" );
if ( obj )
noAutoLowPower = true;
}
if ( noAutoLowPower == false )
{
miiWriteWord( 0x9002, 0x1C ); miiWriteWord( 0xA821, 0x1C ); miiWriteWord( 0x941D, 0x1C ); }
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 88E1011" );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable );
}
else if ( (phyType & MII_MARVELL_MASK) == MII_MARVELL_ID_2 ) {
fPHYType = 0x1011; ELG( this, phyId, '1111', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Marvell 88E1111" );
fpgMediumTable = gMediumTableGigabit;
fMediumTableCount = sizeof( gMediumTableGigabit ) / sizeof( MediumTable );
if ( phyType == MII_MARVELL_ID_2 ) {
miiWriteWord( 0x000A, 0x01D );
miiWriteWord( 0x0821, 0x01E );
miiWriteWord( 0x0006, 0x01D );
miiWriteWord( 0x8600, 0x01E );
miiWriteWord( 0x000B, 0x01D );
miiWriteWord( 0x0100, 0x01E );
miiWriteWord( 0x0004, 0x01D );
miiWriteWord( 0x4850, 0x01E );
}
}
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 if ( (phyType & MII_BCM5221_MASK) == MII_BCM5221_ID )
{
fPHYType = 0x5221;
ELG( this, phyId, '5221', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Broadcom 5221" );
miiReadWord( &phyWord, MII_BCM5221_TestRegister );
phyWord |= MII_BCM5221_ShadowRegEnableBit;
miiWriteWord( phyWord, MII_BCM5221_TestRegister );
miiReadWord( &phyWord, MII_BCM5221_AuxiliaryStatus2 );
phyWord |= MII_BCM5221_APD_EnableBit;
miiWriteWord( phyWord, MII_BCM5221_AuxiliaryStatus2 );
miiReadWord( &phyWord, MII_BCM5221_AuxiliaryMode4 );
phyWord |= MII_BCM5221_EnableClkDuringLowPwr;
miiWriteWord( phyWord, MII_BCM5221_AuxiliaryMode4 );
miiReadWord( &phyWord, MII_BCM5221_TestRegister );
phyWord &= ~MII_BCM5221_ShadowRegEnableBit;
miiWriteWord( phyWord, MII_BCM5221_TestRegister );
miiWriteWord( MII_BCM5201_INTERRUPT_INTREnable, MII_BCM5201_INTERRUPT );
fpgMediumTable = gMediumTable100;
fMediumTableCount = sizeof( gMediumTable100 ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_BCM5241_MASK) == MII_BCM5241_ID )
{
fPHYType = 0x5241;
ELG( this, phyId, '5241', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Broadcom 5241" );
miiReadWord( &phyWord, MII_BCM5221_TestRegister );
phyWord |= MII_BCM5221_ShadowRegEnableBit;
miiWriteWord( phyWord, MII_BCM5221_TestRegister );
miiReadWord( &phyWord, MII_BCM5221_AuxiliaryStatus2 );
phyWord |= MII_BCM5221_APD_EnableBit;
miiWriteWord( phyWord, MII_BCM5221_AuxiliaryStatus2 );
miiReadWord( &phyWord, MII_BCM5221_AuxiliaryMode4 );
phyWord &= ~MII_BCM5241_StandbyPowerMode;
miiWriteWord( phyWord, MII_BCM5221_AuxiliaryMode4 );
miiReadWord( &phyWord, MII_BCM5221_TestRegister );
phyWord &= ~MII_BCM5221_ShadowRegEnableBit;
miiWriteWord( phyWord, MII_BCM5221_TestRegister );
fpgMediumTable = gMediumTable100;
fMediumTableCount = sizeof( gMediumTable100 ) / sizeof( MediumTable ) ;
}
else if ( (phyType & MII_LXT971_MASK) == MII_LXT971_ID )
{
fPHYType = 0x0971;
ELG( this, phyId, 'L971', "UniNEnet::getPhyType" );
setProperty( "PHY type", "Level One LXT971" );
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;
mach_timespec_t timeStamp;
UInt16 *p16;
OSNumber *numObj;
UInt32 busSpeed;
volatile UInt32 vui32;
ELG( 0, phyId, 'ChpI', "initChip" );
fTxConfiguration &= ~kTxConfiguration_Tx_DMA_Enable;
fRxConfiguration &= ~kRxConfiguration_Rx_DMA_Enable;
fTxMACConfiguration &= ~kTxMACConfiguration_TxMac_Enable;
fRxMACConfiguration &= ~kRxMACConfiguration_Rx_Mac_Enable;
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 );
}
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
WRITE_REGISTER( MACControlType, kMACControlType_default );
WRITE_REGISTER( MACControlConfiguration,fMACControlConfiguration );
WRITE_REGISTER( InterruptMask, kInterruptMask_None );
WRITE_REGISTER( TxMACMask, kTxMACMask_default );
WRITE_REGISTER( RxMACMask, kRxMACMask_default );
WRITE_REGISTER( MACControlMask, kMACControlMask_default );
vui32 = READ_REGISTER( TxMACStatus ); vui32 = READ_REGISTER( RxMACStatus );
vui32 = READ_REGISTER( MACControlStatus );
WRITE_REGISTER( Configuration, fConfiguration ); vui32 = READ_REGISTER( Configuration ); if ( (vui32 & kConfiguration_Infinite_Burst) == 0 )
{ ELG( 0, 0, 'Lims', "UniNEnet::initChip: set TX_DMA_Limit and RX_DMA_Limit." );
fConfiguration = (0x02 << 1) | (0x08 << 6); WRITE_REGISTER( Configuration, fConfiguration );
}
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 );
p16 = (UInt16*)myAddress.bytes;
for ( i = 0; i < sizeof( IOEthernetAddress ) / 2; i++ )
{
WRITE_REGISTER( MACAddress[ i ], p16[ 2 - i ] );
WRITE_REGISTER( MACAddress[ i + 3 ], p16[ 2 - i ] ); }
for ( i = 0; i < 3; i++ )
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 & 0x03FF );
WRITE_REGISTER( TxDescriptorBaseLow, fTxDescriptorRingPhys );
WRITE_REGISTER( TxDescriptorBaseHigh, 0 );
WRITE_REGISTER( TxConfiguration, fTxConfiguration );
WRITE_REGISTER( TxMACConfiguration, fTxMACConfiguration );
IOSleep( 4 );
WRITE_REGISTER( RxDescriptorBaseLow, fRxDescriptorRingPhys );
WRITE_REGISTER( RxDescriptorBaseHigh, 0 );
WRITE_REGISTER( RxKick, fRxRingElements - 4 );
WRITE_REGISTER( RxConfiguration, fRxConfiguration );
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
IOSleep( 4 );
WRITE_REGISTER( PauseThresholds, fPauseThresholds );
WRITE_REGISTER( SendPauseCommand, fSendPauseCommand );
fRxBlanking = kRxBlanking_default_66;
if ( !fBuiltin )
{
fRxBlanking = kRxBlanking_default_33;
numObj = OSDynamicCast( OSNumber, getProperty( "clock-frequency" ) );
if ( numObj )
{
busSpeed = numObj->unsigned32BitValue();
if ( busSpeed > 33333333 )
fRxBlanking = kRxBlanking_default_66;
}
}
WRITE_REGISTER( RxBlanking, fRxBlanking );
#ifdef LATER
if ( fPHYType == 0x5221 )
{
phyAdrToPoll = phyId;
phyRegToPoll = MII_BCM5201_INTERRUPT;
phyBitsToMonitor = ~(MII_BCM5201_INTERRUPT_LINKChange
| MII_BCM5201_INTERRUPT_SPDChange
| MII_BCM5201_INTERRUPT_FDXChange);
WRITE_REGISTER( MIFMask, phyBitsToMonitor );
val16 = READ_REGISTER( MIFConfiguration )
| kMIFConfiguration_Poll_Enable
| phyAdrToPoll << kMIFConfiguration_Poll_Phy_Adr_Shift
| phyRegToPoll << kMIFConfiguration_Poll_Reg_Adr_Shift;
WRITE_REGISTER( MIFConfiguration, val16 );
}
#endif // LATER
if ( fBuiltin )
WRITE_REGISTER( WOLWakeupCSR, 0 );
ELG( READ_REGISTER( TxFIFOSize ), READ_REGISTER( RxFIFOSize ), 'FFsz', "initChip - done" );
return true;
}
void UniNEnet::setDuplexMode( bool duplexMode )
{
isFullDuplex = duplexMode;
ELG( fTxMACConfiguration, duplexMode, 'DupM', "setDuplexMode" );
WRITE_REGISTER( TxMACConfiguration, 0 );
IOSleep( 1 );
if ( isFullDuplex )
{
fTxMACConfiguration |= (kTxMACConfiguration_Ignore_Collisions | kTxMACConfiguration_Ignore_Carrier_Sense);
fXIFConfiguration &= ~kXIFConfiguration_Disable_Echo;
}
else
{
fTxMACConfiguration &= ~(kTxMACConfiguration_Ignore_Collisions | kTxMACConfiguration_Ignore_Carrier_Sense);
fXIFConfiguration |= kXIFConfiguration_Disable_Echo;
}
WRITE_REGISTER( TxMACConfiguration, fTxMACConfiguration );
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
return;
}
void UniNEnet::restartTransmitter()
{
UInt32 gemReg;
transmitQueue->stop();
ELG( READ_REGISTER( TxKick ), READ_REGISTER( TxCompletion ), 'TxKC', "UniNEnet::restartTransmitter" );
ELG( READ_REGISTER( TxFIFOSize ), READ_REGISTER( TxFIFOPacketCounter ), 'TxPc', "UniNEnet::restartTransmitter" );
ELG( READ_REGISTER( TxFIFOShadowReadPointer ), READ_REGISTER( TxFIFOReadPointer ), 'TxRp', "UniNEnet::restartTransmitter" );
ELG( READ_REGISTER( TxMACStatus ), READ_REGISTER( MACControlStatus ), 'TM S', "UniNEnet::restartTransmitter" );
ELG( READ_REGISTER( MIFStateMachine ), READ_REGISTER( TxConfiguration ), 'MiCf', "UniNEnet::restartTransmitter" );
ALRT( READ_REGISTER( TxStateMachine ), READ_REGISTER( StateMachine ), '-Tx-', "UniNEnet::restartTransmitter - transmitter appeared to be hung." );
WRITE_REGISTER( TxConfiguration, 0 );
IOSleep( 1 );
WRITE_REGISTER( TxMACConfiguration, 0 );
IOSleep( 4 );
WRITE_REGISTER( TxMACSoftwareResetCommand, kTxMACSoftwareResetCommand_Reset );
IOSleep( 1 );
WRITE_REGISTER( SoftwareReset, kSoftwareReset_TX );
do
{ IOSleep( 1 );
gemReg = READ_REGISTER( SoftwareReset );
}
while( gemReg & kSoftwareReset_TX );
initTxRing();
fTxConfiguration |= kTxConfiguration_Tx_DMA_Enable;
WRITE_REGISTER( TxConfiguration, fTxConfiguration );
WRITE_REGISTER( MACControlConfiguration, fMACControlConfiguration );
WRITE_REGISTER( TxMACConfiguration, fTxMACConfiguration );
transmitQueue->start();
return;
}
void UniNEnet::restartReceiver()
{
UInt16 i, u16;
UInt32 x;
ELG( 0, READ_REGISTER( StatusAlias ), 'StsA', "UniNEnet::restartReceiver" );
ELG( READ_REGISTER( RxKick ), READ_REGISTER( RxCompletion ), 'RxKC', "UniNEnet::restartReceiver" );
ELG( READ_REGISTER( RxConfiguration ), READ_REGISTER( RxFIFOReadPointer ), 'RxCR', "UniNEnet::restartReceiver" );
ELG( READ_REGISTER( RxFIFOShadowWritePointer ), READ_REGISTER( RxFIFOWritePointer ), 'RxWp', "UniNEnet::restartReceiver" );
ELG( 0, READ_REGISTER( RxFIFOPacketCounter ), 'RxPC', "UniNEnet::restartReceiver" );
ALRT( READ_REGISTER( RxStateMachine ), READ_REGISTER( StateMachine ), '=SMs', "UniNEnet::restartReceiver" );
fRxConfiguration &= ~kRxConfiguration_Rx_DMA_Enable;
WRITE_REGISTER( RxConfiguration, fRxConfiguration );
IOSleep( 1 );
WRITE_REGISTER( SoftwareReset, kSoftwareReset_RX );
for ( i = 1000; i; --i )
{ IODelay( 1 );
x = READ_REGISTER( SoftwareReset );
if ( (x & kSoftwareReset_RX) == 0 )
break;
}
if ( i == 0 )
ALRT( 0, x, '-SR-', "UniNEnet::restartReceiver - timeout on SoftwareReset" );
WRITE_REGISTER( RxMACSoftwareResetCommand, kRxMACSoftwareResetCommand_Reset );
for ( i = 0; i < 5000; i++ )
{
if ( (READ_REGISTER( RxMACSoftwareResetCommand )
& kRxMACSoftwareResetCommand_Reset) == 0 )
{
break; }
IODelay( 1 );
}
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration & ~kRxMACConfiguration_Rx_Mac_Enable );
for ( i = 0; i < 5000; i++ )
{
if ( (READ_REGISTER( RxMACConfiguration )
& kRxMACConfiguration_Rx_Mac_Enable) == 0 )
{
break; }
IODelay( 1 );
}
u16 = OSSwapHostToLittleConstInt16( NETWORK_BUFSIZE | kGEMRxDescFrameSize_Own );
for ( i = 0; i < fRxRingElements; ++i )
fRxDescriptorRing[ i ].frameDataSize = u16;
WRITE_REGISTER( RxBlanking, fRxBlanking );
WRITE_REGISTER( PauseThresholds, fPauseThresholds );
rxCommandHead = 0;
WRITE_REGISTER( RxKick, fRxRingElements - 4 );
WRITE_REGISTER( MACControlConfiguration, fMACControlConfiguration );
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
fRxConfiguration |= kRxConfiguration_Rx_DMA_Enable;
WRITE_REGISTER( RxConfiguration, fRxConfiguration );
return;
}
bool UniNEnet::transmitPacket( mbuf_t packet )
{
TxDescriptor *dp; mbuf_t m;
UInt32 i, j, k;
UInt32 segCount = 1; UInt32 length;
addr64_t dataPhys;
UInt32 demandMask;
UInt16 param0, param1;
bool needSegs = true; UInt32 txElementsAvail;
txElementsAvail = (txCommandHead + fTxRingElements - txCommandTail - 1) & (fTxRingElements-1);
for ( m = packet; mbuf_next( m ); m = mbuf_next( m ) )
segCount++;
ELG( READ_REGISTER( TxCompletion ), txElementsAvail << 16 | segCount, ' Tx', "UniNEnet::transmitPacket" );
if ( segCount > txElementsAvail )
{
ELG( txElementsAvail << 16 | segCount, packet, ' Tx-', "UniNEnet::transmitPacket - not enough elements avail." );
if ( segCount < (fTxRingElements - 2) )
return false;
ELG( txElementsAvail << 16 | segCount, packet, 'Tx--', "UniNEnet::transmitPacket - way too many elements req'd." );
freePacket( packet ); return true; }
k = j = txCommandTail;
fTxIntCnt += segCount;
m = packet;
for ( i = 0; i < segCount; i++ )
{
k = j;
length = mbuf_len( m );
dataPhys = (addr64_t)mbuf_data_to_physical( mbuf_data( m ) );
if ( dataPhys == 0 )
{
if ( needSegs )
{ needSegs = false;
segCount = fTxMbufCursor->getPhysicalSegments( packet, fTxSegment, MAX_SEGS_PER_TX_MBUF );
}
ELG( segCount, i, 'mbp-', "UniNEnet::transmitPacket - mbuf segment lacking physical address" );
dataPhys = (addr64_t)fTxSegment[ i ].location;
length = fTxSegment[ i ].length;
ELG( length, dataPhys, 'LocL', "UniNEnet::transmitPacket - length and location." );
}
dp = &fTxDescriptorRing[ j ];
OSWriteLittleInt64( dp, offsetof( TxDescriptor, bufferAddr ), dataPhys );
OSWriteLittleInt32( dp, offsetof( TxDescriptor, flags0 ), length );
dp->flags1 = 0;
j = (j + 1) & (fTxRingElements - 1);
m = mbuf_next( m );
}
fTxMbuf[ k ] = packet;
fTxDescriptorRing[ k ].flags0 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags0_EndOfFrame );
fTxDescriptorRing[ txCommandTail ].flags0 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags0_StartOfFrame );
if ( fTxIntCnt >= TX_DESC_PER_INT )
{
fTxIntCnt = 0;
fTxDescriptorRing[ txCommandTail ].flags1 |= OSSwapHostToLittleConstInt32( kGEMTxDescFlags1_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;
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 ( fReady == 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( mbuf_t packet, u_int size )
{
debuggerPktSize = size;
bcopy( (char*)mbuf_data( packet ), debuggerPkt, size );
return;
}
void UniNEnet::sendPacket( void *pkt, UInt32 pkt_len )
{
mach_timespec_t startTime, currentTime;
UInt32 elapsedTimeMS;
if ( !fReady || !pkt || (pkt_len > (fMaxFrameSize - kIOEthernetCRCSize)) )
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 )
{
ALRT( txCommandHead, txCommandTail, 'db1-', "UniNEnet::sendPacket - Polled transmit timeout - 1." );
return;
}
bcopy( pkt, mbuf_data( txDebuggerPkt ), pkt_len );
mbuf_setlen( txDebuggerPkt, pkt_len );
mbuf_pkthdr_setlen( txDebuggerPkt, 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 )
ALRT( txCommandHead, txCommandTail, 'db2-', "UniNEnet::sendPacket - Polled transmit timeout - 2." );
#if USE_ELG
fpELG->evLogFlag = elgFlag;
#endif // USE_ELG
return;
}
bool UniNEnet::receivePackets( bool debuggerParam )
{
mbuf_t packet;
UInt32 i, last, loopLimit;
int receivedFrameSize, maxFrameSize;
int cksumOffset;
UInt16 dmaFlags;
UInt16 checksum;
UInt32 rxCompletion;
UInt32 rxPktStatus = 0;
UInt8 *pb;
bool reusePkt;
bool useNetif = !debuggerParam && netifEnabled;
bool packetsQueued = false;
bool replaced;
bool vlanPacket;
last = (UInt32)-1;
i = rxCommandHead;
rxCompletion = READ_REGISTER( RxCompletion );
for ( loopLimit = fRxRingElements; loopLimit; --loopLimit )
{
dmaFlags = OSReadLittleInt16( &fRxDescriptorRing[ i ].frameDataSize, 0 );
if ( dmaFlags & kGEMRxDescFrameSize_Own )
break;
if ( i == rxCompletion )
{ rxCompletion = READ_REGISTER( RxCompletion );
if ( i == rxCompletion ) break; }
reusePkt = false;
checksum = OSReadLittleInt16( &fRxDescriptorRing[ i ].tcpPseudoChecksum, 0 );
receivedFrameSize = dmaFlags & kGEMRxDescFrameSize_Mask;
rxPktStatus = OSReadLittleInt32( &fRxDescriptorRing[ i ].flags, 0 );
ELG( READ_REGISTER( RxCompletion ), receivedFrameSize, 'Rx P', "UniNEnet::receivePackets - rx'd packet" );
vlanPacket = FALSE;
cksumOffset = kRxHwCksumStartOffset;
maxFrameSize = kIOEthernetMaxPacketSize;
pb = (UInt8*)mbuf_data( fRxMbuf[ i ] );
if ( (pb[ 12 ] == 0x81) && (pb[ 13 ] == 0x00) ) {
vlanPacket = TRUE;
maxFrameSize += 4;
cksumOffset -= 4;
ELG( 0, receivedFrameSize, 'vlan', "UniNEnet::receivePackets - rx'd VLAN packet" );
}
if ( receivedFrameSize > maxFrameSize
|| receivedFrameSize < (kIOEthernetMinPacketSize - kIOEthernetCRCSize)
|| rxPktStatus & kGEMRxDescFlags_BadCRC )
{
reusePkt = true;
NETWORK_STAT_ADD( inputErrors );
if ( receivedFrameSize < (kIOEthernetMinPacketSize - kIOEthernetCRCSize) )
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 )
{ ELG( i, receivedFrameSize, 'RxDb', "receivePackets - got a debugger packet" );
packetToDebugger( fRxMbuf[ i ], receivedFrameSize );
}
}
packet = 0;
if ( reusePkt == false )
{
packet = replaceOrCopyPacket( &fRxMbuf[i], receivedFrameSize, &replaced );
reusePkt = true;
if ( packet && replaced )
{
genRxDescriptor( i );
reusePkt = false;
}
if ( packet == 0 )
{ NETWORK_STAT_ADD( inputErrors );
if ( packetsQueued )
{ packetsQueued = 0;
networkInterface->flushInputQueue();
}
IOSleep( 1 ); loopLimit = fRxRingElements; ELG( READ_REGISTER( RxFIFOPacketCounter ), READ_REGISTER( RxMACStatus ), 'Pkt-', "UniNEnet::receivePackets - no mBuf available." );
}
}
if ( reusePkt == true )
{
fRxDescriptorRing[i].flags = 0;
fRxDescriptorRing[i].frameDataSize = OSSwapHostToLittleConstInt16( NETWORK_BUFSIZE | kGEMRxDescFrameSize_Own );
}
if ( (i & 3) == 3 ) {
WRITE_REGISTER( RxKick, (i - 3) );
}
last = i;
i = (i + 1) & (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) && !fIsPromiscuous )
setChecksumResult( packet,
kChecksumFamilyTCPIP,
kChecksumTCPSum16,
0, checksum, cksumOffset ); ELG( packet, receivedFrameSize << 16 | last, 'RxP+', "UniNEnet::receivePackets - packet up." );
networkInterface->inputPacket( packet, receivedFrameSize, true );
NETWORK_STAT_ADD( inputPackets );
packetsQueued = true;
}
}
if ( last != (UInt32)-1 )
rxCommandHead = i;
return packetsQueued;
}
bool UniNEnet::transmitInterruptOccurred()
{
ELG( txCommandHead, fTxCompletion, ' Tx+', "UniNEnet::transmitInterruptOccurred" );
fTxIntCnt = 0;
if( txCommandHead == fTxCompletion )
return false;
while ( txCommandHead != fTxCompletion )
{
KERNEL_DEBUG( DBG_UniN_TXCOMPLETE | DBG_FUNC_NONE, fTxMbuf[ txCommandHead ], 0, 0, 0, 0 );
if ( fTxMbuf[ txCommandHead ] )
{
if ( fTxMbuf[ txCommandHead ] != txDebuggerPkt )
{
freePacket( fTxMbuf[ txCommandHead ], kDelayFree );
}
else
{
ELG( txCommandHead, fTxMbuf[ txCommandHead ], 'TxDb', "UniNEnet::transmitInterruptOccurred - recycling txDebuggerPkt" );
txDebuggerPktInUse = false;
}
fTxMbuf[ txCommandHead ] = 0;
}
txCommandHead = (txCommandHead + 1) & (fTxRingElements - 1);
}
fpNetStats->outputPackets += releaseFreePackets();
return true;
}
void UniNEnet::debugTransmitInterruptOccurred()
{
UInt32 i;
debugTxPoll = true;
i = READ_REGISTER( TxCompletion );
while ( i != txCommandHead )
{
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 )
{
addr64_t physAddr;
physAddr = mbuf_data_to_physical( mbuf_data( fRxMbuf[i] ) );
OSWriteLittleInt64( &fRxDescriptorRing[i].bufferAddr, 0, physAddr );
fRxDescriptorRing[i].frameDataSize = OSSwapHostToLittleConstInt16( NETWORK_BUFSIZE | kGEMRxDescFrameSize_Own );
fRxDescriptorRing[ i ].flags = 0;
return true;
}
void UniNEnet::monitorLinkStatus( bool firstPoll )
{
UInt16 phyStatus;
UInt16 linkStatus;
UInt16 linkMode;
UInt16 lpAbility, expansion;
UInt16 phyStatusChange;
bool fullDuplex = false;
bool clockWasOff = false;
UInt32 linkSpeed = 0;
IOMediumType mediumType = kIOMediumEthernetNone;
IONetworkMedium *medium;
bool rc = true;
ELG( phyId, firstPoll, ' MLS', "monitorLinkStatus" );
if ( firstPoll )
{
fPHYStatus = 0;
fLinkStatus = kLinkStatusUnknown;
}
if ( fBuiltin && fCellClockEnabled == false )
{
enableCellClock();
clockWasOff = true;
}
if ( fBuiltin )
{
rc = miiReadWord( &phyStatus, MII_STATUS );
}
else
{
phyStatus = READ_REGISTER( PCSMIIStatus ) & 0x0000FFFF; IODelay( 3 );
if ( firstPoll )
IOSleep( 5000 ); phyStatus = READ_REGISTER( PCSMIIStatus ) & 0x0000FFFF;
}
if ( clockWasOff ) disableCellClock();
if ( rc == false || phyStatus == 0xFFFF ) return;
if ( fLoopback ) phyStatus |= MII_STATUS_LINK_STATUS;
phyStatusChange = (fPHYStatus ^ phyStatus)
& (MII_STATUS_LINK_STATUS | MII_STATUS_NEGOTIATION_COMPLETE);
if ( fMediumType != kIOMediumEthernetAuto )
phyStatusChange &= ~MII_STATUS_NEGOTIATION_COMPLETE;
if ( firstPoll || phyStatusChange )
ELG( fPHYStatus, phyStatusChange, 'LChg', "UniNEnet::monitorLinkStatus - initing or link status changed." );
else return;
if ( firstPoll && fBuiltin )
{
miiReadWord( &phyStatus, MII_STATUS );
if ( fLoopback ) phyStatus |= MII_STATUS_LINK_STATUS;
}
if ( (phyStatus & MII_STATUS_LINK_STATUS)
&& (firstPoll || (phyStatus & MII_STATUS_NEGOTIATION_COMPLETE)
|| (fAutoNegotiate == false)) )
{
if ( !fCellClockEnabled )
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 );
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)
|| ((phyType & MII_BCM5221_MASK) == MII_BCM5221_ID)
|| ((phyType & MII_BCM5241_MASK) == MII_BCM5241_ID) )
{
miiReadWord( &linkStatus, MII_BCM5201_AUXSTATUS );
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) || ((phyType & MII_BCM5400_MASK) == MII_BCM54K2_ID) || ((phyType & MII_BCM5400_MASK) == MII_BCM5462_ID) ) {
miiReadWord( &linkStatus, MII_BCM5400_AUXSTATUS );
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 = kIOMediumEthernet1000BaseT;
}
}
else if ( ((phyType & MII_MARVELL_MASK) == MII_MARVELL_ID) || ((phyType & MII_MARVELL_MASK) == MII_MARVELL_ID_1) || ((phyType & MII_MARVELL_MASK) == MII_MARVELL_ID_2) ) {
miiReadWord( &linkStatus, MII_MARVELL_PHY_SPECIFIC_STATUS );
if ( !(linkStatus & MII_MARVELL_PHY_SPECIFIC_STATUS_RESOLVED) )
{
linkSpeed = 0;
fXIFConfiguration &= ~kXIFConfiguration_GMIIMODE;
}
else if ( linkStatus & MII_MARVELL_PHY_SPECIFIC_STATUS_1000 )
{
linkSpeed = 1000;
mediumType = kIOMediumEthernet1000BaseT;
fXIFConfiguration |= kXIFConfiguration_GMIIMODE;
}
else if ( linkStatus & MII_MARVELL_PHY_SPECIFIC_STATUS_100 )
{
linkSpeed = 100;
mediumType = kIOMediumEthernet100BaseTX;
fXIFConfiguration &= ~kXIFConfiguration_GMIIMODE;
}
else
{
linkSpeed = 10;
mediumType = kIOMediumEthernet10BaseT;
fXIFConfiguration &= ~kXIFConfiguration_GMIIMODE;
}
WRITE_REGISTER( XIFConfiguration, fXIFConfiguration );
if ( linkStatus & MII_MARVELL_PHY_SPECIFIC_STATUS_FULL_DUPLEX )
fullDuplex = true;
else fullDuplex = false;
}
setDuplexMode( fullDuplex );
fMACControlConfiguration = 0;
if ( fBuiltin )
miiReadWord( &lpAbility, MII_LINKPARTNER );
else
lpAbility = READ_REGISTER( PCSMIILinkPartnerAbility ) & 0x0000FFFF;
if ( (lpAbility & MII_LPAR_PAUSE) && isFullDuplex )
{
fMACControlConfiguration = kMACControlConfiguration_Send_Pause_Enable
| kMACControlConfiguration_Receive_Pause_Enable;
mediumType |= kIOMediumOptionFlowControl;
}
WRITE_REGISTER( MACControlConfiguration, fMACControlConfiguration );
if ( fReady == true )
startChip();
if ( linkSpeed != 0 )
{
mediumType |= (fullDuplex == true)
? kIOMediumOptionFullDuplex
: kIOMediumOptionHalfDuplex;
}
medium = IONetworkMedium::getMediumWithType( fMediumDict, mediumType );
setLinkStatus( kIONetworkLinkActive | kIONetworkLinkValid,
medium,
linkSpeed * 1000000 );
ELG( kIONetworkLinkActive | kIONetworkLinkValid, linkSpeed * 1000000, 'SLS+', "UniNEnet::monitorLinkStatus - setLinkStatus." );
miiReadWord( &expansion, MII_EXPANSION );
IOLog( "UniNEnet::monitorLinkStatus - Link is up at %ld Mbps - %s Duplex (PHY regs 5,6:0x%04x,0x%04x)\n",
linkSpeed, fullDuplex ? "Full" : "Half", lpAbility, expansion );
fLinkStatus = kLinkStatusUp;
}
else
{
if ( fCellClockEnabled
&& ((fLinkStatus == kLinkStatusUp) || (fLinkStatus == kLinkStatusUnknown)) )
{
stopChip();
medium = IONetworkMedium::getMediumWithType( fMediumDict, mediumType );
setLinkStatus( kIONetworkLinkValid, medium, 0 ); ELG( kIONetworkLinkValid, medium, 'SLS-', "UniNEnet::monitorLinkStatus - setLinkStatus." );
transmitQueue->flush();
if ( fLinkStatus != kLinkStatusUnknown )
IOLog( "UniNEnet::monitorLinkStatus - Link is down.\n" );
fTxIntCnt = 0;
if ( txCommandHead != txCommandTail )
{
initTxRing();
txCommandHead = READ_REGISTER( TxCompletion );
txCommandTail = txCommandHead;
}
}
fLinkStatus = kLinkStatusDown;
}
fPHYStatus = 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;
}
IOReturn UniNEnet::setHardwareAddress( const IOEthernetAddress *ea )
{
UInt16 *p16;
unsigned int i;
bool clkEnable = fCellClockEnabled;
myAddress = *ea;
if ( !clkEnable )
enableCellClock();
p16 = (UInt16*)myAddress.bytes;
for ( i = 0; i < sizeof( IOEthernetAddress ) / 2; i++ )
{
WRITE_REGISTER( MACAddress[ i ], p16[ 2 - i ] );
WRITE_REGISTER( MACAddress[ i + 3 ], p16[ 2 - i ] ); }
if ( !clkEnable )
disableCellClock();
ELG( p16[0], p16[1] << 16 | p16[2], 'SetA', "UniNEnet::setHardwareAddress" );
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;
return;
}
void UniNEnet::resetHashTableMask()
{
bzero( hashTableUseCount, sizeof( hashTableUseCount ) );
bzero( hashTableMask, sizeof( hashTableMask ) );
return;
}
void UniNEnet::updateHashTableMask()
{
UInt32 i, x;
ELG( this, fRxMACConfiguration, 'updH', "updateHashTableMask" );
WRITE_REGISTER( RxMACConfiguration,
fRxMACConfiguration & ~kRxMACConfiguration_Rx_Mac_Enable );
for ( i = 0; i <= 3; ++i )
{
x = READ_REGISTER( RxMACConfiguration );
if ( (x & (kRxMACConfiguration_Rx_Mac_Enable | kRxMACConfiguration_Hash_Filter_Enable) ) == 0 )
break;
IOSleep( 1 );
}
for ( i = 0; i < 16; i++ )
WRITE_REGISTER( HashTable[ i ], hashTableMask[ 15 - i ] );
fRxMACConfiguration |= kRxMACConfiguration_Hash_Filter_Enable;
WRITE_REGISTER( RxMACConfiguration, fRxMACConfiguration );
return;
}