/** * Reset both TX and RX channels of a DMA engine. * * Any DMA transaction in progress aborts immediately. The DMA engine is in * stop state after the reset. * * @param InstancePtr is a pointer to the DMA engine instance to be worked on. * * @return None. * * @note * - If the hardware is not working properly, this function will enter * infinite loop and never return. * - After the reset, the Normal mode is enabled, and the overflow error * for both TX/RX channels are disabled. * - After the reset, the DMA engine is no longer in pausing state, if * the DMA engine is paused before the reset operation. * - After the reset, the coalescing count value and the delay timeout * value are both set to 1 for TX and RX channels. * - After the reset, all interrupts are disabled. * ******************************************************************************/ void XLlDma_Reset(XLlDma * InstancePtr) { u32 IrqStatus; XLlDma_BdRing *TxRingPtr, *RxRingPtr; TxRingPtr = &XLlDma_mGetTxRing(InstancePtr); RxRingPtr = &XLlDma_mGetRxRing(InstancePtr); /* Save the locations of current BDs both rings are working on * before the reset so later we can resume the rings smoothly. */ XLlDma_mBdRingSnapShotCurrBd(TxRingPtr); XLlDma_mBdRingSnapShotCurrBd(RxRingPtr); /* Start reset process then wait for completion */ XLlDma_mSetCr(InstancePtr, XLLDMA_DMACR_SW_RESET_MASK); /* Loop until the reset is done */ while ((XLlDma_mGetCr(InstancePtr) & XLLDMA_DMACR_SW_RESET_MASK)) { } /* Disable all interrupts after issue software reset */ XLlDma_mBdRingIntDisable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); XLlDma_mBdRingIntDisable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* Clear Interrupt registers of both channels, as the software reset * does not clear any register values. Not doing so will cause * interrupts asserted after the software reset if there is any * interrupt left over before. */ IrqStatus = XLlDma_mBdRingGetIrq(TxRingPtr); XLlDma_mBdRingAckIrq(TxRingPtr, IrqStatus); IrqStatus = XLlDma_mBdRingGetIrq(RxRingPtr); XLlDma_mBdRingAckIrq(RxRingPtr, IrqStatus); /* Enable Normal mode, and disable overflow errors for both channels */ XLlDma_mSetCr(InstancePtr, XLLDMA_DMACR_TAIL_PTR_EN_MASK | XLLDMA_DMACR_RX_OVERFLOW_ERR_DIS_MASK | XLLDMA_DMACR_TX_OVERFLOW_ERR_DIS_MASK); /* Set TX/RX Channel coalescing setting */ XLlDma_BdRingSetCoalesce(TxRingPtr, 1, 1); XLlDma_BdRingSetCoalesce(RxRingPtr, 1, 1); TxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; RxRingPtr->RunState = XST_DMA_SG_IS_STOPPED; }
/** * * This example sends and receives a single packet in loopback mode with checksum * offloading support. * * The transmit frame will be checksummed over the entire Ethernet payload * and inserted into the last 2 bytes of the frame. * * On receive, HW should calculate the Ethernet payload checksum and return a * value of 0xFFFF which means the payload data was likely not corrupted. * * @param TemacInstancePtr is a pointer to the instance of the Temac * component. * * @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int TemacSgDmaChecksumOffloadExample(XLlTemac * TemacInstancePtr, XLlDma * DmaInstancePtr) { int Status; u32 TxFrameLength; int PayloadSize = 1000; XLlDma_BdRing *RxRingPtr = &XLlDma_mGetRxRing(DmaInstancePtr); XLlDma_BdRing *TxRingPtr = &XLlDma_mGetTxRing(DmaInstancePtr); XLlDma_Bd *BdPtr; /* * Cannot run this example if checksum offloading support is not available */ if (!(XLlTemac_IsRxCsum(TemacInstancePtr) && XLlTemac_IsTxCsum(TemacInstancePtr))) { TemacUtilErrorTrap("Checksum offloading not available"); return XST_FAILURE; } /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; /* * Calculate frame length (not including FCS) */ TxFrameLength = XTE_HDR_SIZE + PayloadSize; /* * Setup the packet to be transmitted, * Last 2 bytes are reserved for checksum */ TemacUtilFrameMemClear(&TxFrame); TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC); TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize); TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize - 2); /* * Flush the TX frame before giving it to DMA TX channel to transmit, * in case D-Caching is turned on. */ XCACHE_FLUSH_DCACHE_RANGE(&TxFrame, TxFrameLength); /* * Clear out receive packet memory area */ TemacUtilFrameMemClear(&RxFrame); /* * Invalidate the RX frame before giving it to DMA RX channel to * receive data, in case D-Caching is turned on. */ XCACHE_INVALIDATE_DCACHE_RANGE(&RxFrame, TxFrameLength); /* * Interrupt coalescing parameters are set to their default settings * which is to interrupt the processor after every frame has been * processed by the DMA engine. */ Status = XLlDma_BdRingSetCoalesce(TxRingPtr, 1, 1); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting coalescing for transmit"); return XST_FAILURE; } Status = XLlDma_BdRingSetCoalesce(RxRingPtr, 1, 1); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting coalescing for recv"); return XST_FAILURE; } /* * Make sure Tx and Rx are enabled */ Status = XLlTemac_SetOptions(TemacInstancePtr, XTE_RECEIVER_ENABLE_OPTION | XTE_TRANSMITTER_ENABLE_OPTION); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting options"); return XST_FAILURE; } /* * Start the LLTEMAC and enable its ERROR interrupts */ XLlTemac_Start(TemacInstancePtr); XLlTemac_IntEnable(TemacInstancePtr, XTE_INT_RECV_ERROR_MASK); /* * Allocate 1 RxBD. Note that TEMAC utilizes an in-place allocation * scheme. The returned BdPtr will point to a free BD in the memory * segment setup with the call to XLlTemac_SgSetSpace() */ Status = XLlDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error allocating RxBD"); return XST_FAILURE; } /* * Setup the BD. The BD template used in the call to XLlTemac_SgSetSpace() * set the SOP and EOP fields of all RxBDs. */ XLlDma_mBdSetBufAddr(BdPtr, &RxFrame); XLlDma_mBdSetLength(BdPtr, sizeof(RxFrame)); XLlDma_mBdSetStsCtrl(BdPtr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); /* * Enqueue to HW */ Status = XLlDma_BdRingToHw(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error committing RxBD to HW"); return XST_FAILURE; } /* * Enable DMA receive related interrupts */ XLlDma_mBdRingIntEnable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* * As DMA RX channel has been started in * TemacSgDmaIntrSingleFrameExample() above, there is no need to start * it again here */ /* * Allocate 1 TxBD */ Status = XLlDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error allocating TxBD"); return XST_FAILURE; } /* * Setup the TxBD */ XLlDma_mBdSetBufAddr(BdPtr, &TxFrame); XLlDma_mBdSetLength(BdPtr, TxFrameLength); XLlDma_mBdSetStsCtrl(BdPtr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); /* * Setup TxBd checksum offload attributes. * Note that the checksum offload values can be set globally for all TxBds * when XLlDma_BdRingClone() is called to setup Tx BD space. This would * eliminate the need to set them here. */ /* Enable hardware checksum computation for the buffer descriptor */ XLlDma_mBdWrite((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET, (XLlDma_mBdRead((BdPtr), XLLDMA_BD_STSCTRL_USR0_OFFSET) | CSUM_ENABLE)); /* Write Start Offset and Insert Offset into BD */ XLlDma_mBdWrite(BdPtr, XLLDMA_BD_USR1_OFFSET, XTE_HDR_SIZE << 16 | TxFrameLength - 2); /* Write 0, as the seed value, to the BD */ XLlDma_mBdWrite(BdPtr, XLLDMA_BD_USR2_OFFSET, 0); /* * Enqueue to HW */ Status = XLlDma_BdRingToHw(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error committing TxBD to HW"); return XST_FAILURE; } /* * Enable DMA transmit related interrupts */ XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* * As DMA TX channel has been started in * TemacSgDmaIntrSingleFrameExample() above, there is no need to start * it again here */ /* * Wait for transmission to complete */ while (!FramesTx); /* * Now that the frame has been sent, post process our TxBDs. * Since we have only submitted 2 to HW, then there should be only 2 ready * for post processing. */ if (XLlDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { TemacUtilErrorTrap("TxBDs were not ready for post processing"); return XST_FAILURE; } /* * Examine the TxBDs. * * There isn't much to do. The only thing to check would be DMA exception * bits. But this would also be caught in the error handler. So we just * return these BDs to the free list */ Status = XLlDma_BdRingFree(TxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Wait for Rx indication */ while (!FramesRx); /* * Now that the frame has been received, post process our RxBD. * Since we have only submitted 1 to HW, then there should be only 1 ready * for post processing. */ if (XLlDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { TemacUtilErrorTrap("RxBD was not ready for post processing"); return XST_FAILURE; } /* * There is no device status to check. If there was a DMA error, it should * have been reported to the error handler. Check the receive length against * the transmitted length, then verify the data. * * Note in LLTEMAC case, USR4_OFFSET word in the RX BD is used to store * the real length of the received packet */ if (XLlDma_mBdRead(BdPtr, XLLDMA_BD_USR4_OFFSET) != TxFrameLength) { TemacUtilErrorTrap("Length mismatch"); } /* * Verify the checksum as computed by HW. It should add up to 0xFFFF * if frame was uncorrupted */ if ((u16) (XLlDma_mBdRead(BdPtr, XLLDMA_BD_USR3_OFFSET)) != 0xFFFF) { TemacUtilErrorTrap("Rx checksum incorrect"); return XST_FAILURE; } /* * Return the RxBD back to the channel for later allocation. Free the * exact number we just post processed. */ Status = XLlDma_BdRingFree(RxRingPtr, 1, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error freeing up TxBDs"); return XST_FAILURE; } /* * Finished this example. If everything worked correctly, all TxBDs and * RxBDs should be free for allocation. Stop the device. */ XLlTemac_Stop(TemacInstancePtr); return XST_SUCCESS; }
/** * * This example sends frames with the interrupt coalescing settings altered * from their defaults. * * The default settings will interrupt the processor after every frame has been * sent. This example will increase the threshold resulting in lower CPU * utilization since it spends less time servicing interrupts. * * @param TemacInstancePtr is a pointer to the instance of the Temac * component. * * @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. * * @note None. * ******************************************************************************/ int TemacSgDmaIntrCoalescingExample(XLlTemac * TemacInstancePtr, XLlDma * DmaInstancePtr) { int Status; u32 TxFrameLength; int TxFramesToSend = 1000; int TxFramesSent = 0; int PayloadSize = XTE_MTU; u32 Index; u32 NumBd; u16 Threshold = 64; XLlDma_BdRing *RxRingPtr = &XLlDma_mGetRxRing(DmaInstancePtr); XLlDma_BdRing *TxRingPtr = &XLlDma_mGetTxRing(DmaInstancePtr); XLlDma_Bd *BdPtr, *BdCurPtr; /* * Clear variables shared with callbacks */ FramesRx = 0; FramesTx = 0; DeviceErrors = 0; /* * Calculate the frame length (not including FCS) */ TxFrameLength = XTE_HDR_SIZE + PayloadSize; /* * Setup packet to be transmitted. The same packet will be transmitted * over and over */ TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC); TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize); TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize); /* * Flush the TX frame before giving it to DMA TX channel to transmit, * in case D-Caching is turned on. */ XCACHE_FLUSH_DCACHE_RANGE(&TxFrame, TxFrameLength); /* * We don't care about the receive channel for this example, so turn it off */ Status = XLlTemac_ClearOptions(TemacInstancePtr, XTE_RECEIVER_ENABLE_OPTION); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error clearing option"); return XST_FAILURE; } /* * Set the interrupt coalescing parameters for the test. The waitbound timer * is set to 1 (ms) to catch the last few frames. * * If you set variable Threshold to some value larger than TXBD_CNT, then * there can never be enough frames sent to meet the threshold. In this case * the waitbound timer will always cause the interrupt to occur. */ Status = XLlDma_BdRingSetCoalesce(TxRingPtr, Threshold, 1); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error setting coalescing settings"); return XST_FAILURE; } /* * Prime the engine, allocate all BDs and assign them to the same buffer */ Status = XLlDma_BdRingAlloc(TxRingPtr, TXBD_CNT, &BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error allocating TxBDs prior to starting"); return XST_FAILURE; } /* * Setup the TxBDs */ BdCurPtr = BdPtr; for (Index = 0; Index < TXBD_CNT; Index++) { XLlDma_mBdSetBufAddr(BdCurPtr, &TxFrame); XLlDma_mBdSetLength(BdCurPtr, TxFrameLength); XLlDma_mBdSetStsCtrl(BdCurPtr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); BdCurPtr = XLlDma_mBdRingNext(TxRingPtr, BdCurPtr); } /* * Enqueue all TxBDs to HW */ Status = XLlDma_BdRingToHw(TxRingPtr, TXBD_CNT, BdPtr); TxFramesSent += TXBD_CNT; if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error committing TxBDs prior to starting"); return XST_FAILURE; } /* * Enable the send interrupts. Nothing should be transmitted yet as the * device has not been started */ XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); /* Enable temac interrupts to capture errors */ XLlTemac_IntEnable(TemacInstancePtr, XTE_INT_RECV_ERROR_MASK); /* * Start the device. Transmission commences now! */ XLlTemac_Start(TemacInstancePtr); /* * As DMA TX channel has been started in * TemacSgDmaIntrSingleFrameExample() above, there is no need to start * it again here */ while (TxFramesSent < TxFramesToSend) { /* * Wait for the interrupt */ while (!FramesTx); /* * Some TxBDs are ready for post processing. Get all that are available * at the moment, free them, then allocate the same number and * re-enqueue back to HW. At the same time this all occurs here, * the DMA engine should be processing other TxBDs. If we can stay ahead * of the transmitter like this, then throughput should be at or near * line-rate. * * Note that this retrieves up to TXBD_CNT outstanding packets, * so we may be processing more packets here than the threshold * value, which may result in a seemingly spurious interrupt * next time if we grab twice (or more) of the threshold value * this time around (clear as mud, eh!). Bottom line is that we * ignore if NumBd returns as zero. */ NumBd = XLlDma_BdRingFromHw(TxRingPtr, TXBD_CNT, &BdPtr); if (NumBd > 0) { TxFramesSent += NumBd; /* * Don't bother to check the BDs status, just free them */ Status = XLlDma_BdRingFree(TxRingPtr, NumBd, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error freeing TxBDs"); } /* * Allocate the same number of BDs just freed */ Status = XLlDma_BdRingAlloc(TxRingPtr, NumBd, &BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error allocating TxBDs"); return XST_FAILURE; } /* * Setup the TxBDs */ BdCurPtr = BdPtr; for (Index = 0; Index < NumBd; Index++) { XLlDma_mBdSetBufAddr(BdCurPtr, &TxFrame); XLlDma_mBdSetLength(BdCurPtr, TxFrameLength); XLlDma_mBdSetStsCtrl(BdCurPtr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK); BdCurPtr = XLlDma_mBdRingNext(TxRingPtr, BdCurPtr); } /* * Enqueue TxBDs to HW */ Status = XLlDma_BdRingToHw(TxRingPtr, NumBd, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap ("Error committing TxBDs prior to starting"); return XST_FAILURE; } } /* * Re-enable the interrupts */ FramesTx = 0; XLlDma_mBdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK); } /* * Wait a second and collect any remaining frames that had been * queued up but not post processed */ #ifndef __MICROBLAZE__ usleep(1000000); #else /* * Not sure if we should depend on there being a timer core in a * microblaze system */ TemacUtilPhyDelay(1); #endif NumBd = XLlDma_BdRingFromHw(TxRingPtr, 0xFFFFFFFF, &BdPtr); if (NumBd > 0) { Status = XLlDma_BdRingFree(TxRingPtr, NumBd, BdPtr); if (Status != XST_SUCCESS) { TemacUtilErrorTrap("Error freeing TxBDs"); } } /* * Done sending frames. Stop the device */ XLlTemac_Stop(TemacInstancePtr); return XST_SUCCESS; }