📄 xemac_intr_fifo.c
字号:
* of the hardware is reflected (we have to do this because the status * is level in the device but latched in the interrupt status register). */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_LFIFO_EMPTY_MASK); return XST_NO_DATA; } /* * If configured with DMA, make sure the DMA engine is not busy */ if (XEmac_mIsDma(InstancePtr)) { if (XDmaChannel_GetStatus(&InstancePtr->RecvChannel) & XDC_DMASR_BUSY_MASK) { return XST_DEVICE_BUSY; } } /* * Determine, from the MAC, the length of the next packet available * in the data FIFO (there should be a non-zero length here) */ PktLength = XIo_In32(InstancePtr->BaseAddress + XEM_RPLR_OFFSET); if (PktLength == 0) { return XST_NO_DATA; } /* * We assume that the MAC never has a length bigger than the largest * Ethernet frame, so no need to make another check here. * * Receive either by directly reading the FIFO or using the DMA engine */ if (!XEmac_mIsDma(InstancePtr)) { /* * This is a non-blocking read. The FIFO returns an error if there is * not at least the requested amount of data in the FIFO. */ Result = XPacketFifoV200a_Read(&InstancePtr->RecvFifo, BufPtr, PktLength); if (Result != XST_SUCCESS) { return Result; } } else { /* * Call on DMA to transfer from the FIFO to the buffer. First set up * the DMA control register. */ XDmaChannel_SetControl(&InstancePtr->RecvChannel, XDC_DMACR_DEST_INCR_MASK | XDC_DMACR_SOURCE_LOCAL_MASK | XDC_DMACR_SG_DISABLE_MASK); /* * Now transfer the data */ XDmaChannel_Transfer(&InstancePtr->RecvChannel, (Xuint32 *)(InstancePtr->BaseAddress + XEM_PFIFO_RXDATA_OFFSET), (Xuint32 *)BufPtr, PktLength); /* * Poll here waiting for DMA to be not busy. We think this will * typically be a single read since DMA should be ahead of the SW. */ do { StatusReg = XDmaChannel_GetStatus(&InstancePtr->RecvChannel); } while (StatusReg & XDC_DMASR_BUSY_MASK); /* Return an error if there was a problem with DMA */ if ((StatusReg & XDC_DMASR_BUS_ERROR_MASK) || (StatusReg & XDC_DMASR_BUS_TIMEOUT_MASK)) { InstancePtr->Stats.DmaErrors++; return XST_DMA_ERROR; } } *ByteCountPtr = PktLength; InstancePtr->Stats.RecvFrames++; InstancePtr->Stats.RecvBytes += PktLength; return XST_SUCCESS;}/*****************************************************************************//**** The interrupt handler for the Ethernet driver when configured for direct FIFO* communication or simple DMA.** Get the interrupt status from the IpIf to determine the source of the* interrupt. The source can be: MAC, Recv Packet FIFO, or Send Packet FIFO.* The packet FIFOs only interrupt during "deadlock" conditions. All other* FIFO-related interrupts are generated by the MAC.** @param InstancePtr is a pointer to the XEmac instance that just interrupted.** @return** None.** @note** None.*******************************************************************************/void XEmac_IntrHandlerFifo(void *InstancePtr){ Xuint32 IntrStatus; XEmac *EmacPtr = (XEmac *)InstancePtr; EmacPtr->Stats.TotalIntrs++; /* * Get the interrupt status from the IPIF. There is no clearing of * interrupts in the IPIF. Interrupts must be cleared at the source. */ IntrStatus = XIIF_V123B_READ_DIPR(EmacPtr->BaseAddress); if (IntrStatus & XEM_IPIF_EMAC_MASK) /* MAC interrupt */ { EmacPtr->Stats.EmacInterrupts++; HandleEmacFifoIntr(EmacPtr); } if (IntrStatus & XEM_IPIF_RECV_FIFO_MASK) /* Receive FIFO interrupt */ { EmacPtr->Stats.RecvInterrupts++; XEmac_CheckFifoRecvError(EmacPtr); } if (IntrStatus & XEM_IPIF_SEND_FIFO_MASK) /* Send FIFO interrupt */ { EmacPtr->Stats.XmitInterrupts++; XEmac_CheckFifoSendError(EmacPtr); } if (IntrStatus & XIIF_V123B_ERROR_MASK) { /* * An error occurred internal to the IPIF. This is more of a debug and * integration issue rather than a production error. Don't do anything * other than clear it, which provides a spot for software to trap * on the interrupt and begin debugging. */ XIIF_V123B_WRITE_DISR(EmacPtr->BaseAddress, XIIF_V123B_ERROR_MASK); }}/*****************************************************************************//**** Set the callback function for handling confirmation of transmitted frames when* configured for direct memory-mapped I/O using FIFOs. The upper layer software* should call this function during initialization. The callback is called by the* driver once per frame sent. The callback is responsible for freeing the* transmitted buffer if necessary.** The callback is invoked by the driver within interrupt context, so it needs* to do its job quickly. If there are potentially slow operations within the* callback, these should be done at task-level.** @param InstancePtr is a pointer to the XEmac instance to be worked on.* @param CallBackRef is a reference pointer to be passed back to the adapter in* the callback. This helps the adapter correlate the callback to a* particular driver.* @param FuncPtr is the pointer to the callback function.** @return** None.** @note** None.*******************************************************************************/void XEmac_SetFifoRecvHandler(XEmac *InstancePtr, void *CallBackRef, XEmac_FifoHandler FuncPtr){ XASSERT_VOID(InstancePtr != XNULL); XASSERT_VOID(FuncPtr != XNULL); XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); InstancePtr->FifoRecvHandler = FuncPtr; InstancePtr->FifoRecvRef = CallBackRef;}/*****************************************************************************//**** Set the callback function for handling received frames when configured for* direct memory-mapped I/O using FIFOs. The upper layer software should call* this function during initialization. The callback is called once per frame* received. During the callback, the upper layer software should call FifoRecv* to retrieve the received frame.** The callback is invoked by the driver within interrupt context, so it needs* to do its job quickly. Sending the received frame up the protocol stack* should be done at task-level. If there are other potentially slow operations* within the callback, these too should be done at task-level.** @param InstancePtr is a pointer to the XEmac instance to be worked on.* @param CallBackRef is a reference pointer to be passed back to the adapter in* the callback. This helps the adapter correlate the callback to a* particular driver.* @param FuncPtr is the pointer to the callback function.** @return** None.** @note** None.*******************************************************************************/void XEmac_SetFifoSendHandler(XEmac *InstancePtr, void *CallBackRef, XEmac_FifoHandler FuncPtr){ XASSERT_VOID(InstancePtr != XNULL); XASSERT_VOID(FuncPtr != XNULL); XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); InstancePtr->FifoSendHandler = FuncPtr; InstancePtr->FifoSendRef = CallBackRef;}/******************************************************************************** Handle an interrupt from the Ethernet MAC when configured for direct FIFO* communication. The interrupts handled are:* - Transmit done (transmit status FIFO is non-empty). Used to determine when* a transmission has been completed.* - Receive done (receive length FIFO is non-empty). Used to determine when a* valid frame has been received.** In addition, the interrupt status is checked for errors.** @param InstancePtr is a pointer to the XEmac instance to be worked on.** @return** None.** @note** None.*******************************************************************************/static void HandleEmacFifoIntr(XEmac *InstancePtr){ Xuint32 IntrStatus; /* * The EMAC generates interrupts for errors and generates the transmit * and receive done interrupts for data. 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); if (IntrStatus & XEM_EIR_RECV_DONE_MASK) { /* * Configured for direct memory-mapped I/O using FIFO with interrupts. * This interrupt means the RPLR is non-empty, indicating a frame has * arrived. */ InstancePtr->Stats.RecvInterrupts++; InstancePtr->FifoRecvHandler(InstancePtr->FifoRecvRef); /* * The upper layer has removed as many frames as it wants to, so we * need to clear the RECV_DONE bit before leaving the ISR so that it * reflects the current state of the hardware (because it's a level * interrupt that is latched in the IPIF interrupt status register). * Note that if we've reached this point the bit is guaranteed to be * set because it was cleared at the top of this ISR before any frames * were serviced, so the bit was set again immediately by hardware * because the RPLR was not yet emptied by software. */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_RECV_DONE_MASK); } /* * If configured for direct memory-mapped I/O using FIFO, the xmit status * FIFO must be read and the callback invoked regardless of success or not. */ if (IntrStatus & XEM_EIR_XMIT_DONE_MASK) { Xuint32 XmitStatus; InstancePtr->Stats.XmitInterrupts++; XmitStatus = XIo_In32(InstancePtr->BaseAddress + XEM_TSR_OFFSET); /* * Collision errors are stored in the transmit status register * instead of the interrupt status register */ if (XmitStatus & XEM_TSR_EXCESS_DEFERRAL_MASK) { InstancePtr->Stats.XmitExcessDeferral++; } if (XmitStatus & XEM_TSR_LATE_COLLISION_MASK) { InstancePtr->Stats.XmitLateCollisionErrors++; } InstancePtr->FifoSendHandler(InstancePtr->FifoSendRef); /* * Only one status is retrieved per interrupt. We need to clear the * XMIT_DONE bit before leaving the ISR so that it reflects the current * state of the hardware (because it's a level interrupt that is latched * in the IPIF interrupt status register). Note that if we've reached * this point the bit is guaranteed to be set because it was cleared at * the top of this ISR before any statuses were serviced, so the bit was * set again immediately by hardware because the TSR was not yet emptied * by software. */ XIIF_V123B_WRITE_IISR(InstancePtr->BaseAddress, XEM_EIR_XMIT_DONE_MASK); } /* * Check the MAC for errors */ XEmac_CheckEmacError(InstancePtr, IntrStatus);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -