/** * Retrieve BDs that have been processed by the SGDMA channel. This function is * called typically after the XTE_HANDLER_SGRECV handler has been invoked for * the receive channel or XTE_HANDLER_SGSEND for the transmit channel. * * The set of BDs returned is a list starting with the BdPtr and extending * for 1 or more BDs (the exact number is the return value of this function). * The list can be navigated with macros XTemac_mSgRecvBdNext() for the * XTE_RECV channel, and XTemac_mSgSendBdNext() for the XTE_SEND channel. * Treat the returned BDs as read-only. * * This function and XTemac_SgFree() must be called in the correct order. See * xtemac.h for more information on the SGDMA use model. * * The last BD in the returned list is guaranteed to have the "Last" bit set * (i.e. XDmaBdV2_IsLast evaluates to true). * * The returned BDs can be examined for the outcome of the SGDMA transaction. * * @param InstancePtr is a pointer to the instance to be worked on. * @param Direction is the channel to address (XTE_SEND or XTE_RECV). * @param BdPtr is an output parameter that points to the 1st BD in the returned * list. If no BDs were ready, then this parameter is unchanged. * @param NumBd is an upper limit to the number of BDs to retrieve. * * @return * Number of BDs that are ready for post processing. If the direction parameter * is invalid, then 0 is returned. * * @note * This function is not thread-safe. The user must provide mutually exclusive * access to this function if there are to be multiple threads that can call it. * ******************************************************************************/ unsigned XTemac_SgGetProcessed(XTemac * InstancePtr, u32 Direction, unsigned NumBd, XDmaBdV2 ** BdPtr) { u32 DgieReg; XDmaV2 *DmaPtr; unsigned Rc; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(BdPtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* Which channel to address */ if (Direction == XTE_RECV) { DmaPtr = &InstancePtr->RecvDma; } else if (Direction == XTE_SEND) { DmaPtr = &InstancePtr->SendDma; } else { return (0); } /* This is a critical section. Prevent interrupts from the device while * the BD ring is being modified. */ DgieReg = XTemac_mGetIpifReg(XTE_DGIE_OFFSET); XTemac_mSetIpifReg(XTE_DGIE_OFFSET, 0); /* Extract ready BDs */ Rc = XDmaV2_SgBdFromHw(DmaPtr, NumBd, BdPtr); /* This is where we ack IPXR_PCTR interrupt for the dma channel. This * cannot be done in XTemac_IntrSgDmaHandler() because HW will keep the * interrupt asserted as long as the DMA channel's PCT > threshold. Calling * SgBdFromHw above will decrement PCT which should in most cases allow * the acknowledgement to take effect. * * We have to read the status 1st and test it before clearing * it. Bloody toggle-on-write statuses. Grrrr! */ if (XDmaV2_GetInterruptStatus(DmaPtr) & XDMAV2_IPXR_PCTR_MASK) { XDmaV2_SetInterruptStatus(DmaPtr, XDMAV2_IPXR_PCTR_MASK); } /* End critical section */ XTemac_mSetIpifReg(XTE_DGIE_OFFSET, DgieReg); return (Rc); }
/** * * Master interrupt handler for FIFO direct frame transfer mode. This routine * will query the status of the device, bump statistics, and invoke user * callbacks in the following priority: * * - XTE_HANDLER_ERROR for error class XST_PFIFO_DEADLOCK. * - XTE_HANDLER_ERROR for error class XST_DMA_ERROR for reads. * - XTE_HANDLER_FIFODMAREAD for successfull DMA reads * - XTE_HANDLER_ERROR for error class XST_DMA_ERROR for writes. * - XTE_HANDLER_FIFODMAWRITE for successfull DMA writes * - XTE_HANDLER_ERROR for error class XST_FIFO_ERROR. * - XTE_HANDLER_FIFORECV for newly received frames * - XTE_HANDLER_ERROR for error class XST_SEND_ERROR. * - XTE_HANDLER_FIFOSEND for completed transmits * - XTE_HANDLER_ERROR for error class XST_RECV_ERROR. * * This routine must be connected to an interrupt controller using OS/BSP * specific methods. * * @param InstancePtr is a pointer to the TEMAC instance that has caused the * interrupt. * * @return None * ******************************************************************************/ void XTemac_IntrFifoHandler(void *TemacPtr) { u32 RegDISR; u32 CorePending; u32 RegMisc; u32 Bytes; unsigned Cnt; XTemac *InstancePtr = (XTemac *) TemacPtr; XASSERT_VOID(InstancePtr != NULL); /* This ISR will try to handle as many interrupts as it can in a single * call. However, in most of the places where the user's error handler is * called, this ISR exits because it is expected that the user will reset * the device most of the time. */ /* Log interrupt */ XTemac_mBumpStats(Interrupts, 1); /* Get top level interrupt status. The status is self clearing when the * interrupt source is cleared */ RegDISR = XTemac_mGetIpifReg(XTE_DISR_OFFSET); /* Handle IPIF and packet FIFO errors */ if (RegDISR & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK | XTE_DXR_RECV_FIFO_MASK | XTE_DXR_SEND_FIFO_MASK)) { /* IPIF transaction or data phase error */ if (RegDISR & (XTE_DXR_DPTO_MASK | XTE_DXR_TERR_MASK)) { XTemac_mBumpStats(IpifErrors, 1); ERR_HANDLER(XST_IPIF_ERROR, RegDISR, 0); return; } /* Receive packet FIFO is deadlocked */ if (RegDISR & XTE_DXR_RECV_FIFO_MASK) { XTemac_mBumpStats(RxPktFifoErrors, 1); ERR_HANDLER(XST_PFIFO_DEADLOCK, XTE_RECV, 0); return; } /* Transmit packet FIFO is deadlocked */ if (RegDISR & XTE_DXR_SEND_FIFO_MASK) { XTemac_mBumpStats(TxPktFifoErrors, 1); ERR_HANDLER(XST_PFIFO_DEADLOCK, XTE_SEND, 0); return; } } /* Handle receive side simple DMA channel interrupt. Read and ack the * DMA's interrupt status. If an error is indicated then call the * error handler. If a transfer complete is indicated then call the * DMA read handler */ if (RegDISR & XTE_DXR_RECV_DMA_MASK) { RegMisc = XDmaV2_GetInterruptStatus(&InstancePtr->RecvDma); XDmaV2_SetInterruptStatus(&InstancePtr->RecvDma, RegMisc); if (RegMisc & XDMAV2_IPXR_DE_MASK) { XTemac_mBumpStats(RxDmaErrors, 1); ERR_HANDLER(XST_DMA_ERROR, XTE_RECV, XDmaV2_mGetStatus(&InstancePtr->RecvDma)); return; } if (RegMisc & XDMAV2_IPXR_DD_MASK) { Bytes = InstancePtr->DmaReadLengthRef; InstancePtr->DmaReadLengthRef = 0; DMAREAD_HANDLER(Bytes); } } /* Handle send side simple DMA channel interrupt. Read and ack the * DMA's interrupt status. If an error is indicated then call the * error handler. If a transfer complete is indicated then call the * DMA write handler */ if (RegDISR & XTE_DXR_SEND_DMA_MASK) { RegMisc = XDmaV2_GetInterruptStatus(&InstancePtr->SendDma); XDmaV2_SetInterruptStatus(&InstancePtr->SendDma, RegMisc); if (RegMisc & XDMAV2_IPXR_DE_MASK) { XTemac_mBumpStats(TxDmaErrors, 1); ERR_HANDLER(XST_DMA_ERROR, XTE_SEND, XDmaV2_mGetStatus(&InstancePtr->SendDma)); return; } if (RegMisc & XDMAV2_IPXR_DD_MASK) { Bytes = InstancePtr->DmaWriteLengthRef; InstancePtr->DmaWriteLengthRef = 0; DMAWRITE_HANDLER(Bytes); } } /* Handle core interrupts */ if (RegDISR & XTE_DXR_CORE_MASK) { /* Calculate which enabled interrupts have been asserted */ CorePending = XTemac_mGetIpifReg(XTE_IPIER_OFFSET) & XTemac_mGetIpifReg(XTE_IPISR_OFFSET); /* Check for fatal status/length FIFO errors. These errors can't be * cleared */ if (CorePending & XTE_IPXR_FIFO_FATAL_ERROR_MASK) { XTemac_mBumpStats(FifoErrors, 1); ERR_HANDLER(XST_FIFO_ERROR, CorePending & XTE_IPXR_FIFO_FATAL_ERROR_MASK, 0); return; } /* A receive packet has arrived. Call the receive handler. * * Acking this interrupt is not done here. The handler has a choice: * 1) Call XTemac_FifoRecv() which will ack this interrupt source, or * 2) Call XTemac_IntrFifoDisable() and defer XTEmac_FifoRecv() to a * later time. Failure to do one of these actions will leave this * interupt still pending resulting in an exception loop. */ if (CorePending & XTE_IPXR_RECV_DONE_MASK) { FIFORECV_HANDLER(); } /* A transmit has completed. Pull off all statuses that are available. * For each status that contains a non-fatal error, the error handler * is invoked. For fatal errors, the error handler is invoked once and * assumes the callback will reset the device. * * Unless there was a fatal error, then call the send handler since * resources in the packet FIFO, transmit length FIFO, and transmit * status FIFO have been freed up. This gives the handler a chance * to enqueue new frame(s). */ if (CorePending & XTE_IPXR_XMIT_DONE_MASK) { Cnt = 0; /* While XMIT_DONE persists */ do { /* Get TSR, try to clear XMIT_DONE */ RegMisc = XTemac_mGetIpifReg(XTE_TSR_OFFSET); XTemac_mSetIpifReg(XTE_IPISR_OFFSET, XTE_IPXR_XMIT_DONE_MASK); /* Does TSR indicate error? */ if (RegMisc & XTE_TSR_ERROR_MASK) { XTemac_mBumpStats(TxStatusErrors, 1); ERR_HANDLER(XST_SEND_ERROR, RegMisc, 0); /* Fatal errors end processing immediately */ if (RegMisc & XTE_TSR_PFIFOU_MASK) { return; } } Cnt++; /* Read IPISR and test XMIT_DONE again */ RegMisc = XTemac_mGetIpifReg(XTE_IPISR_OFFSET); } while (RegMisc & XTE_IPXR_XMIT_DONE_MASK); FIFOSEND_HANDLER(Cnt); } /* Check for dropped receive frame. Ack the interupt then call the * error handler */ if (CorePending & XTE_IPXR_RECV_DROPPED_MASK) { XTemac_mSetIpifReg(XTE_IPISR_OFFSET, CorePending & XTE_IPXR_RECV_DROPPED_MASK); XTemac_mBumpStats(RxRejectErrors, 1); ERR_HANDLER(XST_RECV_ERROR, CorePending & XTE_IPXR_RECV_DROPPED_MASK, 0); /* no return here, nonfatal error */ } } }