Esempio n. 1
0
/**
 * Returns a set of BD(s) that have been processed by hardware. 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 XEmacPs_BdRingFree()
 * in the same order which they were retrieved here. Example:
 *
 * <pre>
 *        NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
 *
 *        if (NumBd == 0)
 *        {
 *           // hardware has nothing ready for us yet
 *        }
 *
 *        CurBd = MyBdSet;
 *        for (i=0; i<NumBd; i++)
 *        {
 *           // Examine CurBd for post processing.....
 *
 *           // Onto next BD
 *           CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
 *           }
 *
 *           XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
 *        }
 * </pre>
 *
 * A more advanced use of this function may allocate multiple sets of BDs.
 * They must be retrieved from hardware and freed in the correct sequence:
 * <pre>
 *        // Legal
 *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
 *
 *        // Legal
 *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
 *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
 *
 *        // Not legal
 *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
 *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
 * </pre>
 *
 * If hardware has only partially completed a packet spanning multiple BDs,
 * then none of the BDs for that packet will be included in the results.
 *
 * @param RingPtr is a pointer to the instance to be worked on.
 * @param BdLimit 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 hardware. A value of 0 indicates that no
 *   data is available. No more than BdLimit BDs will be returned.
 *
 * @note Treat BDs returned by this function as read-only.
 *
 * @note This function should not be preempted by another XEmacPs_Bd function
 *       call that modifies the BD space. It is the caller's responsibility to
 *       provide a mutual exclusion mechanism.
 *
 *****************************************************************************/
unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
				 XEmacPs_Bd ** BdSetPtr)
{
	XEmacPs_Bd *CurBdPtr;
	u32 BdStr = 0;
	unsigned BdCount;
	unsigned BdPartialCount;

	CurBdPtr = RingPtr->HwHead;
	BdCount = 0;
	BdPartialCount = 0;

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

	/* Starting at HwHead, keep moving forward in the list until:
	 *  - A BD is encountered with its new/used bit set which means
	 *    hardware has completed processing of that BD.
	 *  - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
	 *  - The number of requested BDs has been processed
	 */
	while (BdCount < BdLimit) {

		/* Read the status */
		XEMACPS_CACHE_INVALIDATE(CurBdPtr);
		BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);

		if (!(XEmacPs_BdIsRxNew(CurBdPtr))) {
			break;
		}

		BdCount++;

		/* hardware 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 (BdStr & XEMACPS_RXBUF_EOF_MASK) {
			BdPartialCount = 0;
		}
		else {
			BdPartialCount++;
		}

		/* Move on to next BD in work group */
		CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
	}

	/* 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 > 0) {
		*BdSetPtr = RingPtr->HwHead;
		RingPtr->HwCnt -= BdCount;
		RingPtr->PostCnt += BdCount;
		XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
		return (BdCount);
	}
	else {
		*BdSetPtr = NULL;
		return (0);
	}
}
Esempio n. 2
0
/**
 * Check the internal data structures of the BD ring for the provided channel.
 * The following checks are made:
 *
 *   - Is the BD ring linked correctly in physical address space.
 *   - Do the internal pointers point to BDs in the ring.
 *   - Do the internal counters add up.
 *
 * The channel should be stopped prior to calling this function.
 *
 * @param RingPtr is a pointer to the instance to be worked on.
 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
 *        which direction.
 *
 * @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 to
 *     avoid data corruption or system instability.
 *
 * @note This function should not be preempted by another XEmacPs_Bd function
 *       call that modifies the BD space. It is the caller's responsibility to
 *       provide a mutual exclusion mechanism.
 *
 *****************************************************************************/
int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
{
	u32 AddrV, AddrP;
	unsigned i;

	if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
		return (XST_INVALID_PARAM);
	}

	/* 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->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
		return (XST_DMA_SG_LIST_ERROR);
	}

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

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

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

	AddrV = (u32) RingPtr->PostHead;
	if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
		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->BaseBdAddr;
	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 (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
			return (XST_DMA_SG_LIST_ERROR);
		}

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

	/* Last BD should have wrap bit set */
	if (XEMACPS_SEND == Direction) {
		if (!XEmacPs_BdIsTxWrap(AddrV)) {
			return (XST_DMA_SG_LIST_ERROR);
		}
	}
	else {			/* XEMACPS_RECV */
		if (!XEmacPs_BdIsRxWrap(AddrV)) {
			return (XST_DMA_SG_LIST_ERROR);
		}
	}

	/* No problems found */
	return (XST_SUCCESS);
}
Esempio n. 3
0
/**
 * Returns a set of BD(s) that have been processed by hardware. 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 XEmacPs_BdRingFree()
 * in the same order which they were retrieved here. Example:
 *
 * <pre>
 *        NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet),
 *        if (NumBd == 0)
 *        {
 *           * hardware has nothing ready for us yet*
 *        }
 *
 *        CurBd = MyBdSet,
 *        for (i=0; i<NumBd; i++)
 *        {
 *           * Examine CurBd for post processing *.....
 *
 *           * Onto next BD *
 *           CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd),
 *           }
 *
 *           XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet),  *Return list*
 *        }
 * </pre>
 *
 * A more advanced use of this function may allocate multiple sets of BDs.
 * They must be retrieved from hardware and freed in the correct sequence:
 * <pre>
 *        * Legal *
 *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
 *
 *        * Legal *
 *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
 *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
 *
 *        * Not legal *
 *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
 *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
 *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
 * </pre>
 *
 * If hardware has only partially completed a packet spanning multiple BDs,
 * then none of the BDs for that packet will be included in the results.
 *
 * @param RingPtr is a pointer to the instance to be worked on.
 * @param BdLimit 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 hardware. A value of 0 indicates that no
 *   data is available. No more than BdLimit BDs will be returned.
 *
 * @note Treat BDs returned by this function as read-only.
 *
 * @note This function should not be preempted by another XEmacPs_Bd function
 *       call that modifies the BD space. It is the caller's responsibility to
 *       provide a mutual exclusion mechanism.
 *
 *****************************************************************************/
u32 XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
				 XEmacPs_Bd ** BdSetPtr)
{
	XEmacPs_Bd *CurBdPtr;
	u32 BdStr = 0U;
	u32 BdCount;
	u32 BdPartialCount;
	u32 Sop = 0U;
	u32 Status;
	u32 BdLimitLoc = BdLimit;
	CurBdPtr = RingPtr->HwHead;
	BdCount = 0U;
	BdPartialCount = 0U;

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

		if (BdLimitLoc > RingPtr->HwCnt){
			BdLimitLoc = RingPtr->HwCnt;
	}
	/* Starting at HwHead, keep moving forward in the list until:
	 *  - A BD is encountered with its new/used bit set which means
	 *    hardware has not completed processing of that BD.
	 *  - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
	 *  - The number of requested BDs has been processed
	 */
		while (BdCount < BdLimitLoc) {
		/* Read the status */
			if(CurBdPtr != NULL){
		BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
			}

			if ((Sop == 0x00000000U) && ((BdStr & XEMACPS_TXBUF_USED_MASK)!=0x00000000U)){
				Sop = 1U;
			}
			if (Sop == 0x00000001U) {
			BdCount++;
			BdPartialCount++;
		}

		/* hardware 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 ((Sop == 0x00000001U) && ((BdStr & XEMACPS_TXBUF_LAST_MASK)!=0x00000000U)) {
				Sop = 0U;
				BdPartialCount = 0U;
		}

		/* Move on to next BD in work group */
		CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
	}

	/* 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 > 0x00000000U) {
		*BdSetPtr = RingPtr->HwHead;
		RingPtr->HwCnt -= BdCount;
		RingPtr->PostCnt += BdCount;
		XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
			Status = (BdCount);
		} else {
			*BdSetPtr = NULL;
			Status = 0U;
	}
	}
	return Status;
}