/** * * This is the DMA TX Interrupt handler function. * * @param Callback is a pointer to TX channel of the DMA engine. * * @return None. * * @note This Interrupt handler MUST clear pending interrupts before * handling them by calling the call back. Otherwise the following * corner case could raise some issue: * * - A packet was transmitted and asserted an TX interrupt, and if * this interrupt handler calls the call back before clears the * interrupt, another packet could get transmitted (and assert the * interrupt) between when the call back function returned and when * the interrupt clearing operation begins, and the interrupt * clearing operation will clear the interrupt raised by the second * packet and won't never process its according buffer descriptors * until a new interrupt occurs. * * Changing the sequence to "Clear interrupts, then handle" solve this * issue. If the interrupt raised by the second packet is before the * the interrupt clearing operation, the descriptors associated with * the second packet must have been finished by hardware and ready for * the handling by the call back; otherwise, the interrupt raised by * the second packet is after the interrupt clearing operation, * the packet's buffer descriptors will be handled by the call back in * current pass, if the descriptors are finished before the call back * is invoked, or next pass otherwise. Please note that if the second * packet is handled by the call back in current pass, the next pass * could find no buffer descriptor finished by the hardware. * ******************************************************************************/ static void TxIntrHandler(XLlDma_BdRing * TxRingPtr) { u32 IrqStatus; /* Read pending interrupts */ IrqStatus = XLlDma_BdRingGetIrq(TxRingPtr); /* Acknowledge pending interrupts */ XLlDma_BdRingAckIrq(TxRingPtr, IrqStatus); /* If error interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if ((IrqStatus & XLLDMA_IRQ_ALL_ERR_MASK)) { DeviceErrors++; TemacUtilErrorTrap ("LlDma: Error: IrqStatus & XLLDMA_IRQ_ALL_ERR_MASK"); XLlDma_Reset(&DmaInstance); return; } /* * If Transmit done interrupt is asserted, call TX call back function * to handle the processed BDs and raise the according flag */ if ((IrqStatus & (XLLDMA_IRQ_DELAY_MASK | XLLDMA_IRQ_COALESCE_MASK))) { TxCallBack(TxRingPtr); } }
/* * * This is the DMA TX Interrupt handler function. * * It gets the interrupt status from the hardware, acknowledges it, and if any * error happens, it resets the hardware. Otherwise, if a completion interrupt * presents, then it calls the callback function. * * @param Callback is a pointer to TX channel of the DMA engine. * * @return None. * * @note None. * ******************************************************************************/ static void TxIntrHandler(void *Callback) { XAxiDma_BdRing *TxRingPtr = (XAxiDma_BdRing *) Callback; u32 IrqStatus; int TimeOut; /* Read pending interrupts */ IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); /* Acknowledge pending interrupts */ XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); /* If no interrupt is asserted, we do not do anything */ if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { return; } /* * If error interrupt is asserted, raise error flag, reset the * hardware to recover from the error, and return with no further * processing. */ if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { XAxiDma_BdRingDumpRegs(TxRingPtr); Error = 1; /* * Reset should never fail for transmit channel */ XAxiDma_Reset(&AxiDma); TimeOut = RESET_TIMEOUT_COUNTER; while (TimeOut) { if (XAxiDma_ResetIsDone(&AxiDma)) { break; } TimeOut -= 1; } return; } /* * If Transmit done interrupt is asserted, call TX call back function * to handle the processed BDs and raise the according flag */ if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { TxCallBack(TxRingPtr); } }