xemac_intr_dma.c
来自「适合KS8695X」· C语言 代码 · 共 1,345 行 · 第 1/4 页
C
1,345 行
* be serviced.
*/
if (Result != XST_SUCCESS) {
break;
}
InstancePtr->Stats.RecvFrames++;
InstancePtr->Stats.RecvBytes += NumBytes;
/*
* Make the callback to the upper layers, passing it the first
* descriptor in the packet and the number of descriptors in the
* packet.
*/
InstancePtr->SgRecvHandler(InstancePtr->SgRecvRef,
FirstBdPtr, NumBuffers);
/*
* Decrement the packet count register to reflect the fact we
* just processed a packet
*/
XDmaChannel_DecrementPktCount(&InstancePtr->
RecvChannel);
} /* end for loop */
/*
* If the interrupt was an end-ack, check the descriptor list again to
* see if it is empty. If not, go ahead and restart the scatter-gather
* channel. This is to fix a possible race condition where, on receive,
* the driver attempted to start a scatter-gather channel that was
* already started, which resulted in no action from the XDmaChannel
* component. But, just after the XDmaChannel component saw that the
* hardware was already started, the hardware stopped because it
* reached the end of the list. In that case, this interrupt is
* generated and we can restart the hardware here.
*/
if (IntrStatus & XDC_IXR_SG_END_MASK) {
/*
* Ignore the return status since we know the list exists and we
* don't care if the list is empty or the channel is already started.
*/
(void) XDmaChannel_SgStart(&InstancePtr->RecvChannel);
}
}
/*
* All interrupts are handled (except the error below) so acknowledge
* (clear) the interrupts by writing the value read above back to the status
* register. The packet count interrupt must be acknowledged after the
* decrement, otherwise it will come right back. We clear the interrupts
* before we handle the error interrupt because the ErrorHandler should
* result in a reset, which clears the interrupt status register. So we
* don't want to toggle the interrupt back on by writing the interrupt
* status register with an old value after a reset.
*/
XDmaChannel_SetIntrStatus(&InstancePtr->RecvChannel, IntrStatus);
/*
* Check for DMA errors and call the error callback function if an error
* occurred (DMA bus or timeout error), which should result in a reset of
* the device by the upper layer software.
*/
if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
InstancePtr->Stats.DmaErrors++;
InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
}
}
/*****************************************************************************/
/*
*
* Handle an interrupt from the DMA send channel. DMA interrupts are:
*
* - DMA error. DMA encountered a bus error or timeout. This is a fatal error
* that requires reset of the channel. The driver calls the error handler
* of the upper layer software with an error code indicating the device should
* be reset.
* - Packet count threshold reached. For scatter-gather operations, indicates
* the threshold for the number of packets not serviced by software has been
* reached. The driver behaves as follows:
* - Get the value of the packet counter, which tells us how many packets
* are ready to be serviced
* - For each packet
* - For each descriptor, remove it from the scatter-gather list
* - Check for the last descriptor in the frame, and if set
* - Bump frame statistics
* - Call the scatter-gather receive callback function
* - Decrement the packet counter by one
* Note that there are no receive errors reported in the status word of
* the buffer descriptor. If receive errors occur, the MAC drops the
* packet, and we only find out about the errors through various error
* count registers.
* - Packet wait bound reached. For scatter-gather, indicates the time to wait
* for the next packet has expired. The driver follows the same logic as when
* the packet count threshold interrupt is received.
* - Scatter-gather end acknowledge. Hardware has reached the end of the
* descriptor list. The driver follows the same logic as when the packet count
* threshold interrupt is received. In addition, the driver restarts the DMA
* scatter-gather channel in case there are newly inserted descriptors.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
*
* @return
*
* Although the function returns void, there are asynchronous errors
* that can be generated from this function. These are:
* - XST_DMA_SG_LIST_EMPTY indicates we tried to get a buffer descriptor from
* the DMA channel, but there was not one ready for software.
* - XST_DMA_ERROR indicates a DMA bus error or timeout occurred. This is a
* fatal error that requires reset.
*
* @note
*
* None.
*
******************************************************************************/
static void
HandleDmaSendIntr(XEmac * InstancePtr)
{
u32 IntrStatus;
/*
* Read the interrupt status
*/
IntrStatus = XDmaChannel_GetIntrStatus(&InstancePtr->SendChannel);
/*
* For packet threshold or wait bound interrupt, process descriptors. Also
* process descriptors on a SG end acknowledgement, which means the end of
* the descriptor list has been reached by the hardware. For transmit,
* this is a normal condition during times of light traffic. In fact, the
* wait bound interrupt may be masked for transmit since the end-ack would
* always occur before the wait bound expires.
*/
if (IntrStatus & (XDC_IXR_PKT_THRESHOLD_MASK |
XDC_IXR_PKT_WAIT_BOUND_MASK | XDC_IXR_SG_END_MASK)) {
XStatus Result = XST_SUCCESS;
u32 NumFrames;
u32 NumProcessed;
u32 NumBuffers;
u32 NumBytes;
u32 IsLast;
XBufDescriptor *FirstBdPtr;
XBufDescriptor *BdPtr;
/*
* Get the number of unserviced packets
*/
NumFrames = XDmaChannel_GetPktCount(&InstancePtr->SendChannel);
for (NumProcessed = 0; NumProcessed < NumFrames; NumProcessed++) {
IsLast = FALSE;
FirstBdPtr = NULL;
NumBuffers = 0;
NumBytes = 0;
/*
* For each frame, traverse the descriptor list and look for
* errors. On the last one in the frame, make the callback.
*/
while (!IsLast) {
Result =
XDmaChannel_GetDescriptor(&InstancePtr->
SendChannel,
&BdPtr);
if (Result != XST_SUCCESS) {
/*
* An error getting a buffer descriptor from the list.
* This should not happen, but if it does, report it to
* the error callback and break out of the loops to service
* other interrupts
*/
InstancePtr->ErrorHandler(InstancePtr->
ErrorRef,
Result);
break;
}
/*
* Keep a pointer to the first descriptor in the list and
* check the device status for errors. The device status is
* only available in the first descriptor of a packet.
*/
if (FirstBdPtr == NULL) {
u32 XmitStatus;
FirstBdPtr = BdPtr;
XmitStatus =
XBufDescriptor_GetDeviceStatus
(BdPtr);
if (XmitStatus &
XEM_TSR_EXCESS_DEFERRAL_MASK) {
InstancePtr->Stats.
XmitExcessDeferral++;
}
if (XmitStatus &
XEM_TSR_LATE_COLLISION_MASK) {
InstancePtr->Stats.
XmitLateCollisionErrors++;
}
}
NumBytes += XBufDescriptor_GetLength(BdPtr);
/*
* Check to see if this is the last descriptor in the frame,
* and if so, set the IsLast flag to get out of the loop. The
* transmit channel must check the last bit in the control
* word, not the status word (the DMA engine does not update
* the last bit in the status word for the transmit direction).
*/
if (XBufDescriptor_IsLastControl(BdPtr)) {
IsLast = TRUE;
}
/*
* Bump the number of buffers in this packet
*/
NumBuffers++;
} /* end while loop */
/*
* Check for error that occurred inside the while loop, and break
* out of the for loop if there was one so other interrupts can
* be serviced.
*/
if (Result != XST_SUCCESS) {
break;
}
InstancePtr->Stats.XmitFrames++;
InstancePtr->Stats.XmitBytes += NumBytes;
/*
* Make the callback to the upper layers, passing it the first
* descriptor in the packet and the number of descriptors in the
* packet.
*/
InstancePtr->SgSendHandler(InstancePtr->SgSendRef,
FirstBdPtr, NumBuffers);
/*
* Decrement the packet count register to reflect the fact we
* just processed a packet
*/
XDmaChannel_DecrementPktCount(&InstancePtr->
SendChannel);
} /* end for loop */
/*
* If the interrupt was an end-ack, check the descriptor list again to
* see if it is empty. If not, go ahead and restart the scatter-gather
* channel. This is to fix a possible race condition where, on transmit,
* the driver attempted to start a scatter-gather channel that was
* already started, which resulted in no action from the XDmaChannel
* component. But, just after the XDmaChannel component saw that the
* hardware was already started, the hardware stopped because it
* reached the end of the list. In that case, this interrupt is
* generated and we can restart the hardware here.
*/
if (IntrStatus & XDC_IXR_SG_END_MASK) {
/*
* Ignore the return status since we know the list exists and we
* don't care if the list is empty or the channel is already started.
*/
(void) XDmaChannel_SgStart(&InstancePtr->SendChannel);
}
}
/*
* All interrupts are handled (except the error below) so acknowledge
* (clear) the interrupts by writing the value read above back to the status
* register. The packet count interrupt must be acknowledged after the
* decrement, otherwise it will come right back. We clear the interrupts
* before we handle the error interrupt because the ErrorHandler should
* result in a reset, which clears the interrupt status register. So we
* don't want to toggle the interrupt back on by writing the interrupt
* status register with an old value after a reset.
*/
XDmaChannel_SetIntrStatus(&InstancePtr->SendChannel, IntrStatus);
/*
* Check for DMA errors and call the error callback function if an error
* occurred (DMA bus or timeout error), which should result in a reset of
* the device by the upper layer software.
*/
if (IntrStatus & XDC_IXR_DMA_ERROR_MASK) {
InstancePtr->Stats.DmaErrors++;
InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XST_DMA_ERROR);
}
}
/*****************************************************************************/
/*
*
* Handle an interrupt from the Ethernet MAC when configured with scatter-gather
* DMA. The only interrupts handled in this case are errors.
*
* @param InstancePtr is a pointer to the XEmac instance to be worked on.
*
* @return
*
* None.
*
* @note
*
* None.
*
******************************************************************************/
static void
HandleEmacDmaIntr(XEmac * InstancePtr)
{
u32 IntrStatus;
/*
* When configured with DMA, the EMAC generates interrupts only when errors
* occur. We clear the interrupts immediately so that any latched status
* interrupt bits will reflect the true status of the device, and so any
* pulsed interrupts (non-status) generated during the Isr will not be lost.
*/
IntrStatus = XIIF_V123B_READ_IISR(InstancePtr->BaseAddress);
XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, IntrStatus);
/*
* Check the MAC for errors
*/
XEmac_CheckEmacError(InstancePtr, IntrStatus);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?