📄 simp911x.c
字号:
privateData->SoftwareInterruptSignal=FALSE;
Lan_SetBitsDW(INT_EN,INT_EN_SW_INT_EN_);
do {
udelay(10);
dwTimeOut--;
} while((dwTimeOut)&&(!(privateData->SoftwareInterruptSignal)));
if(!(privateData->SoftwareInterruptSignal)) {
SMSC_WARNING("ISR failed signal test");
//disable IRQ anyway
Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
}
}
spin_lock(&dev->xmit_lock);
netif_stop_queue(privateData->dev);
spin_unlock(&dev->xmit_lock);
//at this point all Rx and Tx activity is stopped
privateData->stats.rx_dropped+=Lan_GetRegDW(RX_DROP);
Tx_UpdateTxCounters(privateData);
#ifndef LINUX_2_6_OR_NEWER
MOD_DEC_USE_COUNT;
#endif
free_irq(irq[privateData->dwInstanceIndex],privateData);
release_mem_region(privateData->dwLanBase,LAN_REGISTER_EXTENT);
{//preserve important items, clear the rest
DWORD dwLanBase=privateData->dwLanBase;
DWORD dwIdRev=privateData->dwIdRev;
DWORD dwInstanceIndex=privateData->dwInstanceIndex;
struct net_device *tempDev=privateData->dev;
struct net_device_stats tempStats;
memcpy(&tempStats,&(privateData->stats),sizeof(struct net_device_stats));
memset(privateData,0,sizeof(PRIVATE_DATA));
memcpy(&(privateData->stats),&tempStats,sizeof(struct net_device_stats));
privateData->dwLanBase=dwLanBase;
privateData->dwInstanceIndex=dwInstanceIndex;
privateData->dev=tempDev;
privateData->dwIdRev=dwIdRev;
}
DONE:
SMSC_TRACE("<--Simp911x_stop, result=%d",result);
return result;
}
//entry point for transmitting a packet
int Simp911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int result=0;
PPRIVATE_DATA privateData=NULL;
if(skb==NULL) {
SMSC_WARNING("Simp911x_hard_start_xmit(skb==NULL)");
result=-EFAULT;
goto DONE;
}
if(dev==NULL) {
SMSC_WARNING("Simp911x_hard_start_xmit(dev==NULL)");
result=-EFAULT;
goto DONE;
}
if(dev->priv==NULL) {
SMSC_WARNING("Simp911x_hard_start_xmit(dev->priv==NULL)");
result=-EFAULT;
goto DONE;
}
privateData=(PPRIVATE_DATA)(dev->priv);
Tx_SendSkb(privateData,skb);
DONE:
return result;
}
//entry point for getting status counters
struct net_device_stats * Simp911x_get_stats(struct net_device *dev)
{
PPRIVATE_DATA privateData=NULL;
if(dev==NULL) {
SMSC_WARNING("Simp911x_get_stats(dev==NULL)");
return NULL;
}
if(dev->priv==NULL) {
SMSC_WARNING("Simp911x_get_stats(dev->priv==NULL)");
return NULL;
}
privateData=(PPRIVATE_DATA)(dev->priv);
return &(privateData->stats);
}
//entry point for setting addressing modes
void Simp911x_set_multicast_list(struct net_device *dev)
{
SMSC_ASSERT(dev!=NULL);
Rx_SetMulticastList(dev);
}
//primary entry point for ISR
irqreturn_t Simp911x_ISR(int Irq, void *dev_id, struct pt_regs *regs)
{
DWORD dwIntCfg=0;
DWORD dwIntSts=0;
PPRIVATE_DATA privateData=(PPRIVATE_DATA)dev_id;
BOOLEAN serviced=FALSE;
if(privateData==NULL) {
SMSC_WARNING("Simp911x_ISR(privateData==NULL)");
goto DONE;
}
if(privateData->dwLanBase==0) {
SMSC_WARNING("Simp911x_ISR(dwLanBase==0)");
goto DONE;
}
dwIntCfg=Lan_GetRegDW(INT_CFG);
if((dwIntCfg&0x00001100)!=0x00001100) {
SMSC_TRACE("In ISR, not my interrupt, dwIntCfg=0x%08lX",
dwIntCfg);
goto DONE;
}
{
DWORD reservedBits=0x00FFCEEEUL;
if(dwIntCfg&reservedBits) {
SMSC_WARNING("In ISR, reserved bits are high.");
//this could mean surprise removal
goto DONE;
}
}
dwIntSts=Lan_GetRegDW(INT_STS);
if(dwIntSts&INT_STS_SW_INT_) {
Lan_ClrBitsDW(INT_EN,INT_EN_SW_INT_EN_);
Lan_SetRegDW(INT_STS,INT_STS_SW_INT_);
privateData->SoftwareInterruptSignal=TRUE;
serviced=TRUE;
if(privateData->RequestIrqDisable) {
Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
dwIntSts=0;//prevent any pending interrupts from being handled.
}
}
if(Tx_HandleInterrupt(privateData,dwIntSts)) {
serviced=TRUE;
}
if(Rx_HandleInterrupt(privateData,dwIntSts)) {
serviced=TRUE;
}
if(!serviced) {
SMSC_WARNING("unserviced interrupt dwIntCfg=0x%08lX,dwIntSts=0x%08lX,INT_EN=0x%08lX",
dwIntCfg,dwIntSts,Lan_GetRegDW(INT_EN));
}
DONE:
return IRQ_RETVAL(serviced);
}
#ifdef USE_PHY_WORK_AROUND
BOOLEAN Phy_Reset(PPRIVATE_DATA privateData)
{
BOOLEAN result=FALSE;
WORD wTemp=0;
DWORD dwLoopCount=100000;
SMSC_TRACE("Performing PHY BCR Reset");
Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_);
do {
udelay(10);
wTemp=Phy_GetRegW(privateData,PHY_BCR);
dwLoopCount--;
} while((dwLoopCount>0)&&(wTemp&PHY_BCR_RESET_));
if(wTemp&PHY_BCR_RESET_) {
SMSC_WARNING("Phy Reset failed to complete.");
goto DONE;
}
//extra delay required because the phy may not be completed with its reset
// when PHY_BCR_RESET_ is cleared.
// They say 256 uS is enough delay but I'm using 500 here to be safe
udelay(500);
result=TRUE;
DONE:
return result;
}
DWORD Phy_LBT_GetTxStatus(PPRIVATE_DATA privateData)
{
DWORD result=Lan_GetRegDW(TX_FIFO_INF);
result&=TX_FIFO_INF_TSUSED_;
if(result!=0x00000000UL) {
result=Lan_GetRegDW(TX_STATUS_FIFO);
} else {
result=0;
}
return result;
}
DWORD Phy_LBT_GetRxStatus(PPRIVATE_DATA privateData)
{
DWORD result=Lan_GetRegDW(RX_FIFO_INF);
if(result&0x00FF0000UL) {
//Rx status is available, read it
result=Lan_GetRegDW(RX_STATUS_FIFO);
} else {
result=0;
}
return result;
}
BOOLEAN Phy_CheckLoopBackPacket(PPRIVATE_DATA privateData)
{
BOOLEAN result=FALSE;
DWORD tryCount=0;
DWORD dwLoopCount=0;
for(tryCount=0;tryCount<10;tryCount++)
{
DWORD dwTxCmdA=0;
DWORD dwTxCmdB=0;
DWORD dwStatus=0;
DWORD dwPacketLength=0;
//zero-out Rx Packet memory
memset(privateData->LoopBackRxPacket,0,MIN_PACKET_SIZE);
//write Tx Packet to 118
dwTxCmdA=
((((DWORD)(privateData->LoopBackTxPacket))&0x03UL)<<16) | //DWORD alignment adjustment
TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ |
((DWORD)(MIN_PACKET_SIZE));
dwTxCmdB=
(((DWORD)(MIN_PACKET_SIZE))<<16) |
((DWORD)(MIN_PACKET_SIZE));
Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA);
Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB);
Tx_WriteFifo(
privateData->dwLanBase,
(DWORD *)(((DWORD)(privateData->LoopBackTxPacket))&0xFFFFFFFCUL),
(((DWORD)(MIN_PACKET_SIZE))+3+
(((DWORD)(privateData->LoopBackTxPacket))&0x03UL))>>2);
//wait till transmit is done
dwLoopCount=60;
while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetTxStatus(privateData))==0)) {
udelay(5);
dwLoopCount--;
}
if(dwStatus==0) {
SMSC_WARNING("Failed to Transmit during Loop Back Test");
continue;
}
if(dwStatus&0x00008000UL) {
SMSC_WARNING("Transmit encountered errors during Loop Back Test");
continue;
}
//wait till receive is done
dwLoopCount=60;
while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetRxStatus(privateData))==0))
{
udelay(5);
dwLoopCount--;
}
if(dwStatus==0) {
SMSC_WARNING("Failed to Receive during Loop Back Test");
continue;
}
if(dwStatus&RX_STS_ES_)
{
SMSC_WARNING("Receive encountered errors during Loop Back Test");
continue;
}
dwPacketLength=((dwStatus&0x3FFF0000UL)>>16);
Rx_ReadFifo(
privateData->dwLanBase,
((DWORD *)(privateData->LoopBackRxPacket)),
(dwPacketLength+3+(((DWORD)(privateData->LoopBackRxPacket))&0x03UL))>>2);
if(dwPacketLength!=(MIN_PACKET_SIZE+4)) {
SMSC_WARNING("Unexpected packet size during loop back test, size=%ld, will retry",dwPacketLength);
} else {
DWORD byteIndex=0;
BOOLEAN foundMissMatch=FALSE;
for(byteIndex=0;byteIndex<MIN_PACKET_SIZE;byteIndex++) {
if(privateData->LoopBackTxPacket[byteIndex]!=privateData->LoopBackRxPacket[byteIndex])
{
foundMissMatch=TRUE;
break;
}
}
if(!foundMissMatch) {
SMSC_TRACE("Successfully Verified Loop Back Packet");
result=TRUE;
goto DONE;
} else {
SMSC_WARNING("Data miss match during loop back test, will retry.");
}
}
}
DONE:
return result;
}
BOOLEAN Phy_LoopBackTest(PPRIVATE_DATA privateData)
{
BOOLEAN result=FALSE;
DWORD byteIndex=0;
DWORD tryCount=0;
//Initialize Tx Packet
for(byteIndex=0;byteIndex<6;byteIndex++) {
//use broadcast destination address
privateData->LoopBackTxPacket[byteIndex]=(BYTE)0xFF;
}
for(byteIndex=6;byteIndex<12;byteIndex++) {
//use incrementing source address
privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
}
//Set length type field
privateData->LoopBackTxPacket[12]=0x00;
privateData->LoopBackTxPacket[13]=0x00;
for(byteIndex=14;byteIndex<MIN_PACKET_SIZE;byteIndex++)
{
privateData->LoopBackTxPacket[byteIndex]=(BYTE)byteIndex;
}
{
DWORD dwRegVal=Lan_GetRegDW(HW_CFG);
dwRegVal&=HW_CFG_TX_FIF_SZ_;
dwRegVal|=HW_CFG_SF_;
Lan_SetRegDW(HW_CFG,dwRegVal);
}
Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_);
Lan_SetRegDW(RX_CFG,(((DWORD)(privateData->LoopBackRxPacket))&0x03)<<8);
//Set Phy to 10/FD, no ANEG,
Phy_SetRegW(privateData,PHY_BCR,0x0100);
//enable MAC Tx/Rx, FD
Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
//set Phy to loopback mode
Phy_SetRegW(privateData,PHY_BCR,0x4100);
for(tryCount=0;tryCount<10;tryCount++) {
if(Phy_CheckLoopBackPacket(privateData))
{
result=TRUE;
goto DONE;
}
privateData->dwResetCount++;
//disable MAC rx
Mac_SetRegDW(privateData,MAC_CR,0UL);
Phy_Reset(privateData);
//Set Phy to 10/FD, no ANEG, and Loopbackmode
Phy_SetRegW(privateData,PHY_BCR,0x4100);
//enable MAC Tx/Rx, FD
Mac_SetRegDW(privateData,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
}
DONE:
//disable MAC
Mac_SetRegDW(privateData,MAC_CR,0UL);
//Cancel Phy loopback mode
Phy_SetRegW(privateData,PHY_BCR,0U);
Lan_SetRegDW(TX_CFG,0UL);
Lan_SetRegDW(RX_CFG,0UL);
return result;
}
#endif //USE_PHY_WORK_AROUND
//Sets the link mode
void Phy_SetLink(PPRIVATE_DATA privateData)
{
WORD wTemp;
//Because this is part of the single threaded initialization
// path there is no need to acquire the MacPhyAccessLock
wTemp=Phy_GetRegW(pri
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -