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
37 * @addtogroup emacps_v2_0
40 * This file implements buffer descriptor ring related functions.
43 * MODIFICATION HISTORY:
45 * Ver Who Date Changes
46 * ----- ---- -------- -------------------------------------------------------
47 * 1.00a wsy 01/10/10 First release
48 * 1.00a asa 11/21/11 The function XEmacPs_BdRingFromHwTx is modified.
49 * Earlier it used to search in "BdLimit" number of BDs to
50 * know which BDs are processed. Now one more check is
51 * added. It looks for BDs till the current BD pointer
52 * reaches HwTail. By doing this processing time is saved.
53 * 1.00a asa 01/24/12 The function XEmacPs_BdRingFromHwTx in file
54 * xemacps_bdring.c is modified. Now start of packet is
55 * searched for returning the number of BDs processed.
56 * 1.05a asa 09/23/13 Cache operations on BDs are not required and hence
57 * removed. It is expected that all BDs are allocated in
58 * from uncached area. Fix for CR #663885.
60 ******************************************************************************/
62 /***************************** Include Files *********************************/
65 #include "xil_cache.h"
66 #include "xemacps_hw.h"
67 #include "xemacps_bd.h"
68 #include "xemacps_bdring.h"
70 /************************** Constant Definitions *****************************/
72 /**************************** Type Definitions *******************************/
75 /***************** Macros (Inline Functions) Definitions *********************/
77 /****************************************************************************
78 * Compute the virtual address of a descriptor from its physical address
80 * @param BdPtr is the physical address of the BD
82 * @returns Virtual address of BdPtr
84 * @note Assume BdPtr is always a valid BD in the ring
85 ****************************************************************************/
86 #define XEMACPS_PHYS_TO_VIRT(BdPtr) \
87 ((u32)BdPtr + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
89 /****************************************************************************
90 * Compute the physical address of a descriptor from its virtual address
92 * @param BdPtr is the physical address of the BD
94 * @returns Physical address of BdPtr
96 * @note Assume BdPtr is always a valid BD in the ring
97 ****************************************************************************/
98 #define XEMACPS_VIRT_TO_PHYS(BdPtr) \
99 ((u32)BdPtr - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
101 /****************************************************************************
102 * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around
103 * to the beginning of the ring if needed.
105 * We know if a wrapaound should occur if the new BdPtr is greater than
106 * the high address in the ring OR if the new BdPtr crosses over the
107 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
108 * allow a BD space to span this boundary.
110 * @param RingPtr is the ring BdPtr appears in
111 * @param BdPtr on input is the starting BD position and on output is the
113 * @param NumBd is the number of BD spaces to increment
115 ****************************************************************************/
116 #define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \
118 u32 Addr = (u32)BdPtr; \
120 Addr += ((RingPtr)->Separation * NumBd); \
121 if ((Addr > (RingPtr)->HighBdAddr) || ((u32)BdPtr > Addr)) \
123 Addr -= (RingPtr)->Length; \
126 BdPtr = (XEmacPs_Bd*)Addr; \
129 /****************************************************************************
130 * Move the BdPtr argument backwards an arbitrary number of BDs wrapping
131 * around to the end of the ring if needed.
133 * We know if a wrapaound should occur if the new BdPtr is less than
134 * the base address in the ring OR if the new BdPtr crosses over the
135 * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
136 * allow a BD space to span this boundary.
138 * @param RingPtr is the ring BdPtr appears in
139 * @param BdPtr on input is the starting BD position and on output is the
141 * @param NumBd is the number of BD spaces to increment
143 ****************************************************************************/
144 #define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \
146 u32 Addr = (u32)BdPtr; \
148 Addr -= ((RingPtr)->Separation * NumBd); \
149 if ((Addr < (RingPtr)->BaseBdAddr) || ((u32)BdPtr < Addr)) \
151 Addr += (RingPtr)->Length; \
154 BdPtr = (XEmacPs_Bd*)Addr; \
158 /************************** Function Prototypes ******************************/
161 /************************** Variable Definitions *****************************/
163 /*****************************************************************************/
165 * Using a memory segment allocated by the caller, create and setup the BD list
166 * for the given DMA channel.
168 * @param RingPtr is the instance to be worked on.
169 * @param PhysAddr is the physical base address of user memory region.
170 * @param VirtAddr is the virtual base address of the user memory region. If
171 * address translation is not being utilized, then VirtAddr should be
172 * equivalent to PhysAddr.
173 * @param Alignment governs the byte alignment of individual BDs. This function
174 * will enforce a minimum alignment of 4 bytes with no maximum as long
175 * as it is specified as a power of 2.
176 * @param BdCount is the number of BDs to setup in the user memory region. It
177 * is assumed the region is large enough to contain the BDs.
181 * - XST_SUCCESS if initialization was successful
182 * - XST_NO_FEATURE if the provided instance is a non DMA type
184 * - XST_INVALID_PARAM under any of the following conditions:
185 * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment
187 * 2) Alignment parameter does not meet minimum requirements or is not a
190 * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans
191 * over address 0x00000000 in virtual address space.
194 * Make sure to pass in the right alignment value.
195 *****************************************************************************/
196 int XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, u32 PhysAddr,
197 u32 VirtAddr, u32 Alignment, unsigned BdCount)
203 /* In case there is a failure prior to creating list, make sure the
204 * following attributes are 0 to prevent calls to other functions
205 * from doing anything.
208 RingPtr->FreeCnt = 0;
211 RingPtr->PostCnt = 0;
213 /* Make sure Alignment parameter meets minimum requirements */
214 if (Alignment < XEMACPS_DMABD_MINIMUM_ALIGNMENT) {
215 return (XST_INVALID_PARAM);
218 /* Make sure Alignment is a power of 2 */
219 if ((Alignment - 1) & Alignment) {
220 return (XST_INVALID_PARAM);
223 /* Make sure PhysAddr and VirtAddr are on same Alignment */
224 if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) {
225 return (XST_INVALID_PARAM);
228 /* Is BdCount reasonable? */
230 return (XST_INVALID_PARAM);
233 /* Figure out how many bytes will be between the start of adjacent BDs */
234 RingPtr->Separation =
235 (sizeof(XEmacPs_Bd) + (Alignment - 1)) & ~(Alignment - 1);
237 /* Must make sure the ring doesn't span address 0x00000000. If it does,
238 * then the next/prev BD traversal macros will fail.
240 if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) {
241 return (XST_DMA_SG_LIST_ERROR);
244 /* Initial ring setup:
245 * - Clear the entire space
246 * - Setup each BD's BDA field with the physical address of the next BD
248 memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount));
250 BdVirtAddr = VirtAddr;
251 BdPhyAddr = PhysAddr + RingPtr->Separation;
252 for (i = 1; i < BdCount; i++) {
253 BdVirtAddr += RingPtr->Separation;
254 BdPhyAddr += RingPtr->Separation;
257 /* Setup and initialize pointers and counters */
258 RingPtr->RunState = XST_DMA_SG_IS_STOPPED;
259 RingPtr->BaseBdAddr = VirtAddr;
260 RingPtr->PhysBaseAddr = PhysAddr;
261 RingPtr->HighBdAddr = BdVirtAddr;
263 RingPtr->HighBdAddr - RingPtr->BaseBdAddr + RingPtr->Separation;
264 RingPtr->AllCnt = BdCount;
265 RingPtr->FreeCnt = BdCount;
266 RingPtr->FreeHead = (XEmacPs_Bd *) VirtAddr;
267 RingPtr->PreHead = (XEmacPs_Bd *) VirtAddr;
268 RingPtr->HwHead = (XEmacPs_Bd *) VirtAddr;
269 RingPtr->HwTail = (XEmacPs_Bd *) VirtAddr;
270 RingPtr->PostHead = (XEmacPs_Bd *) VirtAddr;
271 RingPtr->BdaRestart = (XEmacPs_Bd *) PhysAddr;
273 return (XST_SUCCESS);
277 /*****************************************************************************/
279 * Clone the given BD into every BD in the list.
280 * every field of the source BD is replicated in every BD of the list.
282 * This function can be called only when all BDs are in the free group such as
283 * they are immediately after initialization with XEmacPs_BdRingCreate().
284 * This prevents modification of BDs while they are in use by hardware or the
287 * @param RingPtr is the pointer of BD ring instance to be worked on.
288 * @param SrcBdPtr is the source BD template to be cloned into the list. This
289 * BD will be modified.
290 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
294 * - XST_SUCCESS if the list was modified.
295 * - XST_DMA_SG_NO_LIST if a list has not been created.
296 * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under
297 * hardware or user control.
298 * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped.
300 *****************************************************************************/
301 int XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
307 /* Can't do this function if there isn't a ring */
308 if (RingPtr->AllCnt == 0) {
309 return (XST_DMA_SG_NO_LIST);
312 /* Can't do this function with the channel running */
313 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
314 return (XST_DEVICE_IS_STARTED);
317 /* Can't do this function with some of the BDs in use */
318 if (RingPtr->FreeCnt != RingPtr->AllCnt) {
319 return (XST_DMA_SG_LIST_ERROR);
322 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
323 return (XST_INVALID_PARAM);
326 /* Starting from the top of the ring, save BD.Next, overwrite the entire
327 * BD with the template, then restore BD.Next
329 for (i = 0, CurBd = (u32) RingPtr->BaseBdAddr;
330 i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) {
331 memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd));
334 CurBd -= RingPtr->Separation;
336 if (Direction == XEMACPS_RECV) {
337 XEmacPs_BdSetRxWrap(CurBd);
340 XEmacPs_BdSetTxWrap(CurBd);
343 return (XST_SUCCESS);
347 /*****************************************************************************/
349 * Reserve locations in the BD list. The set of returned BDs may be modified
350 * in preparation for future DMA transaction(s). Once the BDs are ready to be
351 * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same
352 * order which they were allocated here. Example:
356 * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet);
358 * if (Status != XST_SUCCESS)
360 * // Not enough BDs available for the request
364 * for (i=0; i<NumBd; i++)
366 * // Prepare CurBd.....
369 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
372 * // Give list to hardware
373 * Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet);
376 * A more advanced use of this function may allocate multiple sets of BDs.
377 * They must be allocated and given to hardware in the correct sequence:
380 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
381 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
384 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
385 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
386 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
387 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
390 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
391 * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
392 * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
393 * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
396 * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal
397 * of the BD set can be done using XEmacPs_BdRingNext() and
398 * XEmacPs_BdRingPrev().
400 * @param RingPtr is a pointer to the BD ring instance to be worked on.
401 * @param NumBd is the number of BDs to allocate
402 * @param BdSetPtr is an output parameter, it points to the first BD available
406 * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr
408 * - XST_FAILURE if there were not enough free BDs to satisfy the request.
410 * @note This function should not be preempted by another XEmacPs_Bd function
411 * call that modifies the BD space. It is the caller's responsibility to
412 * provide a mutual exclusion mechanism.
414 * @note Do not modify more BDs than the number requested with the NumBd
415 * parameter. Doing so will lead to data corruption and system
418 *****************************************************************************/
419 int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
420 XEmacPs_Bd ** BdSetPtr)
422 /* Enough free BDs available for the request? */
423 if (RingPtr->FreeCnt < NumBd) {
424 return (XST_FAILURE);
427 /* Set the return argument and move FreeHead forward */
428 *BdSetPtr = RingPtr->FreeHead;
429 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd);
430 RingPtr->FreeCnt -= NumBd;
431 RingPtr->PreCnt += NumBd;
432 return (XST_SUCCESS);
435 /*****************************************************************************/
437 * Fully or partially undo an XEmacPs_BdRingAlloc() operation. Use this
438 * function if all the BDs allocated by XEmacPs_BdRingAlloc() could not be
439 * transferred to hardware with XEmacPs_BdRingToHw().
441 * This function helps out in situations when an unrelated error occurs after
442 * BDs have been allocated but before they have been given to hardware.
443 * An example of this type of error would be an OS running out of resources.
445 * This function is not the same as XEmacPs_BdRingFree(). The Free function
446 * returns BDs to the free list after they have been processed by hardware,
447 * while UnAlloc returns them before being processed by hardware.
449 * There are two scenarios where this function can be used. Full UnAlloc or
450 * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
453 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
457 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
461 * A partial UnAlloc means some of the BDs Alloc'd will be returned:
464 * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
472 * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
475 * CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr);
480 * A partial UnAlloc must include the last BD in the list that was Alloc'd.
482 * @param RingPtr is a pointer to the instance to be worked on.
483 * @param NumBd is the number of BDs to allocate
484 * @param BdSetPtr is an output parameter, it points to the first BD available
488 * - XST_SUCCESS if the BDs were unallocated.
489 * - XST_FAILURE if NumBd parameter was greater that the number of BDs in
490 * the preprocessing state.
492 * @note This function should not be preempted by another XEmacPs_Bd function
493 * call that modifies the BD space. It is the caller's responsibility to
494 * provide a mutual exclusion mechanism.
496 *****************************************************************************/
497 int XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd,
498 XEmacPs_Bd * BdSetPtr)
502 /* Enough BDs in the free state for the request? */
503 if (RingPtr->PreCnt < NumBd) {
504 return (XST_FAILURE);
507 /* Set the return argument and move FreeHead backward */
508 XEMACPS_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd);
509 RingPtr->FreeCnt += NumBd;
510 RingPtr->PreCnt -= NumBd;
511 return (XST_SUCCESS);
515 /*****************************************************************************/
517 * Enqueue a set of BDs to hardware that were previously allocated by
518 * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes
519 * under hardware control. Any changes made to these BDs after this point will
520 * corrupt the BD list leading to data corruption and system instability.
522 * The set will be rejected if the last BD of the set does not mark the end of
523 * a packet (see XEmacPs_BdSetLast()).
525 * @param RingPtr is a pointer to the instance to be worked on.
526 * @param NumBd is the number of BDs in the set.
527 * @param BdSetPtr is the first BD of the set to commit to hardware.
530 * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware.
531 * - XST_FAILURE if the set of BDs was rejected because the last BD of the set
532 * did not have its "last" bit set.
533 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
534 * XEmacPs_BdRingAlloc().
536 * @note This function should not be preempted by another XEmacPs_Bd function
537 * call that modifies the BD space. It is the caller's responsibility to
538 * provide a mutual exclusion mechanism.
540 *****************************************************************************/
541 int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd,
542 XEmacPs_Bd * BdSetPtr)
544 XEmacPs_Bd *CurBdPtr;
547 /* if no bds to process, simply return. */
549 return (XST_SUCCESS);
551 /* Make sure we are in sync with XEmacPs_BdRingAlloc() */
552 if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) {
553 return (XST_DMA_SG_LIST_ERROR);
557 for (i = 0; i < NumBd; i++) {
558 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
561 /* Adjust ring pointers & counters */
562 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd);
563 RingPtr->PreCnt -= NumBd;
565 RingPtr->HwTail = CurBdPtr;
566 RingPtr->HwCnt += NumBd;
568 return (XST_SUCCESS);
572 /*****************************************************************************/
574 * Returns a set of BD(s) that have been processed by hardware. The returned
575 * BDs may be examined to determine the outcome of the DMA transaction(s).
576 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
577 * in the same order which they were retrieved here. Example:
580 * NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet);
584 * // hardware has nothing ready for us yet
588 * for (i=0; i<NumBd; i++)
590 * // Examine CurBd for post processing.....
593 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
596 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
600 * A more advanced use of this function may allocate multiple sets of BDs.
601 * They must be retrieved from hardware and freed in the correct sequence:
604 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
605 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
608 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
609 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
610 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
611 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
614 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
615 * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
616 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
617 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
620 * If hardware has only partially completed a packet spanning multiple BDs,
621 * then none of the BDs for that packet will be included in the results.
623 * @param RingPtr is a pointer to the instance to be worked on.
624 * @param BdLimit is the maximum number of BDs to return in the set.
625 * @param BdSetPtr is an output parameter, it points to the first BD available
629 * The number of BDs processed by hardware. A value of 0 indicates that no
630 * data is available. No more than BdLimit BDs will be returned.
632 * @note Treat BDs returned by this function as read-only.
634 * @note This function should not be preempted by another XEmacPs_Bd function
635 * call that modifies the BD space. It is the caller's responsibility to
636 * provide a mutual exclusion mechanism.
638 *****************************************************************************/
639 unsigned XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
640 XEmacPs_Bd ** BdSetPtr)
642 XEmacPs_Bd *CurBdPtr;
645 unsigned BdPartialCount;
646 unsigned int Sop = 0;
649 CurBdPtr = RingPtr->HwHead;
653 /* If no BDs in work group, then there's nothing to search */
654 if (RingPtr->HwCnt == 0) {
659 if (BdLimit > RingPtr->HwCnt)
660 BdLimit = RingPtr->HwCnt;
662 /* Starting at HwHead, keep moving forward in the list until:
663 * - A BD is encountered with its new/used bit set which means
664 * hardware has not completed processing of that BD.
665 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
666 * - The number of requested BDs has been processed
668 while (BdCount < BdLimit) {
669 /* Read the status */
670 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
672 if ((Sop == 0) && (BdStr & XEMACPS_TXBUF_USED_MASK))
680 /* hardware has processed this BD so check the "last" bit.
681 * If it is clear, then there are more BDs for the current
682 * packet. Keep a count of these partial packet BDs.
684 if ((Sop == 1) && (BdStr & XEMACPS_TXBUF_LAST_MASK)) {
689 /* Move on to next BD in work group */
690 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
693 /* Subtract off any partial packet BDs found */
694 BdCount -= BdPartialCount;
696 /* If BdCount is non-zero then BDs were found to return. Set return
697 * parameters, update pointers and counters, return success
700 *BdSetPtr = RingPtr->HwHead;
701 RingPtr->HwCnt -= BdCount;
702 RingPtr->PostCnt += BdCount;
703 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
713 /*****************************************************************************/
715 * Returns a set of BD(s) that have been processed by hardware. The returned
716 * BDs may be examined to determine the outcome of the DMA transaction(s).
717 * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
718 * in the same order which they were retrieved here. Example:
721 * NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
725 * // hardware has nothing ready for us yet
729 * for (i=0; i<NumBd; i++)
731 * // Examine CurBd for post processing.....
734 * CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd);
737 * XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet); // Return list
741 * A more advanced use of this function may allocate multiple sets of BDs.
742 * They must be retrieved from hardware and freed in the correct sequence:
745 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
746 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
749 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
750 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
751 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
752 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
755 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
756 * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
757 * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
758 * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
761 * If hardware has only partially completed a packet spanning multiple BDs,
762 * then none of the BDs for that packet will be included in the results.
764 * @param RingPtr is a pointer to the instance to be worked on.
765 * @param BdLimit is the maximum number of BDs to return in the set.
766 * @param BdSetPtr is an output parameter, it points to the first BD available
770 * The number of BDs processed by hardware. A value of 0 indicates that no
771 * data is available. No more than BdLimit BDs will be returned.
773 * @note Treat BDs returned by this function as read-only.
775 * @note This function should not be preempted by another XEmacPs_Bd function
776 * call that modifies the BD space. It is the caller's responsibility to
777 * provide a mutual exclusion mechanism.
779 *****************************************************************************/
780 unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit,
781 XEmacPs_Bd ** BdSetPtr)
783 XEmacPs_Bd *CurBdPtr;
786 unsigned BdPartialCount;
788 CurBdPtr = RingPtr->HwHead;
792 /* If no BDs in work group, then there's nothing to search */
793 if (RingPtr->HwCnt == 0) {
798 /* Starting at HwHead, keep moving forward in the list until:
799 * - A BD is encountered with its new/used bit set which means
800 * hardware has completed processing of that BD.
801 * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
802 * - The number of requested BDs has been processed
804 while (BdCount < BdLimit) {
806 /* Read the status */
807 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
809 if (!(XEmacPs_BdIsRxNew(CurBdPtr))) {
815 /* hardware has processed this BD so check the "last" bit. If
816 * it is clear, then there are more BDs for the current packet.
817 * Keep a count of these partial packet BDs.
819 if (BdStr & XEMACPS_RXBUF_EOF_MASK) {
826 /* Move on to next BD in work group */
827 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
830 /* Subtract off any partial packet BDs found */
831 BdCount -= BdPartialCount;
833 /* If BdCount is non-zero then BDs were found to return. Set return
834 * parameters, update pointers and counters, return success
837 *BdSetPtr = RingPtr->HwHead;
838 RingPtr->HwCnt -= BdCount;
839 RingPtr->PostCnt += BdCount;
840 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
850 /*****************************************************************************/
852 * Frees a set of BDs that had been previously retrieved with
853 * XEmacPs_BdRingFromHw().
855 * @param RingPtr is a pointer to the instance to be worked on.
856 * @param NumBd is the number of BDs to free.
857 * @param BdSetPtr is the head of a list of BDs returned by
858 * XEmacPs_BdRingFromHw().
861 * - XST_SUCCESS if the set of BDs was freed.
862 * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
863 * XEmacPs_BdRingFromHw().
865 * @note This function should not be preempted by another XEmacPs_Bd function
866 * call that modifies the BD space. It is the caller's responsibility to
867 * provide a mutual exclusion mechanism.
869 *****************************************************************************/
870 int XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd,
871 XEmacPs_Bd * BdSetPtr)
873 /* if no bds to process, simply return. */
875 return (XST_SUCCESS);
877 /* Make sure we are in sync with XEmacPs_BdRingFromHw() */
878 if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) {
879 return (XST_DMA_SG_LIST_ERROR);
882 /* Update pointers and counters */
883 RingPtr->FreeCnt += NumBd;
884 RingPtr->PostCnt -= NumBd;
885 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd);
886 return (XST_SUCCESS);
890 /*****************************************************************************/
892 * Check the internal data structures of the BD ring for the provided channel.
893 * The following checks are made:
895 * - Is the BD ring linked correctly in physical address space.
896 * - Do the internal pointers point to BDs in the ring.
897 * - Do the internal counters add up.
899 * The channel should be stopped prior to calling this function.
901 * @param RingPtr is a pointer to the instance to be worked on.
902 * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
906 * - XST_SUCCESS if the set of BDs was freed.
907 * - XST_DMA_SG_NO_LIST if the list has not been created.
908 * - XST_IS_STARTED if the channel is not stopped.
909 * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
910 * structures. If this value is returned, the channel should be reset to
911 * avoid data corruption or system instability.
913 * @note This function should not be preempted by another XEmacPs_Bd function
914 * call that modifies the BD space. It is the caller's responsibility to
915 * provide a mutual exclusion mechanism.
917 *****************************************************************************/
918 int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
923 if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) {
924 return (XST_INVALID_PARAM);
927 /* Is the list created */
928 if (RingPtr->AllCnt == 0) {
929 return (XST_DMA_SG_NO_LIST);
932 /* Can't check if channel is running */
933 if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) {
934 return (XST_IS_STARTED);
937 /* RunState doesn't make sense */
938 else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) {
939 return (XST_DMA_SG_LIST_ERROR);
942 /* Verify internal pointers point to correct memory space */
943 AddrV = (u32) RingPtr->FreeHead;
944 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
945 return (XST_DMA_SG_LIST_ERROR);
948 AddrV = (u32) RingPtr->PreHead;
949 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
950 return (XST_DMA_SG_LIST_ERROR);
953 AddrV = (u32) RingPtr->HwHead;
954 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
955 return (XST_DMA_SG_LIST_ERROR);
958 AddrV = (u32) RingPtr->HwTail;
959 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
960 return (XST_DMA_SG_LIST_ERROR);
963 AddrV = (u32) RingPtr->PostHead;
964 if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
965 return (XST_DMA_SG_LIST_ERROR);
968 /* Verify internal counters add up */
969 if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
970 RingPtr->PostCnt) != RingPtr->AllCnt) {
971 return (XST_DMA_SG_LIST_ERROR);
974 /* Verify BDs are linked correctly */
975 AddrV = RingPtr->BaseBdAddr;
976 AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
978 for (i = 1; i < RingPtr->AllCnt; i++) {
979 /* Check BDA for this BD. It should point to next physical addr */
980 if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
981 return (XST_DMA_SG_LIST_ERROR);
984 /* Move on to next BD */
985 AddrV += RingPtr->Separation;
986 AddrP += RingPtr->Separation;
989 /* Last BD should have wrap bit set */
990 if (XEMACPS_SEND == Direction) {
991 if (!XEmacPs_BdIsTxWrap(AddrV)) {
992 return (XST_DMA_SG_LIST_ERROR);
995 else { /* XEMACPS_RECV */
996 if (!XEmacPs_BdIsRxWrap(AddrV)) {
997 return (XST_DMA_SG_LIST_ERROR);
1001 /* No problems found */
1002 return (XST_SUCCESS);