Ejemplo n.º 1
0
/**
 * Clone the given BD into every BD in the list. Except for XDMAV2_BD_BDA_OFFSET,
 * every field of the source BD is replicated in every BD of the list.
 *
 * This function can be called only when all BDs are in the free group such as
 * they are immediately after initialization with XDmaV2_SgListCreate(). This
 * prevents modification of BDs while they are in use by HW or the user.
 *
 * @param InstancePtr is the instance to be worked on.
 * @param SrcBdPtr is the source BD to be cloned into the list.
 *
 * @return
 *   - XST_SUCCESS if the list was modified.
 *   - XST_DMA_SG_NO_LIST if a list has not been created.
 *   - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under HW
 *     or user control.
 *   - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped.
 *
 ******************************************************************************/
XStatus XDmaV2_SgListClone(XDmaV2 * InstancePtr, XDmaBdV2 * SrcBdPtr)
{
	u32 CurBd;
	u32 BdaSave;
	XDmaV2_BdRing *Ring = &InstancePtr->BdRing;

	/* Can't do this function if there isn't a ring */
	if (Ring->AllCnt == 0) {
		return (XST_DMA_SG_NO_LIST);
	}

	/* Can't do this function with the channel running */
	if (Ring->RunState == XST_DMA_SG_IS_STARTED) {
		return (XST_DEVICE_IS_STARTED);
	}

	/* Can't do this function with some of the BDs in use */
	if (Ring->FreeCnt != Ring->AllCnt) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* Starting from the top, save BD.Next, overwrite the entire BD with the
	 * template, then restore BD.Next
	 */
	for (CurBd = Ring->BaseAddr; CurBd <= Ring->HighAddr;
	     CurBd += Ring->Separation) {
		BdaSave = XDmaV2_mReadBd(CurBd, XDMAV2_BD_BDA_OFFSET);
		memcpy((void *)CurBd, SrcBdPtr, sizeof(XDmaBdV2));
		XDmaV2_mWriteBd(CurBd, XDMAV2_BD_BDA_OFFSET, BdaSave);
	}

	return (XST_SUCCESS);
}
Ejemplo n.º 2
0
/**
 * Verify the consistency of the SGDMA BD ring. While the check occurs, the
 * device is stopped. If any problems are found the device is left stopped.
 *
 * Use this function to troubleshoot SGDMA problems.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 * @param Direction is the channel to check (XTE_SEND or XTE_RECV)
 *
 * @return
 * - XST_SUCCESS if no problems are found.
 * - XST_INVALID_PARAM if Direction is not XTE_SEND or XTE_RECV.
 * - XST_DMA_SG_NO_LIST if the SG list has not yet been setup.
 * - XST_DMA_BD_ERROR if a BD has been corrupted.
 * - XST_DMA_SG_LIST_ERROR if the internal data structures of the BD ring are
 *   inconsistent.
 *
 * @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.
 *
 ******************************************************************************/
XStatus XTemac_SgCheck(XTemac * InstancePtr, u32 Direction)
{
	XDmaV2 *DmaPtr;
	XDmaBdV2 *BdPtr;
	int i;
	int Restart = 0;
	u32 Dmacr;
	XStatus Rc = XST_SUCCESS;

	XASSERT_NONVOID(InstancePtr != NULL);

	/* Select channel to check */
	if (Direction == XTE_SEND) {
		DmaPtr = &InstancePtr->SendDma;
	} else if (Direction == XTE_RECV) {
		DmaPtr = &InstancePtr->RecvDma;
	} else {
		return (XST_INVALID_PARAM);
	}

	/* Stop the device if it is running */
	if (InstancePtr->IsStarted == XST_DEVICE_IS_STARTED) {
		XTemac_Stop(InstancePtr);
		Restart = 1;
	}

	/* Perform check of ring structure using DMA driver routine */
	Rc = XDmaV2_SgCheck(DmaPtr);
	if (Rc == XST_SUCCESS) {
		/* Check the BDs for consistency as used by TEMAC */
		if (Direction == XTE_SEND) {
			/* Starting from the beginning of the ring and going to the end:
			 *   1. Verify the destination address is the packet fifo
			 *   2. Verify DMACR is setup for the transmit direction
			 */
			BdPtr = (XDmaBdV2 *) DmaPtr->BdRing.BaseAddr;
			for (i = 0; i < DmaPtr->BdRing.AllCnt; i++) {
				/* Dest address should be address of packet fifo */
				if (XDmaBdV2_mGetDestAddr(BdPtr) !=
				    InstancePtr->Config->BaseAddress +
				    XTE_PFIFO_TXDATA_OFFSET) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				Dmacr =
				    XDmaV2_mReadBd(BdPtr,
						   XDMAV2_BD_DMACR_OFFSET);

				/* DMACR field should have these bits set */
				if (Dmacr !=
				    (Dmacr &
				     (XDMAV2_DMACR_DLOCAL_MASK |
				      XDMAV2_DMACR_SINC_MASK))) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				/* DMACR field should have these bits clear */
				if (Dmacr &
				    (XDMAV2_DMACR_SLOCAL_MASK |
				     XDMAV2_DMACR_DINC_MASK)) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				/* Next BD */
				BdPtr = XDmaV2_mSgBdNext(DmaPtr, BdPtr);
			}
		} else {	/* XTE_RECV */

			/* Starting from the beginning of the ring and going to the end:
			 *   1. Verify the source address is the packet fifo
			 *   2. Verify DMACR is setup for the receive direction
			 */
			BdPtr = (XDmaBdV2 *) DmaPtr->BdRing.BaseAddr;
			for (i = 0; i < DmaPtr->BdRing.AllCnt; i++) {
				/* Src address should be address of packet fifo */
				if (XDmaBdV2_mGetSrcAddr(BdPtr) !=
				    InstancePtr->Config->BaseAddress +
				    XTE_PFIFO_RXDATA_OFFSET) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				Dmacr =
				    XDmaV2_mReadBd(BdPtr,
						   XDMAV2_BD_DMACR_OFFSET);

				/* DMACR field should have these bits set */
				if (Dmacr !=
				    (Dmacr &
				     (XDMAV2_DMACR_SLOCAL_MASK |
				      XDMAV2_DMACR_DINC_MASK))) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				/* DMACR field should have these bits clear */
				if (Dmacr &
				    (XDMAV2_DMACR_DLOCAL_MASK |
				     XDMAV2_DMACR_SINC_MASK)) {
					Rc = XST_DMA_BD_ERROR;
					break;
				}

				/* Next BD */
				BdPtr = XDmaV2_mSgBdNext(DmaPtr, BdPtr);
			}
		}
	}

	/* Restart the device if it was stopped by this function */
	if ((Rc == XST_SUCCESS) && Restart) {
		XTemac_Start(InstancePtr);
	}

	return (Rc);
}
Ejemplo n.º 3
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);
	}
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
0
/**
 * Check the internal data structures of the BD list for the provided channel.
 * The following checks are made:
 *
 *   - Is the BD list linked correctly in physical address space.
 *   - Do the internal pointers point to BDs in the list.
 *   - Do the internal counters add up.
 *
 * The channel should be stopped prior to calling this function.
 *
 * @param InstancePtr is a pointer to the instance to be worked on.
 *
 * @return
 *   - XST_SUCCESS if the set of BDs was freed.
 *   - XST_DMA_SG_NO_LIST if the list has not been created.
 *   - XST_IS_STARTED if the channel is not stopped.
 *   - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
 *     structures. If this value is returned, the channel should be reset and
 *     the list recreated to avoid data corruption or system instability.
 *
 * @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_SgCheck(XDmaV2 * InstancePtr)
{
	XDmaV2_BdRing *RingPtr = &InstancePtr->BdRing;
	u32 AddrV, AddrP;
	int i;

	/* Is the list created */
	if (RingPtr->AllCnt == 0) {
		return (XST_DMA_SG_NO_LIST);
	}

	/* Can't check if channel is running */
	if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
		return (XST_IS_STARTED);
	}

	/* RunState doesn't make sense */
	else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* Verify internal pointers point to correct memory space */
	AddrV = (u32) RingPtr->FreeHead;
	if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	AddrV = (u32) RingPtr->PreHead;
	if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	AddrV = (u32) RingPtr->HwHead;
	if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	AddrV = (u32) RingPtr->HwTail;
	if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	AddrV = (u32) RingPtr->PostHead;
	if ((AddrV < RingPtr->BaseAddr) || (AddrV > RingPtr->HighAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* Verify internal counters add up */
	if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
	     RingPtr->PostCnt) != RingPtr->AllCnt) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* Verify BDs are linked correctly */
	AddrV = RingPtr->BaseAddr;
	AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
	for (i = 1; i < RingPtr->AllCnt; i++) {
		/* Check BDA for this BD. It should point to next physical addr */
		if (XDmaV2_mReadBd(AddrV, XDMAV2_BD_BDA_OFFSET) != AddrP) {
			return (XST_DMA_SG_LIST_ERROR);
		}

		/* Move on to next BD */
		AddrV += RingPtr->Separation;
		AddrP += RingPtr->Separation;
	}

	/* Last BD should point back to the beginning of ring */
	if (XDmaV2_mReadBd(AddrV, XDMAV2_BD_BDA_OFFSET) !=
	    RingPtr->PhysBaseAddr) {
		return (XST_DMA_SG_LIST_ERROR);
	}

	/* No problems found */
	return (XST_SUCCESS);
}