/** * Set the packet waitbound timer for this SGDMA channel. See xdmav2.h for more * information on interrupt coalescing and the effects of the waitbound timer. * * @param InstancePtr is a pointer to the instance to be worked on. * @param TimerVal is the waitbound period to set. If 0 is specified, then * this feature is disabled. Maximum waitbound is 2^12 - 1. LSB is * 1 millisecond (approx). * * @return * - XST_SUCCESS if waitbound set properly. * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA * channel. ******************************************************************************/ XStatus XDmaV2_SgSetPktWaitbound(XDmaV2 * InstancePtr, u16 TimerVal) { if (!IsSgDmaChannel(InstancePtr)) { return (XST_NO_FEATURE); } XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_PWB_OFFSET, (u32) (TimerVal & XDMAV2_PWB_MASK)); return (XST_SUCCESS); }
/** * Set the packet threshold for this SGDMA channel. This has the effect of * delaying processor interrupts until the given number of packets (not BDs) * have been processed. * * @param InstancePtr is a pointer to the instance to be worked on. * @param Threshold is the packet threshold to set. If 0 is specified, then * this feature is disabled. Maximum threshold is 2^10 - 1. * * @return * - XST_SUCCESS if threshold set properly. * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA * channel. ******************************************************************************/ XStatus XDmaV2_SgSetPktThreshold(XDmaV2 * InstancePtr, u16 Threshold) { if (!IsSgDmaChannel(InstancePtr)) { return (XST_NO_FEATURE); } XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_PCT_OFFSET, (u32) (Threshold & XDMAV2_PCT_MASK)); return (XST_SUCCESS); }
/** * Get the waitbound timer for this channel that was set with * XDmaV2_SgSetPktWaitbound(). * * @param InstancePtr is a pointer to the instance to be worked on. * * @return Current waitbound timer as reported by HW. If the channel is not of * SGDMA type then the return value is 0. ******************************************************************************/ u16 XDmaV2_SgGetPktWaitbound(XDmaV2 * InstancePtr) { u32 Reg; if (!IsSgDmaChannel(InstancePtr)) { return (0); } Reg = XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_PWB_OFFSET); Reg &= XDMAV2_PWB_MASK; return ((u16) Reg); }
/** * Get the waitbound timer for this channel that was set with * XDmaV3_SgSetPktWaitbound(). * * @param InstancePtr is a pointer to the instance to be worked on. * * @return Current waitbound timer as reported by HW. If the channel does not * include interrupt coalescing, then the return value will always be 0. ******************************************************************************/ u16 XDmaV3_SgGetPktWaitbound(XDmaV3 * InstancePtr) { u32 Reg; /* Is this a SGDMA channel */ Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); if (!IsSgDmaChannel(InstancePtr)) { return (0); } /* Get the threshold */ Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); Reg &= XDMAV3_SWCR_PWB_MASK; Reg >>= XDMAV3_SWCR_PWB_SHIFT; return ((u16) Reg); }
/** * Set the packet waitbound timer for this SGDMA channel. See xdmav3.h for more * information on interrupt coalescing and the effects of the waitbound timer. * * @param InstancePtr is a pointer to the instance to be worked on. * @param TimerVal is the waitbound period to set. If 0 is specified, then * this feature is disabled. Maximum waitbound is 2^12 - 1. LSB is * 1 millisecond (approx). * * @return * - XST_SUCCESS if waitbound set properly. * - XST_NO_FEATURE if this function was called on a DMA channel that does not * have interrupt coalescing capabilities. * * @note This function should not be prempted by another XDmaV3 function. * ******************************************************************************/ int XDmaV3_SgSetPktWaitbound(XDmaV3 * InstancePtr, u16 TimerVal) { u32 Reg; /* Is this a SGDMA channel */ Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_DMASR_OFFSET); if (!IsSgDmaChannel(InstancePtr)) { return (XST_NO_FEATURE); } /* Replace the waitbound field in the SWCR */ Reg = XDmaV3_mReadReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET); Reg &= ~XDMAV3_SWCR_PWB_MASK; Reg |= ((TimerVal << XDMAV3_SWCR_PWB_SHIFT) & XDMAV3_SWCR_PWB_MASK); XDmaV3_mWriteReg(InstancePtr->RegBase, XDMAV3_SWCR_OFFSET, Reg); /* Finished */ return (XST_SUCCESS); }
/** * Using a memory segment allocated by the caller, create and setup the BD list * for the given SGDMA channel. * * @param InstancePtr is the instance to be worked on. * @param PhysAddr is the physical base address of user memory region. * @param VirtAddr is the virtual base address of the user memory region. If * address translation is not being utilized, then VirtAddr should be * equivalent to PhysAddr. * @param Alignment governs the byte alignment of individual BDs. This function * will enforce a minimum alignment of 4 bytes with no maximum as long as * it is specified as a power of 2. * @param BdCount is the number of BDs to setup in the user memory region. It is * assumed the region is large enough to contain the BDs. Refer to the * "SGDMA List Creation" section in xdmav2.h for more information on list * creation. * * @return * * - XST_SUCCESS if initialization was successful * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA * channel. * - XST_INVALID_PARAM under any of the following conditions: 1) PhysAddr and/or * VirtAddr are not aligned to the given Alignment parameter; 2) Alignment * parameter does not meet minimum requirements or is not a power of 2 value; * 3) BdCount is 0. * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans * over address 0x00000000 in virtual address space. * * @note * * Some DMA HW requires 8 or more byte alignments of BDs. Make sure the correct * value is passed into the Alignment parameter to meet individual DMA HW * requirements. * ******************************************************************************/ XStatus XDmaV2_SgListCreate(XDmaV2 * InstancePtr, u32 PhysAddr, u32 VirtAddr, u32 Alignment, unsigned BdCount) { int i; u32 BdV; u32 BdP; XDmaV2_BdRing *Ring = &InstancePtr->BdRing; u32 Upc; /* In case there is a failure prior to creating list, make sure the following * attributes are 0 to prevent calls to other SG functions from doing anything */ Ring->AllCnt = 0; Ring->FreeCnt = 0; Ring->HwCnt = 0; Ring->PreCnt = 0; Ring->PostCnt = 0; /* Is this a SGDMA channel */ if (!IsSgDmaChannel(InstancePtr)) { return (XST_NO_FEATURE); } /* Make sure Alignment parameter meets minimum requirements */ if (Alignment < XDMABD_MINIMUM_ALIGNMENT) { return (XST_INVALID_PARAM); } /* Make sure Alignment is a power of 2 */ if ((Alignment - 1) & Alignment) { return (XST_INVALID_PARAM); } /* Make sure PhysAddr and VirtAddr are on same Alignment */ if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { return (XST_INVALID_PARAM); } /* Is BdCount is reasonable? */ if (BdCount == 0) { return (XST_INVALID_PARAM); } /* Calculate the number of bytes between the start of adjacent BDs */ Ring->Separation = (sizeof(XDmaBdV2) + (Alignment - 1)) & ~(Alignment - 1); /* Must make sure the ring doesn't span across address 0x00000000. * The design will fail if this occurs. */ if (VirtAddr > (VirtAddr + (Ring->Separation * BdCount))) { return (XST_DMA_SG_LIST_ERROR); } /* Initial ring setup: * - Clear the entire space * - Lay out the BDA fields the HW follows as it processes BDs */ memset((void *)VirtAddr, 0, (Ring->Separation * BdCount)); BdV = VirtAddr; BdP = PhysAddr + Ring->Separation; for (i = 1; i < BdCount; i++) { XDmaV2_mWriteBd(BdV, XDMAV2_BD_BDA_OFFSET, BdP); BdV += Ring->Separation; BdP += Ring->Separation; } /* At the end of the ring, link the last BD back to the top */ XDmaV2_mWriteBd(BdV, XDMAV2_BD_BDA_OFFSET, PhysAddr); /* Setup and initialize pointers and counters */ InstancePtr->BdRing.RunState = XST_DMA_SG_IS_STOPPED; Ring->BaseAddr = VirtAddr; Ring->PhysBaseAddr = PhysAddr; Ring->TO = VirtAddr - PhysAddr; Ring->HighAddr = BdV; Ring->Length = Ring->HighAddr - Ring->BaseAddr + Ring->Separation; Ring->AllCnt = BdCount; Ring->FreeCnt = BdCount; Ring->FreeHead = (XDmaBdV2 *) VirtAddr; Ring->PreHead = (XDmaBdV2 *) VirtAddr; Ring->HwHead = (XDmaBdV2 *) VirtAddr; Ring->HwTail = (XDmaBdV2 *) VirtAddr; Ring->PostHead = (XDmaBdV2 *) VirtAddr; /* Sync HW with the beginning of the ring */ XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_BDA_OFFSET, PhysAddr); /* Make sure the DMACR.SGS is 1 so that no DMA operations proceed until * the start function is called. */ XDMAV2_HW_SGS_SET; /* As a final purging of any previous BD ring, make sure the UPC register * has been cleared to 0. */ Upc = XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_UPC_OFFSET); for (i = 0; i < Upc; i++) { XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_UPC_OFFSET, 1); } return (XST_SUCCESS); }
/** * Using a memory segment allocated by the caller, create and setup the BD list * for the given SGDMA channel. * * @param InstancePtr is the instance to be worked on. * @param PhysAddr is the physical base address of user memory region. * @param VirtAddr is the virtual base address of the user memory region. If * address translation is not being utilized, then VirtAddr should be * equivalent to PhysAddr. * @param Alignment governs the byte alignment of individual BDs. This function * will enforce a minimum alignment of 4 bytes with no maximum as long as * it is specified as a power of 2. * @param BdCount is the number of BDs to setup in the user memory region. It is * assumed the region is large enough to contain the BDs. Refer to the * "SGDMA List Creation" section in xdmav3.h for more information on * list creation. * * @return * * - XST_SUCCESS if initialization was successful * - XST_NO_FEATURE if the provided instance is a non SGDMA type of DMA * channel. * - XST_INVALID_PARAM under any of the following conditions: 1) PhysAddr and/or * VirtAddr are not aligned to the given Alignment parameter; 2) Alignment * parameter does not meet minimum requirements or is not a power of 2 value; * 3) BdCount is 0. * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans * over address 0x00000000 in virtual address space. * * @note * * Some DMA HW requires 8 or more byte alignments of BDs. Make sure the correct * value is passed into the Alignment parameter to meet individual DMA HW * requirements. * ******************************************************************************/ int XDmaV3_SgListCreate(XDmaV3 * InstancePtr, u32 PhysAddr, u32 VirtAddr, u32 Alignment, unsigned BdCount) { unsigned i; u32 BdV; u32 BdP; XDmaV3_BdRing *Ring = &InstancePtr->BdRing; /* In case there is a failure prior to creating list, make sure the following * attributes are 0 to prevent calls to other SG functions from doing anything */ Ring->AllCnt = 0; Ring->FreeCnt = 0; Ring->HwCnt = 0; Ring->PreCnt = 0; Ring->PostCnt = 0; /* Is this a SGDMA channel */ if (!IsSgDmaChannel(InstancePtr)) { return (XST_NO_FEATURE); } /* Make sure Alignment parameter meets minimum requirements */ if (Alignment < XDMABDV3_MINIMUM_ALIGNMENT) { return (XST_INVALID_PARAM); } /* Make sure Alignment is a power of 2 */ if ((Alignment - 1) & Alignment) { return (XST_INVALID_PARAM); } /* Make sure PhysAddr and VirtAddr are on same Alignment */ if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { return (XST_INVALID_PARAM); } /* Is BdCount reasonable? */ if (BdCount == 0) { return (XST_INVALID_PARAM); } /* Parameters are sane. Stop the HW just to be safe */ XDmaV3_SgStop(InstancePtr); /* Figure out how many bytes will be between the start of adjacent BDs */ Ring->Separation = (sizeof(XDmaBdV3) + (Alignment - 1)) & ~(Alignment - 1); /* Must make sure the ring doesn't span address 0x00000000. If it does, * then the next/prev BD traversal macros will fail. */ if (VirtAddr > (VirtAddr + (Ring->Separation * BdCount) - 1)) { return (XST_DMA_SG_LIST_ERROR); } /* Initial ring setup: * - Clear the entire space * - Setup each BD's BDA field with the physical address of the next BD * - Set each BD's DMASR.DMADONE bit */ memset((void *) VirtAddr, 0, (Ring->Separation * BdCount)); BdV = VirtAddr; BdP = PhysAddr + Ring->Separation; for (i = 1; i < BdCount; i++) { XDmaV3_mWriteBd(BdV, XDMAV3_BD_BDA_OFFSET, BdP); XDmaV3_mWriteBd(BdV, XDMAV3_BD_DMASR_OFFSET, XDMAV3_DMASR_DMADONE_MASK); XDMAV3_CACHE_FLUSH(BdV); BdV += Ring->Separation; BdP += Ring->Separation; } /* At the end of the ring, link the last BD back to the top */ XDmaV3_mWriteBd(BdV, XDMAV3_BD_BDA_OFFSET, PhysAddr); /* Setup and initialize pointers and counters */ InstancePtr->BdRing.RunState = XST_DMA_SG_IS_STOPPED; Ring->BaseAddr = VirtAddr; Ring->PhysBaseAddr = PhysAddr; Ring->HighAddr = BdV; Ring->Length = Ring->HighAddr - Ring->BaseAddr + Ring->Separation; Ring->AllCnt = BdCount; Ring->FreeCnt = BdCount; Ring->FreeHead = (XDmaBdV3 *) VirtAddr; Ring->PreHead = (XDmaBdV3 *) VirtAddr; Ring->HwHead = (XDmaBdV3 *) VirtAddr; Ring->HwTail = (XDmaBdV3 *) VirtAddr; Ring->PostHead = (XDmaBdV3 *) VirtAddr; Ring->BdaRestart = (XDmaBdV3 *) PhysAddr; /* Make sure the DMACR.SGS is 1 so that no DMA operations proceed until * the start function is called. */ XDMAV3_HW_SGS_SET; return (XST_SUCCESS); }