📄 eth_smsc911x.c
字号:
TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ | ((DWORD)(bufptr)); dwTxCmdB= (((DWORD)(bufptr))<<16) | ((DWORD)(bufptr)); Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdA); Lan_SetRegDW(TX_DATA_FIFO,dwTxCmdB); Platform_WriteFifo(privateData->dwLanBase, (DWORD *)(((DWORD)(EthTxBuffer))&0xFFFFFFFCUL), (((DWORD)(bufptr))+3+ (((DWORD)(EthTxBuffer))&0x03UL))>>2); dwLoopCount=bufptr; while((dwLoopCount>0) && ((dwStatus=Phy_LBT_GetTxStatus(privateData))==0)) { dwLoopCount--; } if(dwStatus==0) { SMSC_WARNING("Failed to Transmit during Packet Test"); return -1; } if(dwStatus&0x00008000UL) { SMSC_WARNING("Transmit encountered errors during Packet Test"); return -1; } return 0;}/************************************************************************* * *************************************************************************/static int smsc911x_eth_rx_init(void){ DWORD tmp; privateData->dwRxOffCount=1; Lan_SetRegDW(RX_CFG,0x0); tmp = Lan_GetRegDW(FIFO_INT) & 0xffff00ff; Lan_SetRegDW(FIFO_INT, tmp | (0x18 << 8)); Rx_ReceiverOn(privateData); return 0;}/************************************************************************* * *************************************************************************/static void Rx_FastForward(PPRIVATE_DATA privateData,DWORD dwDwordCount){ privateData->RxFastForwardCount++; if((dwDwordCount>=4) && ( (((privateData->dwIdRev&0x0000FFFFUL)==0x00000000UL) && (privateData->dwFpgaRev>=0x36)) || ((privateData->dwIdRev&0x0000FFFFUL)!=0UL) ) ) { DWORD dwTimeOut=500; Lan_SetRegDW(RX_DP_CTRL,(dwDwordCount|RX_DP_CTRL_FFWD_BUSY_)); while((dwTimeOut)&&(Lan_GetRegDW(RX_DP_CTRL)& RX_DP_CTRL_FFWD_BUSY_)) { udelay(1); dwTimeOut--; } if(dwTimeOut==0) { SMSC_WARNING("timed out waiting for RX FFWD to finish, RX_DP_CTRL=0x%08lX", Lan_GetRegDW(RX_DP_CTRL)); } } else { while(dwDwordCount) { DWORD dwTemp=Lan_GetRegDW(RX_DATA_FIFO); dwTemp=dwTemp; dwDwordCount--; } }}/************************************************************************* * *************************************************************************/static DWORD Rx_PopRxStatus(PPRIVATE_DATA privateData){ DWORD result=Lan_GetRegDW(RX_FIFO_INF); if((privateData->RxCongested==FALSE)|| ((privateData->RxCongested==TRUE)&&((result&0x00FF0000UL)==0UL))) { if(result&0x00FF0000UL) { DWORD dwIntSts=Lan_GetRegDW(INT_STS); if(IS_REV_A(privateData)) { if(dwIntSts&INT_STS_RDFL_) { SMSC_WARNING("%s(): INT_STS_RDFL_\n",__FUNCTION__); Lan_SetRegDW(INT_STS,INT_STS_RDFL_); } } else { if(dwIntSts&INT_STS_RDFO_) { SMSC_WARNING("%s(): INT_STS_RDFD_\n",__FUNCTION__); Lan_SetRegDW(INT_STS,INT_STS_RDFO_); } } if(dwIntSts&INT_STS_RXE_){ SMSC_WARNING("%s(): INT_STS_RXE_\n",__FUNCTION__); Lan_SetRegDW(INT_STS, INT_STS_RXE_); } if(dwIntSts&INT_STS_TXE_){ SMSC_WARNING("%s(): INT_STS_TXE_\n",__FUNCTION__); Lan_SetRegDW(INT_STS, INT_STS_TXE_); } if(dwIntSts&0xff8){ SMSC_WARNING("%s(): INT_STS: %p\n", __FUNCTION__, dwIntSts); Lan_SetRegDW(INT_STS, 0xff8); } if((privateData->RxFlowControlActive==FALSE)|| ((privateData->RxFlowControlActive==TRUE)&& (privateData->RxFlowBurstActive==TRUE))) { /* Rx status is available, read it */ result=Lan_GetRegDW(RX_STATUS_FIFO); privateData->RxStatusDWReadCount++; privateData->LastRxStatus3= privateData->LastRxStatus2; privateData->LastRxStatus2= privateData->LastRxStatus1; privateData->LastRxStatus1=result; if(privateData->RxOverrun) { DWORD dwPacketLength=((result&0x3FFF0000UL)>>16); DWORD dwByteCount=((dwPacketLength+2+3)&0xFFFFFFFCUL); if((privateData->RxUnloadProgress+dwByteCount)>= ((privateData->RxMaxDataFifoSize)-16)) { /* This is the packet that crosses the corruption point */ /* so just ignore it and complete the overrun processing. */ result=0; goto FINISH_OVERRUN_PROCESSING; } privateData->RxUnloadProgress+=dwByteCount; privateData->RxUnloadPacketProgress++; } privateData->RxFlowCurrentThroughput+= ((((result&0x3FFF0000UL)>>16)-4UL)); privateData->RxFlowCurrentPacketCount++; privateData->RxFlowCurrentWorkLoad+= ((((result&0x3FFF0000UL)>>16)-4UL)+privateData->RxFlowParameters.PacketCost); if(privateData->RxFlowControlActive) { privateData->RxFlowBurstWorkLoad+= ((((result&0x3FFF0000UL)>>16)-4UL)+privateData->RxFlowParameters.PacketCost); if(privateData->RxFlowBurstWorkLoad>= privateData->RxFlowBurstMaxWorkLoad) { privateData->RxFlowBurstActive=FALSE; } } } else { result=0; } } else { if(privateData->RxOverrun) { DWORD timeOut; DWORD temp;FINISH_OVERRUN_PROCESSING: SMSC_WARNING("rx overrun\n"); temp=0; { timeOut=2000; while((timeOut>0)&&(!(Lan_GetRegDW(INT_STS)&(INT_STS_RXSTOP_INT_)))) { udelay(1); timeOut--; } if(timeOut==0) { SMSC_WARNING("Timed out waiting for Rx to Stop\n"); } Lan_SetRegDW(INT_STS,INT_STS_RXSTOP_INT_); } temp=Lan_GetRegDW(RX_CFG); Lan_SetRegDW(RX_CFG,(temp&0x3FFFFFFFUL)); timeOut=10000000; Lan_SetBitsDW(RX_CFG,RX_CFG_RX_DUMP_); while((timeOut>0)&&(Lan_GetRegDW(RX_CFG)&(RX_CFG_RX_DUMP_))) { udelay(1); timeOut--; } if(timeOut==0) { SMSC_WARNING("Timed out waiting for Rx Dump to complete\n"); } Lan_SetRegDW(RX_CFG,temp); privateData->RxDumpCount++; Lan_SetRegDW(INT_STS,INT_STS_RDFL_); Rx_ReceiverOn(privateData); privateData->RxOverrun=FALSE; } result=0; privateData->LastReasonForReleasingCPU=1;/* Status FIFO Empty */ } } else { /* disable and reenable the INT_EN */ /* This will allow the deassertion interval to begin */ DWORD temp=Lan_GetRegDW(INT_EN); Lan_SetRegDW(INT_EN,0); Lan_SetRegDW(INT_EN,temp); result=0; privateData->LastReasonForReleasingCPU=2;/* High Congestion */ } return result;}/************************************************************************* * *************************************************************************/static void Rx_CountErrors(PPRIVATE_DATA privateData,DWORD dwRxStatus) {}/************************************************************************* * *************************************************************************/int smsc911x_eth_recv(const unsigned char *mac, eth_frame **ethfr, void **pbuf, unsigned int *pbuflen, int *timeout){ DWORD dwRxStatus=0; PPLATFORM_DATA platformData=NULL; privateData->RxCongested=FALSE; platformData=&(privateData->PlatformData); Lan_SetRegDW(RX_CFG,0x0); while(1){ if((dwRxStatus=Rx_PopRxStatus(privateData))==0){ timeout--; if(timeout<0){ SMSC_WARNING("recv timeout\n"); return -1; } udelay(1); continue; } DWORD dwPacketLength=((dwRxStatus&0x3FFF0000UL)>>16); Rx_CountErrors(privateData,dwRxStatus); if((dwRxStatus&RX_STS_ES_)==0) { Platform_ReadFifo(privateData->dwLanBase, ((DWORD *)EthRxBuffer), (dwPacketLength+3)>>2); *ethfr = (eth_frame *)(EthRxBuffer); *pbuf = (void *)(EthRxBuffer + ETH_FRAME_LEN); *pbuflen = (dwPacketLength - 4) - ETH_FRAME_LEN; return 0; } /* if we get here then the packet is to be read */ /* out of the fifo and discarded */ dwPacketLength+=(2+3); dwPacketLength>>=2; Rx_FastForward(privateData,dwPacketLength); } return -1;}/************************************************************************* * *************************************************************************/int smsc911x_eth_rxbuf_free(const int idx){ return 0;}/************************************************************************* * *************************************************************************/static BOOLEAN Lan_Initialize(PPRIVATE_DATA privateData, DWORD dwIntCfg, DWORD dwTxFifSz, DWORD dwAfcCfg){ BOOLEAN result=FALSE; DWORD dwTimeOut=0; DWORD dwTemp=0; DWORD dwResetCount=3; SMSC_TRACE("-->Lan_Initialize"); /* Reset the LAN911x */ dwResetCount=1; while(dwResetCount>0) { Lan_SetRegDW(HW_CFG,HW_CFG_SRST_); dwTimeOut=1000000; do { dwTemp=Lan_GetRegDW(HW_CFG); dwTimeOut--; } while((dwTimeOut>0)&&(dwTemp&HW_CFG_SRST_)); if(dwTemp&HW_CFG_SRST_) { SMSC_WARNING(" Failed to complete reset."); goto DONE; } dwResetCount--; } SMSC_ASSERT(dwTxFifSz>=0x00020000UL); SMSC_ASSERT(dwTxFifSz<=0x000E0000UL); SMSC_ASSERT((dwTxFifSz&(~HW_CFG_TX_FIF_SZ_))==0); dwTxFifSz = 0x00040000UL; Lan_SetRegDW(HW_CFG,dwTxFifSz); privateData->RxMaxDataFifoSize=0; switch(dwTxFifSz>>16) { case 2:privateData->RxMaxDataFifoSize=13440;break; case 3:privateData->RxMaxDataFifoSize=12480;break; case 4:privateData->RxMaxDataFifoSize=11520;break; case 5:privateData->RxMaxDataFifoSize=10560;break; case 6:privateData->RxMaxDataFifoSize=9600;break; case 7:privateData->RxMaxDataFifoSize=8640;break; case 8:privateData->RxMaxDataFifoSize=7680;break; case 9:privateData->RxMaxDataFifoSize=6720;break; case 10:privateData->RxMaxDataFifoSize=5760;break; case 11:privateData->RxMaxDataFifoSize=4800;break; case 12:privateData->RxMaxDataFifoSize=3840;break; case 13:privateData->RxMaxDataFifoSize=2880;break; case 14:privateData->RxMaxDataFifoSize=1920;break; default:SMSC_ASSERT(FALSE);break; } if(dwAfcCfg==0xFFFFFFFF) { switch(dwTxFifSz) { /* AFC_HI is about ((Rx Data Fifo Size)*2/3)/64 */ /* AFC_LO is AFC_HI/2 */ /* BACK_DUR is about 5uS*(AFC_LO) rounded down */ case 0x00020000UL:/* 13440 Rx Data Fifo Size */ dwAfcCfg=0x008C46AF;break; case 0x00030000UL:/* 12480 Rx Data Fifo Size */ dwAfcCfg=0x0082419F;break; case 0x00040000UL:/* 11520 Rx Data Fifo Size */ dwAfcCfg=0x00783C9F;break; case 0x00050000UL:/* 10560 Rx Data Fifo Size */ dwAfcCfg=0x006E374F;break; case 0x00060000UL:/* 9600 Rx Data Fifo Size */ dwAfcCfg=0x0064328F;break; case 0x00070000UL:/* 8640 Rx Data Fifo Size */ dwAfcCfg=0x005A2D7F;break; case 0x00080000UL:/* 7680 Rx Data Fifo Size */ dwAfcCfg=0x0050287F;break; case 0x00090000UL:/* 6720 Rx Data Fifo Size */ dwAfcCfg=0x0046236F;break; case 0x000A0000UL:/* 5760 Rx Data Fifo Size */ dwAfcCfg=0x003C1E6F;break; case 0x000B0000UL:/* 4800 Rx Data Fifo Size */ dwAfcCfg=0x0032195F;break; /* AFC_HI is ~1520 bytes less than RX Data Fifo Size */ /* AFC_LO is AFC_HI/2 */ /* BACK_DUR is about 5uS*(AFC_LO) rounded down */ case 0x000C0000UL:/* 3840 Rx Data Fifo Size */ dwAfcCfg=0x0024124F;break; case 0x000D0000UL:/* 2880 Rx Data Fifo Size */ dwAfcCfg=0x0015073F;break; case 0x000E0000UL:/* 1920 Rx Data Fifo Size */ dwAfcCfg=0x0006032F;break; default:SMSC_ASSERT(FALSE);break; } } Lan_SetRegDW(AFC_CFG,(dwAfcCfg&0xFFFFFFF0UL)); /* make sure EEPROM has finished loading before setting GPIO_CFG */ dwTimeOut=1000; while((dwTimeOut>0)&&(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_)) { dwTimeOut--; } if(dwTimeOut==0) { SMSC_WARNING("Lan_Initialize: Timed out waiting for EEPROM busy bit to clear\n"); } Lan_SetRegDW(GPIO_CFG,0x70000000UL); /* initialize interrupts */ Lan_SetRegDW(INT_EN,0); Lan_SetRegDW(INT_STS,0xFFFFFFFFUL); result=TRUE;DONE: SMSC_TRACE("<--Lan_Initialize"); return result;}/************************************************************************* * *************************************************************************/static int smsc911x_open(PPRIVATE_DATA privateData){ if(!Lan_Initialize(privateData,0,0x00050000,0xFFFFFFFF)) { SMSC_WARNING("Failed Lan_Initialize"); return -ENODEV; } SMSC_TRACE("<--Smsc911x_open"); return 0;}/************************************************************************* * *************************************************************************/void smsc911x_enable_phy_module(void){}/************************************************************************* * *************************************************************************/void smsc911x_disable_phy_module(void){}/************************************************************************* * *************************************************************************/int arch_get_mac(unsigned char *mac){ int i; unsigned long mac_hi, mac_low; privateData->dwLanBase=LAN_CSBASE; mac_hi = Mac_GetRegDW(privateData,ADDRH); mac_low = Mac_GetRegDW(privateData,ADDRL); if((mac_hi == 0x0000ffff) && (mac_low == 0xffffffff)){ SMSC_WARNING("Error: read MAC addr." "using default 00:01:02:03:04:05.\n"); for(i=0;i<6;i++) mac[i] = i; }else{ mac[0] = (mac_low >> 0) & 0xff; mac[1] = (mac_low >> 8) & 0xff; mac[2] = (mac_low >> 16) & 0xff; mac[3] = (mac_low >> 24) & 0xff; mac[4] = (mac_hi >> 0) & 0xff; mac[5] = (mac_hi >> 8) & 0xff; } return 0;}/************************************************************************* * *************************************************************************/int smsc911x_eth_init(const unsigned char *ipaddr){ hwif_eth hwif; DWORD dwLanBase=0UL; DWORD dwIdRev=0UL; DWORD dwFpgaRev=0UL; int result=-ENODEV; int ret; memzero(&_privateData, sizeof(_platformData)); memzero(&_platformData, sizeof(_platformData)); dwLanBase=Platform_Initialize(platformData, 0, 16); privateData->dwLanBase=dwLanBase; dwIdRev=Lan_GetRegDW(ID_REV); if(HIWORD(dwIdRev)==LOWORD(dwIdRev)) { /* this may mean the chip is set for 32 bit */ /* while the bus is reading as 16 bit */ SMSC_WARNING(" LAN911x NOT Identified, dwIdRev==%p",dwIdRev); result=-ENODEV; return -1; } SMSC_TRACE(" LAN911x identified, dwIdRev==%p", dwIdRev); dwFpgaRev=Lan_GetRegDW(FPGA_REV); SMSC_TRACE(" FPGA_REV == %p",dwFpgaRev); ret = Phy_Initialize(privateData, 0xffffffff,0x7f ); ret = smsc911x_open(privateData); ret = Phy_CheckLink((unsigned long)privateData); if(ret < 0){ return -1; } safe_memset(&hwif, 0, sizeof(hwif_eth)); hwif.enable_phy_module = smsc911x_enable_phy_module; hwif.disable_phy_module = smsc911x_disable_phy_module; hwif.eth_send = smsc911x_eth_send; hwif.eth_recv = smsc911x_eth_recv; hwif.eth_rxbuf_free = smsc911x_eth_rxbuf_free; safe_memcpy(&hwif.eth_ipaddr, ipaddr, 4); arch_get_mac(hwif.eth_mac); register_hwif_eth(&hwif); smsc911x_eth_rx_init(); smsc911x_eth_tx_init(); Lan_SetRegDW(FIFO_INT, 0x48ff2020); /* Interrupt Status Clear */ Lan_SetRegDW(INT_STS, 0xffffffff); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -