📄 smsc911x.c
字号:
/* Calculate the total memory for all the M-Blks and CL-Blks. */
smsc911xMclBlkConfig.mBlkNum = pDrvCtrl->numFrames*2;
smsc911xClDescTbl[0].clNum = pDrvCtrl->numFrames;
smsc911xMclBlkConfig.clBlkNum = smsc911xClDescTbl[0].clNum;
smsc911xMclBlkConfig.memSize = (smsc911xMclBlkConfig.mBlkNum *
(MSIZE + sizeof (long))) +
(smsc911xMclBlkConfig.clBlkNum *
(CL_BLK_SZ + sizeof(long)));
if ((smsc911xMclBlkConfig.memArea = (char *) memalign (sizeof(long),
smsc911xMclBlkConfig.memSize)) == NULL)
{
SMSC_TRACE(" system memory unavailable\r\n-smsc911xMemInit\r\n") ;
return (ERROR);
}
/* Calculate the memory size of all the clusters. */
smsc911xClDescTbl[0].memSize = (smsc911xClDescTbl[0].clNum *
(SMSC911X_BUFSIZE + 8)) + sizeof(int);
/* Allocate the memory for the clusters from cache safe memory. */
smsc911xClDescTbl[0].memArea =
(char *) cacheDmaMalloc (smsc911xClDescTbl[0].memSize);
if ((int)smsc911xClDescTbl[0].memArea == NULL)
{
SMSC_TRACE("system memory unavailable\r\n-smsc911xMemInit\r\n");
return (ERROR);
}
/* Initialize the memory pool. */
if (netPoolInit(pDrvCtrl->endObj.pNetPool, &smsc911xMclBlkConfig,
&smsc911xClDescTbl[0], smsc911xClDescTblNumEnt,
NULL) == ERROR)
{
SMSC_TRACE(" Could not init buffering\r\n-smsc911xMemInit\r\n");
return (ERROR);
}
/* Store a reference to the cluster pool */
if ((pDrvCtrl->pClPoolId = netClPoolIdGet (pDrvCtrl->endObj.pNetPool,
sizeof (TX_PKT), FALSE))
== NULL)
{
SMSC_TRACE("Could not get pool id\r\n-smsc911xMemInit\r\n");
return (ERROR);
}
/*
* If you need clusters to store received packets into then get them
* here ahead of time.
*/
pDrvCtrl->pTxBase = (TX_PKT *)calloc(TX_PACKETS * sizeof(TX_PKT),1);
pDrvCtrl->pTxReadIndex = pDrvCtrl->pTxBase;
pDrvCtrl->pTxWriteIndex = pDrvCtrl->pTxBase;
pDrvCtrl->pRxBase = (RX_PKT *)calloc(RX_PACKETS * sizeof(RX_PKT),1);
pDrvCtrl->pRxReadIndex = pDrvCtrl->pRxBase;
pDrvCtrl->pRxWriteIndex = pDrvCtrl->pRxBase;
pDrvCtrl->sendBuf = (unsigned char *)calloc(2048, 1);
SMSC_TRACE(" smsc911xMemInit success\r\n");
SMSC_TRACE("-smsc911xMemInit\r\n");
return OK;
}
void Mac_Initialize(PPRIVATE_DATA privateData)
{
SMSC_ASSERT(privateData!=NULL);
/*nothing to do here in the simple driver
but this function is kept as a place holder. */
}
void smscDelay(unsigned uCount)
{
int i;
while ( uCount-->0)
for(i=0; i<50; i++);
}
BOOLEAN Lan_Initialize( PPRIVATE_DATA privateData, DWORD dwIntCfg)
{
BOOLEAN result=FALSE;
DWORD dwTimeOut=0;
DWORD dwTemp=0;
DWORD dwBase = privateData->dwLanBase ;
SMSC_TRACE("+Lan_Initialize(dwIntCfg=0x%08lX)\r\n",dwIntCfg);
SMSC_ASSERT(privateData!=NULL);
/* check to see the device is ready */
dwTimeOut = 10000 ;
dwTemp = Lan_GetRegDW(dwBase, PMT_CTRL) ;
while ( !(dwTemp & PMT_CTRL_READY_) && dwTimeOut>0 )
{
smscDelay(10) ;
dwTemp= Lan_GetRegDW(dwBase, PMT_CTRL) ;
dwTimeOut -- ;
}
if (!(dwTemp & PMT_CTRL_READY_)) {
SMSC_WARNING(" Device Not Ready \r\n") ;
goto DONE ;
}
/* Reset the LAN911x */
Lan_SetRegDW(dwBase, HW_CFG,HW_CFG_SRST_);
dwTimeOut=100000;
do {
smscDelay(10);
dwTemp=Lan_GetRegDW(dwBase, HW_CFG);
dwTimeOut--;
} while((dwTimeOut>0)&&(dwTemp&HW_CFG_SRST_));
if(dwTemp&HW_CFG_SRST_) {
SMSC_WARNING(" Failed to complete reset.\r\n");
goto DONE;
}
Lan_SetRegDW(dwBase, HW_CFG,0x00050000UL);
Lan_SetRegDW(dwBase, AFC_CFG,0x006E3740UL);
/* make sure EEPROM has finished loading before setting GPIO_CFG */
dwTimeOut=50;
while((dwTimeOut>0)&&(Lan_GetRegDW(dwBase, E2P_CMD)&E2P_CMD_EPC_BUSY_)) {
smscDelay(10);
dwTimeOut--;
}
if(dwTimeOut==0) {
SMSC_WARNING("Lan_Initialize: Timed out waiting for EEPROM busy bit to clear\r\n");
}
/* set gpio */
Lan_SetRegDW(dwBase, GPIO_CFG,0x70000000UL);
/* initialize interrupts */
Lan_SetRegDW(dwBase,INT_EN,0);
Lan_SetRegDW(dwBase,INT_STS,0xFFFFFFFFUL);
dwIntCfg|=INT_CFG_IRQ_EN_;
Lan_SetRegDW(dwBase,INT_CFG,dwIntCfg);
result=TRUE;
DONE:
SMSC_TRACE("-Lan_Initialize\r\n");
return result;
}
void Tx_WriteFifo(
DWORD dwLanBase,
DWORD *pdwBuf,
DWORD dwDwordCount)
{
volatile DWORD *pdwReg;
pdwReg = (volatile DWORD *)(dwLanBase+TX_DATA_FIFO);
while(dwDwordCount)
{
*pdwReg = *pdwBuf++;
dwDwordCount--;
}
}
void Rx_ReadFifo(
DWORD dwLanBase,
DWORD *pdwBuf,
DWORD dwDwordCount)
{
const volatile DWORD * const pdwReg =
(const volatile DWORD * const)(dwLanBase+RX_DATA_FIFO);
while (dwDwordCount)
{
*pdwBuf++ = *pdwReg;
dwDwordCount--;
}
}
#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\r\n");
Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_);
do {
smscDelay(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.\r\n");
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 */
smscDelay(500);
result=TRUE;
DONE:
return result;
}
DWORD Phy_LBT_GetTxStatus(PPRIVATE_DATA privateData)
{
DWORD dwBase = privateData->dwLanBase ;
DWORD result=Lan_GetRegDW(dwBase, TX_FIFO_INF);
result&=TX_FIFO_INF_TSUSED_;
if(result!=0x00000000UL) {
result=Lan_GetRegDW(dwBase,TX_STATUS_FIFO);
} else {
result=0;
}
return result;
}
DWORD Phy_LBT_GetRxStatus(PPRIVATE_DATA privateData)
{
DWORD dwBase = privateData->dwLanBase ;
DWORD result=Lan_GetRegDW(dwBase,RX_FIFO_INF);
if(result&0x00FF0000UL) {
/* Rx status is available, read it */
result=Lan_GetRegDW(dwBase,RX_STATUS_FIFO);
} else {
result=0;
}
return result;
}
BOOLEAN Phy_CheckLoopBackPacket(PPRIVATE_DATA privateData)
{
BOOLEAN result=FALSE;
DWORD tryCount=0;
DWORD dwLoopCount=0;
DWORD dwBase = privateData->dwLanBase ;
for(tryCount=0;tryCount<10;tryCount++)
{
DWORD dwTxCmdA=0;
DWORD dwTxCmdB=0;
DWORD dwStatus=0;
DWORD dwPacketLength=0;
/* zero-out Rx Packet memory */
bzero(privateData->LoopBackRxPacket,MIN_PACKET_SIZE);
/* write Tx Packet to 118 */
dwTxCmdA=
((((DWORD)(privateData->LoopBackTxPacket))&0x03UL)<<16) |
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(dwBase,TX_DATA_FIFO,dwTxCmdA);
Lan_SetRegDW(dwBase,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)) {
smscDelay(5);
dwLoopCount--;
}
if(dwStatus==0) {
SMSC_WARNING("Failed to Transmit during Loop Back Test\r\n");
continue;
}
if(dwStatus&0x00008000UL) {
SMSC_WARNING("Transmit encountered errors during Loop Back Test\r\n");
continue;
}
/* wait till receive is done */
dwLoopCount=60;
while((dwLoopCount>0)&&((dwStatus=Phy_LBT_GetRxStatus(privateData))==0))
{
smscDelay(5);
dwLoopCount--;
}
if(dwStatus==0) {
SMSC_WARNING("Failed to Receive during Loop Back Test\r\n");
continue;
}
if(dwStatus&RX_STS_ES_)
{
SMSC_WARNING("Receive encountered errors during Loop Back Test\r\n");
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\r\n",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\r\n");
result=TRUE;
goto DONE;
} else {
SMSC_WARNING("Data miss match during loop back test, will retry.\r\n");
}
}
}
DONE:
return result;
}
BOOLEAN Phy_LoopBackTest(PPRIVATE_DATA privateData)
{
BOOLEAN result=FALSE;
DWORD byteIndex=0;
DWORD tryCount=0;
DWORD dwBase = privateData->dwLanBase ;
/* 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(dwBase, HW_CFG);
dwRegVal&=HW_CFG_TX_FIF_SZ_;
dwRegVal|=HW_CFG_SF_;
Lan_SetRegDW(dwBase,HW_CFG,dwRegVal);
}
Lan_SetRegDW(dwBase,TX_CFG,TX_CFG_TX_ON_);
Lan_SetRegDW(dwBase,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(dwBase ,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(dwBase,MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
}
DONE:
/* disable MAC */
Mac_SetRegDW(dwBase,MAC_CR,0UL);
/* Cancel Phy loopback mode */
Phy_SetRegW(privateData,PHY_BCR,0U);
Lan_SetRegDW(dwBase, TX_CFG,0UL);
Lan_SetRegDW(dwBase, RX_CFG,0UL);
return result;
}
#endif /* USE_PHY_WORK_AROUND */
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(privateData, PHY_ANEG_ADV);
/* Advertise all speeds and pause capabilities*/
wTemp|=(PHY_ANEG_ADV_PAUSE_|PHY_ANEG_ADV_SPEED_);
Phy_SetRegW(privateData,PHY_ANEG_ADV,wTemp);
/* begin to establish link */
Phy_SetRegW(privateData,
PHY_BCR,
PHY_BCR_AUTO_NEG_ENABLE_|
PHY_BCR_RESTART_AUTO_NEG_);
}
BOOLEAN Phy_Initialize( PPRIVATE_DATA privateData, DWORD dwPhyAddr)
{
BOOLEAN result=FALSE;
#ifndef USE_PHY_WORK_AROUND
WORD wTemp=0;
#endif
WORD wPhyId1=0;
WORD wPhyId2=0;
#ifndef USE_PHY_WORK_AROUND
DWORD dwLoopCount=0;
#endif
DWORD dwBase = privateData->dwLanBase ;
SMSC_TRACE("-Phy_Initialize\r\n");
SMSC_ASSERT(privateData!=NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -