📄 eth_smsc911x.c
字号:
Platform_WriteFifo( privateData->dwLanBase, (DWORD *)(((DWORD)(LoopBackTxPacket))&0xFFFFFFFCUL), (((DWORD)(MIN_PACKET_SIZE))+3+ (((DWORD)(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 Packet Test"); goto DONE; } if(dwStatus&0x00008000UL) { SMSC_WARNING("Transmit encountered errors during Packet Test"); goto DONE; }DONE: return result;}#endif/************************************************************************* * *************************************************************************/static void Phy_GetLinkMode(PPRIVATE_DATA privateData){ DWORD result=LINK_OFF; WORD wRegVal=0; WORD wRegBSR=Phy_GetRegW( privateData, PHY_BSR); privateData->dwLinkSettings=LINK_OFF; if(wRegBSR&PHY_BSR_LINK_STATUS_) { wRegVal=Phy_GetRegW( privateData, PHY_BCR); if(wRegVal&PHY_BCR_AUTO_NEG_ENABLE_) { DWORD linkSettings=LINK_AUTO_NEGOTIATE; WORD wRegADV=privateData->wLastADVatRestart; WORD wRegLPA=Phy_GetRegW( privateData, PHY_ANEG_LPA); if(wRegADV&PHY_ANEG_ADV_ASYMP_) { linkSettings|=LINK_ASYMMETRIC_PAUSE; } if(wRegADV&PHY_ANEG_ADV_SYMP_) { linkSettings|=LINK_SYMMETRIC_PAUSE; } if(wRegADV&PHY_ANEG_LPA_100FDX_) { linkSettings|=LINK_SPEED_100FD; } if(wRegADV&PHY_ANEG_LPA_100HDX_) { linkSettings|=LINK_SPEED_100HD; } if(wRegADV&PHY_ANEG_LPA_10FDX_) { linkSettings|=LINK_SPEED_10FD; } if(wRegADV&PHY_ANEG_LPA_10HDX_) { linkSettings|=LINK_SPEED_10HD; } privateData->dwLinkSettings=linkSettings; wRegLPA&=wRegADV; if(wRegLPA&PHY_ANEG_LPA_100FDX_) { result=LINK_SPEED_100FD; } else if(wRegLPA&PHY_ANEG_LPA_100HDX_) { result=LINK_SPEED_100HD; } else if(wRegLPA&PHY_ANEG_LPA_10FDX_) { result=LINK_SPEED_10FD; } else if(wRegLPA&PHY_ANEG_LPA_10HDX_) { result=LINK_SPEED_10HD; } } else { if(wRegVal&PHY_BCR_SPEED_SELECT_) { if(wRegVal&PHY_BCR_DUPLEX_MODE_) { privateData->dwLinkSettings=result=LINK_SPEED_100FD; } else { privateData->dwLinkSettings=result=LINK_SPEED_100HD; } } else { if(wRegVal&PHY_BCR_DUPLEX_MODE_) { privateData->dwLinkSettings=result=LINK_SPEED_10FD; } else { privateData->dwLinkSettings=result=LINK_SPEED_10HD; } } } } privateData->dwLinkSpeed=result;}/************************************************************************* * *************************************************************************/static int Phy_UpdateLinkMode(PPRIVATE_DATA privateData){ Phy_GetLinkMode(privateData); if(privateData->dwLinkSpeed!=LINK_OFF) { DWORD dwRegVal=0; switch(privateData->dwLinkSpeed) { case LINK_SPEED_10HD: SMSC_TRACE("Link is now UP at 10Mbps HD"); break; case LINK_SPEED_10FD: SMSC_TRACE("Link is now UP at 10Mbps FD"); break; case LINK_SPEED_100HD: SMSC_TRACE("Link is now UP at 100Mbps HD"); break; case LINK_SPEED_100FD: SMSC_TRACE("Link is now UP at 100Mbps FD"); break; default: SMSC_WARNING("Link is now UP at Unknown Link Speed, dwLinkSpeed=0x%08lX", privateData->dwLinkSpeed); break; } dwRegVal=Mac_GetRegDW(privateData,MAC_CR); dwRegVal&=~(MAC_CR_FDPX_|MAC_CR_RCVOWN_); switch(privateData->dwLinkSpeed) { case LINK_SPEED_10HD: case LINK_SPEED_100HD: dwRegVal|=MAC_CR_RCVOWN_; break; case LINK_SPEED_10FD: case LINK_SPEED_100FD: dwRegVal|=MAC_CR_FDPX_; break; default: break;/* make lint happy */ } Mac_SetRegDW(privateData,MAC_CR,dwRegVal); if(privateData->dwLinkSettings&LINK_AUTO_NEGOTIATE) { WORD linkPartner=0; WORD localLink=0; localLink=Phy_GetRegW(privateData,4); linkPartner=Phy_GetRegW(privateData,5); switch(privateData->dwLinkSpeed) { case LINK_SPEED_10FD: case LINK_SPEED_100FD: if(((localLink&linkPartner)&((WORD)0x0400U)) != ((WORD)0U)) { /* Enable PAUSE receive and transmit */ Mac_SetRegDW(privateData,FLOW,0xFFFF0002UL); Lan_SetBitsDW(AFC_CFG,0x00000000UL); } else if(((localLink&((WORD)0x0C00U))==((WORD)0x0C00U)) && ((linkPartner&((WORD)0x0C00U))==((WORD)0x0800U))) { /* Enable PAUSE receive, disable PAUSE transmit */ Mac_SetRegDW(privateData,FLOW,0xFFFF0002UL); Lan_ClrBitsDW(AFC_CFG,0x0000000FUL); } else { /* Disable PAUSE receive and transmit */ Mac_SetRegDW(privateData,FLOW,0UL); Lan_ClrBitsDW(AFC_CFG,0x0000000FUL); }; break; case LINK_SPEED_10HD: case LINK_SPEED_100HD: Mac_SetRegDW(privateData,FLOW,0UL); Lan_SetBitsDW(AFC_CFG,0x0000000FUL); break; default: break;/* make lint happy */ } SMSC_TRACE("LAN911x: %s,%s,%s,%s,%s,%s", (localLink&PHY_ANEG_ADV_ASYMP_)?"ASYMP":" ", (localLink&PHY_ANEG_ADV_SYMP_)?"SYMP ":" ", (localLink&PHY_ANEG_ADV_100F_)?"100FD":" ", (localLink&PHY_ANEG_ADV_100H_)?"100HD":" ", (localLink&PHY_ANEG_ADV_10F_)?"10FD ":" ", (localLink&PHY_ANEG_ADV_10H_)?"10HD ":" "); SMSC_TRACE("Partner: %s,%s,%s,%s,%s,%s", (linkPartner&PHY_ANEG_LPA_ASYMP_)?"ASYMP":" ", (linkPartner&PHY_ANEG_LPA_SYMP_)?"SYMP ":" ", (linkPartner&PHY_ANEG_LPA_100FDX_)?"100FD":" ", (linkPartner&PHY_ANEG_LPA_100HDX_)?"100HD":" ", (linkPartner&PHY_ANEG_LPA_10FDX_)?"10FD ":" ", (linkPartner&PHY_ANEG_LPA_10HDX_)?"10HD ":" "); } else { switch(privateData->dwLinkSpeed) { case LINK_SPEED_10HD: case LINK_SPEED_100HD: Mac_SetRegDW(privateData,FLOW,0x0UL); Lan_SetBitsDW(AFC_CFG,0x0000000FUL); break; default: Mac_SetRegDW(privateData,FLOW,0x0UL); Lan_ClrBitsDW(AFC_CFG,0x0000000FUL); break; } } } else { SMSC_TRACE("Link is now DOWN"); Mac_SetRegDW(privateData,FLOW,0UL); Lan_ClrBitsDW(AFC_CFG,0x0000000FUL); return -1; } return 0;}/************************************************************************* * *************************************************************************/static int Phy_CheckLink(unsigned long ptr){ PPRIVATE_DATA privateData=(PPRIVATE_DATA)ptr; if(privateData==NULL) { SMSC_WARNING("Phy_CheckLink(ptr==0)"); return -1; } /* must call this twice */ return Phy_UpdateLinkMode(privateData);}/************************************************************************* * *************************************************************************/static int Phy_SetLink(PPRIVATE_DATA privateData,DWORD dwLinkRequest) { if(dwLinkRequest&LINK_AUTO_NEGOTIATE) { WORD wTemp; wTemp=Phy_GetRegW(privateData, PHY_ANEG_ADV); wTemp&=~PHY_ANEG_ADV_PAUSE_; if(dwLinkRequest&LINK_ASYMMETRIC_PAUSE) { wTemp|=PHY_ANEG_ADV_ASYMP_; } if(dwLinkRequest&LINK_SYMMETRIC_PAUSE) { wTemp|=PHY_ANEG_ADV_SYMP_; } wTemp&=~PHY_ANEG_ADV_SPEED_; if(dwLinkRequest&LINK_SPEED_10HD) { wTemp|=PHY_ANEG_ADV_10H_; } if(dwLinkRequest&LINK_SPEED_10FD) { wTemp|=PHY_ANEG_ADV_10F_; } if(dwLinkRequest&LINK_SPEED_100HD) { wTemp|=PHY_ANEG_ADV_100H_; } if(dwLinkRequest&LINK_SPEED_100FD) { wTemp|=PHY_ANEG_ADV_100F_; } Phy_SetRegW(privateData,PHY_ANEG_ADV,wTemp); /* begin to establish link */ privateData->dwRemoteFaultCount=0; Phy_SetRegW(privateData, PHY_BCR, PHY_BCR_AUTO_NEG_ENABLE_| PHY_BCR_RESTART_AUTO_NEG_); { int timeout=5000; while(timeout--){ DWORD reg = Phy_GetRegW(privateData, PHY_BSR); if(reg & 0x20) break; mdelay(1); timeout--; } if(timeout <=0) return -1; } } else { WORD wTemp=0; if(dwLinkRequest&(LINK_SPEED_100FD)) { dwLinkRequest=LINK_SPEED_100FD; } else if(dwLinkRequest&(LINK_SPEED_100HD)) { dwLinkRequest=LINK_SPEED_100HD; } else if(dwLinkRequest&(LINK_SPEED_10FD)) { dwLinkRequest=LINK_SPEED_10FD; } else if(dwLinkRequest&(LINK_SPEED_10HD)) { dwLinkRequest=LINK_SPEED_10HD; } if(dwLinkRequest&(LINK_SPEED_10FD|LINK_SPEED_100FD)) { wTemp|=PHY_BCR_DUPLEX_MODE_; } if(dwLinkRequest&(LINK_SPEED_100HD|LINK_SPEED_100FD)) { wTemp|=PHY_BCR_SPEED_SELECT_; } Phy_SetRegW(privateData,PHY_BCR,wTemp); } return 0;}/************************************************************************* * *************************************************************************/static BOOLEAN Phy_Initialize(PPRIVATE_DATA privateData, DWORD dwPhyAddr, DWORD dwLinkRequest){ BOOLEAN result=FALSE; DWORD dwTemp=0; WORD wTemp=0; DWORD dwLoopCount=0; SMSC_TRACE("-->Phy_Initialize"); SMSC_ASSERT(privateData!=NULL); SMSC_ASSERT(privateData->dwLanBase!=0); SMSC_ASSERT(dwLinkRequest<=0x7FUL); if(dwPhyAddr!=0xFFFFFFFFUL) { switch(privateData->dwIdRev&0xFFFF0000) { case 0x01170000UL: case 0x01150000UL: if(privateData->dwIdRev&0x0000FFFF) { DWORD dwHwCfg=Lan_GetRegDW(HW_CFG); if(dwHwCfg&HW_CFG_EXT_PHY_DET_) { /* External phy is requested, supported, and detected */ /* Attempt to switch */ /* NOTE: Assuming Rx and Tx are stopped */ /* because Phy_Initialize is called before */ /* Rx_Initialize and Tx_Initialize */ WORD wPhyId1=0; WORD wPhyId2=0; /* Disable phy clocks to the mac */ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_); dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_; Lan_SetRegDW(HW_CFG,dwHwCfg); udelay(10);/* wait for clocks to acutally stop */ dwHwCfg|=HW_CFG_EXT_PHY_EN_; Lan_SetRegDW(HW_CFG,dwHwCfg); dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_); dwHwCfg|= HW_CFG_PHY_CLK_SEL_EXT_PHY_; Lan_SetRegDW(HW_CFG,dwHwCfg); udelay(10);/* wait for clocks to actually start */ dwHwCfg|=HW_CFG_SMI_SEL_; Lan_SetRegDW(HW_CFG,dwHwCfg); { if(dwPhyAddr<=31) { /* only check the phy address specified */ privateData->dwPhyAddress=dwPhyAddr; wPhyId1=Phy_GetRegW(privateData,PHY_ID_1); wPhyId2=Phy_GetRegW(privateData,PHY_ID_2); } else { /* auto detect phy */ DWORD address=0; for(address=0;address<=31;address++) { privateData->dwPhyAddress=address; if((wPhyId1!=0xFFFFU)||(wPhyId2!=0xFFFFU)) { SMSC_TRACE("Detected Phy at address = 0x%02lX = %ld", address,address); break; } } if(address>=32) { SMSC_WARNING("Failed to auto detect external phy"); } } } if((wPhyId1==0xFFFFU)&&(wPhyId2==0xFFFFU)) { SMSC_WARNING("External Phy is not accessable"); SMSC_WARNING(" using internal phy instead"); /* revert back to interal phy settings. */ /* Disable phy clocks to the mac */ dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_); dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_; Lan_SetRegDW(HW_CFG,dwHwCfg); udelay(10);/* wait for clocks to actually stop */ dwHwCfg&=(~HW_CFG_EXT_PHY_EN_); Lan_SetRegDW(HW_CFG,dwHwCfg); dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_); dwHwCfg|= HW_CFG_PHY_CLK_SEL_INT_PHY_; Lan_SetRegDW(HW_CFG,dwHwCfg); udelay(10);/* wait for clocks to actually start */ dwHwCfg&=(~HW_CFG_SMI_SEL_); Lan_SetRegDW(HW_CFG,dwHwCfg); goto USE_INTERNAL_PHY; } else { SMSC_TRACE("Successfully switched to external phy"); } } else { SMSC_WARNING("No External Phy Detected"); SMSC_WARNING(" using internal phy instead"); goto USE_INTERNAL_PHY; } } else { SMSC_WARNING("External Phy is not supported"); SMSC_WARNING(" using internal phy instead"); goto USE_INTERNAL_PHY; };break; default: SMSC_WARNING("External Phy is not supported"); SMSC_WARNING(" using internal phy instead"); goto USE_INTERNAL_PHY; } } else {USE_INTERNAL_PHY: privateData->dwPhyAddress=1; } dwTemp=Phy_GetRegW(privateData,PHY_ID_2); privateData->bPhyRev=((BYTE)(dwTemp&(0x0FUL))); privateData->bPhyModel=((BYTE)((dwTemp>>4)&(0x3FUL))); privateData->dwPhyId=((dwTemp&(0xFC00UL))<<8); dwTemp=Phy_GetRegW(privateData,PHY_ID_1); privateData->dwPhyId|=((dwTemp&(0x0000FFFFUL))<<2); SMSC_TRACE("dwPhyId==%p,bPhyModel==%p,bPhyRev==%p", privateData->dwPhyId, privateData->bPhyModel, privateData->bPhyRev); privateData->dwLinkSpeed=LINK_OFF; privateData->dwLinkSettings=LINK_OFF; /* reset the PHY */ Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_); dwLoopCount=100000; 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; } if(Phy_SetLink(privateData,dwLinkRequest)<0) return -1; result=TRUE;DONE: SMSC_TRACE("<--Phy_Initialize, result=%s",result?"TRUE":"FALSE"); return result;}/************************************************************************* * *************************************************************************/static void Rx_ReceiverOn(PPRIVATE_DATA privateData){ if(privateData->dwRxOffCount>0) { privateData->dwRxOffCount--; if(privateData->dwRxOffCount==0) { DWORD dwMacCr=Mac_GetRegDW(privateData,MAC_CR); if(dwMacCr&MAC_CR_RXEN_) { SMSC_WARNING("Rx_ReceiverOn: Receiver is already on"); } dwMacCr|=MAC_CR_RXEN_; Mac_SetRegDW(privateData,MAC_CR,dwMacCr); } } else { SMSC_ASSERT(FALSE); }}/************************************************************************* * *************************************************************************/static int smsc911x_eth_tx_init(void){ DWORD dwRegVal=0; DWORD dwMacCr; dwRegVal=Lan_GetRegDW(HW_CFG); dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL); dwRegVal|=HW_CFG_SF_; Lan_SetRegDW(HW_CFG,dwRegVal); dwMacCr=Mac_GetRegDW(privateData,MAC_CR); dwMacCr|=(MAC_CR_TXEN_|MAC_CR_HBDIS_); Mac_SetRegDW(privateData,MAC_CR,dwMacCr); Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_ | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_); return 0;}/************************************************************************* * *************************************************************************/int smsc911x_eth_send(const eth_frame *ethfr, const void *pfr, const unsigned int pfrlen){ DWORD dwTxCmdA; DWORD dwTxCmdB; int bufptr=0; DWORD dwStatus = 0; int dwLoopCount; memcpy(EthTxBuffer, ethfr, bufptr = ETH_FRAME_LEN); memcpy(&EthTxBuffer[bufptr], pfr, pfrlen); bufptr+=pfrlen; if(bufptr < 60){ memset(&EthTxBuffer[bufptr], 0, 60-bufptr); bufptr=60; } dwTxCmdA= ((((DWORD)(EthTxBuffer))&0x03UL)<<16) | /* DWORD alignment adjustment */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -