/** * Enqueue a set of BDs to hardware that were previously allocated by * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes * under hardware 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 XEmacPs_BdSetLast()). * * @param RingPtr 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 hardware. * * @return * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. * - 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 * XEmacPs_BdRingAlloc(). * * @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_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd, XEmacPs_Bd * BdSetPtr) { XEmacPs_Bd *CurBdPtr; unsigned i; /* if no bds to process, simply return. */ if (0 == NumBd) return (XST_SUCCESS); /* Make sure we are in sync with XEmacPs_BdRingAlloc() */ if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { return (XST_DMA_SG_LIST_ERROR); } CurBdPtr = BdSetPtr; for (i = 0; i < NumBd; i++) { XEMACPS_CACHE_FLUSH(CurBdPtr); CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); } /* Adjust ring pointers & counters */ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); RingPtr->PreCnt -= NumBd; RingPtr->HwTail = CurBdPtr; RingPtr->HwCnt += NumBd; return (XST_SUCCESS); }
/** * Enqueue a set of BDs to hardware that were previously allocated by * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes * under hardware 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 XEmacPs_BdSetLast()). * * @param RingPtr 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 hardware. * * @return * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. * - 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 * XEmacPs_BdRingAlloc(). * * @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. * *****************************************************************************/ LONG XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, u32 NumBd, XEmacPs_Bd * BdSetPtr) { XEmacPs_Bd *CurBdPtr; u32 i; LONG Status; /* if no bds to process, simply return. */ if (0U == NumBd){ Status = (LONG)(XST_SUCCESS); } else { /* Make sure we are in sync with XEmacPs_BdRingAlloc() */ if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { Status = (LONG)(XST_DMA_SG_LIST_ERROR); } else { CurBdPtr = BdSetPtr; for (i = 0U; i < NumBd; i++) { CurBdPtr = (XEmacPs_Bd *)((void *)XEmacPs_BdRingNext(RingPtr, CurBdPtr)); } /* Adjust ring pointers & counters */ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); RingPtr->PreCnt -= NumBd; RingPtr->HwTail = CurBdPtr; RingPtr->HwCnt += NumBd; Status = (LONG)(XST_SUCCESS); } } return Status; }
/** * Reserve locations in the BD list. The set of returned BDs may be modified * in preparation for future DMA transaction(s). Once the BDs are ready to be * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same * order which they were allocated here. Example: * * <pre> * NumBd = 2; * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet); * * if (Status != XST_SUCCESS) * { * // Not enough BDs available for the request * } * * CurBd = MyBdSet; * for (i=0; i<NumBd; i++) * { * // Prepare CurBd..... * * // Onto next BD * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd); * } * * // Give list to hardware * Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet); * </pre> * * A more advanced use of this function may allocate multiple sets of BDs. * They must be allocated and given to hardware in the correct sequence: * <pre> * // Legal * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1); * * // Legal * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2); * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1); * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2); * * // Not legal * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1); * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2); * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2); * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1); * </pre> * * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal * of the BD set can be done using XEmacPs_BdRingNext() and * XEmacPs_BdRingPrev(). * * @param RingPtr is a pointer to the BD ring instance to be worked on. * @param NumBd is the number of BDs to allocate * @param BdSetPtr is an output parameter, it points to the first BD available * for modification. * * @return * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr * parameter. * - XST_FAILURE if there were not enough free BDs to satisfy the request. * * @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. * * @note Do not modify more BDs than the number requested with the NumBd * parameter. Doing so will lead to data corruption and system * instability. * *****************************************************************************/ int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd, XEmacPs_Bd ** BdSetPtr) { /* Enough free BDs available for the request? */ if (RingPtr->FreeCnt < NumBd) { return (XST_FAILURE); } /* Set the return argument and move FreeHead forward */ *BdSetPtr = RingPtr->FreeHead; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); RingPtr->FreeCnt -= NumBd; RingPtr->PreCnt += NumBd; return (XST_SUCCESS); }
/** * Reserve locations in the BD list. The set of returned BDs may be modified * in preparation for future DMA transaction(s). Once the BDs are ready to be * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same * order which they were allocated here. Example: * * <pre> * NumBd = 2, * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet), * * if (Status != XST_SUCCESS) * { * *Not enough BDs available for the request* * } * * CurBd = MyBdSet, * for (i=0; i<NumBd; i++) * { * * Prepare CurBd *..... * * * Onto next BD * * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd), * } * * * Give list to hardware * * Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet), * </pre> * * A more advanced use of this function may allocate multiple sets of BDs. * They must be allocated and given to hardware in the correct sequence: * <pre> * * Legal * * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1), * * * Legal * * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2), * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1), * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2), * * * Not legal * * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1), * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2), * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2), * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1), * </pre> * * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal * of the BD set can be done using XEmacPs_BdRingNext() and * XEmacPs_BdRingPrev(). * * @param RingPtr is a pointer to the BD ring instance to be worked on. * @param NumBd is the number of BDs to allocate * @param BdSetPtr is an output parameter, it points to the first BD available * for modification. * * @return * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr * parameter. * - XST_FAILURE if there were not enough free BDs to satisfy the request. * * @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. * * @note Do not modify more BDs than the number requested with the NumBd * parameter. Doing so will lead to data corruption and system * instability. * *****************************************************************************/ LONG XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd, XEmacPs_Bd ** BdSetPtr) { LONG Status; /* Enough free BDs available for the request? */ if (RingPtr->FreeCnt < NumBd) { Status = (LONG)(XST_FAILURE); } else { /* Set the return argument and move FreeHead forward */ *BdSetPtr = RingPtr->FreeHead; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); RingPtr->FreeCnt -= NumBd; RingPtr->PreCnt += NumBd; Status = (LONG)(XST_SUCCESS); } return Status; }
/** * Frees a set of BDs that had been previously retrieved with * XEmacPs_BdRingFromHw(). * * @param RingPtr is a pointer to the instance to be worked on. * @param NumBd is the number of BDs to free. * @param BdSetPtr is the head of a list of BDs returned by * XEmacPs_BdRingFromHw(). * * @return * - XST_SUCCESS if the set of BDs was freed. * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with * XEmacPs_BdRingFromHw(). * * @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_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd, XEmacPs_Bd * BdSetPtr) { /* if no bds to process, simply return. */ if (0 == NumBd) return (XST_SUCCESS); /* Make sure we are in sync with XEmacPs_BdRingFromHw() */ if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { return (XST_DMA_SG_LIST_ERROR); } /* Update pointers and counters */ RingPtr->FreeCnt += NumBd; RingPtr->PostCnt -= NumBd; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd); return (XST_SUCCESS); }
/** * Frees a set of BDs that had been previously retrieved with * XEmacPs_BdRingFromHw(). * * @param RingPtr is a pointer to the instance to be worked on. * @param NumBd is the number of BDs to free. * @param BdSetPtr is the head of a list of BDs returned by * XEmacPs_BdRingFromHw(). * * @return * - XST_SUCCESS if the set of BDs was freed. * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with * XEmacPs_BdRingFromHw(). * * @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. * *****************************************************************************/ LONG XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, u32 NumBd, XEmacPs_Bd * BdSetPtr) { LONG Status; /* if no bds to process, simply return. */ if (0x00000000U == NumBd){ Status = (LONG)(XST_SUCCESS); } else { /* Make sure we are in sync with XEmacPs_BdRingFromHw() */ if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { Status = (LONG)(XST_DMA_SG_LIST_ERROR); } else { /* Update pointers and counters */ RingPtr->FreeCnt += NumBd; RingPtr->PostCnt -= NumBd; XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd); Status = (LONG)(XST_SUCCESS); } } return Status; }
/** * 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); } }
/** * 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; }