Exemple #1
0
/**
 * Stop the SGDMA or Simple SGDMA channel gracefully. Any DMA operation
 * currently in progress is allowed to finish.
 *
 * An interrupt may be generated as the DMA engine finishes the packet in
 * process. To prevent this (if desired) then disabled DMA interrupts prior to
 * invoking this function.
 *
 * If after stopping the channel, new BDs are enqueued with XDmaV2_SgBdToHw(),
 * then those BDs will not be processed until after XDmaV2_SgStart() is called.
 *
 * @param InstancePtr is a pointer to the instance to be stopped.
 *
 * @note This function will block until the HW indicates that DMA has stopped.
 *
 ******************************************************************************/
void XDmaV2_SgStop(XDmaV2 * InstancePtr)
{
	volatile u32 Swcr;
	u32 Ier;

	/* Save the contents of the interrupt enable register then disable
	 * interrupts. This register will be restored at the end of the function
	 */
	Ier = XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_IER_OFFSET);
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_IER_OFFSET, 0);

	/* Clear the SGE bit of the SWCR register and wait for SGE to clear */
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_SWCR_OFFSET, 0);

	/* Wait for SWCR.SGE = 0 */
	while (Swcr & XDMAV2_SWCR_SGE_MASK) {
		Swcr =
		    XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_SWCR_OFFSET);
	}

	/* Note as stopped */
	InstancePtr->BdRing.RunState = XST_DMA_SG_IS_STOPPED;

	/* Restore interrupt enables. If an interrupt occurs due to this function
	 * stopping the channel then it will happen right here
	 */
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_IER_OFFSET, Ier);
}
Exemple #2
0
/**
 * 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);
}
Exemple #3
0
/**
 * 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);
}
Exemple #4
0
/**
 * Returns a set of BD(s) that have been processed by HW. The returned BDs may
 * be examined to determine the outcome of the DMA transaction(s). Once the BDs
 * have been examined, the user must call XDmaV2_SgBdFree() in the same order
 * which they were retrieved here. Example:
 *
 * <pre>
 *        NumBd = 0xFFFFFFFF;   // Ensure we get all that are ready
 *
 *        Status = XDmaV2_SgBdFromHw(MyDmaInstPtr, &NumBd, &MyBdSet);
 *
 *        if (Status != XST_SUCCESS)
 *        {
 *           // HW has nothing ready for us yet
 *        }
 *
 *        CurBd = MyBdSet;
 *        for (i=0; i<NumBd; i++)
 *        {
 *           // Examine CurBd for post processing.....
 *
 *           // Onto next BD
 *           CurBd = XDmaV2_mSgBdNext(MyDmaInstPtr, CurBd);
 *           }
 *
 *           XDmaV2_SgBdFree(MyDmaInstPtr, NumBd, MyBdSet); // Return the list
 *        }
 * </pre>
 *
 * A more advanced use of this function may allocate multiple sets of BDs.
 * They must be retrieved from HW and freed in the correct sequence:
 * <pre>
 *        // Legal
 *        XDmaV2_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1);
 *        XDmaV2_SgBdFree(MyDmaInstPtr, NumBd1, MySet1);
 *
 *        // Legal
 *        XDmaV2_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1);
 *        XDmaV2_SgBdFromHw(MyDmaInstPtr, NumBd2, &MySet2);
 *        XDmaV2_SgBdFree(MyDmaInstPtr, NumBd1, MySet1);
 *        XDmaV2_SgBdFree(MyDmaInstPtr, NumBd2, MySet2);
 *
 *        // Not legal
 *        XDmaV2_SgBdFromHw(MyDmaInstPtr, NumBd1, &MySet1);
 *        XDmaV2_SgBdFromHw(MyDmaInstPtr, NumBd2, &MySet2);
 *        XDmaV2_SgBdFree(MyDmaInstPtr, NumBd2, MySet2);
 *        XDmaV2_SgBdFree(MyDmaInstPtr, NumBd1, MySet1);
 * </pre>
 *
 * If HW has only partially completed a packet spanning multiple BDs, then none
 * of the BDs for that packet will be included in the results.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param NumBd is the maximum number of BDs to return in the set.
 * @param BdSetPtr is an output parameter, it points to the first BD available
 *        for examination.
 *
 * @return
 *   The number of BDs processed by HW. A value of 0 indicates that no data
 *   is available.
 *
 * @note Treat BDs returned by this function as read-only.
 *
 * @note This function should not be preempted by another XDmaV2 function call
 *       that modifies the BD space. It is the caller's responsibility to
 *       provide a mutual exclusion mechanism.
 *
 ******************************************************************************/
unsigned XDmaV2_SgBdFromHw(XDmaV2 * InstancePtr, unsigned NumBd,
			   XDmaBdV2 ** BdSetPtr)
{
	XDmaV2_BdRing *Ring = &InstancePtr->BdRing;
	XDmaBdV2 *CurBd;
	unsigned BdCount;
	unsigned PktCount;
	unsigned BdPartialCount;
	unsigned BdLimit = NumBd;
	u32 Dmasr;
	u32 Upc;

	CurBd = Ring->HwHead;
	PktCount = 0;
	BdCount = 0;
	BdPartialCount = 0;

	/* If no BDs in work group, then there's nothing to search */
	if (Ring->HwCnt == 0) {
		*BdSetPtr = NULL;
		return (0);
	}

	/* Get the number of packets HW is reporting completed */
	Upc = XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_UPC_OFFSET);

	/* Starting at HwHead, keep moving forward in the list until:
	 *  - A BD is encountered with its DMASR.DMABSY bit set which means HW has
	 *    not completed processing of that BD.
	 *  - We've processed the number of packets HW has reported completed
	 *  - Ring->HwTail is reached
	 *  - The number of requested BDs has been processed
	 */
	while (BdCount < BdLimit) {
		/* Read the status */
		XDMAV2_CACHE_INVALIDATE(CurBd);
		Dmasr = XDmaV2_mReadBd(CurBd, XDMAV2_BD_DMASR_OFFSET);

		/* If the HW still hasn't processed this BD then we are done */
		if (Dmasr & XDMAV2_DMASR_DMABSY_MASK) {
			break;
		}

		BdCount++;

		/* HW has processed this BD so check the "last" bit. If it is clear,
		 * then there are more BDs for the current packet. Keep a count of
		 * these partial packet BDs.
		 */
		if (Dmasr & XDMAV2_DMASR_L_MASK) {
			/* Tell HW a packet has been serviced */
			XDmaV2_mWriteReg(InstancePtr->RegBase,
					 XDMAV2_UPC_OFFSET, 1);
			BdPartialCount = 0;

			/* We are done if we have serviced the number of packets HW has
			 * reported completed.
			 */
			if (++PktCount == Upc) {
				break;
			}
		} else {
			BdPartialCount++;
		}

		/* Reached the end of the work group */
		if (CurBd == Ring->HwTail) {
			break;
		}

		/* Move on to next BD in work group */
		CurBd = XDmaV2_mSgBdNext(InstancePtr, CurBd);
	}

	/* Subtract off any partial packet BDs found */
	BdCount -= BdPartialCount;

	/* If BdCount is non-zero then BDs were found to return. Set return
	 * parameters, update pointers and counters, return success
	 */
	if (BdCount) {
		*BdSetPtr = Ring->HwHead;
		Ring->HwCnt -= BdCount;
		Ring->PostCnt += BdCount;
		XDMAV2_RING_SEEKAHEAD(Ring, Ring->HwHead, BdCount);
		return (BdCount);
	} else {
		*BdSetPtr = NULL;
		return (0);
	}
}
Exemple #5
0
/**
 * Enqueue a set of BDs to HW that were previously allocated by
 * XDmaV2_SgBdAlloc(). Once this function returns, the argument BD set goes
 * under HW control. Any changes made to these BDs after this point will corrupt
 * the BD list leading to data corruption and system instability.
 *
 * The set will be rejected if the last BD of the set does not mark the end of
 * a packet (see XDmaBdV2_mSetLast()).
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param NumBd is the number of BDs in the set.
 * @param BdSetPtr is the first BD of the set to commit to HW.
 *
 * @return
 *   - XST_SUCCESS if the set of BDs was accepted and enqueued to HW.
 *   - XST_FAILURE if the set of BDs was rejected because the last BD of the set
 *     did not have its "last" bit set.
 *   - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
 *     XDmaV2_SgBdAlloc().
 *
 * @note This function should not be preempted by another XDmaV2 function call
 *       that modifies the BD space. It is the caller's responsibility to
 *       provide a mutual exclusion mechanism.
 *
 ******************************************************************************/
XStatus XDmaV2_SgBdToHw(XDmaV2 * InstancePtr, unsigned NumBd,
			XDmaBdV2 * BdSetPtr)
{
	XDmaV2_BdRing *Ring = &InstancePtr->BdRing;
	XDmaBdV2 *LastBdPtr;
	int i;
	u32 Dmacr;
	u32 Swcr;

	/* Make sure we are in sync with XDmaV2_SgBdAlloc() */
	if ((Ring->PreCnt < NumBd) || (Ring->PreHead != BdSetPtr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* For all BDs in this set (except the last one)
	 *   - Clear DMASR except for DMASR.DMABSY
	 *   - Clear DMACR.SGS
	 *
	 * For the last BD in this set
	 *   - Clear DMASR except for DMASR.DMABSY
	 *   - Set DMACR.SGS
	 */
	LastBdPtr = BdSetPtr;
	for (i = 1; i < NumBd; i++) {
		XDmaV2_mWriteBd(LastBdPtr, XDMAV2_BD_DMASR_OFFSET,
				XDMAV2_DMASR_DMABSY_MASK);

		Dmacr = XDmaV2_mReadBd(LastBdPtr, XDMAV2_BD_DMACR_OFFSET);
		XDmaV2_mWriteBd(LastBdPtr, XDMAV2_BD_DMACR_OFFSET,	/* DMACR.SGS = 0 */
				Dmacr & ~XDMAV2_DMACR_SGS_MASK);
		XDMAV2_CACHE_FLUSH(LastBdPtr);

		LastBdPtr = XDmaV2_mSgBdNext(InstancePtr, LastBdPtr);
	}

	/* Last BD */
	XDmaV2_mWriteBd(LastBdPtr, XDMAV2_BD_DMASR_OFFSET,
			XDMAV2_DMASR_DMABSY_MASK);

	Dmacr = XDmaV2_mReadBd(LastBdPtr, XDMAV2_BD_DMACR_OFFSET);
	XDmaV2_mWriteBd(LastBdPtr, XDMAV2_BD_DMACR_OFFSET,	/* DMACR.SGS = 1 */
			Dmacr | XDMAV2_DMACR_SGS_MASK);
	XDMAV2_CACHE_FLUSH(LastBdPtr);

	/* The last BD should have DMACR.LAST set */
	if (!(Dmacr & XDMAV2_DMACR_L_MASK)) {
		return (XST_FAILURE);
	}

	/* This set has completed pre-processing, adjust ring pointers & counters */
	XDMAV2_RING_SEEKAHEAD(Ring, Ring->PreHead, NumBd);
	Ring->PreCnt -= NumBd;

	/* This set is now ready to be added to the work group.
	 *
	 * Case 1: If there are no BDs in the list, then we know HW is idle, simply
	 * reset the list to begin and end on the current BD set
	 */
	if (Ring->HwCnt == 0) {
		/* Update pointers and counters. XDMAV2_RING_SEEKAHEAD could be used to
		 * advance HwTail, but it will always evaluate to LastBdPtr
		 */
		Ring->HwTail = LastBdPtr;
		Ring->HwCnt += NumBd;

		/* HW DMACR.SGS = 0 */
		XDMAV2_HW_SGS_CLEAR;
	}

	/* Case 2: There are BDs in the work group so we extend it in such a way
	 * that the channel doesn't need to be stopped
	 */
	else {
		/* Extend the work list: HwTail->DMACR.SGS = 0 */
		Dmacr = XDmaV2_mReadBd(Ring->HwTail, XDMAV2_BD_DMACR_OFFSET);
		XDmaV2_mWriteBd(Ring->HwTail, XDMAV2_BD_DMACR_OFFSET,
				Dmacr & ~XDMAV2_DMACR_SGS_MASK);
		XDMAV2_CACHE_FLUSH(Ring->HwTail);

		/* Update pointers and counters. HwTail now points to a new BD. */
		Ring->HwTail = LastBdPtr;
		Ring->HwCnt += NumBd;

		/* HW DMACR.SGS = 0 (with conditions)
		 *
		 * Must be careful here, the HW SGS may be set because it encountered
		 * the end of the work list before we extended it. If that is the
		 * situation, then clear it as we did in Case 1 so HW will see the
		 * BDs just added.
		 *
		 * The HW SGS bit may also be set because it has finished processing
		 * the set of BDs we just added! If that is the case then do nothing.
		 *
		 * If the HW SGS is clear, then HW is actively processing BDs so it will
		 * continue on getting to the list we just added.
		 */
		Dmacr =
		    XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_DMACR_OFFSET);
		if (Dmacr & XDMAV2_DMACR_SGS_MASK) {
			/* Did HW just finish processing what we added? This is checked by
			 * comparing the BDA register with HwTail. If they are the same
			 * then the channel has loaded the HwTail BD so we shouldn't enable
			 * the engine by setting SGS = 0.
			 */
			XDMAV2_CACHE_INVALIDATE(Ring->HwTail);
			if (XDMAV2_VIRT_TO_PHYS(Ring, Ring->HwTail) !=
			    XDmaV2_mReadReg(InstancePtr->RegBase,
					    XDMAV2_BDA_OFFSET)) {
				/* No, SGS = 0 */
				XDmaV2_mWriteReg(InstancePtr->RegBase,
						 XDMAV2_DMACR_OFFSET,
						 Dmacr &
						 ~XDMAV2_DMACR_SGS_MASK);
			}
		}
	}

	/* If the channel was in a running state, then keep it that way. It may have
	 * stopped because DMACR.SGS got set for any reason.
	 */
	if (Ring->RunState == XST_DMA_SG_IS_STARTED) {
		/* If SWCR.SGE was 0, then set it to 1 */
		Swcr =
		    XDmaV2_mReadReg(InstancePtr->RegBase, XDMAV2_SWCR_OFFSET);
		if (!(Swcr & XDMAV2_SWCR_SGE_MASK)) {
			XDmaV2_mWriteReg(InstancePtr->RegBase,
					 XDMAV2_SWCR_OFFSET,
					 Swcr | XDMAV2_SWCR_SGE_MASK);
		}
	}

	return (XST_SUCCESS);
}
Exemple #6
0
/**
 * 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);
}
Exemple #7
0
/**
 * Start the SGDMA channel.
 *
 * @param InstancePtr is a pointer to the instance to be started.
 *
 * @return
 * - XST_SUCCESS if channel was started.
 * - XST_DMA_SG_NO_LIST if buffer descriptor space has not been assigned to
 *   the channel. See XDmaV2_SgListCreate().
 *
 ******************************************************************************/
XStatus XDmaV2_SgStart(XDmaV2 * InstancePtr)
{
	XDmaV2_BdRing *Ring = &InstancePtr->BdRing;
	u32 BdaV;
	int i;

	/* BD list has yet to be created for this channel */
	if (Ring->AllCnt == 0) {
		return (XST_DMA_SG_NO_LIST);
	}

	/* Do nothing if already started */
	if (Ring->RunState == XST_DMA_SG_IS_STARTED) {
		return (XST_SUCCESS);
	}

	/* Note as started */
	Ring->RunState = XST_DMA_SG_IS_STARTED;

	/* Sync HW.BDA with the driver and start the engine if unprocessed BDs
	 * are present. This process is quite complex since we have to assume
	 * that HW may have been reset since it was stopped. Additionally, we
	 * have to account for calls made to XDmaV2_SgBdToHw() and
	 * XDmaV2_SgBdFromHw() while stopped. Several cases are handled below.
	 *
	 * Wherever HW.BDA is set, that will be the 1st BD processed once
	 * the engine starts.
	 */

	/* Case 1: Virgin BD ring that hasn't changed state since it was
	 * created. No BDs have ever been enqueued.
	 */
	if (!(XDmaV2_mReadBd(Ring->HwTail, XDMAV2_BD_DMACR_OFFSET) &
	      XDMAV2_DMACR_SGS_MASK)) {
		XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_BDA_OFFSET,
				 Ring->PhysBaseAddr);
	}

	/* Case 2: There are no active BDs. In this case, HwHead has overtaken
	 * HwTail and points one BD past the last one HW has processed. This is
	 * the BD to set HW to start from. Any new BDs will be enqueued at this
	 * point.
	 */
	else if (Ring->HwCnt == 0) {
		XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_BDA_OFFSET,
				 XDMAV2_VIRT_TO_PHYS(Ring, Ring->HwHead));
	}

	/* Case 3: There are 1 or more BDs between HwHead and HwTail.
	 * To find the restart point, look for the first BD between HwHead and
	 * HwTail where the DMABSY bit is set. This will be the 1st unprocessed
	 * BD. Set HW here then tell the engine to begin processing straight away.
	 *
	 * If the end of the list is reached before a DMABSY set bit is found, then
	 * there are no BDs unprocessed by HW. In this case set HW to HwTail.BDA.
	 * Any new BDs will be enqueued at this point.
	 */
	else {
		BdaV = (u32) Ring->HwHead;

		for (i = 0; i < Ring->HwCnt; i++) {
			/* Found a BD with DMABSY set? */
			if (XDmaV2_mReadBd(BdaV, XDMAV2_BD_DMASR_OFFSET) &
			    XDMAV2_DMASR_DMABSY_MASK) {
				/* Yes, this is where to point HW */
				XDmaV2_mWriteReg(InstancePtr->RegBase,
						 XDMAV2_BDA_OFFSET,
						 XDMAV2_VIRT_TO_PHYS(Ring,
								     BdaV));

				/* Since this BD is unprocessed by HW, enable processing */
				XDMAV2_HW_SGS_CLEAR;
				break;
			}

			/* Onto next BD */
			BdaV = (u32) XDmaV2_mSgBdNext(InstancePtr, BdaV);
		}

		/* Made it through loop without finding a DMABSY? */
		if (i == Ring->HwCnt) {
			/* Point HW to the next BD location that will be read once
			 * new BDs are enqueued. This position is at HwTail.BDA which
			 * is where BdaV should be after completing the loop above.
			 */
			XDmaV2_mWriteReg(InstancePtr->RegBase,
					 XDMAV2_BDA_OFFSET,
					 XDMAV2_VIRT_TO_PHYS(Ring, BdaV));
		}
	}

	/* Enable the engine */
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_SWCR_OFFSET,
			 XDMAV2_SWCR_SGE_MASK);

	/* Note: If while the channel was XDmaV2_SgStop'd and new BDs were enqueued
	 * to HW, XDmaV2_SgBdToHw() will have cleared DMACR.SGS. Once we set
	 * SWCR.SGE, then processing will begin.
	 */
	return (XST_SUCCESS);
}
Exemple #8
0
/**
 * Set the interrupt status register for this channel. Use this function
 * to ack pending interrupts.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param Mask is a logical OR of XDMAV2_IPXR_*_MASK constants found in
 *        xdmav2_l.h.
 *
 ******************************************************************************/
void XDmaV2_SetInterruptStatus(XDmaV2 * InstancePtr, u32 Mask)
{
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_ISR_OFFSET, Mask);
}
Exemple #9
0
/**
 * Enable specific DMA interrupts.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param Mask is a logical OR of of XDMAV2_IPXR_*_MASK constants found in
 *        xdmav2_l.h.
 *
 ******************************************************************************/
void XDmaV2_SetInterruptEnable(XDmaV2 * InstancePtr, u32 Mask)
{
	XDmaV2_mWriteReg(InstancePtr->RegBase, XDMAV2_IER_OFFSET, Mask);
}