]> git.sur5r.net Git - freertos/blob
d837e1df1f5e75d8d52a1341f8427e90a16a3fa1
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xemacps_bdring.c
36 * @addtogroup emacps_v3_1
37 * @{
38 *
39 * This file implements buffer descriptor ring related functions.
40 *
41 * <pre>
42 * MODIFICATION HISTORY:
43 *
44 * Ver   Who  Date     Changes
45 * ----- ---- -------- -------------------------------------------------------
46 * 1.00a wsy  01/10/10 First release
47 * 1.00a asa  11/21/11 The function XEmacPs_BdRingFromHwTx is modified.
48 *                     Earlier it used to search in "BdLimit" number of BDs to
49 *                     know which BDs are processed. Now one more check is
50 *                     added. It looks for BDs till the current BD pointer
51 *                     reaches HwTail. By doing this processing time is saved.
52 * 1.00a asa  01/24/12 The function XEmacPs_BdRingFromHwTx in file
53 *                     xemacps_bdring.c is modified. Now start of packet is
54 *                     searched for returning the number of BDs processed.
55 * 1.05a asa  09/23/13 Cache operations on BDs are not required and hence
56 *                     removed. It is expected that all BDs are allocated in
57 *                     from uncached area. Fix for CR #663885.
58 * 2.1   srt  07/15/14 Add support for Zynq Ultrascale Mp architecture.
59 * 3.0   kvn  02/13/15 Modified code for MISRA-C:2012 compliance.
60 *
61 * </pre>
62 ******************************************************************************/
63
64 /***************************** Include Files *********************************/
65
66 #include "xstatus.h"
67 #include "xil_cache.h"
68 #include "xemacps_hw.h"
69 #include "xemacps_bd.h"
70 #include "xemacps_bdring.h"
71
72 /************************** Constant Definitions *****************************/
73
74 /**************************** Type Definitions *******************************/
75
76
77 /***************** Macros (Inline Functions) Definitions *********************/
78
79 /****************************************************************************
80  * Compute the virtual address of a descriptor from its physical address
81  *
82  * @param BdPtr is the physical address of the BD
83  *
84  * @returns Virtual address of BdPtr
85  *
86  * @note Assume BdPtr is always a valid BD in the ring
87  ****************************************************************************/
88 #define XEMACPS_PHYS_TO_VIRT(BdPtr) \
89     ((UINTPTR)(BdPtr) + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
90
91 /****************************************************************************
92  * Compute the physical address of a descriptor from its virtual address
93  *
94  * @param BdPtr is the physical address of the BD
95  *
96  * @returns Physical address of BdPtr
97  *
98  * @note Assume BdPtr is always a valid BD in the ring
99  ****************************************************************************/
100 #define XEMACPS_VIRT_TO_PHYS(BdPtr) \
101     ((UINTPTR)(BdPtr) - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr))
102
103 /****************************************************************************
104  * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around
105  * to the beginning of the ring if needed.
106  *
107  * We know if a wrapaound should occur if the new BdPtr is greater than
108  * the high address in the ring OR if the new BdPtr crosses over the
109  * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
110  * allow a BD space to span this boundary.
111  *
112  * @param RingPtr is the ring BdPtr appears in
113  * @param BdPtr on input is the starting BD position and on output is the
114  *        final BD position
115  * @param NumBd is the number of BD spaces to increment
116  *
117  ****************************************************************************/
118 #define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd)                  \
119     {                                                                   \
120         UINTPTR Addr = (UINTPTR)(void *)(BdPtr);                        \
121                                                                         \
122         Addr += ((RingPtr)->Separation * (NumBd));                        \
123         if ((Addr > (RingPtr)->HighBdAddr) || ((UINTPTR)(void *)(BdPtr) > Addr))  \
124         {                                                               \
125             Addr -= (RingPtr)->Length;                                  \
126         }                                                               \
127                                                                         \
128         (BdPtr) = (XEmacPs_Bd*)(void *)Addr;                                     \
129     }
130
131 /****************************************************************************
132  * Move the BdPtr argument backwards an arbitrary number of BDs wrapping
133  * around to the end of the ring if needed.
134  *
135  * We know if a wrapaound should occur if the new BdPtr is less than
136  * the base address in the ring OR if the new BdPtr crosses over the
137  * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not
138  * allow a BD space to span this boundary.
139  *
140  * @param RingPtr is the ring BdPtr appears in
141  * @param BdPtr on input is the starting BD position and on output is the
142  *        final BD position
143  * @param NumBd is the number of BD spaces to increment
144  *
145  ****************************************************************************/
146 #define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd)                   \
147     {                                                                   \
148         UINTPTR Addr = (UINTPTR)(void *)(BdPtr);                                  \
149                                                                         \
150         Addr -= ((RingPtr)->Separation * (NumBd));                        \
151         if ((Addr < (RingPtr)->BaseBdAddr) || ((UINTPTR)(void*)(BdPtr) < Addr))  \
152         {                                                               \
153             Addr += (RingPtr)->Length;                                  \
154         }                                                               \
155                                                                         \
156         (BdPtr) = (XEmacPs_Bd*)(void*)Addr;                                     \
157     }
158
159
160 /************************** Function Prototypes ******************************/
161
162 static void XEmacPs_BdSetRxWrap(UINTPTR BdPtr);
163 static void XEmacPs_BdSetTxWrap(UINTPTR BdPtr);
164
165 /************************** Variable Definitions *****************************/
166
167 /*****************************************************************************/
168 /**
169  * Using a memory segment allocated by the caller, create and setup the BD list
170  * for the given DMA channel.
171  *
172  * @param RingPtr is the instance to be worked on.
173  * @param PhysAddr is the physical base address of user memory region.
174  * @param VirtAddr is the virtual base address of the user memory region. If
175  *        address translation is not being utilized, then VirtAddr should be
176  *        equivalent to PhysAddr.
177  * @param Alignment governs the byte alignment of individual BDs. This function
178  *        will enforce a minimum alignment of 4 bytes with no maximum as long
179  *        as it is specified as a power of 2.
180  * @param BdCount is the number of BDs to setup in the user memory region. It
181  *        is assumed the region is large enough to contain the BDs.
182  *
183  * @return
184  *
185  * - XST_SUCCESS if initialization was successful
186  * - XST_NO_FEATURE if the provided instance is a non DMA type
187  *   channel.
188  * - XST_INVALID_PARAM under any of the following conditions:
189  *   1) PhysAddr and/or VirtAddr are not aligned to the given Alignment
190  *      parameter.
191  *   2) Alignment parameter does not meet minimum requirements or is not a
192  *      power of 2 value.
193  *   3) BdCount is 0.
194  * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans
195  *   over address 0x00000000 in virtual address space.
196  *
197  * @note
198  * Make sure to pass in the right alignment value.
199  *****************************************************************************/
200 LONG XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, UINTPTR PhysAddr,
201                           UINTPTR VirtAddr, u32 Alignment, u32 BdCount)
202 {
203         u32 i;
204         UINTPTR BdVirtAddr;
205         UINTPTR BdPhyAddr;
206         UINTPTR VirtAddrLoc = VirtAddr;
207
208         /* In case there is a failure prior to creating list, make sure the
209          * following attributes are 0 to prevent calls to other functions
210          * from doing anything.
211          */
212         RingPtr->AllCnt = 0U;
213         RingPtr->FreeCnt = 0U;
214         RingPtr->HwCnt = 0U;
215         RingPtr->PreCnt = 0U;
216         RingPtr->PostCnt = 0U;
217
218         /* Make sure Alignment parameter meets minimum requirements */
219         if (Alignment < (u32)XEMACPS_DMABD_MINIMUM_ALIGNMENT) {
220                 return (LONG)(XST_INVALID_PARAM);
221         }
222
223         /* Make sure Alignment is a power of 2 */
224         if (((Alignment - 0x00000001U) & Alignment)!=0x00000000U) {
225                 return (LONG)(XST_INVALID_PARAM);
226         }
227
228         /* Make sure PhysAddr and VirtAddr are on same Alignment */
229         if (((PhysAddr % Alignment)!=(u32)0) || ((VirtAddrLoc % Alignment)!=(u32)0)) {
230                 return (LONG)(XST_INVALID_PARAM);
231         }
232
233         /* Is BdCount reasonable? */
234         if (BdCount == 0x00000000U) {
235                 return (LONG)(XST_INVALID_PARAM);
236         }
237
238         /* Figure out how many bytes will be between the start of adjacent BDs */
239         RingPtr->Separation = ((u32)sizeof(XEmacPs_Bd));
240
241         /* Must make sure the ring doesn't span address 0x00000000. If it does,
242          * then the next/prev BD traversal macros will fail.
243          */
244         if (VirtAddrLoc > ((VirtAddrLoc + (RingPtr->Separation * BdCount)) - (u32)1)) {
245                 return (LONG)(XST_DMA_SG_LIST_ERROR);
246         }
247
248         /* Initial ring setup:
249          *  - Clear the entire space
250          *  - Setup each BD's BDA field with the physical address of the next BD
251          */
252         (void)memset((void *) VirtAddrLoc, 0, (RingPtr->Separation * BdCount));
253
254         BdVirtAddr = VirtAddrLoc;
255         BdPhyAddr = PhysAddr + RingPtr->Separation;
256         for (i = 1U; i < BdCount; i++) {
257                 BdVirtAddr += RingPtr->Separation;
258                 BdPhyAddr += RingPtr->Separation;
259         }
260
261         /* Setup and initialize pointers and counters */
262         RingPtr->RunState = (u32)(XST_DMA_SG_IS_STOPPED);
263         RingPtr->BaseBdAddr = VirtAddrLoc;
264         RingPtr->PhysBaseAddr = PhysAddr;
265         RingPtr->HighBdAddr = BdVirtAddr;
266         RingPtr->Length =
267                 ((RingPtr->HighBdAddr - RingPtr->BaseBdAddr) + RingPtr->Separation);
268         RingPtr->AllCnt = (u32)BdCount;
269         RingPtr->FreeCnt = (u32)BdCount;
270         RingPtr->FreeHead = (XEmacPs_Bd *)(void *)VirtAddrLoc;
271         RingPtr->PreHead = (XEmacPs_Bd *)VirtAddrLoc;
272         RingPtr->HwHead = (XEmacPs_Bd *)VirtAddrLoc;
273         RingPtr->HwTail = (XEmacPs_Bd *)VirtAddrLoc;
274         RingPtr->PostHead = (XEmacPs_Bd *)VirtAddrLoc;
275         RingPtr->BdaRestart = (XEmacPs_Bd *)(void *)PhysAddr;
276
277         return (LONG)(XST_SUCCESS);
278 }
279
280
281 /*****************************************************************************/
282 /**
283  * Clone the given BD into every BD in the list.
284  * every field of the source BD is replicated in every BD of the list.
285  *
286  * This function can be called only when all BDs are in the free group such as
287  * they are immediately after initialization with XEmacPs_BdRingCreate().
288  * This prevents modification of BDs while they are in use by hardware or the
289  * user.
290  *
291  * @param RingPtr is the pointer of BD ring instance to be worked on.
292  * @param SrcBdPtr is the source BD template to be cloned into the list. This
293  *        BD will be modified.
294  * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
295  *        which direction.
296  *
297  * @return
298  *   - XST_SUCCESS if the list was modified.
299  *   - XST_DMA_SG_NO_LIST if a list has not been created.
300  *   - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under
301  *     hardware or user control.
302  *   - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped.
303  *
304  *****************************************************************************/
305 LONG XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
306                          u8 Direction)
307 {
308         u32 i;
309         UINTPTR CurBd;
310
311         /* Can't do this function if there isn't a ring */
312         if (RingPtr->AllCnt == 0x00000000U) {
313                 return (LONG)(XST_DMA_SG_NO_LIST);
314         }
315
316         /* Can't do this function with the channel running */
317         if (RingPtr->RunState == (u32)XST_DMA_SG_IS_STARTED) {
318                 return (LONG)(XST_DEVICE_IS_STARTED);
319         }
320
321         /* Can't do this function with some of the BDs in use */
322         if (RingPtr->FreeCnt != RingPtr->AllCnt) {
323                 return (LONG)(XST_DMA_SG_LIST_ERROR);
324         }
325
326         if ((Direction != (u8)XEMACPS_SEND) && (Direction != (u8)XEMACPS_RECV)) {
327                 return (LONG)(XST_INVALID_PARAM);
328         }
329
330         /* Starting from the top of the ring, save BD.Next, overwrite the entire
331          * BD with the template, then restore BD.Next
332          */
333         CurBd = RingPtr->BaseBdAddr;
334         for (i = 0U; i < RingPtr->AllCnt; i++) {
335                 memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd));
336         CurBd += RingPtr->Separation;
337         }
338
339         CurBd -= RingPtr->Separation;
340
341         if (Direction == XEMACPS_RECV) {
342                 XEmacPs_BdSetRxWrap(CurBd);
343         }
344         else {
345                 XEmacPs_BdSetTxWrap(CurBd);
346         }
347
348         return (LONG)(XST_SUCCESS);
349 }
350
351
352 /*****************************************************************************/
353 /**
354  * Reserve locations in the BD list. The set of returned BDs may be modified
355  * in preparation for future DMA transaction(s). Once the BDs are ready to be
356  * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same
357  * order which they were allocated here. Example:
358  *
359  * <pre>
360  *        NumBd = 2,
361  *        Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet),
362  *
363  *        if (Status != XST_SUCCESS)
364  *        {
365  *            *Not enough BDs available for the request*
366  *        }
367  *
368  *        CurBd = MyBdSet,
369  *        for (i=0; i<NumBd; i++)
370  *        {
371  *            * Prepare CurBd *.....
372  *
373  *            * Onto next BD *
374  *            CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd),
375  *        }
376  *
377  *        * Give list to hardware *
378  *        Status = XEmacPs_BdRingToHw(MyRingPtr, NumBd, MyBdSet),
379  * </pre>
380  *
381  * A more advanced use of this function may allocate multiple sets of BDs.
382  * They must be allocated and given to hardware in the correct sequence:
383  * <pre>
384  *        * Legal *
385  *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
386  *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
387  *
388  *        * Legal *
389  *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
390  *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2),
391  *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
392  *        XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2),
393  *
394  *        * Not legal *
395  *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
396  *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2),
397  *        XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2),
398  *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
399  * </pre>
400  *
401  * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal
402  * of the BD set can be done using XEmacPs_BdRingNext() and
403  * XEmacPs_BdRingPrev().
404  *
405  * @param RingPtr is a pointer to the BD ring instance to be worked on.
406  * @param NumBd is the number of BDs to allocate
407  * @param BdSetPtr is an output parameter, it points to the first BD available
408  *        for modification.
409  *
410  * @return
411  *   - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr
412  *     parameter.
413  *   - XST_FAILURE if there were not enough free BDs to satisfy the request.
414  *
415  * @note This function should not be preempted by another XEmacPs_Bd function
416  *       call that modifies the BD space. It is the caller's responsibility to
417  *       provide a mutual exclusion mechanism.
418  *
419  * @note Do not modify more BDs than the number requested with the NumBd
420  *       parameter. Doing so will lead to data corruption and system
421  *       instability.
422  *
423  *****************************************************************************/
424 LONG XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
425                          XEmacPs_Bd ** BdSetPtr)
426 {
427         LONG Status;
428         /* Enough free BDs available for the request? */
429         if (RingPtr->FreeCnt < NumBd) {
430                 Status = (LONG)(XST_FAILURE);
431         } else {
432         /* Set the return argument and move FreeHead forward */
433         *BdSetPtr = RingPtr->FreeHead;
434         XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd);
435         RingPtr->FreeCnt -= NumBd;
436         RingPtr->PreCnt += NumBd;
437                 Status = (LONG)(XST_SUCCESS);
438         }
439         return Status;
440 }
441
442 /*****************************************************************************/
443 /**
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().
447  *
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.
451  *
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.
455  *
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:
458  *
459  * <pre>
460  *    Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr),
461  *        ...
462  *    if (Error)
463  *    {
464  *        Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr),
465  *    }
466  * </pre>
467  *
468  * A partial UnAlloc means some of the BDs Alloc'd will be returned:
469  *
470  * <pre>
471  *    Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr),
472  *    BdsLeft = 10,
473  *    CurBdPtr = BdPtr,
474  *
475  *    while (BdsLeft)
476  *    {
477  *       if (Error)
478  *       {
479  *          Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr),
480  *       }
481  *
482  *       CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr),
483  *       BdsLeft--,
484  *    }
485  * </pre>
486  *
487  * A partial UnAlloc must include the last BD in the list that was Alloc'd.
488  *
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
492  *        for modification.
493  *
494  * @return
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.
498  *
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.
502  *
503  *****************************************************************************/
504 LONG XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
505                            XEmacPs_Bd * BdSetPtr)
506 {
507         LONG Status;
508         (void *)BdSetPtr;
509         Xil_AssertNonvoid(RingPtr != NULL);
510         Xil_AssertNonvoid(BdSetPtr != NULL);
511
512         /* Enough BDs in the free state for the request? */
513         if (RingPtr->PreCnt < NumBd) {
514                 Status = (LONG)(XST_FAILURE);
515         } else {
516         /* Set the return argument and move FreeHead backward */
517                 XEMACPS_RING_SEEKBACK(RingPtr, (RingPtr->FreeHead), NumBd);
518         RingPtr->FreeCnt += NumBd;
519         RingPtr->PreCnt -= NumBd;
520                 Status = (LONG)(XST_SUCCESS);
521         }
522         return Status;
523 }
524
525
526 /*****************************************************************************/
527 /**
528  * Enqueue a set of BDs to hardware that were previously allocated by
529  * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes
530  * under hardware control. Any changes made to these BDs after this point will
531  * corrupt the BD list leading to data corruption and system instability.
532  *
533  * The set will be rejected if the last BD of the set does not mark the end of
534  * a packet (see XEmacPs_BdSetLast()).
535  *
536  * @param RingPtr is a pointer to the instance to be worked on.
537  * @param NumBd is the number of BDs in the set.
538  * @param BdSetPtr is the first BD of the set to commit to hardware.
539  *
540  * @return
541  *   - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware.
542  *   - XST_FAILURE if the set of BDs was rejected because the last BD of the set
543  *     did not have its "last" bit set.
544  *   - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
545  *     XEmacPs_BdRingAlloc().
546  *
547  * @note This function should not be preempted by another XEmacPs_Bd function
548  *       call that modifies the BD space. It is the caller's responsibility to
549  *       provide a mutual exclusion mechanism.
550  *
551  *****************************************************************************/
552 LONG XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, u32 NumBd,
553                         XEmacPs_Bd * BdSetPtr)
554 {
555         XEmacPs_Bd *CurBdPtr;
556         u32 i;
557         LONG Status;
558         /* if no bds to process, simply return. */
559         if (0U == NumBd){
560                 Status = (LONG)(XST_SUCCESS);
561         } else {
562         /* Make sure we are in sync with XEmacPs_BdRingAlloc() */
563         if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) {
564                         Status = (LONG)(XST_DMA_SG_LIST_ERROR);
565                 } else {
566         CurBdPtr = BdSetPtr;
567                         for (i = 0U; i < NumBd; i++) {
568                                 CurBdPtr = (XEmacPs_Bd *)((void *)XEmacPs_BdRingNext(RingPtr, CurBdPtr));
569         }
570         /* Adjust ring pointers & counters */
571         XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd);
572         RingPtr->PreCnt -= NumBd;
573         RingPtr->HwTail = CurBdPtr;
574         RingPtr->HwCnt += NumBd;
575
576                         Status = (LONG)(XST_SUCCESS);
577                 }
578         }
579         return Status;
580 }
581
582
583 /*****************************************************************************/
584 /**
585  * Returns a set of BD(s) that have been processed by hardware. The returned
586  * BDs may be examined to determine the outcome of the DMA transaction(s).
587  * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
588  * in the same order which they were retrieved here. Example:
589  *
590  * <pre>
591  *        NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet),
592  *        if (NumBd == 0)
593  *        {
594  *           * hardware has nothing ready for us yet*
595  *        }
596  *
597  *        CurBd = MyBdSet,
598  *        for (i=0; i<NumBd; i++)
599  *        {
600  *           * Examine CurBd for post processing *.....
601  *
602  *           * Onto next BD *
603  *           CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd),
604  *           }
605  *
606  *           XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet),  *Return list*
607  *        }
608  * </pre>
609  *
610  * A more advanced use of this function may allocate multiple sets of BDs.
611  * They must be retrieved from hardware and freed in the correct sequence:
612  * <pre>
613  *        * Legal *
614  *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
615  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
616  *
617  *        * Legal *
618  *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
619  *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
620  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
621  *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
622  *
623  *        * Not legal *
624  *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
625  *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
626  *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
627  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
628  * </pre>
629  *
630  * If hardware has only partially completed a packet spanning multiple BDs,
631  * then none of the BDs for that packet will be included in the results.
632  *
633  * @param RingPtr is a pointer to the instance to be worked on.
634  * @param BdLimit is the maximum number of BDs to return in the set.
635  * @param BdSetPtr is an output parameter, it points to the first BD available
636  *        for examination.
637  *
638  * @return
639  *   The number of BDs processed by hardware. A value of 0 indicates that no
640  *   data is available. No more than BdLimit BDs will be returned.
641  *
642  * @note Treat BDs returned by this function as read-only.
643  *
644  * @note This function should not be preempted by another XEmacPs_Bd function
645  *       call that modifies the BD space. It is the caller's responsibility to
646  *       provide a mutual exclusion mechanism.
647  *
648  *****************************************************************************/
649 u32 XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
650                                  XEmacPs_Bd ** BdSetPtr)
651 {
652         XEmacPs_Bd *CurBdPtr;
653         u32 BdStr = 0U;
654         u32 BdCount;
655         u32 BdPartialCount;
656         u32 Sop = 0U;
657         u32 Status;
658         u32 BdLimitLoc = BdLimit;
659         CurBdPtr = RingPtr->HwHead;
660         BdCount = 0U;
661         BdPartialCount = 0U;
662
663         /* If no BDs in work group, then there's nothing to search */
664         if (RingPtr->HwCnt == 0x00000000U) {
665                 *BdSetPtr = NULL;
666                 Status = 0U;
667         } else {
668
669                 if (BdLimitLoc > RingPtr->HwCnt){
670                         BdLimitLoc = RingPtr->HwCnt;
671         }
672         /* Starting at HwHead, keep moving forward in the list until:
673          *  - A BD is encountered with its new/used bit set which means
674          *    hardware has not completed processing of that BD.
675          *  - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
676          *  - The number of requested BDs has been processed
677          */
678                 while (BdCount < BdLimitLoc) {
679                 /* Read the status */
680                         if(CurBdPtr != NULL){
681                 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
682                         }
683
684                         if ((Sop == 0x00000000U) && ((BdStr & XEMACPS_TXBUF_USED_MASK)!=0x00000000U)){
685                                 Sop = 1U;
686                         }
687                         if (Sop == 0x00000001U) {
688                         BdCount++;
689                         BdPartialCount++;
690                 }
691
692                 /* hardware has processed this BD so check the "last" bit.
693                  * If it is clear, then there are more BDs for the current
694                  * packet. Keep a count of these partial packet BDs.
695                  */
696                         if ((Sop == 0x00000001U) && ((BdStr & XEMACPS_TXBUF_LAST_MASK)!=0x00000000U)) {
697                                 Sop = 0U;
698                                 BdPartialCount = 0U;
699                 }
700
701                 /* Move on to next BD in work group */
702                 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
703         }
704
705         /* Subtract off any partial packet BDs found */
706         BdCount -= BdPartialCount;
707
708         /* If BdCount is non-zero then BDs were found to return. Set return
709          * parameters, update pointers and counters, return success
710          */
711                 if (BdCount > 0x00000000U) {
712                 *BdSetPtr = RingPtr->HwHead;
713                 RingPtr->HwCnt -= BdCount;
714                 RingPtr->PostCnt += BdCount;
715                 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
716                         Status = (BdCount);
717                 } else {
718                         *BdSetPtr = NULL;
719                         Status = 0U;
720         }
721         }
722         return Status;
723 }
724
725
726 /*****************************************************************************/
727 /**
728  * Returns a set of BD(s) that have been processed by hardware. The returned
729  * BDs may be examined to determine the outcome of the DMA transaction(s).
730  * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
731  * in the same order which they were retrieved here. Example:
732  *
733  * <pre>
734  *        NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet),
735  *
736  *        if (NumBd == 0)
737  *        {
738  *           *hardware has nothing ready for us yet*
739  *        }
740  *
741  *        CurBd = MyBdSet,
742  *        for (i=0; i<NumBd; i++)
743  *        {
744  *           * Examine CurBd for post processing *.....
745  *
746  *           * Onto next BD *
747  *           CurBd = XEmacPs_BdRingNext(MyRingPtr, CurBd),
748  *           }
749  *
750  *           XEmacPs_BdRingFree(MyRingPtr, NumBd, MyBdSet),  * Return list *
751  *        }
752  * </pre>
753  *
754  * A more advanced use of this function may allocate multiple sets of BDs.
755  * They must be retrieved from hardware and freed in the correct sequence:
756  * <pre>
757  *        * Legal *
758  *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
759  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
760  *
761  *        * Legal *
762  *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
763  *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2),
764  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
765  *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
766  *
767  *        * Not legal *
768  *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
769  *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2),
770  *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
771  *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
772  * </pre>
773  *
774  * If hardware has only partially completed a packet spanning multiple BDs,
775  * then none of the BDs for that packet will be included in the results.
776  *
777  * @param RingPtr is a pointer to the instance to be worked on.
778  * @param BdLimit is the maximum number of BDs to return in the set.
779  * @param BdSetPtr is an output parameter, it points to the first BD available
780  *        for examination.
781  *
782  * @return
783  *   The number of BDs processed by hardware. A value of 0 indicates that no
784  *   data is available. No more than BdLimit BDs will be returned.
785  *
786  * @note Treat BDs returned by this function as read-only.
787  *
788  * @note This function should not be preempted by another XEmacPs_Bd function
789  *       call that modifies the BD space. It is the caller's responsibility to
790  *       provide a mutual exclusion mechanism.
791  *
792  *****************************************************************************/
793 u32 XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
794                                  XEmacPs_Bd ** BdSetPtr)
795 {
796         XEmacPs_Bd *CurBdPtr;
797         u32 BdStr = 0U;
798         u32 BdCount;
799         u32 BdPartialCount;
800         u32 Status;
801
802         CurBdPtr = RingPtr->HwHead;
803         BdCount = 0U;
804         BdPartialCount = 0U;
805
806         /* If no BDs in work group, then there's nothing to search */
807         if (RingPtr->HwCnt == 0x00000000U) {
808                 *BdSetPtr = NULL;
809                 Status = 0U;
810         } else {
811
812         /* Starting at HwHead, keep moving forward in the list until:
813          *  - A BD is encountered with its new/used bit set which means
814          *    hardware has completed processing of that BD.
815          *  - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
816          *  - The number of requested BDs has been processed
817          */
818         while (BdCount < BdLimit) {
819
820                 /* Read the status */
821                         if(CurBdPtr!=NULL){
822                 BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
823                         }
824                         if ((!(XEmacPs_BdIsRxNew(CurBdPtr)))==TRUE) {
825                         break;
826                 }
827
828                 BdCount++;
829
830                 /* hardware has processed this BD so check the "last" bit. If
831                  * it is clear, then there are more BDs for the current packet.
832                  * Keep a count of these partial packet BDs.
833                  */
834                         if ((BdStr & XEMACPS_RXBUF_EOF_MASK)!=0x00000000U) {
835                                 BdPartialCount = 0U;
836                         } else {
837                         BdPartialCount++;
838                 }
839
840                 /* Move on to next BD in work group */
841                 CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
842         }
843
844         /* Subtract off any partial packet BDs found */
845         BdCount -= BdPartialCount;
846
847         /* If BdCount is non-zero then BDs were found to return. Set return
848          * parameters, update pointers and counters, return success
849          */
850                 if (BdCount > 0x00000000U) {
851                 *BdSetPtr = RingPtr->HwHead;
852                 RingPtr->HwCnt -= BdCount;
853                 RingPtr->PostCnt += BdCount;
854                 XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
855                         Status = (BdCount);
856         }
857         else {
858                 *BdSetPtr = NULL;
859                         Status = 0U;
860         }
861 }
862         return Status;
863 }
864
865
866 /*****************************************************************************/
867 /**
868  * Frees a set of BDs that had been previously retrieved with
869  * XEmacPs_BdRingFromHw().
870  *
871  * @param RingPtr is a pointer to the instance to be worked on.
872  * @param NumBd is the number of BDs to free.
873  * @param BdSetPtr is the head of a list of BDs returned by
874  * XEmacPs_BdRingFromHw().
875  *
876  * @return
877  *   - XST_SUCCESS if the set of BDs was freed.
878  *   - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
879  *     XEmacPs_BdRingFromHw().
880  *
881  * @note This function should not be preempted by another XEmacPs_Bd function
882  *       call that modifies the BD space. It is the caller's responsibility to
883  *       provide a mutual exclusion mechanism.
884  *
885  *****************************************************************************/
886 LONG XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, u32 NumBd,
887                         XEmacPs_Bd * BdSetPtr)
888 {
889         LONG Status;
890         /* if no bds to process, simply return. */
891         if (0x00000000U == NumBd){
892                 Status = (LONG)(XST_SUCCESS);
893         } else {
894         /* Make sure we are in sync with XEmacPs_BdRingFromHw() */
895         if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) {
896                         Status = (LONG)(XST_DMA_SG_LIST_ERROR);
897                 } else {
898         /* Update pointers and counters */
899         RingPtr->FreeCnt += NumBd;
900         RingPtr->PostCnt -= NumBd;
901         XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd);
902                         Status = (LONG)(XST_SUCCESS);
903                 }
904         }
905         return Status;
906 }
907
908
909 /*****************************************************************************/
910 /**
911  * Check the internal data structures of the BD ring for the provided channel.
912  * The following checks are made:
913  *
914  *   - Is the BD ring linked correctly in physical address space.
915  *   - Do the internal pointers point to BDs in the ring.
916  *   - Do the internal counters add up.
917  *
918  * The channel should be stopped prior to calling this function.
919  *
920  * @param RingPtr is a pointer to the instance to be worked on.
921  * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
922  *        which direction.
923  *
924  * @return
925  *   - XST_SUCCESS if the set of BDs was freed.
926  *   - XST_DMA_SG_NO_LIST if the list has not been created.
927  *   - XST_IS_STARTED if the channel is not stopped.
928  *   - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
929  *     structures. If this value is returned, the channel should be reset to
930  *     avoid data corruption or system instability.
931  *
932  * @note This function should not be preempted by another XEmacPs_Bd function
933  *       call that modifies the BD space. It is the caller's responsibility to
934  *       provide a mutual exclusion mechanism.
935  *
936  *****************************************************************************/
937 LONG XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
938 {
939         UINTPTR AddrV, AddrP;
940         u32 i;
941
942         if ((Direction != (u8)XEMACPS_SEND) && (Direction != (u8)XEMACPS_RECV)) {
943                 return (LONG)(XST_INVALID_PARAM);
944         }
945
946         /* Is the list created */
947         if (RingPtr->AllCnt == 0x00000000U) {
948                 return (LONG)(XST_DMA_SG_NO_LIST);
949         }
950
951         /* Can't check if channel is running */
952         if (RingPtr->RunState == (u32)XST_DMA_SG_IS_STARTED) {
953                 return (LONG)(XST_IS_STARTED);
954         }
955
956         /* RunState doesn't make sense */
957         if (RingPtr->RunState != (u32)XST_DMA_SG_IS_STOPPED) {
958                 return (LONG)(XST_DMA_SG_LIST_ERROR);
959         }
960
961         /* Verify internal pointers point to correct memory space */
962         AddrV = (UINTPTR) RingPtr->FreeHead;
963         if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
964                 return (LONG)(XST_DMA_SG_LIST_ERROR);
965         }
966
967         AddrV = (UINTPTR) RingPtr->PreHead;
968         if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
969                 return (LONG)(XST_DMA_SG_LIST_ERROR);
970         }
971
972         AddrV = (UINTPTR) RingPtr->HwHead;
973         if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
974                 return (LONG)(XST_DMA_SG_LIST_ERROR);
975         }
976
977         AddrV = (UINTPTR) RingPtr->HwTail;
978         if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
979                 return (LONG)(XST_DMA_SG_LIST_ERROR);
980         }
981
982         AddrV = (UINTPTR) RingPtr->PostHead;
983         if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
984                 return (LONG)(XST_DMA_SG_LIST_ERROR);
985         }
986
987         /* Verify internal counters add up */
988         if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
989              RingPtr->PostCnt) != RingPtr->AllCnt) {
990                 return (LONG)(XST_DMA_SG_LIST_ERROR);
991         }
992
993         /* Verify BDs are linked correctly */
994         AddrV = RingPtr->BaseBdAddr;
995         AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
996
997         for (i = 1U; i < RingPtr->AllCnt; i++) {
998                 /* Check BDA for this BD. It should point to next physical addr */
999                 if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
1000                         return (LONG)(XST_DMA_SG_LIST_ERROR);
1001                 }
1002
1003                 /* Move on to next BD */
1004                 AddrV += RingPtr->Separation;
1005                 AddrP += RingPtr->Separation;
1006         }
1007
1008         /* Last BD should have wrap bit set */
1009         if (XEMACPS_SEND == Direction) {
1010                 if ((!XEmacPs_BdIsTxWrap(AddrV))==TRUE) {
1011                         return (LONG)(XST_DMA_SG_LIST_ERROR);
1012                 }
1013         }
1014         else {                  /* XEMACPS_RECV */
1015                 if ((!XEmacPs_BdIsRxWrap(AddrV))==TRUE) {
1016                         return (LONG)(XST_DMA_SG_LIST_ERROR);
1017                 }
1018         }
1019
1020         /* No problems found */
1021         return (LONG)(XST_SUCCESS);
1022 }
1023
1024 /*****************************************************************************/
1025 /**
1026  * Set this bit to mark the last descriptor in the receive buffer descriptor
1027  * list.
1028  *
1029  * @param  BdPtr is the BD pointer to operate on
1030  *
1031  * @note
1032  * C-style signature:
1033  *    void XEmacPs_BdSetRxWrap(XEmacPs_Bd* BdPtr)
1034  *
1035  *****************************************************************************/
1036 static void XEmacPs_BdSetRxWrap(UINTPTR BdPtr)
1037 {
1038     u32 DataValueRx;
1039         u32 *TempPtr;
1040
1041         BdPtr += (u32)(XEMACPS_BD_ADDR_OFFSET);
1042         TempPtr = (u32 *)BdPtr;
1043         if(TempPtr != NULL) {
1044                 DataValueRx = *TempPtr;
1045                 DataValueRx |= XEMACPS_RXBUF_WRAP_MASK;
1046                 *TempPtr = DataValueRx;
1047         }
1048 }
1049
1050 /*****************************************************************************/
1051 /**
1052  * Sets this bit to mark the last descriptor in the transmit buffer
1053  * descriptor list.
1054  *
1055  * @param  BdPtr is the BD pointer to operate on
1056  *
1057  * @note
1058  * C-style signature:
1059  *    void XEmacPs_BdSetTxWrap(XEmacPs_Bd* BdPtr)
1060  *
1061  *****************************************************************************/
1062 static void XEmacPs_BdSetTxWrap(UINTPTR BdPtr)
1063 {
1064     u32 DataValueTx;
1065         u32 *TempPtr;
1066
1067         BdPtr += (u32)(XEMACPS_BD_STAT_OFFSET);
1068         TempPtr = (u32 *)BdPtr;
1069         if(TempPtr != NULL) {
1070                 DataValueTx = *TempPtr;
1071                 DataValueTx |= XEMACPS_TXBUF_WRAP_MASK;
1072                 *TempPtr = DataValueTx;
1073         }
1074 }
1075 /** @} */