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