📄 smsc911x.c
字号:
SMSC_ASSERT(privateData->dwLanBase!=0);
if(dwPhyAddr!=0xFFFFFFFFUL) {
switch(privateData->dwIdRev&0xFFFF0000) {
case 0x01170000UL:
case 0x01150000UL:
{
DWORD dwHwCfg=Lan_GetRegDW(dwBase, 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 */
/*Disable phy clocks to the mac */
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
Lan_SetRegDW(dwBase,HW_CFG,dwHwCfg);
smscDelay(10);/* wait for clocks to acutally stop */
/*switch to external phy */
dwHwCfg|=HW_CFG_EXT_PHY_EN_;
Lan_SetRegDW(dwBase,HW_CFG,dwHwCfg);
/*Enable phy clocks to the mac */
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
Lan_SetRegDW(dwBase,HW_CFG,dwHwCfg);
smscDelay(10);/*wait for clocks to actually start*/
dwHwCfg|=HW_CFG_SMI_SEL_;
Lan_SetRegDW(dwBase,HW_CFG,dwHwCfg);
/*Because this is part of the single threaded initialization
// path there is no need to acquire the MacPhyAccessLock */
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;
wPhyId1=Phy_GetRegW(privateData,PHY_ID_1);
wPhyId2=Phy_GetRegW(privateData,PHY_ID_2);
if((wPhyId1!=0xFFFFU)||(wPhyId2!=0xFFFFU)) {
SMSC_TRACE("Detected Phy at address = 0x%02lX = %ld\r\n",
address,address);
break;
}
}
if(address>=32) {
SMSC_WARNING("Failed to auto detect external phy\r\n");
}
}
if((wPhyId1==0xFFFFU)&&(wPhyId2==0xFFFFU)) {
SMSC_WARNING("External Phy is not accessable\r\n");
SMSC_WARNING(" using internal phy instead\r\n");
/*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(dwBase,HW_CFG,dwHwCfg);
smscDelay(10);/*wait for clocks to actually stop */
/*switch to internal phy */
dwHwCfg&=(~HW_CFG_EXT_PHY_EN_);
Lan_SetRegDW(dwBase, HW_CFG,dwHwCfg);
/* Enable phy clocks to the mac */
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_INT_PHY_;
Lan_SetRegDW(dwBase, HW_CFG,dwHwCfg);
smscDelay(10);/*wait for clocks to actually start */
dwHwCfg&=(~HW_CFG_SMI_SEL_);
Lan_SetRegDW(dwBase,HW_CFG,dwHwCfg);
goto USE_INTERNAL_PHY;
} else {
SMSC_TRACE("Successfully switched to external phy\r\n");
#ifdef USE_LED1_WORK_AROUND
privateData->NotUsingExtPhy=0;
#endif
}
} else {
SMSC_WARNING("No External Phy Detected\r\n");
SMSC_WARNING(" using internal phy instead\r\n");
goto USE_INTERNAL_PHY;
}
};break;
default:
SMSC_WARNING("External Phy is not supported\r\n");
SMSC_WARNING(" using internal phy instead\r\n");
goto USE_INTERNAL_PHY;
}
} else {
USE_INTERNAL_PHY:
privateData->dwPhyAddress=1;
#ifdef USE_LED1_WORK_AROUND
privateData->NotUsingExtPhy=1;
#endif
}
/*Because this is part of the single threaded initialization
// path there is no need to acquire the MacPhyAccessLock */
wPhyId1=Phy_GetRegW(privateData,PHY_ID_1);
wPhyId2=Phy_GetRegW(privateData,PHY_ID_2);
if((wPhyId1==0xFFFFU)&&(wPhyId2==0xFFFFU)) {
SMSC_WARNING("Phy Not detected\r\n");
goto DONE;
}
/* reset the PHY */
#ifdef USE_PHY_WORK_AROUND
Phy_Reset(privateData);
if(!Phy_LoopBackTest(privateData)) {
SMSC_WARNING("Failed Loop Back Test\r\n");
goto DONE;
} else {
SMSC_TRACE("Passed Loop Back Test\r\n");
}
#else
Phy_SetRegW(privateData,PHY_BCR,PHY_BCR_RESET_);
dwLoopCount=100000;
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;
}
#endif /* not USE_PHY_WORK_AROUND */
Phy_SetLink(privateData);
/*
init_timer(&(privateData->LinkPollingTimer));
privateData->LinkPollingTimer.function=Phy_CheckLink;
privateData->LinkPollingTimer.data=(unsigned long)privateData;
privateData->LinkPollingTimer.expires=jiffies+HZ;
add_timer(&(privateData->LinkPollingTimer));
*/
result=TRUE;
DONE:
SMSC_TRACE("-Phy_Initialize, result=%s\r\n",result?"TRUE":"FALSE");
return result;
}
void Tx_Initialize(
PPRIVATE_DATA privateData)
{
DWORD dwRegVal=0;
DWORD dwBase ;
DWORD dwMacCr;
SMSC_ASSERT(privateData!=NULL);
SMSC_ASSERT(privateData->dwLanBase!=0);
dwBase = privateData->dwLanBase ;
dwRegVal=Lan_GetRegDW(dwBase, HW_CFG);
dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL);
dwRegVal|=HW_CFG_SF_;
Lan_SetRegDW(dwBase,HW_CFG,dwRegVal);
Lan_SetBitsDW(dwBase,FIFO_INT,0xFF000000UL);
Lan_SetBitsDW(dwBase,INT_EN,INT_EN_TDFA_EN_);
/*Because this is part of the single threaded initialization
// path there is no need to acquire the MacPhyAccessLock */
dwMacCr=Mac_GetRegDW(dwBase, MAC_CR);
dwMacCr|=(MAC_CR_TXEN_|MAC_CR_HBDIS_);
Mac_SetRegDW(dwBase,MAC_CR,dwMacCr);
Lan_SetRegDW(dwBase,TX_CFG,TX_CFG_TX_ON_);
}
void Rx_Initialize(
PPRIVATE_DATA privateData)
{
DWORD dwMacCr=0;
DWORD dwBase ;
SMSC_ASSERT(privateData!=NULL);
dwBase = privateData->dwLanBase ;
Lan_SetRegDW(dwBase, RX_CFG,0x00000200UL);
/* Because this is part of the single threaded initialization
// path there is no need to acquire the MacPhyAccessLock */
dwMacCr=Mac_GetRegDW(dwBase,MAC_CR);
dwMacCr|=MAC_CR_RXEN_;
Mac_SetRegDW(dwBase,MAC_CR,dwMacCr);
Lan_ClrBitsDW(dwBase,FIFO_INT,0x000000FFUL);
Lan_SetBitsDW(dwBase,INT_EN,INT_EN_RSFL_EN_);
}
/*******************************************************************************
* smsc911xStart - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*
*/
STATUS smsc911xStart ( END_OBJ * pEnd /* device ID */)
{
SMSC_TRACE( "+smsc911xStart\r\n") ;
MEDUSA_INT_UNMASK() ;
SMSC_TRACE("-smsc911xStart: Success\r\n");
return (OK);
}
/*******************************************************************************
* smsc911xInt - handle controller interrupt
*
* This routine is called at interrupt level in response to an interrupt from
* the controller.
*
* RETURNS: N/A.
*/
int netIntCount,netTest;
void smsc911xInt
(
SMSC911XEND_DEVICE * pDrvCtrl /* device to be initialized */
)
{
DWORD dwIntSts, dwIntCfg;
int currentKey;
DWORD dwBase ;
DWORD reservedBits=0x00FFCEEEUL;
PPRIVATE_DATA privateData ;
BOOLEAN serviced ;
dwBase = pDrvCtrl->private_data.dwLanBase ;
privateData = & pDrvCtrl->private_data ;
currentKey = intLock();
dwIntCfg=Lan_GetRegDW(dwBase, INT_CFG);
netIntCount++;
netTest = dwIntCfg;
if((dwIntCfg&0x00001100)!=0x00001100) {
SMSC_TRACE("In ISR, not my interrupt, dwIntCfg=0x%08lX\r\n", dwIntCfg);
goto DONE;
}
if(dwIntCfg&reservedBits) {
SMSC_WARNING("In ISR, reserved bits are high.\r\n");
goto DONE;
}
dwIntSts=Lan_GetRegDW(dwBase,INT_STS);
if(dwIntSts&INT_STS_SW_INT_) {
Lan_ClrBitsDW(dwBase,INT_EN,INT_EN_SW_INT_EN_);
Lan_SetRegDW(dwBase,INT_STS,INT_STS_SW_INT_);
}
if(dwIntSts&INT_STS_RXE_) {
Lan_SetRegDW(dwBase,INT_STS,INT_STS_RXE_);
goto DONE;
}
if(dwIntSts&INT_STS_RSFL_) {
HandlerRxISR(pDrvCtrl) ;
Lan_SetRegDW(dwBase, INT_STS, INT_STS_RSFL_);
}
if(dwIntSts&INT_STS_TDFA_) {
HandlerTxISR(pDrvCtrl) ;
Lan_SetRegDW(dwBase, INT_STS, INT_STS_TDFA_);
}
DONE:
MEDUSA_INT_CLEAR();
SPARC_COMMIT();
SPARC_COMMIT();
intUnlock(currentKey);
return;
}
/*******************************************************************************
* smsc911xRecv - process the next incoming packet
*
* Handle one incoming packet. The packet is checked for errors.
*
* RETURNS: N/A.
*/
STATUS smsc911xRecv
(
SMSC911XEND_DEVICE *pDrvCtrl
/*
char *pData,
UINT len*/
)
{
M_BLK_ID pMblk;
CL_BLK_ID pClBlk;
int len,type;
int i;
/* Grab a cluster block to marry to the cluster we received. */
if ((pClBlk = netClBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT)) == NULL)
{
netClFree (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pRxReadIndex->pData);
SMSC_TRACE("smsc911xRecv: Out of Cluster Blocks!\r\n");
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
goto cleanRXD;
}
/*
* OK, let's get an M_BLK_ID and marry it to the
* one in the ring.
*/
if ((pMblk = mBlkGet (pDrvCtrl->endObj.pNetPool, M_DONTWAIT, MT_DATA)) == NULL)
{
netClBlkFree (pDrvCtrl->endObj.pNetPool, pClBlk);
netClFree (pDrvCtrl->endObj.pNetPool, pDrvCtrl->pRxReadIndex->pData);
SMSC_TRACE( "smsc911xRecv: Out of M Blocks!\n");
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_ERRS, +1);
goto cleanRXD;
}
/* Join the cluster to the MBlock */
netClBlkJoin (pClBlk,(char*) pDrvCtrl->pRxReadIndex->pData, smsc911xClDescTbl[0].clSize, NULL, 0, 0, 0);
netMblkClJoin (pMblk, pClBlk);
len = pDrvCtrl->pRxReadIndex->len;
pMblk->mBlkHdr.mData = (char *)(pDrvCtrl->pRxReadIndex->pData + 2);
pMblk->mBlkHdr.mLen = len ;
pMblk->mBlkHdr.mFlags |= M_PKTHDR;
pMblk->mBlkPktHdr.len = len;
SMSC_TRACE("RX : Pkt : Len %d\n",len);
pDrvCtrl->pRxReadIndex->pData = NULL; /* free the slot */
if(pDrvCtrl->pRxReadIndex < pDrvCtrl->pRxBase + RX_PACKETS - 1)
pDrvCtrl->pRxReadIndex++;
else
pDrvCtrl->pRxReadIndex = pDrvCtrl->pRxBase;
END_ERR_ADD (&pDrvCtrl->endObj, MIB2_IN_UCAST, +1);
END_RCV_RTN_CALL(&pDrvCtrl->endObj, pMblk);
cleanRXD:
return (OK);
}
/*******************************************************************************
* smsc911xHandleRcvInt - task level interrupt service for input packets
*
* This routine is called at task level indirectly by the interrupt
* service routine to do any message received processing.
*
* The double loop is to protect against a race condition where the interrupt
* code see rxHandling as TRUE, but it is then turned off by task code.
* This race is not fatal, but does cause occassional delays until a second
* packet is received and then triggers the netTask to call this routine again.
*
* RETURNS: N/A.
*/
void smsc911xHandleRcvInt
(
SMSC911XEND_DEVICE *pDrvCtrl /* interrupting device */
)
{
UINT receiveReady;
int loopCount=0;
pDrvCtrl->rxHandling = TRUE;
SMSC_TRACE("+smsc911xHandleRcvInt\r\n");
do
{
smsc911xRecv (pDrvCtrl);
receiveReady = pDrvCtrl->pRxReadIndex->pData ? 1 : 0;
loopCount++;
} while ((receiveReady != 0) && (loopCount <= 30));
pDrvCtrl->rxHandling = FALSE;
SMSC_TRACE("-smsc911xHandleRcvInt\r\n");
return;
}
/******************************************************************************
* smsc911xSend - end send routine
*
* This routine will be called by the network stack whenever the upper layer want
* to send the datagram. It takes a pointer to mbuf. It extacts the data from the
* mbuf and writes in chip.
*
* RETURNS: status of the write operation
*/
STATUS smsc911xSend(END_OBJ *pEnd,M_BLK_ID pMblk)
{
SMSC911XEND_DEVICE *pDrvCtrl = (SMSC911XEND_DEVICE *)pEnd;
int currentKey;
SMSC_TRACE("+smsc911xSend\r\n");
/* This Block is to put the packet sent by the upper layers in a ring Buffer.Here
we are using ReadIndex and WriteIndex instead of allocpending and writepending Queues*/
/* First of all, put the upper layer into the queue.*/
currentKey = intL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -