📄 at91emacend.c
字号:
*
* at91EmacEndInt - handle controller interrupt
*
* This routine is called at interrupt level in response to an interrupt from
* the controller.
*
* RETURNS: N/A.
*/
LOCAL void at91EmacEndInt
(
EMAC_END_DEVICE *pDrvCtrl /* interrupting device */
)
{
UINT32 stat;
at91EmacEndIntCount++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Got an interrupt!\n", 1, 2, 3, 4, 5, 6);
/* Read the device status register */
stat = EMAC_REG(EMAC_ISR);
/* Receive complete */
if ((stat & EMAC_INT_RCOM) == EMAC_INT_RCOM)
{
at91EmacEndIntRCOM++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx complete.\n", 0,0,0,0,0,0);
if (!(pDrvCtrl->rxHandling))
{
pDrvCtrl->rxHandling = TRUE;
netJobAdd ((FUNCPTR)at91EmacEndHandleRcvInt, (int)pDrvCtrl, 0,0,0,0);
EMAC_REG(EMAC_IDR) = EMAC_INT_RCOM; /* disable interrupt to reduce RX interrupts overhead */
}
}
/* Transmit complete */
if ((stat & EMAC_INT_TCOM) == EMAC_INT_TCOM)
{
at91EmacEndIntTCOM++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Tx complete.\n", 0,0,0,0,0,0);
/* The TCOM bit is set even if the transmission failed. */
if ((stat & EMAC_INT_TUND) == EMAC_INT_TUND)
{
at91EmacEndIntTUND++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Tx Buffer underrun.\n", 0,0,0,0,0,0);
}
if ((stat & EMAC_INT_RTRY) == EMAC_INT_RTRY)
{
at91EmacEndIntRTRY++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Transmit Retry limt.\n", 0,0,0,0,0,0);
}
/* send next packet */
(void) at91EmacEndNextSend(pDrvCtrl);
}
/* Receive Buffer Not Available */
if ((stat & EMAC_INT_RBNA) == EMAC_INT_RBNA)
{
at91EmacEndIntRBNA++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx Buffer Not Available.\n", 0,0,0,0,0,0);
/*
* Workaround for errata #11 -> stop and restart receiver
* (occurs even if receive buffer is 64 bytes aligned)
*/
EMAC_REG(EMAC_CTL) &= ~EMAC_CTL_RE;
EMAC_REG(EMAC_CTL) |= EMAC_CTL_RE;
}
/* Rx Overrun */
if ((stat & EMAC_INT_ROVR) == EMAC_INT_ROVR)
{
at91EmacEndIntROVR++;
EMAC_END_LOG (EMAC_END_DBG_INT, "at91EmacEndInt: Rx Overrun.\n", 0,0,0,0,0,0);
}
}
/*******************************************************************************
*
* at91EmacEndRecv - process the next incoming packet
*
* Handle one incoming packet. The packet is checked for errors.
*
* RETURNS: N/A.
*/
LOCAL STATUS at91EmacEndRecv
(
EMAC_END_DEVICE * pDrvCtrl, /* device structure */
char * pData, /* packet to process */
int len /* length of packet to process */
)
{
M_BLK_ID pMblk;
char * pNewCluster;
CL_BLK_ID pClBlk;
/*
* loaning is not used here (due to alignement required for IP Header),
* the data must be copied before being passed up to the protocols.
*/
pNewCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId);
if (pNewCluster == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Cannot Get Cluster !\n", 1, 2, 3, 4, 5, 6);
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
return(ERROR);
}
/* Grab a cluster block to marry to the cluster we received. */
if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL)
{
netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Out of Cluster Blocks!\n", 1, 2, 3, 4, 5, 6);
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
return(ERROR);
}
if ((pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL)
{
netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk);
netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pNewCluster);
EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Out of M Blocks!\n", 1, 2, 3, 4, 5, 6);
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1);
return(ERROR);
}
/* make the packet data coherent */
END_CACHE_INVALIDATE (pData, len);
/* Join the cluster to the MBlock */
netClBlkJoin (pClBlk, pNewCluster, len, NULL, 0, 0, 0);
netMblkClJoin (pMblk, pClBlk);
END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1);
/* copy the data */
pMblk->mBlkHdr.mData += 2; /* Hints to ensure that IP header is word aligned !!! */
/* Dest MAC + Src MAC + length/Type = 14 bytes */
bcopy (pData, pMblk->mBlkHdr.mData, len);
pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */
pMblk->mBlkHdr.mLen = len; /* set the data len */
pMblk->mBlkPktHdr.len = len; /* set the total len */
at91EmacEndNumRecv++;
EMAC_END_LOG (EMAC_END_DBG_RX, "at91EmacEndRecv: Calling upper layer!\n", 1, 2, 3, 4, 5, 6);
/* Call the upper layer's receive routine. */
END_RCV_RTN_CALL(&pDrvCtrl->end, pMblk);
return (OK);
}
/*******************************************************************************
*
* at91EmacEndHandleRcvInt - 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.
*
* RETURNS: N/A.
*/
LOCAL void at91EmacEndHandleRcvInt
(
EMAC_END_DEVICE *pDrvCtrl /* interrupting device */
)
{
int len;
char * pData;
int nLoop = 0;
EMAC_END_LOG(EMAC_END_DBG_RX,"at91EmacEndHandleRcvInt: Entering...\n", 1, 2, 3, 4, 5, 6 );
pDrvCtrl->rxHandling = TRUE;
/* check for all packet received */
while ((pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs & RXBUF_ADD_OWNED) == RXBUF_ADD_OWNED)
{
len = pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status & RXBUF_STAT_LEN_MASK; /* size including FCS */
pData = (char *) (pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs & RXBUF_ADD_BASE_MASK);
EMAC_END_LOG(EMAC_END_DBG_RX,"rxIndex = %i, adrs = 0x%x, status = 0x%08x\n",
pDrvCtrl->rxIndex,
pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs,
pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status,
4, 5, 6);
#ifdef DELAY_RX
EMAC_END_LOG_DELAY(EMAC_END_DBG_RX);
#endif /* DELAY_RX */
at91EmacEndRecv(pDrvCtrl, pData, len);
/* give back buffer to DMA */
pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].status = 0;
pDrvCtrl->rxHdrs[pDrvCtrl->rxIndex].adrs &= ~RXBUF_ADD_OWNED;
/* update index */
if (pDrvCtrl->rxIndex == (pDrvCtrl->rxNum - 1))
{
pDrvCtrl->rxIndex = 0;
}
else
{
pDrvCtrl->rxIndex++;
}
nLoop++;
}
/* update watermark */
if (nLoop > at91EmacEndMaxLoopRecv)
{
at91EmacEndMaxLoopRecv = nLoop;
}
pDrvCtrl->rxHandling = FALSE;
EMAC_REG(EMAC_IER) = EMAC_INT_RCOM; /* re-enable RX interrupt */
EMAC_END_LOG(EMAC_END_DBG_RX,"at91EmacEndHandleRcvInt: End.\n", 1, 2, 3, 4, 5, 6 );
}
/*******************************************************************************
*
* at91EmacEndSend - the driver send routine
*
* This routine takes a M_BLK_ID sends off the data in the M_BLK_ID.
* The buffer must already have the addressing information properly installed
* in it. This is done by a higher layer. The last arguments are a free
* routine to be called when the device is done with the buffer and a pointer
* to the argument to pass to the free routine.
*
* RETURNS: OK, ERROR, or END_ERR_BLOCK.
*/
LOCAL STATUS at91EmacEndSend
(
EMAC_END_DEVICE * pDrvCtrl, /* device ptr */
M_BLK_ID pMblk /* data to send */
)
{
int oldLevel = 0;
int length;
char * pBuf;
volatile TXBUF_HDR * pBufHdr;
if (pDrvCtrl->flags & EMAC_POLLING)
{
return(ERROR);
}
/*
* Obtain exclusive access to transmitter. This is necessary because
* we might have more than one stack transmitting at once.
*/
END_TX_SEM_TAKE (&pDrvCtrl->end, WAIT_FOREVER);
/* check if buffer available (tx underrun ?) */
pBufHdr = (volatile TXBUF_HDR *) &pDrvCtrl->txHdrs[pDrvCtrl->txIndexWr];
if (pBufHdr->inUse)
{
at91EmacEndNumTXRetry++;
EMAC_END_LOG(EMAC_END_DBG_TX,"at91EmacEndSend: TX buffer underrun !\n", 1, 2, 3, 4, 5, 6 );
END_TX_SEM_GIVE (&pDrvCtrl->end);
return(END_ERR_BLOCK);
}
/* put packet to transmit in TX queue (use txIndexWr) */
pBuf = pBufHdr->pAdrs;
length = netMblkToBufCopy (pMblk, pBuf, NULL);
length = max (ETHERSMALL, length);
pBufHdr->length = length;
pBufHdr->inUse = TRUE;
/* next index */
if (pDrvCtrl->txIndexWr == (pDrvCtrl->txNum -1))
{
pDrvCtrl->txIndexWr = 0;
}
else
{
pDrvCtrl->txIndexWr++;
}
EMAC_END_LOG(EMAC_END_DBG_TX,"at91EmacEndSend: enqueue -> pMblk=0x%x, pBuf=0x%x, len=%i\n",
(int) pMblk, (int) pBuf, length, 4, 5, 6 );
END_CACHE_FLUSH(pBuf,length);
/* initiate transmit of next packet (if required) (use txIndexRd) */
oldLevel = intLock (); /* protect at91EmacEndInt */
/* send next packet */
(void) at91EmacEndNextSend(pDrvCtrl);
intUnlock (oldLevel);
END_TX_SEM_GIVE (&pDrvCtrl->end);
/* Bump the statistics counters. */
END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1);
/*
* Cleanup. free the mblk chain
* after the device is finished with the TFD.
*/
netMblkClChainFree (pMblk);
return (OK);
}
/*******************************************************************************
*
* at91EmacEndIoctl - the driver I/O control routine
*
* Process an ioctl request.
*
* RETURNS: A command specific response, usually OK or ERROR.
*/
LOCAL int at91EmacEndIoctl
(
EMAC_END_DEVICE * pDrvCtrl, /* device receiving command */
int cmd, /* ioctl command code */
caddr_t data /* command argument */
)
{
int error = 0;
long value;
switch ((unsigned)cmd)
{
case EIOCSADDR: /* set MAC address */
if (data == NULL)
return(EINVAL);
bcopy ((char *)data, (char *)END_HADDR(&pDrvCtrl->end),
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCGADDR: /* get MAC address */
if (data == NULL)
return(EINVAL);
bcopy ((char *)END_HADDR(&pDrvCtrl->end), (char *)data,
END_HADDR_LEN(&pDrvCtrl->end));
break;
case EIOCSFLAGS: /* set (or clear) flags */
value = (long)data;
if (value < 0)
{
value = -value;
value--;
END_FLAGS_CLR (&pDrvCtrl->end, value);
}
else
{
END_FLAGS_SET (&pDrvCtrl->end, value);
}
at91EmacEndConfig (pDrvCtrl);
break;
case EIOCGFLAGS: /* get flags */
*(int *)data = END_FLAGS_GET(&pDrvCtrl->end);
break;
case EIOCPOLLSTART: /* Begin polled operation */
at91EmacEndPollStart (pDrvCtrl);
break;
case EIOCPOLLSTOP: /* End polled operation */
at91EmacEndPollStop (pDrvCtrl);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -