1 /* $Id: xemacps_bdring.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */
2 /******************************************************************************
4 * (c) Copyright 2010 Xilinx, Inc. All rights reserved.
6 * This file contains confidential and proprietary information of Xilinx, Inc.
7 * and is protected under U.S. and international copyright and other
8 * intellectual property laws.
11 * This disclaimer is not a license and does not grant any rights to the
12 * materials distributed herewith. Except as otherwise provided in a valid
13 * license issued to you by Xilinx, and to the maximum extent permitted by
14 * applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL
15 * FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS,
16 * IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
17 * MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE;
18 * and (2) Xilinx shall not be liable (whether in contract or tort, including
19 * negligence, or under any other theory of liability) for any loss or damage
20 * of any kind or nature related to, arising under or in connection with these
21 * materials, including for any direct, or any indirect, special, incidental,
22 * or consequential loss or damage (including loss of data, profits, goodwill,
23 * or any type of loss or damage suffered as a result of any action brought by
24 * a third party) even if such damage or loss was reasonably foreseeable or
25 * Xilinx had been advised of the possibility of the same.
27 * CRITICAL APPLICATIONS
28 * Xilinx products are not designed or intended to be fail-safe, or for use in
29 * any application requiring fail-safe performance, such as life-support or
30 * safety devices or systems, Class III medical devices, nuclear facilities,
31 * applications related to the deployment of airbags, or any other applications
32 * that could lead to death, personal injury, or severe property or
33 * environmental damage (individually and collectively, "Critical
34 * Applications"). Customer assumes the sole risk and liability of any use of
35 * Xilinx products in Critical Applications, subject only to applicable laws
36 * and regulations governing limitations on product liability.
38 * THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE
41 ******************************************************************************/
42 /*****************************************************************************/
45 * @file xemacps_bdring.c
47 * This file implements buffer descriptor ring related functions.
50 * MODIFICATION HISTORY:
52 * Ver Who Date Changes
53 * ----- ---- -------- -------------------------------------------------------
54 * 1.00a wsy 01/10/10 First release
55 * 1.00a asa 11/21/11 The function XEmacPs_BdRingFromHwTx is modified.
56 * Earlier it used to search in "BdLimit" number of BDs to
57 * know which BDs are processed. Now one more check is
58 * added. It looks for BDs till the current BD pointer
59 * reaches HwTail. By doing this processing time is saved.
60 * 1.00a asa 01/24/12 The function XEmacPs_BdRingFromHwTx in file
61 * xemacps_bdring.c is modified. Now start of packet is
62 * searched for returning the number of BDs processed.
63 * 1.05a asa 09/23/13 Cache operations on BDs are not required and hence
64 * removed. It is expected that all BDs are allocated in
65 * from uncached area. Fix for CR #663885.
67 ******************************************************************************/
69 /***************************** Include Files *********************************/
72 #include "xil_cache.h"
73 #include "xemacps_hw.h"
74 #include "xemacps_bd.h"
75 #include "xemacps_bdring.h"
77 /************************** Constant Definitions *****************************/
79 /**************************** Type Definitions *******************************/
82 /***************** Macros (Inline Functions) Definitions *********************/
84 /****************************************************************************
85 * Compute the virtual address of a descriptor from its physical address
87 * @param BdPtr is the physical address of the BD
89 * @returns Virtual address of BdPtr
91 * @note Assume BdPtr is always a valid BD in the ring
92 ****************************************************************************/
93 #define XEMACPS_PHYS_TO_VIRT(BdPtr) \
94 ((u32)BdPtr + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
96 /****************************************************************************
97 * Compute the physical address of a descriptor from its virtual address
99 * @param BdPtr is the physical address of the BD
101 * @returns Physical address of BdPtr
103 * @note Assume BdPtr is always a valid BD in the ring
104 ****************************************************************************/
105 #define XEMACPS_VIRT_TO_PHYS(BdPtr) \
106 ((u32)BdPtr - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
108 /****************************************************************************
109 * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around
110 * to the beginning of the ring if needed.
112 * We know if a wrapaound should occur if the new BdPtr is greater than
113 * the high address in the ring OR if the new BdPtr crosses over the
114 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
115 * allow a BD space to span this boundary.
117 * @param RingPtr is the ring BdPtr appears in
118 * @param BdPtr on input is the starting BD position and on output is the
120 * @param NumBd is the number of BD spaces to increment
122 ****************************************************************************/
123 #define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \
125 u32 Addr = (u32)BdPtr; \
127 Addr += ((RingPtr)->Separation * NumBd); \
128 if ((Addr > (RingPtr)->HighBdAddr) || ((u32)BdPtr > Addr)) \
130 Addr -= (RingPtr)->Length; \
133 BdPtr = (XEmacPs_Bd*)Addr; \
136 /****************************************************************************
137 * Move the BdPtr argument backwards an arbitrary number of BDs wrapping
138 * around to the end of the ring if needed.
140 * We know if a wrapaound should occur if the new BdPtr is less than
141 * the base address in the ring OR if the new BdPtr crosses over the
142 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
143 * allow a BD space to span this boundary.
145 * @param RingPtr is the ring BdPtr appears in
146 * @param BdPtr on input is the starting BD position and on output is the
148 * @param NumBd is the number of BD spaces to increment
150 ****************************************************************************/
151 #define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \
153 u32 Addr = (u32)BdPtr; \
155 Addr -= ((RingPtr)->Separation * NumBd); \
156 if ((Addr < (RingPtr)->BaseBdAddr) || ((u32)BdPtr < Addr)) \
158 Addr += (RingPtr)->Length; \
161 BdPtr = (XEmacPs_Bd*)Addr; \
165 /************************** Function Prototypes ******************************/
168 /************************** Variable Definitions *****************************/
170 /*****************************************************************************/
172 * Using a memory segment allocated by the caller, create and setup the BD list
173 * for the given DMA channel.
175 * @param RingPtr is the instance to be worked on.
176 * @param PhysAddr is the physical base address of user memory region.
177 * @param VirtAddr is the virtual base address of the user memory region. If
178 * address translation is not being utilized, then VirtAddr should be
179 * equivalent to PhysAddr.
180 * @param Alignment governs the byte alignment of individual BDs. This function
181 * will enforce a minimum alignment of 4 bytes with no maximum as long
182 * as it is specified as a power of 2.
183 * @param BdCount is the number of BDs to setup in the user memory region. It
184 * is assumed the region is large enough to contain the BDs.
188 * - XST_SUCCESS if initialization was successful
189 * - XST_NO_FEATURE if the provided instance is a non DMA type
191 * - XST_INVALID_PARAM under any of the following conditions:
192 * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment
194 * 2) Alignment parameter does not meet minimum requirements or is not a
197 * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans
198 * over address 0x00000000 in virtual address space.
201 * Make sure to pass in the right alignment value.
202 *****************************************************************************/
203 int XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, u32 PhysAddr,
204 u32 VirtAddr, u32 Alignment, unsigned BdCount)
210 /* In case there is a failure prior to creating list, make sure the
211 * following attributes are 0 to prevent calls to other functions
212 * from doing anything.
215 RingPtr->FreeCnt = 0;
218 RingPtr->PostCnt = 0;
220 /* Make sure Alignment parameter meets minimum requirements */
221 if (Alignment < XEMACPS_DMABD_MINIMUM_ALIGNMENT) {
222 return (XST_INVALID_PARAM);
225 /* Make sure Alignment is a power of 2 */
226 if ((Alignment - 1) & Alignment) {
227 return (XST_INVALID_PARAM);
230 /* Make sure PhysAddr and VirtAddr are on same Alignment */
231 if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) {
232 return (XST_INVALID_PARAM);
235 /* Is BdCount reasonable? */
237 return (XST_INVALID_PARAM);
240 /* Figure out how many bytes will be between the start of adjacent BDs */
241 RingPtr->Separation =
242 (sizeof(XEmacPs_Bd) + (Alignment - 1)) & ~(Alignment - 1);
244 /* Must make sure the ring doesn't span address 0x00000000. If it does,
245 * then the next/prev BD traversal macros will fail.
247 if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) {
248 return (XST_DMA_SG_LIST_ERROR);
251 /* Initial ring setup:
252 * - Clear the entire space
253 * - Setup each BD's BDA field with the physical address of the next BD
255 memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount));
257 BdVirtAddr = VirtAddr;
258 BdPhyAddr = PhysAddr + RingPtr->Separation;
259 for (i = 1; i < BdCount; i++) {
260 BdVirtAddr += RingPtr->Separation;
261 BdPhyAddr += RingPtr->Separation;
264 /* Setup and initialize pointers and counters */
265 RingPtr->RunState = XST_DMA_SG_IS_STOPPED;
266 RingPtr->BaseBdAddr = VirtAddr;
267 RingPtr->PhysBaseAddr = PhysAddr;
268 RingPtr->HighBdAddr = BdVirtAddr;
270 RingPtr->HighBdAddr - RingPtr->BaseBdAddr + RingPtr->Separation;
271 RingPtr->AllCnt = BdCount;
272 RingPtr->FreeCnt = BdCount;
273 RingPtr->FreeHead = (XEmacPs_Bd *) VirtAddr;
274 RingPtr->PreHead = (XEmacPs_Bd *) VirtAddr;
275 RingPtr->HwHead = (XEmacPs_Bd *) VirtAddr;
276 RingPtr->HwTail = (XEmacPs_Bd *) VirtAddr;
277 RingPtr->PostHead = (XEmacPs_Bd *) VirtAddr;
278 RingPtr->BdaRestart = (XEmacPs_Bd *) PhysAddr;
280 return (XST_SUCCESS);
284 /*****************************************************************************/
286 * Clone the given BD into every BD in the list.
287 * every field of the source BD is replicated in every BD of the list.
289 * This function can be called only when all BDs are in the free group such as
290 * they are immediately after initialization with XEmacPs_BdRingCreate().
291 * This prevents modification of BDs while they are in use by hardware or the
294 * @param RingPtr is the pointer of BD ring instance to be worked on.
295 * @param SrcBdPtr is the source BD template to be cloned into the list. This
296 * BD will be modified.
297 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
301 * - XST_SUCCESS if the list was modified.
302 * - XST_DMA_SG_NO_LIST if a list has not been created.
303 * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under
304 * hardware or user control.
305 * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped.
307 *****************************************************************************/
308 int XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
314 /* Can't do this function if there isn't a ring */
315 if (RingPtr->AllCnt == 0) {
316 return (XST_DMA_SG_NO_LIST);
319 /* Can't do this function with the channel running */
320 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
321 return (XST_DEVICE_IS_STARTED);
324 /* Can't do this function with some of the BDs in use */
325 if (RingPtr->FreeCnt != RingPtr->AllCnt) {
326 return (XST_DMA_SG_LIST_ERROR);
329 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
330 return (XST_INVALID_PARAM);
333 /* Starting from the top of the ring, save BD.Next, overwrite the entire
334 * BD with the template, then restore BD.Next
336 for (i = 0, CurBd = (u32) RingPtr->BaseBdAddr;
337 i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) {
338 memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd));
341 CurBd -= RingPtr->Separation;
343 if (Direction == XEMACPS_RECV) {
344 XEmacPs_BdSetRxWrap(CurBd);
347 XEmacPs_BdSetTxWrap(CurBd);
350 return (XST_SUCCESS);
354 /*****************************************************************************/
356 * Reserve locations in the BD list. The set of returned BDs may be modified
357 * in preparation for future DMA transaction(s). Once the BDs are ready to be
358 * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same
359 * order which they were allocated here. Example:
363 * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet);
365 * if (Status != XST_SUCCESS)
367 * // Not enough BDs available for the request
371 * for (i=0; i<NumBd; i++)
373 * // Prepare CurBd.....
376 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
379 * // Give list to hardware
380 * Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet);
383 * A more advanced use of this function may allocate multiple sets of BDs.
384 * They must be allocated and given to hardware in the correct sequence:
387 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
388 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
391 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
392 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
393 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
394 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
397 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
398 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
399 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
400 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
403 * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal
404 * of the BD set can be done using XEmacPs_BdRingNext() and
405 * XEmacPs_BdRingPrev().
407 * @param RingPtr is a pointer to the BD ring instance to be worked on.
408 * @param NumBd is the number of BDs to allocate
409 * @param BdSetPtr is an output parameter, it points to the first BD available
413 * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr
415 * - XST_FAILURE if there were not enough free BDs to satisfy the request.
417 * @note This function should not be preempted by another XEmacPs_Bd function
418 * call that modifies the BD space. It is the caller's responsibility to
419 * provide a mutual exclusion mechanism.
421 * @note Do not modify more BDs than the number requested with the NumBd
422 * parameter. Doing so will lead to data corruption and system
425 *****************************************************************************/
426 int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
427 XEmacPs_Bd ** BdSetPtr)
429 /* Enough free BDs available for the request? */
430 if (RingPtr->FreeCnt < NumBd) {
431 return (XST_FAILURE);
434 /* Set the return argument and move FreeHead forward */
435 *BdSetPtr = RingPtr->FreeHead;
436 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd);
437 RingPtr->FreeCnt -= NumBd;
438 RingPtr->PreCnt += NumBd;
439 return (XST_SUCCESS);
442 /*****************************************************************************/
444 * Fully or partially undo an XEmacPs_BdRingAlloc() operation. Use this
445 * function if all the BDs allocated by XEmacPs_BdRingAlloc() could not be
446 * transferred to hardware with XEmacPs_BdRingToHw().
448 * This function helps out in situations when an unrelated error occurs after
449 * BDs have been allocated but before they have been given to hardware.
450 * An example of this type of error would be an OS running out of resources.
452 * This function is not the same as XEmacPs_BdRingFree(). The Free function
453 * returns BDs to the free list after they have been processed by hardware,
454 * while UnAlloc returns them before being processed by hardware.
456 * There are two scenarios where this function can be used. Full UnAlloc or
457 * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
460 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
464 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
468 * A partial UnAlloc means some of the BDs Alloc'd will be returned:
471 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
479 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
482 * CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr);
487 * A partial UnAlloc must include the last BD in the list that was Alloc'd.
489 * @param RingPtr is a pointer to the instance to be worked on.
490 * @param NumBd is the number of BDs to allocate
491 * @param BdSetPtr is an output parameter, it points to the first BD available
495 * - XST_SUCCESS if the BDs were unallocated.
496 * - XST_FAILURE if NumBd parameter was greater that the number of BDs in
497 * the preprocessing state.
499 * @note This function should not be preempted by another XEmacPs_Bd function
500 * call that modifies the BD space. It is the caller's responsibility to
501 * provide a mutual exclusion mechanism.
503 *****************************************************************************/
504 int XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
505 XEmacPs_Bd * BdSetPtr)
509 /* Enough BDs in the free state for the request? */
510 if (RingPtr->PreCnt < NumBd) {
511 return (XST_FAILURE);
514 /* Set the return argument and move FreeHead backward */
515 XEMACPS_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd);
516 RingPtr->FreeCnt += NumBd;
517 RingPtr->PreCnt -= NumBd;
518 return (XST_SUCCESS);
522 /*****************************************************************************/
524 * Enqueue a set of BDs to hardware that were previously allocated by
525 * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes
526 * under hardware control. Any changes made to these BDs after this point will
527 * corrupt the BD list leading to data corruption and system instability.
529 * The set will be rejected if the last BD of the set does not mark the end of
530 * a packet (see XEmacPs_BdSetLast()).
532 * @param RingPtr is a pointer to the instance to be worked on.
533 * @param NumBd is the number of BDs in the set.
534 * @param BdSetPtr is the first BD of the set to commit to hardware.
537 * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware.
538 * - XST_FAILURE if the set of BDs was rejected because the last BD of the set
539 * did not have its "last" bit set.
540 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
541 * XEmacPs_BdRingAlloc().
543 * @note This function should not be preempted by another XEmacPs_Bd function
544 * call that modifies the BD space. It is the caller's responsibility to
545 * provide a mutual exclusion mechanism.
547 *****************************************************************************/
548 int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd,
549 XEmacPs_Bd * BdSetPtr)
551 XEmacPs_Bd *CurBdPtr;
554 /* if no bds to process, simply return. */
556 return (XST_SUCCESS);
558 /* Make sure we are in sync with XEmacPs_BdRingAlloc() */
559 if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) {
560 return (XST_DMA_SG_LIST_ERROR);
564 for (i = 0; i < NumBd; i++) {
565 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
568 /* Adjust ring pointers & counters */
569 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd);
570 RingPtr->PreCnt -= NumBd;
572 RingPtr->HwTail = CurBdPtr;
573 RingPtr->HwCnt += NumBd;
575 return (XST_SUCCESS);
579 /*****************************************************************************/
581 * Returns a set of BD(s) that have been processed by hardware. The returned
582 * BDs may be examined to determine the outcome of the DMA transaction(s).
583 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
584 * in the same order which they were retrieved here. Example:
587 * NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet);
591 * // hardware has nothing ready for us yet
595 * for (i=0; i<NumBd; i++)
597 * // Examine CurBd for post processing.....
600 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
603 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
607 * A more advanced use of this function may allocate multiple sets of BDs.
608 * They must be retrieved from hardware and freed in the correct sequence:
611 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
612 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
615 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
616 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
617 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
618 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
621 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
622 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
623 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
624 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
627 * If hardware has only partially completed a packet spanning multiple BDs,
628 * then none of the BDs for that packet will be included in the results.
630 * @param RingPtr is a pointer to the instance to be worked on.
631 * @param BdLimit is the maximum number of BDs to return in the set.
632 * @param BdSetPtr is an output parameter, it points to the first BD available
636 * The number of BDs processed by hardware. A value of 0 indicates that no
637 * data is available. No more than BdLimit BDs will be returned.
639 * @note Treat BDs returned by this function as read-only.
641 * @note This function should not be preempted by another XEmacPs_Bd function
642 * call that modifies the BD space. It is the caller's responsibility to
643 * provide a mutual exclusion mechanism.
645 *****************************************************************************/
646 unsigned XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
647 XEmacPs_Bd ** BdSetPtr)
649 XEmacPs_Bd *CurBdPtr;
652 unsigned BdPartialCount;
653 unsigned int Sop = 0;
656 CurBdPtr = RingPtr->HwHead;
660 /* If no BDs in work group, then there's nothing to search */
661 if (RingPtr->HwCnt == 0) {
666 if (BdLimit > RingPtr->HwCnt)
667 BdLimit = RingPtr->HwCnt;
669 /* Starting at HwHead, keep moving forward in the list until:
670 * - A BD is encountered with its new/used bit set which means
671 * hardware has not completed processing of that BD.
672 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
673 * - The number of requested BDs has been processed
675 while (BdCount < BdLimit) {
676 /* Read the status */
677 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
679 if ((Sop == 0) && (BdStr & XEMACPS_TXBUF_USED_MASK))
687 /* hardware has processed this BD so check the "last" bit.
688 * If it is clear, then there are more BDs for the current
689 * packet. Keep a count of these partial packet BDs.
691 if ((Sop == 1) && (BdStr & XEMACPS_TXBUF_LAST_MASK)) {
696 /* Move on to next BD in work group */
697 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
700 /* Subtract off any partial packet BDs found */
701 BdCount -= BdPartialCount;
703 /* If BdCount is non-zero then BDs were found to return. Set return
704 * parameters, update pointers and counters, return success
707 *BdSetPtr = RingPtr->HwHead;
708 RingPtr->HwCnt -= BdCount;
709 RingPtr->PostCnt += BdCount;
710 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
720 /*****************************************************************************/
722 * Returns a set of BD(s) that have been processed by hardware. The returned
723 * BDs may be examined to determine the outcome of the DMA transaction(s).
724 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
725 * in the same order which they were retrieved here. Example:
728 * NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
732 * // hardware has nothing ready for us yet
736 * for (i=0; i<NumBd; i++)
738 * // Examine CurBd for post processing.....
741 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
744 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
748 * A more advanced use of this function may allocate multiple sets of BDs.
749 * They must be retrieved from hardware and freed in the correct sequence:
752 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
753 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
756 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
757 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
758 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
759 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
762 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
763 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
764 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
765 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
768 * If hardware has only partially completed a packet spanning multiple BDs,
769 * then none of the BDs for that packet will be included in the results.
771 * @param RingPtr is a pointer to the instance to be worked on.
772 * @param BdLimit is the maximum number of BDs to return in the set.
773 * @param BdSetPtr is an output parameter, it points to the first BD available
777 * The number of BDs processed by hardware. A value of 0 indicates that no
778 * data is available. No more than BdLimit BDs will be returned.
780 * @note Treat BDs returned by this function as read-only.
782 * @note This function should not be preempted by another XEmacPs_Bd function
783 * call that modifies the BD space. It is the caller's responsibility to
784 * provide a mutual exclusion mechanism.
786 *****************************************************************************/
787 unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
788 XEmacPs_Bd ** BdSetPtr)
790 XEmacPs_Bd *CurBdPtr;
793 unsigned BdPartialCount;
795 CurBdPtr = RingPtr->HwHead;
799 /* If no BDs in work group, then there's nothing to search */
800 if (RingPtr->HwCnt == 0) {
805 /* Starting at HwHead, keep moving forward in the list until:
806 * - A BD is encountered with its new/used bit set which means
807 * hardware has completed processing of that BD.
808 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
809 * - The number of requested BDs has been processed
811 while (BdCount < BdLimit) {
813 /* Read the status */
814 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
816 if (!(XEmacPs_BdIsRxNew(CurBdPtr))) {
822 /* hardware has processed this BD so check the "last" bit. If
823 * it is clear, then there are more BDs for the current packet.
824 * Keep a count of these partial packet BDs.
826 if (BdStr & XEMACPS_RXBUF_EOF_MASK) {
833 /* Move on to next BD in work group */
834 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
837 /* Subtract off any partial packet BDs found */
838 BdCount -= BdPartialCount;
840 /* If BdCount is non-zero then BDs were found to return. Set return
841 * parameters, update pointers and counters, return success
844 *BdSetPtr = RingPtr->HwHead;
845 RingPtr->HwCnt -= BdCount;
846 RingPtr->PostCnt += BdCount;
847 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
857 /*****************************************************************************/
859 * Frees a set of BDs that had been previously retrieved with
860 * XEmacPs_BdRingFromHw().
862 * @param RingPtr is a pointer to the instance to be worked on.
863 * @param NumBd is the number of BDs to free.
864 * @param BdSetPtr is the head of a list of BDs returned by
865 * XEmacPs_BdRingFromHw().
868 * - XST_SUCCESS if the set of BDs was freed.
869 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
870 * XEmacPs_BdRingFromHw().
872 * @note This function should not be preempted by another XEmacPs_Bd function
873 * call that modifies the BD space. It is the caller's responsibility to
874 * provide a mutual exclusion mechanism.
876 *****************************************************************************/
877 int XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd,
878 XEmacPs_Bd * BdSetPtr)
880 /* if no bds to process, simply return. */
882 return (XST_SUCCESS);
884 /* Make sure we are in sync with XEmacPs_BdRingFromHw() */
885 if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) {
886 return (XST_DMA_SG_LIST_ERROR);
889 /* Update pointers and counters */
890 RingPtr->FreeCnt += NumBd;
891 RingPtr->PostCnt -= NumBd;
892 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd);
893 return (XST_SUCCESS);
897 /*****************************************************************************/
899 * Check the internal data structures of the BD ring for the provided channel.
900 * The following checks are made:
902 * - Is the BD ring linked correctly in physical address space.
903 * - Do the internal pointers point to BDs in the ring.
904 * - Do the internal counters add up.
906 * The channel should be stopped prior to calling this function.
908 * @param RingPtr is a pointer to the instance to be worked on.
909 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
913 * - XST_SUCCESS if the set of BDs was freed.
914 * - XST_DMA_SG_NO_LIST if the list has not been created.
915 * - XST_IS_STARTED if the channel is not stopped.
916 * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
917 * structures. If this value is returned, the channel should be reset to
918 * avoid data corruption or system instability.
920 * @note This function should not be preempted by another XEmacPs_Bd function
921 * call that modifies the BD space. It is the caller's responsibility to
922 * provide a mutual exclusion mechanism.
924 *****************************************************************************/
925 int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
930 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
931 return (XST_INVALID_PARAM);
934 /* Is the list created */
935 if (RingPtr->AllCnt == 0) {
936 return (XST_DMA_SG_NO_LIST);
939 /* Can't check if channel is running */
940 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
941 return (XST_IS_STARTED);
944 /* RunState doesn't make sense */
945 else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) {
946 return (XST_DMA_SG_LIST_ERROR);
949 /* Verify internal pointers point to correct memory space */
950 AddrV = (u32) RingPtr->FreeHead;
951 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
952 return (XST_DMA_SG_LIST_ERROR);
955 AddrV = (u32) RingPtr->PreHead;
956 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
957 return (XST_DMA_SG_LIST_ERROR);
960 AddrV = (u32) RingPtr->HwHead;
961 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
962 return (XST_DMA_SG_LIST_ERROR);
965 AddrV = (u32) RingPtr->HwTail;
966 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
967 return (XST_DMA_SG_LIST_ERROR);
970 AddrV = (u32) RingPtr->PostHead;
971 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
972 return (XST_DMA_SG_LIST_ERROR);
975 /* Verify internal counters add up */
976 if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
977 RingPtr->PostCnt) != RingPtr->AllCnt) {
978 return (XST_DMA_SG_LIST_ERROR);
981 /* Verify BDs are linked correctly */
982 AddrV = RingPtr->BaseBdAddr;
983 AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
985 for (i = 1; i < RingPtr->AllCnt; i++) {
986 /* Check BDA for this BD. It should point to next physical addr */
987 if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
988 return (XST_DMA_SG_LIST_ERROR);
991 /* Move on to next BD */
992 AddrV += RingPtr->Separation;
993 AddrP += RingPtr->Separation;
996 /* Last BD should have wrap bit set */
997 if (XEMACPS_SEND == Direction) {
998 if (!XEmacPs_BdIsTxWrap(AddrV)) {
999 return (XST_DMA_SG_LIST_ERROR);
1002 else { /* XEMACPS_RECV */
1003 if (!XEmacPs_BdIsRxWrap(AddrV)) {
1004 return (XST_DMA_SG_LIST_ERROR);
1008 /* No problems found */
1009 return (XST_SUCCESS);