1 /* $Id: xemacps_bdring.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */
2 /******************************************************************************
4 * Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * Use of the Software is limited solely to applications:
17 * (a) running on a Xilinx device, or
18 * (b) that interact with a Xilinx device through a bus or interconnect.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
25 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * Except as contained in this notice, the name of the Xilinx shall not be used
29 * in advertising or otherwise to promote the sale, use or other dealings in
30 * this Software without prior written authorization from Xilinx.
32 ******************************************************************************/
33 /*****************************************************************************/
36 * @file xemacps_bdring.c
38 * This file implements buffer descriptor ring related functions.
41 * MODIFICATION HISTORY:
43 * Ver Who Date Changes
44 * ----- ---- -------- -------------------------------------------------------
45 * 1.00a wsy 01/10/10 First release
46 * 1.00a asa 11/21/11 The function XEmacPs_BdRingFromHwTx is modified.
47 * Earlier it used to search in "BdLimit" number of BDs to
48 * know which BDs are processed. Now one more check is
49 * added. It looks for BDs till the current BD pointer
50 * reaches HwTail. By doing this processing time is saved.
51 * 1.00a asa 01/24/12 The function XEmacPs_BdRingFromHwTx in file
52 * xemacps_bdring.c is modified. Now start of packet is
53 * searched for returning the number of BDs processed.
54 * 1.05a asa 09/23/13 Cache operations on BDs are not required and hence
55 * removed. It is expected that all BDs are allocated in
56 * from uncached area. Fix for CR #663885.
58 ******************************************************************************/
60 /***************************** Include Files *********************************/
63 #include "xil_cache.h"
64 #include "xemacps_hw.h"
65 #include "xemacps_bd.h"
66 #include "xemacps_bdring.h"
68 /************************** Constant Definitions *****************************/
70 /**************************** Type Definitions *******************************/
73 /***************** Macros (Inline Functions) Definitions *********************/
75 /****************************************************************************
76 * Compute the virtual address of a descriptor from its physical address
78 * @param BdPtr is the physical address of the BD
80 * @returns Virtual address of BdPtr
82 * @note Assume BdPtr is always a valid BD in the ring
83 ****************************************************************************/
84 #define XEMACPS_PHYS_TO_VIRT(BdPtr) \
85 ((u32)BdPtr + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
87 /****************************************************************************
88 * Compute the physical address of a descriptor from its virtual address
90 * @param BdPtr is the physical address of the BD
92 * @returns Physical address of BdPtr
94 * @note Assume BdPtr is always a valid BD in the ring
95 ****************************************************************************/
96 #define XEMACPS_VIRT_TO_PHYS(BdPtr) \
97 ((u32)BdPtr - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
99 /****************************************************************************
100 * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around
101 * to the beginning of the ring if needed.
103 * We know if a wrapaound should occur if the new BdPtr is greater than
104 * the high address in the ring OR if the new BdPtr crosses over the
105 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
106 * allow a BD space to span this boundary.
108 * @param RingPtr is the ring BdPtr appears in
109 * @param BdPtr on input is the starting BD position and on output is the
111 * @param NumBd is the number of BD spaces to increment
113 ****************************************************************************/
114 #define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \
116 u32 Addr = (u32)BdPtr; \
118 Addr += ((RingPtr)->Separation * NumBd); \
119 if ((Addr > (RingPtr)->HighBdAddr) || ((u32)BdPtr > Addr)) \
121 Addr -= (RingPtr)->Length; \
124 BdPtr = (XEmacPs_Bd*)Addr; \
127 /****************************************************************************
128 * Move the BdPtr argument backwards an arbitrary number of BDs wrapping
129 * around to the end of the ring if needed.
131 * We know if a wrapaound should occur if the new BdPtr is less than
132 * the base address in the ring OR if the new BdPtr crosses over the
133 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
134 * allow a BD space to span this boundary.
136 * @param RingPtr is the ring BdPtr appears in
137 * @param BdPtr on input is the starting BD position and on output is the
139 * @param NumBd is the number of BD spaces to increment
141 ****************************************************************************/
142 #define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \
144 u32 Addr = (u32)BdPtr; \
146 Addr -= ((RingPtr)->Separation * NumBd); \
147 if ((Addr < (RingPtr)->BaseBdAddr) || ((u32)BdPtr < Addr)) \
149 Addr += (RingPtr)->Length; \
152 BdPtr = (XEmacPs_Bd*)Addr; \
156 /************************** Function Prototypes ******************************/
159 /************************** Variable Definitions *****************************/
161 /*****************************************************************************/
163 * Using a memory segment allocated by the caller, create and setup the BD list
164 * for the given DMA channel.
166 * @param RingPtr is the instance to be worked on.
167 * @param PhysAddr is the physical base address of user memory region.
168 * @param VirtAddr is the virtual base address of the user memory region. If
169 * address translation is not being utilized, then VirtAddr should be
170 * equivalent to PhysAddr.
171 * @param Alignment governs the byte alignment of individual BDs. This function
172 * will enforce a minimum alignment of 4 bytes with no maximum as long
173 * as it is specified as a power of 2.
174 * @param BdCount is the number of BDs to setup in the user memory region. It
175 * is assumed the region is large enough to contain the BDs.
179 * - XST_SUCCESS if initialization was successful
180 * - XST_NO_FEATURE if the provided instance is a non DMA type
182 * - XST_INVALID_PARAM under any of the following conditions:
183 * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment
185 * 2) Alignment parameter does not meet minimum requirements or is not a
188 * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans
189 * over address 0x00000000 in virtual address space.
192 * Make sure to pass in the right alignment value.
193 *****************************************************************************/
194 int XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, u32 PhysAddr,
195 u32 VirtAddr, u32 Alignment, unsigned BdCount)
201 /* In case there is a failure prior to creating list, make sure the
202 * following attributes are 0 to prevent calls to other functions
203 * from doing anything.
206 RingPtr->FreeCnt = 0;
209 RingPtr->PostCnt = 0;
211 /* Make sure Alignment parameter meets minimum requirements */
212 if (Alignment < XEMACPS_DMABD_MINIMUM_ALIGNMENT) {
213 return (XST_INVALID_PARAM);
216 /* Make sure Alignment is a power of 2 */
217 if ((Alignment - 1) & Alignment) {
218 return (XST_INVALID_PARAM);
221 /* Make sure PhysAddr and VirtAddr are on same Alignment */
222 if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) {
223 return (XST_INVALID_PARAM);
226 /* Is BdCount reasonable? */
228 return (XST_INVALID_PARAM);
231 /* Figure out how many bytes will be between the start of adjacent BDs */
232 RingPtr->Separation =
233 (sizeof(XEmacPs_Bd) + (Alignment - 1)) & ~(Alignment - 1);
235 /* Must make sure the ring doesn't span address 0x00000000. If it does,
236 * then the next/prev BD traversal macros will fail.
238 if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) {
239 return (XST_DMA_SG_LIST_ERROR);
242 /* Initial ring setup:
243 * - Clear the entire space
244 * - Setup each BD's BDA field with the physical address of the next BD
246 memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount));
248 BdVirtAddr = VirtAddr;
249 BdPhyAddr = PhysAddr + RingPtr->Separation;
250 for (i = 1; i < BdCount; i++) {
251 BdVirtAddr += RingPtr->Separation;
252 BdPhyAddr += RingPtr->Separation;
255 /* Setup and initialize pointers and counters */
256 RingPtr->RunState = XST_DMA_SG_IS_STOPPED;
257 RingPtr->BaseBdAddr = VirtAddr;
258 RingPtr->PhysBaseAddr = PhysAddr;
259 RingPtr->HighBdAddr = BdVirtAddr;
261 RingPtr->HighBdAddr - RingPtr->BaseBdAddr + RingPtr->Separation;
262 RingPtr->AllCnt = BdCount;
263 RingPtr->FreeCnt = BdCount;
264 RingPtr->FreeHead = (XEmacPs_Bd *) VirtAddr;
265 RingPtr->PreHead = (XEmacPs_Bd *) VirtAddr;
266 RingPtr->HwHead = (XEmacPs_Bd *) VirtAddr;
267 RingPtr->HwTail = (XEmacPs_Bd *) VirtAddr;
268 RingPtr->PostHead = (XEmacPs_Bd *) VirtAddr;
269 RingPtr->BdaRestart = (XEmacPs_Bd *) PhysAddr;
271 return (XST_SUCCESS);
275 /*****************************************************************************/
277 * Clone the given BD into every BD in the list.
278 * every field of the source BD is replicated in every BD of the list.
280 * This function can be called only when all BDs are in the free group such as
281 * they are immediately after initialization with XEmacPs_BdRingCreate().
282 * This prevents modification of BDs while they are in use by hardware or the
285 * @param RingPtr is the pointer of BD ring instance to be worked on.
286 * @param SrcBdPtr is the source BD template to be cloned into the list. This
287 * BD will be modified.
288 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
292 * - XST_SUCCESS if the list was modified.
293 * - XST_DMA_SG_NO_LIST if a list has not been created.
294 * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under
295 * hardware or user control.
296 * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped.
298 *****************************************************************************/
299 int XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
305 /* Can't do this function if there isn't a ring */
306 if (RingPtr->AllCnt == 0) {
307 return (XST_DMA_SG_NO_LIST);
310 /* Can't do this function with the channel running */
311 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
312 return (XST_DEVICE_IS_STARTED);
315 /* Can't do this function with some of the BDs in use */
316 if (RingPtr->FreeCnt != RingPtr->AllCnt) {
317 return (XST_DMA_SG_LIST_ERROR);
320 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
321 return (XST_INVALID_PARAM);
324 /* Starting from the top of the ring, save BD.Next, overwrite the entire
325 * BD with the template, then restore BD.Next
327 for (i = 0, CurBd = (u32) RingPtr->BaseBdAddr;
328 i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) {
329 memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd));
332 CurBd -= RingPtr->Separation;
334 if (Direction == XEMACPS_RECV) {
335 XEmacPs_BdSetRxWrap(CurBd);
338 XEmacPs_BdSetTxWrap(CurBd);
341 return (XST_SUCCESS);
345 /*****************************************************************************/
347 * Reserve locations in the BD list. The set of returned BDs may be modified
348 * in preparation for future DMA transaction(s). Once the BDs are ready to be
349 * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same
350 * order which they were allocated here. Example:
354 * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet);
356 * if (Status != XST_SUCCESS)
358 * // Not enough BDs available for the request
362 * for (i=0; i<NumBd; i++)
364 * // Prepare CurBd.....
367 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
370 * // Give list to hardware
371 * Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet);
374 * A more advanced use of this function may allocate multiple sets of BDs.
375 * They must be allocated and given to hardware in the correct sequence:
378 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
379 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
382 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
383 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
384 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
385 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
388 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
389 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
390 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
391 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
394 * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal
395 * of the BD set can be done using XEmacPs_BdRingNext() and
396 * XEmacPs_BdRingPrev().
398 * @param RingPtr is a pointer to the BD ring instance to be worked on.
399 * @param NumBd is the number of BDs to allocate
400 * @param BdSetPtr is an output parameter, it points to the first BD available
404 * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr
406 * - XST_FAILURE if there were not enough free BDs to satisfy the request.
408 * @note This function should not be preempted by another XEmacPs_Bd function
409 * call that modifies the BD space. It is the caller's responsibility to
410 * provide a mutual exclusion mechanism.
412 * @note Do not modify more BDs than the number requested with the NumBd
413 * parameter. Doing so will lead to data corruption and system
416 *****************************************************************************/
417 int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
418 XEmacPs_Bd ** BdSetPtr)
420 /* Enough free BDs available for the request? */
421 if (RingPtr->FreeCnt < NumBd) {
422 return (XST_FAILURE);
425 /* Set the return argument and move FreeHead forward */
426 *BdSetPtr = RingPtr->FreeHead;
427 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd);
428 RingPtr->FreeCnt -= NumBd;
429 RingPtr->PreCnt += NumBd;
430 return (XST_SUCCESS);
433 /*****************************************************************************/
435 * Fully or partially undo an XEmacPs_BdRingAlloc() operation. Use this
436 * function if all the BDs allocated by XEmacPs_BdRingAlloc() could not be
437 * transferred to hardware with XEmacPs_BdRingToHw().
439 * This function helps out in situations when an unrelated error occurs after
440 * BDs have been allocated but before they have been given to hardware.
441 * An example of this type of error would be an OS running out of resources.
443 * This function is not the same as XEmacPs_BdRingFree(). The Free function
444 * returns BDs to the free list after they have been processed by hardware,
445 * while UnAlloc returns them before being processed by hardware.
447 * There are two scenarios where this function can be used. Full UnAlloc or
448 * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
451 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
455 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
459 * A partial UnAlloc means some of the BDs Alloc'd will be returned:
462 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
470 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
473 * CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr);
478 * A partial UnAlloc must include the last BD in the list that was Alloc'd.
480 * @param RingPtr is a pointer to the instance to be worked on.
481 * @param NumBd is the number of BDs to allocate
482 * @param BdSetPtr is an output parameter, it points to the first BD available
486 * - XST_SUCCESS if the BDs were unallocated.
487 * - XST_FAILURE if NumBd parameter was greater that the number of BDs in
488 * the preprocessing state.
490 * @note This function should not be preempted by another XEmacPs_Bd function
491 * call that modifies the BD space. It is the caller's responsibility to
492 * provide a mutual exclusion mechanism.
494 *****************************************************************************/
495 int XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
496 XEmacPs_Bd * BdSetPtr)
500 /* Enough BDs in the free state for the request? */
501 if (RingPtr->PreCnt < NumBd) {
502 return (XST_FAILURE);
505 /* Set the return argument and move FreeHead backward */
506 XEMACPS_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd);
507 RingPtr->FreeCnt += NumBd;
508 RingPtr->PreCnt -= NumBd;
509 return (XST_SUCCESS);
513 /*****************************************************************************/
515 * Enqueue a set of BDs to hardware that were previously allocated by
516 * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes
517 * under hardware control. Any changes made to these BDs after this point will
518 * corrupt the BD list leading to data corruption and system instability.
520 * The set will be rejected if the last BD of the set does not mark the end of
521 * a packet (see XEmacPs_BdSetLast()).
523 * @param RingPtr is a pointer to the instance to be worked on.
524 * @param NumBd is the number of BDs in the set.
525 * @param BdSetPtr is the first BD of the set to commit to hardware.
528 * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware.
529 * - XST_FAILURE if the set of BDs was rejected because the last BD of the set
530 * did not have its "last" bit set.
531 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
532 * XEmacPs_BdRingAlloc().
534 * @note This function should not be preempted by another XEmacPs_Bd function
535 * call that modifies the BD space. It is the caller's responsibility to
536 * provide a mutual exclusion mechanism.
538 *****************************************************************************/
539 int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd,
540 XEmacPs_Bd * BdSetPtr)
542 XEmacPs_Bd *CurBdPtr;
545 /* if no bds to process, simply return. */
547 return (XST_SUCCESS);
549 /* Make sure we are in sync with XEmacPs_BdRingAlloc() */
550 if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) {
551 return (XST_DMA_SG_LIST_ERROR);
555 for (i = 0; i < NumBd; i++) {
556 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
559 /* Adjust ring pointers & counters */
560 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd);
561 RingPtr->PreCnt -= NumBd;
563 RingPtr->HwTail = CurBdPtr;
564 RingPtr->HwCnt += NumBd;
566 return (XST_SUCCESS);
570 /*****************************************************************************/
572 * Returns a set of BD(s) that have been processed by hardware. The returned
573 * BDs may be examined to determine the outcome of the DMA transaction(s).
574 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
575 * in the same order which they were retrieved here. Example:
578 * NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet);
582 * // hardware has nothing ready for us yet
586 * for (i=0; i<NumBd; i++)
588 * // Examine CurBd for post processing.....
591 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
594 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
598 * A more advanced use of this function may allocate multiple sets of BDs.
599 * They must be retrieved from hardware and freed in the correct sequence:
602 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
603 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
606 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
607 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
608 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
609 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
612 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
613 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
614 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
615 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
618 * If hardware has only partially completed a packet spanning multiple BDs,
619 * then none of the BDs for that packet will be included in the results.
621 * @param RingPtr is a pointer to the instance to be worked on.
622 * @param BdLimit is the maximum number of BDs to return in the set.
623 * @param BdSetPtr is an output parameter, it points to the first BD available
627 * The number of BDs processed by hardware. A value of 0 indicates that no
628 * data is available. No more than BdLimit BDs will be returned.
630 * @note Treat BDs returned by this function as read-only.
632 * @note This function should not be preempted by another XEmacPs_Bd function
633 * call that modifies the BD space. It is the caller's responsibility to
634 * provide a mutual exclusion mechanism.
636 *****************************************************************************/
637 unsigned XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
638 XEmacPs_Bd ** BdSetPtr)
640 XEmacPs_Bd *CurBdPtr;
643 unsigned BdPartialCount;
644 unsigned int Sop = 0;
647 CurBdPtr = RingPtr->HwHead;
651 /* If no BDs in work group, then there's nothing to search */
652 if (RingPtr->HwCnt == 0) {
657 if (BdLimit > RingPtr->HwCnt)
658 BdLimit = RingPtr->HwCnt;
660 /* Starting at HwHead, keep moving forward in the list until:
661 * - A BD is encountered with its new/used bit set which means
662 * hardware has not completed processing of that BD.
663 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
664 * - The number of requested BDs has been processed
666 while (BdCount < BdLimit) {
667 /* Read the status */
668 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
670 if ((Sop == 0) && (BdStr & XEMACPS_TXBUF_USED_MASK))
678 /* hardware has processed this BD so check the "last" bit.
679 * If it is clear, then there are more BDs for the current
680 * packet. Keep a count of these partial packet BDs.
682 if ((Sop == 1) && (BdStr & XEMACPS_TXBUF_LAST_MASK)) {
687 /* Move on to next BD in work group */
688 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
691 /* Subtract off any partial packet BDs found */
692 BdCount -= BdPartialCount;
694 /* If BdCount is non-zero then BDs were found to return. Set return
695 * parameters, update pointers and counters, return success
698 *BdSetPtr = RingPtr->HwHead;
699 RingPtr->HwCnt -= BdCount;
700 RingPtr->PostCnt += BdCount;
701 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
711 /*****************************************************************************/
713 * Returns a set of BD(s) that have been processed by hardware. The returned
714 * BDs may be examined to determine the outcome of the DMA transaction(s).
715 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
716 * in the same order which they were retrieved here. Example:
719 * NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
723 * // hardware has nothing ready for us yet
727 * for (i=0; i<NumBd; i++)
729 * // Examine CurBd for post processing.....
732 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
735 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
739 * A more advanced use of this function may allocate multiple sets of BDs.
740 * They must be retrieved from hardware and freed in the correct sequence:
743 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
744 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
747 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
748 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
749 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
750 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
753 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
754 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
755 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
756 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
759 * If hardware has only partially completed a packet spanning multiple BDs,
760 * then none of the BDs for that packet will be included in the results.
762 * @param RingPtr is a pointer to the instance to be worked on.
763 * @param BdLimit is the maximum number of BDs to return in the set.
764 * @param BdSetPtr is an output parameter, it points to the first BD available
768 * The number of BDs processed by hardware. A value of 0 indicates that no
769 * data is available. No more than BdLimit BDs will be returned.
771 * @note Treat BDs returned by this function as read-only.
773 * @note This function should not be preempted by another XEmacPs_Bd function
774 * call that modifies the BD space. It is the caller's responsibility to
775 * provide a mutual exclusion mechanism.
777 *****************************************************************************/
778 unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
779 XEmacPs_Bd ** BdSetPtr)
781 XEmacPs_Bd *CurBdPtr;
784 unsigned BdPartialCount;
786 CurBdPtr = RingPtr->HwHead;
790 /* If no BDs in work group, then there's nothing to search */
791 if (RingPtr->HwCnt == 0) {
796 /* Starting at HwHead, keep moving forward in the list until:
797 * - A BD is encountered with its new/used bit set which means
798 * hardware has completed processing of that BD.
799 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
800 * - The number of requested BDs has been processed
802 while (BdCount < BdLimit) {
804 /* Read the status */
805 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
807 if (!(XEmacPs_BdIsRxNew(CurBdPtr))) {
813 /* hardware has processed this BD so check the "last" bit. If
814 * it is clear, then there are more BDs for the current packet.
815 * Keep a count of these partial packet BDs.
817 if (BdStr & XEMACPS_RXBUF_EOF_MASK) {
824 /* Move on to next BD in work group */
825 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
828 /* Subtract off any partial packet BDs found */
829 BdCount -= BdPartialCount;
831 /* If BdCount is non-zero then BDs were found to return. Set return
832 * parameters, update pointers and counters, return success
835 *BdSetPtr = RingPtr->HwHead;
836 RingPtr->HwCnt -= BdCount;
837 RingPtr->PostCnt += BdCount;
838 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
848 /*****************************************************************************/
850 * Frees a set of BDs that had been previously retrieved with
851 * XEmacPs_BdRingFromHw().
853 * @param RingPtr is a pointer to the instance to be worked on.
854 * @param NumBd is the number of BDs to free.
855 * @param BdSetPtr is the head of a list of BDs returned by
856 * XEmacPs_BdRingFromHw().
859 * - XST_SUCCESS if the set of BDs was freed.
860 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
861 * XEmacPs_BdRingFromHw().
863 * @note This function should not be preempted by another XEmacPs_Bd function
864 * call that modifies the BD space. It is the caller's responsibility to
865 * provide a mutual exclusion mechanism.
867 *****************************************************************************/
868 int XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd,
869 XEmacPs_Bd * BdSetPtr)
871 /* if no bds to process, simply return. */
873 return (XST_SUCCESS);
875 /* Make sure we are in sync with XEmacPs_BdRingFromHw() */
876 if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) {
877 return (XST_DMA_SG_LIST_ERROR);
880 /* Update pointers and counters */
881 RingPtr->FreeCnt += NumBd;
882 RingPtr->PostCnt -= NumBd;
883 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd);
884 return (XST_SUCCESS);
888 /*****************************************************************************/
890 * Check the internal data structures of the BD ring for the provided channel.
891 * The following checks are made:
893 * - Is the BD ring linked correctly in physical address space.
894 * - Do the internal pointers point to BDs in the ring.
895 * - Do the internal counters add up.
897 * The channel should be stopped prior to calling this function.
899 * @param RingPtr is a pointer to the instance to be worked on.
900 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
904 * - XST_SUCCESS if the set of BDs was freed.
905 * - XST_DMA_SG_NO_LIST if the list has not been created.
906 * - XST_IS_STARTED if the channel is not stopped.
907 * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
908 * structures. If this value is returned, the channel should be reset to
909 * avoid data corruption or system instability.
911 * @note This function should not be preempted by another XEmacPs_Bd function
912 * call that modifies the BD space. It is the caller's responsibility to
913 * provide a mutual exclusion mechanism.
915 *****************************************************************************/
916 int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
921 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
922 return (XST_INVALID_PARAM);
925 /* Is the list created */
926 if (RingPtr->AllCnt == 0) {
927 return (XST_DMA_SG_NO_LIST);
930 /* Can't check if channel is running */
931 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
932 return (XST_IS_STARTED);
935 /* RunState doesn't make sense */
936 else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) {
937 return (XST_DMA_SG_LIST_ERROR);
940 /* Verify internal pointers point to correct memory space */
941 AddrV = (u32) RingPtr->FreeHead;
942 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
943 return (XST_DMA_SG_LIST_ERROR);
946 AddrV = (u32) RingPtr->PreHead;
947 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
948 return (XST_DMA_SG_LIST_ERROR);
951 AddrV = (u32) RingPtr->HwHead;
952 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
953 return (XST_DMA_SG_LIST_ERROR);
956 AddrV = (u32) RingPtr->HwTail;
957 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
958 return (XST_DMA_SG_LIST_ERROR);
961 AddrV = (u32) RingPtr->PostHead;
962 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
963 return (XST_DMA_SG_LIST_ERROR);
966 /* Verify internal counters add up */
967 if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
968 RingPtr->PostCnt) != RingPtr->AllCnt) {
969 return (XST_DMA_SG_LIST_ERROR);
972 /* Verify BDs are linked correctly */
973 AddrV = RingPtr->BaseBdAddr;
974 AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
976 for (i = 1; i < RingPtr->AllCnt; i++) {
977 /* Check BDA for this BD. It should point to next physical addr */
978 if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
979 return (XST_DMA_SG_LIST_ERROR);
982 /* Move on to next BD */
983 AddrV += RingPtr->Separation;
984 AddrP += RingPtr->Separation;
987 /* Last BD should have wrap bit set */
988 if (XEMACPS_SEND == Direction) {
989 if (!XEmacPs_BdIsTxWrap(AddrV)) {
990 return (XST_DMA_SG_LIST_ERROR);
993 else { /* XEMACPS_RECV */
994 if (!XEmacPs_BdIsRxWrap(AddrV)) {
995 return (XST_DMA_SG_LIST_ERROR);
999 /* No problems found */
1000 return (XST_SUCCESS);