]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxEthAccDataPlane.c
Merge branch 'master' of git://www.denx.de/git/u-boot-cfi-flash
[karo-tx-uboot.git] / drivers / net / npe / IxEthAccDataPlane.c
1 /**
2  * @file IxEthDataPlane.c
3  *
4  * @author Intel Corporation
5  * @date 12-Feb-2002
6  *
7  * @brief This file contains the implementation of the IXPxxx
8  * Ethernet Access Data plane component
9  *
10  * Design Notes:
11  *
12  * @par
13  * IXP400 SW Release version 2.0
14  *
15  * -- Copyright Notice --
16  *
17  * @par
18  * Copyright 2001-2005, Intel Corporation.
19  * All rights reserved.
20  *
21  * @par
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the above copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. Neither the name of the Intel Corporation nor the names of its contributors
31  *    may be used to endorse or promote products derived from this software
32  *    without specific prior written permission.
33  *
34  * @par
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
36  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
39  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45  * SUCH DAMAGE.
46  *
47  * @par
48  * -- End of Copyright Notice --
49  */
50
51 #include "IxNpeMh.h"
52 #include "IxEthAcc.h"
53 #include "IxEthDB.h"
54 #include "IxOsal.h"
55 #include "IxEthDBPortDefs.h"
56 #include "IxFeatureCtrl.h"
57 #include "IxEthAcc_p.h"
58 #include "IxEthAccQueueAssign_p.h"
59
60 extern PUBLIC IxEthAccMacState ixEthAccMacState[];
61 extern PUBLIC UINT32 ixEthAccNewSrcMask;
62
63 /**
64  * private functions prototype
65  */
66 PRIVATE IX_OSAL_MBUF *
67 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
68
69 PRIVATE UINT32
70 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
71
72 PRIVATE UINT32
73 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
74
75 PRIVATE IxEthAccStatus
76 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
77                                 IxEthAccTxPriority *priorityPtr);
78
79 PRIVATE IxEthAccStatus
80 ixEthAccTxFromSwQ(IxEthAccPortId portId,
81                   IxEthAccTxPriority priority);
82
83 PRIVATE IxEthAccStatus
84 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
85
86 PRIVATE void
87 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
88
89 PRIVATE void
90 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
91
92 PRIVATE IX_STATUS
93 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
94                         UINT32 qBuffer);
95
96 PRIVATE IX_STATUS
97 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
98                         UINT32 qBuffer);
99
100 PRIVATE IX_STATUS
101 ixEthAccQmgrTxWrite(IxEthAccPortId portId,
102                     UINT32 qBuffer,
103                     UINT32 priority);
104
105 /**
106  * @addtogroup IxEthAccPri
107  *@{
108  */
109
110 /* increment a counter only when stats are enabled */
111 #define TX_STATS_INC(port,field) \
112         IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccTxData.stats.field)
113 #define RX_STATS_INC(port,field) \
114         IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccRxData.stats.field)
115
116 /* always increment the counter (mainly used for unexpected errors) */
117 #define TX_INC(port,field) \
118         ixEthAccPortData[port].ixEthAccTxData.stats.field++
119 #define RX_INC(port,field) \
120         ixEthAccPortData[port].ixEthAccRxData.stats.field++
121
122 PRIVATE IxEthAccDataPlaneStats     ixEthAccDataStats;
123
124 extern IxEthAccPortDataInfo   ixEthAccPortData[];
125 extern IxEthAccInfo   ixEthAccDataInfo;
126
127 PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
128 PRIVATE IxOsalFastMutex rxWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
129
130 /**
131  *
132  * @brief Mbuf header conversion macros : they implement the
133  *  different conversions using a temporary value. They also double-check
134  *  that the parameters can be converted to/from NPE format.
135  *
136  */
137 #if defined(__wince) && !defined(IN_KERNEL)
138 #define PTR_VIRT2NPE(ptrSrc,dst) \
139   do { UINT32 temp; \
140       IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \
141       IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \
142       temp = (UINT32)IX_OSAL_MBUF_MBUF_VIRTUAL_TO_PHYSICAL_TRANSLATION((IX_OSAL_MBUF*)ptrSrc); \
143       (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
144   while(0)
145
146 #define PTR_NPE2VIRT(type,src,ptrDst) \
147   do { void *temp; \
148       IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \
149       IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \
150       IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \
151       temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \
152       (ptrDst) = (type)IX_OSAL_MBUF_MBUF_PHYSICAL_TO_VIRTUAL_TRANSLATION(temp); } \
153   while(0)
154 #else
155 #define PTR_VIRT2NPE(ptrSrc,dst) \
156   do { UINT32 temp; \
157       IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \
158       IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \
159       temp = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(ptrSrc); \
160       (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
161   while(0)
162
163 #define PTR_NPE2VIRT(type,src,ptrDst) \
164   do { void *temp; \
165       IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \
166       IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \
167       IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \
168       temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \
169       (ptrDst) = (type)IX_OSAL_MMU_PHYS_TO_VIRT(temp); } \
170   while(0)
171 #endif
172
173 /**
174  *
175  * @brief Mbuf payload pointer conversion macros : Wince has its own
176  *  method to convert the buffer pointers
177  */
178 #if defined(__wince) && !defined(IN_KERNEL)
179 #define DATAPTR_VIRT2NPE(ptrSrc,dst) \
180   do { UINT32 temp; \
181       temp = (UINT32)IX_OSAL_MBUF_DATA_VIRTUAL_TO_PHYSICAL_TRANSLATION(ptrSrc); \
182       (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
183   while(0)
184
185 #else
186 #define DATAPTR_VIRT2NPE(ptrSrc,dst) PTR_VIRT2NPE(IX_OSAL_MBUF_MDATA(ptrSrc),dst)
187 #endif
188
189
190 /* Flush the shared part of the mbuf header */
191 #define IX_ETHACC_NE_CACHE_FLUSH(mbufPtr) \
192   do { \
193       IX_OSAL_CACHE_FLUSH(IX_ETHACC_NE_SHARED(mbufPtr), \
194                               sizeof(IxEthAccNe)); \
195     } \
196   while(0)
197
198 /* Invalidate the shared part of the mbuf header */
199 #define IX_ETHACC_NE_CACHE_INVALIDATE(mbufPtr) \
200   do { \
201       IX_OSAL_CACHE_INVALIDATE(IX_ETHACC_NE_SHARED(mbufPtr), \
202                                    sizeof(IxEthAccNe)); \
203     } \
204   while(0)
205
206 /* Preload one cache line (shared mbuf headers are aligned
207  * and their size is 1 cache line)
208  *
209  * IX_OSAL_CACHED  is defined when the mbuf headers are
210  * allocated from cached memory.
211  *
212  * Other processor on emulation environment may not implement
213  * preload function
214  */
215 #ifdef IX_OSAL_CACHED
216         #if (CPU!=SIMSPARCSOLARIS) && !defined (__wince)
217                 #define IX_ACC_DATA_CACHE_PRELOAD(ptr) \
218                 do { /* preload a cache line (Xscale Processor) */ \
219                         __asm__ (" pld [%0]\n": : "r" (ptr)); \
220                 } \
221                 while(0)
222         #else
223                 /* preload not implemented on different processor */
224                 #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
225                 do { /* nothing */ } while (0)
226         #endif
227 #else
228         /* preload not needed if cache is not enabled */
229         #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
230         do { /* nothing */ } while (0)
231 #endif
232
233 /**
234  *
235  * @brief function to retrieve the correct pointer from
236  * a queue entry posted by the NPE
237  *
238  * @param qEntry : entry from qmgr queue
239  *        mask : applicable mask for this queue
240  *        (4 most significant bits are used for additional informations)
241  *
242  * @return IX_OSAL_MBUF * pointer to mbuf header
243  *
244  * @internal
245  */
246 PRIVATE IX_OSAL_MBUF *
247 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask)
248 {
249     IX_OSAL_MBUF *mbufPtr;
250
251     if (qEntry != 0)
252     {
253         /* mask NPE bits (e.g. priority, port ...) */
254         qEntry &= mask;
255
256 #if IX_ACC_DRAM_PHYS_OFFSET != 0
257         /* restore the original address pointer (if PHYS_OFFSET is not 0) */
258         qEntry |= (IX_ACC_DRAM_PHYS_OFFSET & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
259 #endif
260         /* get the mbuf pointer address from the npe-shared address */
261         qEntry -= offsetof(IX_OSAL_MBUF,ix_ne);
262
263         /* phys2virt mbuf */
264         mbufPtr = (IX_OSAL_MBUF *)IX_OSAL_MMU_PHYS_TO_VIRT(qEntry);
265
266         /* preload the cacheline shared with NPE */
267         IX_ACC_DATA_CACHE_PRELOAD(IX_ETHACC_NE_SHARED(mbufPtr));
268
269         /* preload the cacheline used by xscale */
270         IX_ACC_DATA_CACHE_PRELOAD(mbufPtr);
271     }
272     else
273     {
274         mbufPtr = NULL;
275     }
276
277     return mbufPtr;
278 }
279
280 /* Convert the mbuf header for NPE transmission */
281 PRIVATE UINT32
282 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf)
283 {
284     UINT32 qbuf;
285     UINT32 len;
286
287     /* endianess swap for tci and flags
288        note: this is done only once, even for chained buffers */
289     IX_ETHACC_NE_FLAGS(mbuf)   = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf));
290     IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf));
291
292     /* test for unchained mbufs */
293     if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
294     {
295         /* "best case" scenario : unchained mbufs */
296         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxMBufs);
297
298         /* payload pointer conversion */
299         DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
300
301         /* unchained mbufs : the frame length is the mbuf length
302          * and the 2 identical lengths are stored in the same
303          * word.
304          */
305         len = IX_OSAL_MBUF_MLEN(mbuf);
306
307         /* set the length in both length and pktLen 16-bits fields */
308         len |= (len << IX_ETHNPE_ACC_LENGTH_OFFSET);
309         IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
310
311         /* unchained mbufs : next contains 0 */
312         IX_ETHACC_NE_NEXT(mbuf) = 0;
313
314         /* flush shared header after all address conversions */
315         IX_ETHACC_NE_CACHE_FLUSH(mbuf);
316     }
317     else
318     {
319         /* chained mbufs */
320         IX_OSAL_MBUF *ptr = mbuf;
321         IX_OSAL_MBUF *nextPtr;
322         UINT32 frmLen;
323
324         /* get the frame length from the header of the first buffer */
325         frmLen = IX_OSAL_MBUF_PKT_LEN(mbuf);
326
327         do
328         {
329             IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxMBufs);
330
331             /* payload pointer */
332             DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
333             /* Buffer length and frame length are stored in the same word */
334             len = IX_OSAL_MBUF_MLEN(ptr);
335             len = frmLen | (len << IX_ETHNPE_ACC_LENGTH_OFFSET);
336             IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
337
338             /* get the virtual next chain pointer */
339             nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
340             if (nextPtr != NULL)
341             {
342                 /* shared pointer of the next buffer is chained */
343                 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
344                              IX_ETHACC_NE_NEXT(ptr));
345             }
346             else
347             {
348                 IX_ETHACC_NE_NEXT(ptr) = 0;
349             }
350
351             /* flush shared header after all address conversions */
352             IX_ETHACC_NE_CACHE_FLUSH(ptr);
353
354             /* move to next buffer */
355             ptr = nextPtr;
356
357             /* the frame length field is set only in the first buffer
358              * and is zeroed in the next buffers
359              */
360             frmLen = 0;
361         }
362         while(ptr != NULL);
363
364     }
365
366     /* virt2phys mbuf itself */
367     qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
368                   IX_ETHACC_NE_SHARED(mbuf));
369
370     /* Ensure the bits which are reserved to exchange information with
371      * the NPE are cleared
372      *
373      * If the mbuf address is not correctly aligned, or from an
374      * incompatible memory range, there is no point to continue
375      */
376     IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_TXENET_ADDR_MASK) == 0),
377               "Invalid address range");
378
379     return qbuf;
380 }
381
382 /* Convert the mbuf header for NPE reception */
383 PRIVATE UINT32
384 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf)
385 {
386     UINT32 len;
387     UINT32 qbuf;
388
389     if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
390     {
391         /* "best case" scenario : unchained mbufs */
392         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxFreeMBufs);
393
394         /* unchained mbufs : payload pointer */
395         DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
396
397         /* unchained mbufs : set the buffer length
398         * and the frame length field is zeroed
399         */
400         len = (IX_OSAL_MBUF_MLEN(mbuf) << IX_ETHNPE_ACC_LENGTH_OFFSET);
401         IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
402
403         /* unchained mbufs : next pointer is null */
404         IX_ETHACC_NE_NEXT(mbuf) = 0;
405
406         /* flush shared header after all address conversions */
407         IX_ETHACC_NE_CACHE_FLUSH(mbuf);
408
409         /* remove shared header cache line */
410         IX_ETHACC_NE_CACHE_INVALIDATE(mbuf);
411     }
412     else
413     {
414         /* chained mbufs */
415         IX_OSAL_MBUF *ptr = mbuf;
416         IX_OSAL_MBUF *nextPtr;
417
418         do
419         {
420             /* chained mbufs */
421             IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxFreeMBufs);
422
423             /* we must save virtual next chain pointer */
424             nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
425
426             if (nextPtr != NULL)
427             {
428                 /* chaining pointer for NPE */
429                 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
430                              IX_ETHACC_NE_NEXT(ptr));
431             }
432             else
433             {
434                 IX_ETHACC_NE_NEXT(ptr) = 0;
435             }
436
437             /* payload pointer */
438             DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
439
440             /* buffer length */
441             len = (IX_OSAL_MBUF_MLEN(ptr) << IX_ETHNPE_ACC_LENGTH_OFFSET);
442             IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
443
444             /* flush shared header after all address conversions */
445             IX_ETHACC_NE_CACHE_FLUSH(ptr);
446
447             /* remove shared header cache line */
448             IX_ETHACC_NE_CACHE_INVALIDATE(ptr);
449
450             /* next mbuf in the chain */
451             ptr = nextPtr;
452         }
453         while(ptr != NULL);
454     }
455
456     /* virt2phys mbuf itself */
457     qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
458                   IX_ETHACC_NE_SHARED(mbuf));
459
460     /* Ensure the bits which are reserved to exchange information with
461      * the NPE are cleared
462      *
463      * If the mbuf address is not correctly aligned, or from an
464      * incompatible memory range, there is no point to continue
465      */
466     IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0),
467               "Invalid address range");
468
469     return qbuf;
470 }
471
472 /* Convert the mbuf header after NPE transmission
473  * Since there is nothing changed by the NPE, there is no need
474  * to process anything but the update of internal stats
475  * when they are enabled
476 */
477 PRIVATE void
478 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf)
479 {
480 #ifndef NDEBUG
481     /* test for unchained mbufs */
482     if (IX_ETHACC_NE_NEXT(mbuf) == 0)
483     {
484         /* unchained mbufs : update the stats */
485         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs);
486     }
487     else
488     {
489         /* chained mbufs : walk the chain and update the stats */
490         IX_OSAL_MBUF *ptr = mbuf;
491
492         do
493         {
494             IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs);
495             ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
496         }
497         while (ptr != NULL);
498     }
499 #endif
500 }
501
502 /* Convert the mbuf header after NPE reception */
503 PRIVATE void
504 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf)
505 {
506     UINT32 len;
507
508     /* endianess swap for tci and flags
509        note: this is done only once, even for chained buffers */
510     IX_ETHACC_NE_FLAGS(mbuf)   = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf));
511     IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf));
512
513     /* test for unchained mbufs */
514     if (IX_ETHACC_NE_NEXT(mbuf) == 0)
515     {
516         /* unchained mbufs */
517         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs);
518
519         /* get the frame length. it is the same than the buffer length */
520         len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf));
521         len &= IX_ETHNPE_ACC_PKTLENGTH_MASK;
522         IX_OSAL_MBUF_PKT_LEN(mbuf) = IX_OSAL_MBUF_MLEN(mbuf) = len;
523
524         /* clears the next packet field */
525         IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL;
526     }
527     else
528     {
529         IX_OSAL_MBUF *ptr = mbuf;
530         IX_OSAL_MBUF *nextPtr;
531         UINT32 frmLen;
532
533         /* convert the frame length */
534         frmLen = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf));
535         IX_OSAL_MBUF_PKT_LEN(mbuf) = (frmLen & IX_ETHNPE_ACC_PKTLENGTH_MASK);
536
537         /* chained mbufs */
538         do
539         {
540             IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs);
541
542             /* convert the length */
543             len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(ptr));
544             IX_OSAL_MBUF_MLEN(ptr) = (len >> IX_ETHNPE_ACC_LENGTH_OFFSET);
545
546             /* get the next pointer */
547             PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr);
548             if (nextPtr != NULL)
549             {
550                 nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne));
551             }
552             /* set the next pointer */
553             IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr;
554
555             /* move to the next buffer */
556             ptr = nextPtr;
557         }
558         while (ptr != NULL);
559     }
560 }
561
562 /* write to qmgr if possible and report an overflow if not possible
563  * Use a fast lock to protect the queue write.
564  * This way, the tx feature is reentrant.
565  */
566 PRIVATE IX_STATUS
567 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer)
568 {
569     IX_STATUS qStatus;
570     if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS)
571     {
572         qStatus = ixQMgrQWrite(
573                IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
574                &qBuffer);
575 #ifndef NDEBUG
576         if (qStatus != IX_SUCCESS)
577         {
578             TX_STATS_INC(portId, txOverflow);
579         }
580 #endif
581         ixOsalFastMutexUnlock(&txWriteMutex[portId]);
582     }
583     else
584     {
585         TX_STATS_INC(portId, txLock);
586         qStatus = IX_QMGR_Q_OVERFLOW;
587     }
588     return qStatus;
589 }
590
591 /* write to qmgr if possible and report an overflow if not possible
592  * Use a fast lock to protect the queue write.
593  * This way, the Rx feature is reentrant.
594  */
595 PRIVATE IX_STATUS
596 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer)
597 {
598     IX_STATUS qStatus;
599     if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS)
600     {
601         qStatus = ixQMgrQWrite(
602                IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
603                &qBuffer);
604 #ifndef NDEBUG
605         if (qStatus != IX_SUCCESS)
606         {
607             RX_STATS_INC(portId, rxFreeOverflow);
608         }
609 #endif
610         ixOsalFastMutexUnlock(&rxWriteMutex[portId]);
611     }
612     else
613     {
614         RX_STATS_INC(portId, rxFreeLock);
615         qStatus = IX_QMGR_Q_OVERFLOW;
616     }
617     return qStatus;
618 }
619
620 /*
621  * Set the priority and write to a qmgr queue.
622  */
623 PRIVATE IX_STATUS
624 ixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority)
625 {
626     /* fill the priority field */
627     qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R);
628
629     return ixEthAccQmgrLockTxWrite(portId, qBuffer);
630 }
631
632 /**
633  *
634  * @brief This function will discover the highest priority S/W Tx Q that
635  *        has entries in it
636  *
637  * @param portId - (in) the id of the port whose S/W Tx queues are to be searched
638  *        priorityPtr - (out) the priority of the highest priority occupied q will be written
639  *                      here
640  *
641  * @return IX_ETH_ACC_SUCCESS if an occupied Q is found
642  *         IX_ETH_ACC_FAIL if no Q has entries
643  *
644  * @internal
645  */
646 PRIVATE IxEthAccStatus
647 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
648                                 IxEthAccTxPriority *priorityPtr)
649 {
650     if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline
651         == FIFO_NO_PRIORITY)
652     {
653         if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
654                ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY]))
655         {
656             return IX_ETH_ACC_FAIL;
657         }
658         else
659         {
660             *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
661             TX_STATS_INC(portId,txPriority[*priorityPtr]);
662             return IX_ETH_ACC_SUCCESS;
663         }
664     }
665     else
666     {
667         IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7;
668         while(1)
669         {
670             if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
671                ixEthAccTxData.txQ[highestPriority]))
672             {
673
674                 *priorityPtr = highestPriority;
675                 TX_STATS_INC(portId,txPriority[highestPriority]);
676                 return IX_ETH_ACC_SUCCESS;
677
678             }
679             if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0)
680             {
681                 return IX_ETH_ACC_FAIL;
682             }
683             highestPriority--;
684         }
685     }
686 }
687
688 /**
689  *
690  * @brief This function will take a buffer from a TX S/W Q and attempt
691  *        to add it to the relevant TX H/W Q
692  *
693  * @param portId - the port whose TX queue is to be written to
694  *        priority - identifies the queue from which the entry is to be read
695  *
696  * @internal
697  */
698 PRIVATE IxEthAccStatus
699 ixEthAccTxFromSwQ(IxEthAccPortId portId,
700                   IxEthAccTxPriority priority)
701 {
702     IX_OSAL_MBUF        *mbuf;
703     IX_STATUS      qStatus;
704
705     IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority");
706
707     IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
708         ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
709         mbuf);
710
711     if (mbuf != NULL)
712     {
713         /*
714          * Add the Tx buffer to the H/W Tx Q
715          * We do not need to flush here as it is already done
716          * in TxFrameSubmit().
717          */
718         qStatus = ixEthAccQmgrTxWrite(
719               portId,
720               IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)),
721               priority);
722
723         if (qStatus == IX_SUCCESS)
724         {
725             TX_STATS_INC(portId,txFromSwQOK);
726             return IX_SUCCESS;
727         }
728         else if (qStatus == IX_QMGR_Q_OVERFLOW)
729         {
730             /*
731              * H/W Q overflow, need to save the buffer
732              * back on the s/w Q.
733              * we must put it back on the head of the q to avoid
734              * reordering packet tx
735              */
736             TX_STATS_INC(portId,txFromSwQDelayed);
737             IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
738                 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
739                 mbuf);
740
741             /*enable Q notification*/
742             qStatus = ixQMgrNotificationEnable(
743                 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
744                 IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
745
746             if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING)
747             {
748                 TX_INC(portId,txUnexpectedError);
749                 IX_ETH_ACC_FATAL_LOG(
750                     "ixEthAccTxFromSwQ:Unexpected Error: %u\n",
751                     qStatus, 0, 0, 0, 0, 0);
752             }
753         }
754         else
755         {
756             TX_INC(portId,txUnexpectedError);
757
758             /* recovery attempt */
759             IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
760                 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
761                 mbuf);
762
763             IX_ETH_ACC_FATAL_LOG(
764                 "ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n",
765                 qStatus, 0, 0, 0, 0, 0);
766         }
767     }
768     else
769     {
770         /* sw queue is empty */
771     }
772     return IX_ETH_ACC_FAIL;
773 }
774
775 /**
776  *
777  * @brief This function will take a buffer from a RXfree S/W Q and attempt
778  *        to add it to the relevant RxFree H/W Q
779  *
780  * @param portId - the port whose RXFree queue is to be written to
781  *
782  * @internal
783  */
784 PRIVATE IxEthAccStatus
785 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId)
786 {
787     IX_OSAL_MBUF        *mbuf;
788     IX_STATUS      qStatus = IX_SUCCESS;
789
790     IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
791           ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
792           mbuf);
793     if (mbuf != NULL)
794     {
795         /*
796          * Add The Rx Buffer to the H/W Free buffer Q if possible
797          */
798         qStatus = ixEthAccQmgrLockRxWrite(portId,
799                   IX_OSAL_MMU_VIRT_TO_PHYS(
800                          (UINT32)IX_ETHACC_NE_SHARED(mbuf)));
801
802         if (qStatus == IX_SUCCESS)
803         {
804             RX_STATS_INC(portId,rxFreeRepFromSwQOK);
805             /*
806              * Buffer added to h/w Q.
807              */
808             return IX_SUCCESS;
809         }
810         else if (qStatus == IX_QMGR_Q_OVERFLOW)
811         {
812             /*
813              * H/W Q overflow, need to save the buffer back on the s/w Q.
814              */
815             RX_STATS_INC(portId,rxFreeRepFromSwQDelayed);
816
817             IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
818                    ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
819                    mbuf);
820         }
821         else
822         {
823             /* unexpected qmgr error */
824             RX_INC(portId,rxUnexpectedError);
825
826             IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
827                     ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
828                     mbuf);
829
830             IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n",
831                                  qStatus, 0, 0, 0, 0, 0);
832         }
833     }
834     else
835     {
836         /* sw queue is empty */
837     }
838     return IX_ETH_ACC_FAIL;
839 }
840
841
842 IX_ETH_ACC_PUBLIC
843 IxEthAccStatus ixEthAccInitDataPlane()
844 {
845     UINT32 portId;
846
847     /*
848      * Initialize the service and register callback to other services.
849      */
850
851     IX_ETH_ACC_MEMSET(&ixEthAccDataStats,
852                       0,
853                       sizeof(ixEthAccDataStats));
854
855     for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
856     {
857         ixOsalFastMutexInit(&txWriteMutex[portId]);
858         ixOsalFastMutexInit(&rxWriteMutex[portId]);
859
860         IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId],
861                           0,
862                           sizeof(ixEthAccPortData[portId]));
863
864         ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY;
865     }
866
867     return (IX_ETH_ACC_SUCCESS);
868 }
869
870
871 IX_ETH_ACC_PUBLIC
872 IxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId,
873                                                   IxEthAccPortTxDoneCallback
874                                                   txCallbackFn,
875                                                   UINT32 callbackTag)
876 {
877     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
878     {
879         return (IX_ETH_ACC_FAIL);
880     }
881     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
882     {
883         return (IX_ETH_ACC_INVALID_PORT);
884     }
885
886 /* HACK: removing this code to enable NPE-A preliminary testing
887  *    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
888  *    {
889  *        IX_ETH_ACC_WARNING_LOG("ixEthAccPortTxDoneCallbackRegister: Unavailable Eth %d: Cannot register TxDone Callback.\n",(INT32)portId,0,0,0,0,0);
890  *        return IX_ETH_ACC_SUCCESS ;
891  *    }
892  */
893
894     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
895     {
896         return (IX_ETH_ACC_PORT_UNINITIALIZED);
897     }
898     if (txCallbackFn == 0)
899         /* Check for null function pointer here. */
900     {
901         return (IX_ETH_ACC_INVALID_ARG);
902     }
903     ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn;
904     ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag;
905     return (IX_ETH_ACC_SUCCESS);
906 }
907
908
909 IX_ETH_ACC_PUBLIC
910 IxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId,
911                                               IxEthAccPortRxCallback
912                                               rxCallbackFn,
913                                               UINT32 callbackTag)
914 {
915     IxEthAccPortId port;
916
917     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
918     {
919         return (IX_ETH_ACC_FAIL);
920     }
921     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
922     {
923         return (IX_ETH_ACC_INVALID_PORT);
924     }
925
926     if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
927     {
928         IX_ETH_ACC_WARNING_LOG("ixEthAccPortRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0);
929         return IX_ETH_ACC_SUCCESS ;
930     }
931
932     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
933     {
934         return (IX_ETH_ACC_PORT_UNINITIALIZED);
935     }
936
937     /* Check for null function pointer here. */
938     if (rxCallbackFn == NULL)
939     {
940         return (IX_ETH_ACC_INVALID_ARG);
941     }
942
943     /* Check the user is not changing the callback type
944      * when the port is enabled.
945     */
946     if (ixEthAccMacState[portId].portDisableState == ACTIVE)
947     {
948         for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
949         {
950             if ((ixEthAccMacState[port].portDisableState == ACTIVE)
951                 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == true))
952             {
953                 /* one of the active ports has a different rx callback type.
954                  * Changing the callback type when the port is enabled
955                  * is not safe
956                  */
957                 return (IX_ETH_ACC_INVALID_ARG);
958             }
959         }
960     }
961
962     /* update the callback pointer : this is done before
963      * registering the new qmgr callback
964      */
965     ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = rxCallbackFn;
966     ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = callbackTag;
967
968     /* update the qmgr callback for rx queues */
969     if (ixEthAccQMgrRxCallbacksRegister(ixEthRxFrameQMCallback)
970         != IX_ETH_ACC_SUCCESS)
971     {
972         /* unexpected qmgr error */
973         IX_ETH_ACC_FATAL_LOG("ixEthAccPortRxCallbackRegister: unexpected QMgr error, " \
974             "could not register Rx single-buffer callback\n", 0, 0, 0, 0, 0, 0);
975
976         RX_INC(portId,rxUnexpectedError);
977         return (IX_ETH_ACC_INVALID_ARG);
978     }
979
980     ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = false;
981
982     return (IX_ETH_ACC_SUCCESS);
983 }
984
985 IX_ETH_ACC_PUBLIC
986 IxEthAccStatus ixEthAccPortMultiBufferRxCallbackRegister(
987                          IxEthAccPortId portId,
988                          IxEthAccPortMultiBufferRxCallback
989                          rxCallbackFn,
990                          UINT32 callbackTag)
991 {
992     IxEthAccPortId port;
993
994     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
995     {
996         return (IX_ETH_ACC_FAIL);
997     }
998     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
999     {
1000         return (IX_ETH_ACC_INVALID_PORT);
1001     }
1002
1003     if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
1004     {
1005         IX_ETH_ACC_WARNING_LOG("ixEthAccPortMultiBufferRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0);
1006         return IX_ETH_ACC_SUCCESS ;
1007     }
1008
1009     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1010     {
1011         return (IX_ETH_ACC_PORT_UNINITIALIZED);
1012     }
1013
1014     /* Check for null function pointer here. */
1015     if (rxCallbackFn == NULL)
1016     {
1017         return (IX_ETH_ACC_INVALID_ARG);
1018     }
1019
1020     /* Check the user is not changing the callback type
1021      * when the port is enabled.
1022     */
1023     if (ixEthAccMacState[portId].portDisableState == ACTIVE)
1024     {
1025         for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
1026         {
1027             if ((ixEthAccMacState[port].portDisableState == ACTIVE)
1028                 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == false))
1029             {
1030                 /* one of the active ports has a different rx callback type.
1031                  * Changing the callback type when the port is enabled
1032                  * is not safe
1033                  */
1034                 return (IX_ETH_ACC_INVALID_ARG);
1035             }
1036         }
1037     }
1038
1039     /* update the callback pointer : this is done before
1040      * registering the new qmgr callback
1041      */
1042     ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = rxCallbackFn;
1043     ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = callbackTag;
1044
1045     /* update the qmgr callback for rx queues */
1046     if (ixEthAccQMgrRxCallbacksRegister(ixEthRxMultiBufferQMCallback)
1047         != IX_ETH_ACC_SUCCESS)
1048     {
1049         /* unexpected qmgr error */
1050         RX_INC(portId,rxUnexpectedError);
1051
1052         IX_ETH_ACC_FATAL_LOG("ixEthAccPortMultiBufferRxCallbackRegister: unexpected QMgr error, " \
1053             "could not register Rx multi-buffer callback\n", 0, 0, 0, 0, 0, 0);
1054
1055         return (IX_ETH_ACC_INVALID_ARG);
1056     }
1057
1058     ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = true;
1059
1060     return (IX_ETH_ACC_SUCCESS);
1061 }
1062
1063 IX_ETH_ACC_PUBLIC
1064 IxEthAccStatus ixEthAccPortTxFrameSubmit(IxEthAccPortId portId,
1065                                          IX_OSAL_MBUF *buffer,
1066                                          IxEthAccTxPriority priority)
1067 {
1068     IX_STATUS   qStatus = IX_SUCCESS;
1069     UINT32      qBuffer;
1070     IxEthAccTxPriority highestPriority;
1071     IxQMgrQStatus txQStatus;
1072
1073 #ifndef NDEBUG
1074     if (buffer == NULL)
1075     {
1076         return (IX_ETH_ACC_FAIL);
1077     }
1078     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1079     {
1080         return (IX_ETH_ACC_FAIL);
1081     }
1082     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1083     {
1084         return (IX_ETH_ACC_INVALID_PORT);
1085     }
1086
1087     if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
1088     {
1089         IX_ETH_ACC_FATAL_LOG("ixEthAccPortTxFrameSubmit: Unavailable Eth %d: Cannot submit Tx Frame.\n",
1090                              (INT32)portId,0,0,0,0,0);
1091         return IX_ETH_ACC_PORT_UNINITIALIZED ;
1092     }
1093
1094     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1095     {
1096         return (IX_ETH_ACC_PORT_UNINITIALIZED);
1097     }
1098     if ((UINT32)priority > (UINT32)IX_ETH_ACC_TX_PRIORITY_7)
1099     {
1100         return (IX_ETH_ACC_INVALID_ARG);
1101     }
1102 #endif
1103
1104     /*
1105      * Need to Flush the MBUF and its contents (data) as it may be
1106      * read from the NPE. Convert virtual addresses to physical addresses also.
1107      */
1108     qBuffer = ixEthAccMbufTxQPrepare(buffer);
1109
1110     /*
1111      * If no fifo priority set on Xscale ...
1112      */
1113     if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
1114         FIFO_NO_PRIORITY)
1115     {
1116         /*
1117          * Add The Tx Buffer to the H/W Tx Q if possible
1118          * (the priority is passed to the NPE, because
1119          * the NPE is able to reorder the frames
1120          * before transmission to the underlying hardware)
1121          */
1122         qStatus = ixEthAccQmgrTxWrite(portId,
1123                                       qBuffer,
1124                                       IX_ETH_ACC_TX_DEFAULT_PRIORITY);
1125
1126         if (qStatus == IX_SUCCESS)
1127         {
1128             TX_STATS_INC(portId,txQOK);
1129
1130             /*
1131              * "best case" scenario : Buffer added to h/w Q.
1132              */
1133             return (IX_SUCCESS);
1134         }
1135         else if (qStatus == IX_QMGR_Q_OVERFLOW)
1136         {
1137             /*
1138              * We were unable to write the buffer to the
1139              * appropriate H/W Q,  Save it in the sw Q.
1140              * (use the default priority queue regardless of
1141              * input parameter)
1142              */
1143             priority = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
1144         }
1145         else
1146         {
1147             /* unexpected qmgr error */
1148             TX_INC(portId,txUnexpectedError);
1149             IX_ETH_ACC_FATAL_LOG(
1150                 "ixEthAccPortTxFrameSubmit:Error: qStatus = %u\n",
1151                 (UINT32)qStatus, 0, 0, 0, 0, 0);
1152             return (IX_ETH_ACC_FAIL);
1153         }
1154     }
1155     else if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
1156              FIFO_PRIORITY)
1157     {
1158
1159         /*
1160          * For priority transmission, put the frame directly on the H/W queue
1161          * if the H/W queue is empty, otherwise, put it in a S/W Q
1162          */
1163         ixQMgrQStatusGet(IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &txQStatus);
1164         if((txQStatus & IX_QMGR_Q_STATUS_E_BIT_MASK) != 0)
1165         {
1166             /*The tx queue is empty, check whether there are buffers on the s/w queues*/
1167             if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
1168                !=IX_ETH_ACC_FAIL)
1169             {
1170                 /*there are buffers on the s/w queues, submit them*/
1171                 ixEthAccTxFromSwQ(portId, highestPriority);
1172
1173                 /* the queue was empty, 1 buffer is already supplied
1174                  * but is likely to be immediately transmitted and the
1175                  * hw queue is likely to be empty again, so submit
1176                  * more from the sw queues
1177                  */
1178                 if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
1179                    !=IX_ETH_ACC_FAIL)
1180                 {
1181                     ixEthAccTxFromSwQ(portId, highestPriority);
1182                     /*
1183                      * and force the buffer supplied to be placed
1184                      * on a priority queue
1185                      */
1186                     qStatus = IX_QMGR_Q_OVERFLOW;
1187                 }
1188                 else
1189                 {
1190                     /*there are no buffers in the s/w queues, submit directly*/
1191                     qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1192                 }
1193             }
1194             else
1195             {
1196                 /*there are no buffers in the s/w queues, submit directly*/
1197                 qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1198             }
1199         }
1200         else
1201         {
1202             qStatus = IX_QMGR_Q_OVERFLOW;
1203         }
1204     }
1205     else
1206     {
1207         TX_INC(portId,txUnexpectedError);
1208         IX_ETH_ACC_FATAL_LOG(
1209             "ixEthAccPortTxFrameSubmit:Error: wrong schedule discipline setup\n",
1210             0, 0, 0, 0, 0, 0);
1211         return (IX_ETH_ACC_FAIL);
1212     }
1213
1214     if(qStatus == IX_SUCCESS )
1215     {
1216         TX_STATS_INC(portId,txQOK);
1217         return IX_ETH_ACC_SUCCESS;
1218     }
1219     else if(qStatus == IX_QMGR_Q_OVERFLOW)
1220     {
1221         TX_STATS_INC(portId,txQDelayed);
1222         /*
1223          * We were unable to write the buffer to the
1224          * appropriate H/W Q,  Save it in a s/w Q.
1225          */
1226         IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1227                 ixEthAccPortData[portId].
1228                 ixEthAccTxData.txQ[priority],
1229                 buffer);
1230
1231         qStatus = ixQMgrNotificationEnable(
1232                 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
1233                 IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
1234
1235         if (qStatus != IX_SUCCESS)
1236         {
1237             if (qStatus == IX_QMGR_WARNING)
1238             {
1239                 /* notification is enabled for a queue
1240                  * which is already empty (the condition is already met)
1241                  * and there will be no more queue event to drain the sw queue
1242                  */
1243                 TX_STATS_INC(portId,txLateNotificationEnabled);
1244
1245                 /* pull a buffer from the sw queue */
1246                 if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
1247                    !=IX_ETH_ACC_FAIL)
1248                 {
1249                     /*there are buffers on the s/w queues, submit from them*/
1250                     ixEthAccTxFromSwQ(portId, highestPriority);
1251                 }
1252             }
1253             else
1254             {
1255                 TX_INC(portId,txUnexpectedError);
1256                 IX_ETH_ACC_FATAL_LOG(
1257                      "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
1258                      qStatus, 0, 0, 0, 0, 0);
1259             }
1260         }
1261     }
1262     else
1263     {
1264         TX_INC(portId,txUnexpectedError);
1265         IX_ETH_ACC_FATAL_LOG(
1266              "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
1267              qStatus, 0, 0, 0, 0, 0);
1268         return (IX_ETH_ACC_FAIL);
1269     }
1270
1271     return (IX_ETH_ACC_SUCCESS);
1272 }
1273
1274
1275 /**
1276  *
1277  * @brief replenish: convert a chain of mbufs to the format
1278  *        expected by the NPE
1279  *
1280   */
1281
1282 IX_ETH_ACC_PUBLIC
1283 IxEthAccStatus ixEthAccPortRxFreeReplenish(IxEthAccPortId portId,
1284                                            IX_OSAL_MBUF *buffer)
1285 {
1286     IX_STATUS   qStatus = IX_SUCCESS;
1287     UINT32      qBuffer;
1288
1289     /*
1290      * Check buffer is valid.
1291      */
1292
1293 #ifndef NDEBUG
1294     /* check parameter value */
1295     if (buffer == 0)
1296     {
1297         return (IX_ETH_ACC_FAIL);
1298     }
1299     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1300     {
1301         return (IX_ETH_ACC_FAIL);
1302     }
1303     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1304     {
1305         return (IX_ETH_ACC_INVALID_PORT);
1306     }
1307
1308     /* check initialisation is done */
1309     if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
1310     {
1311         IX_ETH_ACC_FATAL_LOG(" ixEthAccPortRxFreeReplenish: Unavailable Eth %d: Cannot replenish Rx Free Q.\n",(INT32)portId,0,0,0,0,0);
1312         return IX_ETH_ACC_PORT_UNINITIALIZED ;
1313     }
1314
1315     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1316     {
1317         return (IX_ETH_ACC_PORT_UNINITIALIZED);
1318     }
1319     /* check boundaries and constraints */
1320     if (IX_OSAL_MBUF_MLEN(buffer) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
1321     {
1322         return (IX_ETH_ACC_FAIL);
1323     }
1324 #endif
1325
1326     qBuffer = ixEthAccMbufRxQPrepare(buffer);
1327
1328     /*
1329      * Add The Rx Buffer to the H/W Free buffer Q if possible
1330      */
1331     qStatus = ixEthAccQmgrLockRxWrite(portId, qBuffer);
1332
1333     if (qStatus == IX_SUCCESS)
1334     {
1335         RX_STATS_INC(portId,rxFreeRepOK);
1336         /*
1337          * Buffer added to h/w Q.
1338          */
1339         return (IX_SUCCESS);
1340     }
1341     else if (qStatus == IX_QMGR_Q_OVERFLOW)
1342     {
1343         RX_STATS_INC(portId,rxFreeRepDelayed);
1344         /*
1345          * We were unable to write the buffer to the approprate H/W Q,
1346          * Save it in a s/w Q.
1347          */
1348         IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1349             ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
1350             buffer);
1351
1352         qStatus = ixQMgrNotificationEnable(
1353             IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
1354             IX_ETH_ACC_PORT_TO_RX_FREE_Q_SOURCE(portId));
1355
1356         if (qStatus != IX_SUCCESS)
1357         {
1358             if (qStatus == IX_QMGR_WARNING)
1359             {
1360                 /* notification is enabled for a queue
1361                  * which is already empty (the condition is already met)
1362                  * and there will be no more queue event to drain the sw queue
1363                  * move an entry from the sw queue to the hw queue */
1364                 RX_STATS_INC(portId,rxFreeLateNotificationEnabled);
1365                 ixEthAccRxFreeFromSwQ(portId);
1366             }
1367             else
1368             {
1369                 RX_INC(portId,rxUnexpectedError);
1370                 IX_ETH_ACC_FATAL_LOG(
1371                      "ixEthAccRxPortFreeReplenish:Error: %u\n",
1372                      qStatus, 0, 0, 0, 0, 0);
1373             }
1374         }
1375     }
1376     else
1377     {
1378         RX_INC(portId,rxUnexpectedError);
1379         IX_ETH_ACC_FATAL_LOG(
1380             "ixEthAccRxPortFreeReplenish:Error: qStatus = %u\n",
1381             (UINT32)qStatus, 0, 0, 0, 0, 0);
1382         return(IX_ETH_ACC_FAIL);
1383     }
1384     return (IX_ETH_ACC_SUCCESS);
1385 }
1386
1387
1388 IX_ETH_ACC_PUBLIC
1389 IxEthAccStatus ixEthAccTxSchedulingDisciplineSetPriv(IxEthAccPortId portId,
1390                                                  IxEthAccSchedulerDiscipline
1391                                                  sched)
1392 {
1393     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1394     {
1395         return (IX_ETH_ACC_INVALID_PORT);
1396     }
1397
1398     if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
1399     {
1400         IX_ETH_ACC_WARNING_LOG("ixEthAccTxSchedulingDisciplineSet: Unavailable Eth %d: Cannot set Tx Scheduling Discipline.\n",(INT32)portId,0,0,0,0,0);
1401         return IX_ETH_ACC_SUCCESS ;
1402     }
1403
1404     if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1405     {
1406         return (IX_ETH_ACC_PORT_UNINITIALIZED);
1407     }
1408
1409     if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1410     {
1411         return (IX_ETH_ACC_INVALID_ARG);
1412     }
1413
1414     ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = sched;
1415     return (IX_ETH_ACC_SUCCESS);
1416 }
1417
1418 IX_ETH_ACC_PUBLIC
1419 IxEthAccStatus ixEthAccRxSchedulingDisciplineSetPriv(IxEthAccSchedulerDiscipline
1420                                                  sched)
1421 {
1422     if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1423     {
1424         return (IX_ETH_ACC_INVALID_ARG);
1425     }
1426
1427     ixEthAccDataInfo.schDiscipline = sched;
1428
1429     return (IX_ETH_ACC_SUCCESS);
1430 }
1431
1432
1433 /**
1434  * @fn ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1435  *
1436  * @brief process incoming frame :
1437  *
1438  * @param @ref IxQMgrCallback IxQMgrMultiBufferCallback
1439  *
1440  * @return none
1441  *
1442  * @internal
1443  *
1444  */
1445 IX_ETH_ACC_PRIVATE BOOL
1446 ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1447 {
1448     UINT32 flags;
1449     IxEthDBStatus result;
1450
1451 #ifndef NDEBUG
1452     /* Prudent to at least check the port is within range */
1453     if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
1454     {
1455         ixEthAccDataStats.unexpectedError++;
1456         IX_ETH_ACC_FATAL_LOG(
1457              "ixEthRxFrameProcess: Illegal port: %u\n",
1458              (UINT32)portId, 0, 0, 0, 0, 0);
1459         return false;
1460     }
1461 #endif
1462
1463     /* convert fields from mbuf header */
1464     ixEthAccMbufFromRxQ(mbufPtr);
1465
1466     /* check about any special processing for this frame */
1467     flags = IX_ETHACC_NE_FLAGS(mbufPtr);
1468     if ((flags & (IX_ETHACC_NE_FILTERMASK | IX_ETHACC_NE_NEWSRCMASK)) == 0)
1469     {
1470         /* "best case" scenario : nothing special to do for this frame */
1471         return true;
1472     }
1473
1474 #ifdef CONFIG_IXP425_COMPONENT_ETHDB
1475     /* if a new source MAC address is detected by the NPE,
1476      * update IxEthDB with the portId and the MAC address.
1477      */
1478     if ((flags & IX_ETHACC_NE_NEWSRCMASK & ixEthAccNewSrcMask) != 0)
1479     {
1480         result = ixEthDBFilteringDynamicEntryProvision(portId,
1481                           (IxEthDBMacAddr *) IX_ETHACC_NE_SOURCEMAC(mbufPtr));
1482
1483         if (result != IX_ETH_DB_SUCCESS && result != IX_ETH_DB_FEATURE_UNAVAILABLE)
1484         {
1485             if ((ixEthAccMacState[portId].portDisableState == ACTIVE) && (result != IX_ETH_DB_BUSY))
1486             {
1487                 RX_STATS_INC(portId, rxUnexpectedError);
1488                 IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to add source MAC \
1489                                     to the Learning/Filtering database\n", 0, 0, 0, 0, 0, 0);
1490             }
1491             else
1492             {
1493                 /* we expect this to fail during PortDisable, as EthDB is disabled for
1494                  * that port and will refuse to learn new addresses
1495                  */
1496             }
1497         }
1498         else
1499         {
1500             RX_STATS_INC(portId, rxUnlearnedMacAddress);
1501         }
1502     }
1503 #endif
1504
1505     /* check if this frame should have been filtered
1506      * by the NPE and take the appropriate action
1507      */
1508     if (((flags & IX_ETHACC_NE_FILTERMASK) != 0)
1509         && (ixEthAccMacState[portId].portDisableState == ACTIVE))
1510     {
1511         /* If the mbuf was allocated with a small data size, or the current data pointer is not
1512          * within the allocated data area, then the buffer is non-standard and has to be
1513          * replenished with the minimum size only
1514          */
1515         if( (IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
1516            || ((UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) > IX_OSAL_MBUF_MDATA(mbufPtr))
1517            || ((UINT8 *)(IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) +
1518               IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr))
1519                < IX_OSAL_MBUF_MDATA(mbufPtr)) )
1520         {
1521             /* set to minimum length */
1522             IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) =
1523                 IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN;
1524         }
1525         else
1526         {
1527             /* restore original length */
1528             IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) =
1529                 ( IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) -
1530                  (IX_OSAL_MBUF_MDATA(mbufPtr) - (UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr)) );
1531         }
1532
1533         /* replenish from here */
1534         if (ixEthAccPortRxFreeReplenish(portId, mbufPtr) != IX_ETH_ACC_SUCCESS)
1535         {
1536                 IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to replenish with filtered frame\
1537                                       on port %d\n", portId, 0, 0, 0, 0, 0);
1538         }
1539
1540         RX_STATS_INC(portId, rxFiltered);
1541
1542         /* indicate that frame should not be subjected to further processing */
1543         return false;
1544     }
1545
1546     return true;
1547 }
1548
1549
1550 /**
1551  * @fn ixEthRxFrameQMCallback
1552  *
1553  * @brief receive callback for Frame receive Q from NPE
1554  *
1555  * Frames are passed one-at-a-time to the user
1556  *
1557  * @param @ref IxQMgrCallback
1558  *
1559  * @return none
1560  *
1561  * @internal
1562  *
1563  * Design note : while processing the entry X, entry X+1 is preloaded
1564  * into memory to reduce the number of stall cycles
1565  *
1566  */
1567 void ixEthRxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1568 {
1569     IX_OSAL_MBUF    *mbufPtr;
1570     IX_OSAL_MBUF    *nextMbufPtr;
1571     UINT32     qEntry;
1572     UINT32     nextQEntry;
1573     UINT32     *qEntryPtr;
1574     UINT32     portId;
1575     UINT32     destPortId;
1576     UINT32     npeId;
1577     UINT32     rxQReadStatus;
1578
1579     /*
1580      * Design note : entries are read in a buffer, This buffer contains
1581      * an extra zeroed entry so the loop will
1582      * always terminate on a null entry, whatever the result of Burst read is.
1583      */
1584     UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
1585
1586     /*
1587      * Indication of the number of times the callback is used.
1588      */
1589     IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1590
1591     do
1592     {
1593         /*
1594          * Indication of the number of times the queue is drained
1595          */
1596         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
1597
1598         /* ensure the last entry of the array contains a zeroed value */
1599         qEntryPtr = rxQEntry;
1600         qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0;
1601
1602         rxQReadStatus = ixQMgrQBurstRead(qId,
1603                  IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1604                  qEntryPtr);
1605
1606 #ifndef NDEBUG
1607         if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1608             && (rxQReadStatus != IX_SUCCESS))
1609         {
1610             ixEthAccDataStats.unexpectedError++;
1611             /*major error*/
1612             IX_ETH_ACC_FATAL_LOG(
1613                 "ixEthRxFrameQMCallback:Error: %u\n",
1614                 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
1615             return;
1616         }
1617 #endif
1618
1619         /* convert and preload the next entry
1620          * (the conversion function takes care about null pointers which
1621          * are used to mark the end of the loop)
1622          */
1623         nextQEntry = *qEntryPtr;
1624         nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1625                           IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1626
1627         while(nextQEntry != 0)
1628         {
1629             /* get the next entry */
1630             qEntry = nextQEntry;
1631             mbufPtr = nextMbufPtr;
1632
1633 #ifndef NDEBUG
1634             if (mbufPtr == NULL)
1635             {
1636                 ixEthAccDataStats.unexpectedError++;
1637                 IX_ETH_ACC_FATAL_LOG(
1638                     "ixEthRxFrameQMCallback: Null Mbuf Ptr\n",
1639                     0, 0, 0, 0, 0, 0);
1640                 return;
1641             }
1642 #endif
1643
1644             /* convert the next entry
1645              * (the conversion function takes care about null pointers which
1646              * are used to mark the end of the loop)
1647              */
1648             nextQEntry = *(++qEntryPtr);
1649             nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1650                               IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1651
1652             /*
1653              * Get Port and Npe ID from message.
1654              */
1655             npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
1656                       qEntry) >> IX_ETHNPE_QM_Q_FIELD_NPEID_R);
1657             portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
1658
1659             /* process frame, check the return code and skip the remaining of
1660              * the loop if the frame is to be filtered out
1661              */
1662             if (ixEthRxFrameProcess(portId, mbufPtr))
1663             {
1664                 /* destination portId for this packet */
1665                 destPortId = IX_ETHACC_NE_DESTPORTID(mbufPtr);
1666
1667                 if (destPortId != IX_ETH_DB_UNKNOWN_PORT)
1668                 {
1669                     destPortId = IX_ETH_DB_NPE_LOGICAL_ID_TO_PORT_ID(destPortId);
1670                 }
1671
1672                 /* test if QoS is enabled in ethAcc
1673                 */
1674                 if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1675                 {
1676                     /* check if there is a higher priority queue
1677                     * which may require processing and then process it.
1678                     */
1679                     if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1680                     {
1681                         ixEthRxFrameQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1682                                             callbackId);
1683                     }
1684                 }
1685
1686                 /*
1687                 * increment priority stats
1688                 */
1689                 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1690
1691                 /*
1692                 * increment callback count stats
1693                 */
1694                 RX_STATS_INC(portId,rxFrameClientCallback);
1695
1696                 /*
1697                 * Call user level callback.
1698                 */
1699                 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn(
1700                     ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag,
1701                     mbufPtr,
1702                     destPortId);
1703             }
1704         }
1705     } while (rxQReadStatus == IX_SUCCESS);
1706 }
1707
1708 /**
1709  * @fn ixEthRxMultiBufferQMCallback
1710  *
1711  * @brief receive callback for Frame receive Q from NPE
1712  *
1713  * Frames are passed as an array to the user
1714  *
1715  * @param @ref IxQMgrCallback
1716  *
1717  * @return none
1718  *
1719  * @internal
1720  *
1721  * Design note : while processing the entry X, entry X+1 is preloaded
1722  * into memory to reduce the number of stall cycles
1723  *
1724  */
1725 void ixEthRxMultiBufferQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1726 {
1727     IX_OSAL_MBUF    *mbufPtr;
1728     IX_OSAL_MBUF    *nextMbufPtr;
1729     UINT32     qEntry;
1730     UINT32     nextQEntry;
1731     UINT32     *qEntryPtr;
1732     UINT32     portId;
1733     UINT32     npeId;
1734     UINT32     rxQReadStatus;
1735     /*
1736      * Design note : entries are read in a static buffer, This buffer contains
1737      * an extra zeroed entry so the loop will
1738      * always terminate on a null entry, whatever the result of Burst read is.
1739      */
1740     static UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
1741     static IX_OSAL_MBUF *rxMbufPortArray[IX_ETH_ACC_NUMBER_OF_PORTS][IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
1742     IX_OSAL_MBUF **rxMbufPtr[IX_ETH_ACC_NUMBER_OF_PORTS];
1743
1744     for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1745     {
1746         rxMbufPtr[portId] = rxMbufPortArray[portId];
1747     }
1748
1749     /*
1750      * Indication of the number of times the callback is used.
1751      */
1752     IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1753
1754     do
1755     {
1756         /*
1757          * Indication of the number of times the queue is drained
1758          */
1759         IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
1760
1761         /* ensure the last entry of the array contains a zeroed value */
1762         qEntryPtr = rxQEntry;
1763         qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0;
1764
1765         rxQReadStatus = ixQMgrQBurstRead(qId,
1766                  IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1767                  qEntryPtr);
1768
1769 #ifndef NDEBUG
1770         if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1771             && (rxQReadStatus != IX_SUCCESS))
1772         {
1773             ixEthAccDataStats.unexpectedError++;
1774             /*major error*/
1775             IX_ETH_ACC_FATAL_LOG(
1776                 "ixEthRxFrameMultiBufferQMCallback:Error: %u\n",
1777                 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
1778             return;
1779         }
1780 #endif
1781
1782         /* convert and preload the next entry
1783          * (the conversion function takes care about null pointers which
1784          * are used to mark the end of the loop)
1785          */
1786         nextQEntry = *qEntryPtr;
1787         nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1788                           IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1789
1790         while(nextQEntry != 0)
1791         {
1792             /* get the next entry */
1793             qEntry = nextQEntry;
1794             mbufPtr = nextMbufPtr;
1795
1796 #ifndef NDEBUG
1797             if (mbufPtr == NULL)
1798             {
1799                 ixEthAccDataStats.unexpectedError++;
1800                 IX_ETH_ACC_FATAL_LOG(
1801                     "ixEthRxFrameMultiBufferQMCallback:Error: Null Mbuf Ptr\n",
1802                     0, 0, 0, 0, 0, 0);
1803                 return;
1804             }
1805 #endif
1806
1807             /* convert the next entry
1808              * (the conversion function takes care about null pointers which
1809              * are used to mark the end of the loop)
1810              */
1811             nextQEntry = *(++qEntryPtr);
1812             nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1813                               IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1814
1815             /*
1816              * Get Port and Npe ID from message.
1817              */
1818             npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
1819                       qEntry) >>
1820                      IX_ETHNPE_QM_Q_FIELD_NPEID_R);
1821             portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
1822
1823             /* skip the remaining of the loop if the frame is
1824              * to be filtered out
1825              */
1826             if (ixEthRxFrameProcess(portId, mbufPtr))
1827             {
1828                 /* store a mbuf pointer in an array */
1829                 *rxMbufPtr[portId]++ = mbufPtr;
1830
1831                 /*
1832                  * increment priority stats
1833                  */
1834                 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1835             }
1836
1837             /* test for QoS enabled in ethAcc */
1838             if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1839             {
1840                 /* check if there is a higher priority queue
1841                  * which may require processing and then process it.
1842                  */
1843                 if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1844                 {
1845                     ixEthRxMultiBufferQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1846                                                  callbackId);
1847                 }
1848             }
1849         }
1850
1851         /* check if any of the the arrays contains any entry */
1852         for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1853         {
1854             if (rxMbufPtr[portId] != rxMbufPortArray[portId])
1855             {
1856                 /* add a last NULL pointer at the end of the
1857                  * array of mbuf pointers
1858                  */
1859                 *rxMbufPtr[portId] = NULL;
1860
1861                 /*
1862                  * increment callback count stats
1863                  */
1864                 RX_STATS_INC(portId,rxFrameClientCallback);
1865
1866                 /*
1867                  * Call user level callback with an array of
1868                  * buffers (NULL terminated)
1869                  */
1870                 ixEthAccPortData[portId].ixEthAccRxData.
1871                     rxMultiBufferCallbackFn(
1872                             ixEthAccPortData[portId].ixEthAccRxData.
1873                                    rxMultiBufferCallbackTag,
1874                             rxMbufPortArray[portId]);
1875
1876                 /* reset the buffer pointer to the beginning of
1877                  * the array
1878                  */
1879                 rxMbufPtr[portId] = rxMbufPortArray[portId];
1880             }
1881         }
1882
1883     } while (rxQReadStatus == IX_SUCCESS);
1884 }
1885
1886
1887 /**
1888  * @brief  rxFree low event handler
1889  *
1890  */
1891 void ixEthRxFreeQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1892 {
1893     IxEthAccPortId      portId = (IxEthAccPortId) callbackId;
1894     int                 lockVal;
1895     UINT32              maxQWritesToPerform = IX_ETH_ACC_MAX_RX_FREE_BUFFERS_LOAD;
1896     IX_STATUS           qStatus = IX_SUCCESS;
1897
1898     /*
1899      * We have reached a low threshold on one of the Rx Free Qs
1900      */
1901
1902     /*note that due to the fact that we are working off an Empty threshold, this callback
1903       need only write a single entry to the Rx Free queue in order to re-arm the notification
1904     */
1905
1906     RX_STATS_INC(portId,rxFreeLowCallback);
1907
1908     /*
1909      * Get buffers from approprite S/W Rx freeBufferList Q.
1910      */
1911
1912 #ifndef NDEBUG
1913     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1914     {
1915         ixEthAccDataStats.unexpectedError++;
1916         IX_ETH_ACC_FATAL_LOG(
1917             "ixEthRxFreeQMCallback:Error: Invalid Port 0x%08X\n",
1918             portId, 0, 0, 0, 0, 0);
1919         return;
1920     }
1921 #endif
1922     IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1923     if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1924                                         ixEthAccRxData.freeBufferList))
1925     {
1926         /*
1927          * Turn off Q callback notification for Q in Question.
1928          */
1929         qStatus = ixQMgrNotificationDisable(
1930             IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1931
1932
1933         IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1934
1935         if (qStatus != IX_SUCCESS)
1936         {
1937             RX_INC(portId,rxUnexpectedError);
1938             IX_ETH_ACC_FATAL_LOG(
1939                 "ixEthRxFreeQMCallback:Error: unexpected QM status 0x%08X\n",
1940                 qStatus, 0, 0, 0, 0, 0);
1941             return;
1942         }
1943     }
1944     else
1945     {
1946         IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1947         /*
1948          * Load the H/W Q with buffers from the s/w Q.
1949          */
1950
1951         do
1952         {
1953             /*
1954              * Consume Q entries. - Note Q contains Physical addresss,
1955              * and have already been flushed to memory,
1956              * And endianess converted if required.
1957              */
1958             if (ixEthAccRxFreeFromSwQ(portId) != IX_SUCCESS)
1959             {
1960                 /*
1961                  * No more entries in s/w Q.
1962                  * Turn off Q callback indication
1963                  */
1964
1965                 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1966                 if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1967                     ixEthAccRxData.freeBufferList))
1968                 {
1969                     qStatus = ixQMgrNotificationDisable(
1970                         IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1971                 }
1972                 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1973                 break;
1974             }
1975         }
1976         while (--maxQWritesToPerform);
1977     }
1978 }
1979 /**
1980  * @fn Tx queue low event handler
1981  *
1982  */
1983 void
1984 ixEthTxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1985 {
1986     IxEthAccPortId portId = (IxEthAccPortId) callbackId;
1987     int            lockVal;
1988     UINT32         maxQWritesToPerform = IX_ETH_ACC_MAX_TX_FRAME_TX_CONSUME_PER_CALLBACK;
1989     IX_STATUS      qStatus = IX_SUCCESS;
1990     IxEthAccTxPriority highestPriority;
1991
1992
1993     /*
1994      * We have reached a low threshold on the Tx Q, and are being asked to
1995      * supply a buffer for transmission from our S/W TX queues
1996      */
1997     TX_STATS_INC(portId,txLowThreshCallback);
1998
1999     /*
2000      * Get buffers from approprite Q.
2001      */
2002
2003 #ifndef NDEBUG
2004     if (!IX_ETH_ACC_IS_PORT_VALID(portId))
2005     {
2006         ixEthAccDataStats.unexpectedError++;
2007         IX_ETH_ACC_FATAL_LOG(
2008             "ixEthTxFrameQMCallback:Error: Invalid Port 0x%08X\n",
2009             portId, 0, 0, 0, 0, 0);
2010         return;
2011     }
2012 #endif
2013
2014     do
2015     {
2016         /*
2017          * Consume Q entries. - Note Q contains Physical addresss,
2018          * and have already been flushed to memory,
2019          * and endianess already sone if required.
2020          */
2021
2022         IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
2023
2024         if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) ==
2025            IX_ETH_ACC_FAIL)
2026         {
2027             /*
2028              * No more entries in s/w Q.
2029              * Turn off Q callback indication
2030              */
2031             qStatus = ixQMgrNotificationDisable(
2032                 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId));
2033
2034             IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2035
2036             if (qStatus != IX_SUCCESS)
2037             {
2038                 ixEthAccDataStats.unexpectedError++;
2039                 IX_ETH_ACC_FATAL_LOG(
2040                     "ixEthTxFrameQMCallback:Error: unexpected QM status 0x%08X\n",
2041                     qStatus, 0, 0, 0, 0, 0);
2042             }
2043
2044             return;
2045         }
2046         else
2047         {
2048             IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2049             if (ixEthAccTxFromSwQ(portId,highestPriority)!=IX_SUCCESS)
2050             {
2051                 /* nothing left in the sw queue or the hw queues are
2052                 * full. There is no point to continue to drain the
2053                 * sw queues
2054                 */
2055                 return;
2056             }
2057         }
2058     }
2059     while (--maxQWritesToPerform);
2060 }
2061
2062 /**
2063  * @brief TxDone event handler
2064  *
2065  * Design note : while processing the entry X, entry X+1 is preloaded
2066  * into memory to reduce the number of stall cycles
2067  *
2068  */
2069
2070 void
2071 ixEthTxFrameDoneQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
2072 {
2073     IX_OSAL_MBUF    *mbufPtr;
2074     UINT32     qEntry;
2075     UINT32     *qEntryPtr;
2076     UINT32     txDoneQReadStatus;
2077     UINT32     portId;
2078     UINT32     npeId;
2079
2080     /*
2081      * Design note : entries are read in a static buffer, This buffer contains
2082      * an extra entyry (which is zeroed by the compiler), so the loop will
2083      * always terminate on a null entry, whatever the result of Burst read is.
2084      */
2085     static UINT32 txDoneQEntry[IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK + 1];
2086
2087     /*
2088      * Indication that Tx frames have been transmitted from the NPE.
2089      */
2090
2091     IX_ETH_ACC_STATS_INC(ixEthAccDataStats.txDoneCallbackCounter);
2092
2093     do{
2094         qEntryPtr = txDoneQEntry;
2095         txDoneQReadStatus = ixQMgrQBurstRead(IX_ETH_ACC_TX_FRAME_DONE_ETH_Q,
2096                      IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK,
2097                      qEntryPtr);
2098
2099 #ifndef NDEBUG
2100         if (txDoneQReadStatus != IX_QMGR_Q_UNDERFLOW
2101             && (txDoneQReadStatus != IX_SUCCESS))
2102         {
2103             /*major error*/
2104             ixEthAccDataStats.unexpectedError++;
2105             IX_ETH_ACC_FATAL_LOG(
2106                 "ixEthTxFrameDoneQMCallback:Error: %u\n",
2107                 (UINT32)txDoneQReadStatus, 0, 0, 0, 0, 0);
2108             return;
2109         }
2110 #endif
2111
2112         qEntry = *qEntryPtr;
2113
2114         while(qEntry != 0)
2115         {
2116             mbufPtr = ixEthAccEntryFromQConvert(qEntry,
2117                       IX_ETHNPE_QM_Q_TXENET_ADDR_MASK);
2118
2119 #ifndef NDEBUG
2120             if (mbufPtr == NULL)
2121             {
2122                 ixEthAccDataStats.unexpectedError++;
2123                 IX_ETH_ACC_FATAL_LOG(
2124                     "ixEthTxFrameDoneQMCallback:Error: Null Mbuf Ptr\n",
2125                     0, 0, 0, 0, 0, 0);
2126                 return;
2127             }
2128 #endif
2129
2130             /* endianness conversions and stats updates */
2131             ixEthAccMbufFromTxQ(mbufPtr);
2132
2133             /*
2134              * Get NPE id from message, then convert to portId.
2135              */
2136             npeId = ((IX_ETHNPE_QM_Q_TXENETDONE_NPEID_MASK &
2137                        qEntry) >>
2138                       IX_ETHNPE_QM_Q_FIELD_NPEID_R);
2139             portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
2140
2141 #ifndef NDEBUG
2142             /* Prudent to at least check the port is within range */
2143             if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
2144             {
2145                 ixEthAccDataStats.unexpectedError++;
2146                 IX_ETH_ACC_FATAL_LOG(
2147                     "ixEthTxFrameDoneQMCallback: Illegal port: %u\n",
2148                     (UINT32)portId, 0, 0, 0, 0, 0);
2149                 return;
2150             }
2151 #endif
2152
2153             TX_STATS_INC(portId,txDoneClientCallback);
2154
2155             /*
2156              * Call user level callback.
2157              */
2158             ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn(
2159                 ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag,
2160                 mbufPtr);
2161
2162             /* move to next queue entry */
2163             qEntry = *(++qEntryPtr);
2164
2165         }
2166     } while( txDoneQReadStatus == IX_SUCCESS );
2167 }
2168
2169 IX_ETH_ACC_PUBLIC
2170 void ixEthAccDataPlaneShow(void)
2171 {
2172     UINT32 numTx0Entries;
2173     UINT32 numTx1Entries;
2174     UINT32 numTxDoneEntries;
2175     UINT32 numRxEntries;
2176     UINT32 numRxFree0Entries;
2177     UINT32 numRxFree1Entries;
2178     UINT32 portId;
2179 #ifdef __ixp46X
2180     UINT32 numTx2Entries;
2181     UINT32 numRxFree2Entries;
2182 #endif
2183 #ifndef NDEBUG
2184     UINT32 priority;
2185     UINT32 numBuffersInRx=0;
2186     UINT32 numBuffersInTx=0;
2187     UINT32 numBuffersInSwQ=0;
2188     UINT32 totalBuffers=0;
2189     UINT32 rxFreeCallbackCounter = 0;
2190     UINT32 txCallbackCounter = 0;
2191 #endif
2192     UINT32 key;
2193
2194     /* snapshot of stats */
2195     IxEthAccTxDataStats tx[IX_ETH_ACC_NUMBER_OF_PORTS];
2196     IxEthAccRxDataStats rx[IX_ETH_ACC_NUMBER_OF_PORTS];
2197     IxEthAccDataPlaneStats stats;
2198
2199     if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
2200     {
2201         return;
2202     }
2203
2204     /* get a reliable snapshot */
2205     key = ixOsalIrqLock();
2206
2207     numTx0Entries = 0;
2208     ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET0_Q, &numTx0Entries);
2209     numTx1Entries = 0;
2210     ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET1_Q, &numTx1Entries);
2211     numTxDoneEntries = 0;
2212     ixQMgrQNumEntriesGet( IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, &numTxDoneEntries);
2213     numRxEntries = 0;
2214     ixEthAccQMgrRxQEntryGet(&numRxEntries);
2215     numRxFree0Entries = 0;
2216     ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q, &numRxFree0Entries);
2217     numRxFree1Entries = 0;
2218     ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q, &numRxFree1Entries);
2219
2220 #ifdef __ixp46X
2221     numTx2Entries = 0;
2222     ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET2_Q, &numTx2Entries);
2223     numRxFree2Entries = 0;
2224     ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q, &numRxFree2Entries);
2225 #endif
2226
2227     for(portId=IX_ETH_PORT_1; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2228     {
2229         memcpy(&tx[portId],
2230                &ixEthAccPortData[portId].ixEthAccTxData.stats,
2231                sizeof(tx[portId]));
2232         memcpy(&rx[portId],
2233                &ixEthAccPortData[portId].ixEthAccRxData.stats,
2234                sizeof(rx[portId]));
2235     }
2236     memcpy(&stats, &ixEthAccDataStats, sizeof(stats));
2237
2238     ixOsalIrqUnlock(key);
2239
2240 #ifdef NDEBUG
2241     printf("Detailed statistics collection not supported in this load\n");
2242 #endif
2243
2244     /* print snapshot */
2245     for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2246     {
2247         /* If not IXP42X A0 stepping, proceed to check for existence of coprocessors */
2248         if ((IX_FEATURE_CTRL_SILICON_TYPE_A0 !=
2249              (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK))
2250             || (IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X != ixFeatureCtrlDeviceRead ()))
2251         {
2252                 if ((IX_ETH_PORT_1 == portId) &&
2253                     (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
2254                      IX_FEATURE_CTRL_COMPONENT_DISABLED))
2255                 {
2256                    continue ;
2257                 }
2258                 if ((IX_ETH_PORT_2 == portId) &&
2259                     (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
2260                      IX_FEATURE_CTRL_COMPONENT_DISABLED))
2261                 {
2262                     continue ;
2263                 }
2264                 if ((IX_ETH_PORT_3 == portId) &&
2265                     (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) ==
2266                      IX_FEATURE_CTRL_COMPONENT_DISABLED))
2267                 {
2268                     continue ;
2269                 }
2270         }
2271
2272         printf("PORT %u --------------------------------\n",
2273                portId);
2274 #ifndef NDEBUG
2275         printf("Tx Done Frames                : %u\n",
2276                tx[portId].txDoneClientCallback +
2277                tx[portId].txDoneSwQDuringDisable +
2278                tx[portId].txDoneDuringDisable);
2279         printf("Tx Frames                     : %u\n",
2280                tx[portId].txQOK + tx[portId].txQDelayed);
2281         printf("Tx H/W Q Added OK             : %u\n",
2282                tx[portId].txQOK);
2283         printf("Tx H/W Q Delayed              : %u\n",
2284                tx[portId].txQDelayed);
2285         printf("Tx From S/W Q Added OK        : %u\n",
2286                tx[portId].txFromSwQOK);
2287         printf("Tx From S/W Q Delayed         : %u\n",
2288                tx[portId].txFromSwQDelayed);
2289         printf("Tx Overflow                   : %u\n",
2290                tx[portId].txOverflow);
2291         printf("Tx Mutual Lock                : %u\n",
2292                tx[portId].txLock);
2293         printf("Tx Late Ntf Enabled           : %u\n",
2294                tx[portId].txLateNotificationEnabled);
2295         printf("Tx Low Thresh CB              : %u\n",
2296                tx[portId].txLowThreshCallback);
2297         printf("Tx Done from H/W Q (Disable)  : %u\n",
2298                tx[portId].txDoneDuringDisable);
2299         printf("Tx Done from S/W Q (Disable)  : %u\n",
2300                tx[portId].txDoneSwQDuringDisable);
2301         for (priority = IX_ETH_ACC_TX_PRIORITY_0;
2302              priority <= IX_ETH_ACC_TX_PRIORITY_7;
2303              priority++)
2304         {
2305             if (tx[portId].txPriority[priority])
2306             {
2307                 printf("Tx Priority %u                 : %u\n",
2308                        priority,
2309                        tx[portId].txPriority[priority]);
2310             }
2311         }
2312 #endif
2313         printf("Tx unexpected errors          : %u (should be 0)\n",
2314                tx[portId].txUnexpectedError);
2315
2316 #ifndef NDEBUG
2317         printf("Rx Frames                     : %u\n",
2318                rx[portId].rxFrameClientCallback +
2319                rx[portId].rxSwQDuringDisable+
2320                rx[portId].rxDuringDisable);
2321         printf("Rx Free Replenish             : %u\n",
2322                rx[portId].rxFreeRepOK + rx[portId].rxFreeRepDelayed);
2323         printf("Rx Free H/W Q Added OK        : %u\n",
2324                rx[portId].rxFreeRepOK);
2325         printf("Rx Free H/W Q Delayed         : %u\n",
2326                rx[portId].rxFreeRepDelayed);
2327         printf("Rx Free From S/W Q Added OK   : %u\n",
2328                rx[portId].rxFreeRepFromSwQOK);
2329         printf("Rx Free From S/W Q Delayed    : %u\n",
2330                rx[portId].rxFreeRepFromSwQDelayed);
2331         printf("Rx Free Overflow              : %u\n",
2332                rx[portId].rxFreeOverflow);
2333         printf("Rx Free Mutual Lock           : %u\n",
2334                rx[portId].rxFreeLock);
2335         printf("Rx Free Late Ntf Enabled      : %u\n",
2336                rx[portId].rxFreeLateNotificationEnabled);
2337         printf("Rx Free Low CB                : %u\n",
2338                rx[portId].rxFreeLowCallback);
2339         printf("Rx From H/W Q (Disable)       : %u\n",
2340                rx[portId].rxDuringDisable);
2341         printf("Rx From S/W Q (Disable)       : %u\n",
2342                rx[portId].rxSwQDuringDisable);
2343         printf("Rx unlearned Mac Address      : %u\n",
2344                rx[portId].rxUnlearnedMacAddress);
2345         printf("Rx Filtered (Rx => RxFree)    : %u\n",
2346             rx[portId].rxFiltered);
2347
2348         for (priority = IX_ETH_ACC_TX_PRIORITY_0;
2349              priority <= IX_ETH_ACC_TX_PRIORITY_7;
2350              priority++)
2351         {
2352             if (rx[portId].rxPriority[priority])
2353             {
2354                 printf("Rx Priority %u                 : %u\n",
2355                        priority,
2356                        rx[portId].rxPriority[priority]);
2357             }
2358         }
2359 #endif
2360         printf("Rx unexpected errors          : %u (should be 0)\n",
2361                rx[portId].rxUnexpectedError);
2362
2363 #ifndef NDEBUG
2364         numBuffersInTx = tx[portId].txQOK +
2365             tx[portId].txQDelayed -
2366             tx[portId].txDoneClientCallback -
2367             tx[portId].txDoneSwQDuringDisable -
2368             tx[portId].txDoneDuringDisable;
2369
2370         printf("# Tx Buffers currently for transmission : %u\n",
2371                numBuffersInTx);
2372
2373         numBuffersInRx = rx[portId].rxFreeRepOK +
2374             rx[portId].rxFreeRepDelayed -
2375             rx[portId].rxFrameClientCallback -
2376             rx[portId].rxSwQDuringDisable -
2377             rx[portId].rxDuringDisable;
2378
2379         printf("# Rx Buffers currently for reception    : %u\n",
2380                numBuffersInRx);
2381
2382         totalBuffers += numBuffersInRx + numBuffersInTx;
2383 #endif
2384     }
2385
2386     printf("---------------------------------------\n");
2387
2388 #ifndef NDEBUG
2389     printf("\n");
2390     printf("Mbufs :\n");
2391     printf("Tx Unchained mbufs            : %u\n",
2392            stats.unchainedTxMBufs);
2393     printf("Tx Chained bufs               : %u\n",
2394            stats.chainedTxMBufs);
2395     printf("TxDone Unchained mbufs        : %u\n",
2396            stats.unchainedTxDoneMBufs);
2397     printf("TxDone Chained bufs           : %u\n",
2398            stats.chainedTxDoneMBufs);
2399     printf("RxFree Unchained mbufs        : %u\n",
2400            stats.unchainedRxFreeMBufs);
2401     printf("RxFree Chained bufs           : %u\n",
2402            stats.chainedRxFreeMBufs);
2403     printf("Rx Unchained mbufs            : %u\n",
2404            stats.unchainedRxMBufs);
2405     printf("Rx Chained bufs               : %u\n",
2406            stats.chainedRxMBufs);
2407
2408     printf("\n");
2409     printf("Software queue usage :\n");
2410     printf("Buffers added to S/W Q        : %u\n",
2411            stats.addToSwQ);
2412     printf("Buffers removed from S/W Q    : %u\n",
2413            stats.removeFromSwQ);
2414
2415     printf("\n");
2416     printf("Hardware queues callbacks :\n");
2417
2418     for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2419     {
2420         rxFreeCallbackCounter += rx[portId].rxFreeLowCallback;
2421         txCallbackCounter += tx[portId].txLowThreshCallback;
2422     }
2423     printf("Tx Done QM Callback invoked   : %u\n",
2424            stats.txDoneCallbackCounter);
2425     printf("Tx QM Callback invoked        : %u\n",
2426            txCallbackCounter);
2427     printf("Rx QM Callback invoked        : %u\n",
2428            stats.rxCallbackCounter);
2429     printf("Rx QM Callback burst read     : %u\n",
2430            stats.rxCallbackBurstRead);
2431     printf("Rx Free QM Callback invoked   : %u\n",
2432            rxFreeCallbackCounter);
2433 #endif
2434     printf("Unexpected errors in CB       : %u (should be 0)\n",
2435            stats.unexpectedError);
2436     printf("\n");
2437
2438     printf("Hardware queues levels :\n");
2439     printf("Transmit Port 1 Q             : %u \n",numTx0Entries);
2440     printf("Transmit Port 2 Q             : %u \n",numTx1Entries);
2441 #ifdef __ixp46X
2442     printf("Transmit Port 3 Q             : %u \n",numTx2Entries);
2443 #endif
2444     printf("Transmit Done Q               : %u \n",numTxDoneEntries);
2445     printf("Receive Q                     : %u \n",numRxEntries);
2446     printf("Receive Free Port 1 Q         : %u \n",numRxFree0Entries);
2447     printf("Receive Free Port 2 Q         : %u \n",numRxFree1Entries);
2448 #ifdef __ixp46X
2449     printf("Receive Free Port 3 Q         : %u \n",numRxFree2Entries);
2450 #endif
2451
2452 #ifndef NDEBUG
2453     printf("\n");
2454     printf("# Total Buffers accounted for : %u\n",
2455            totalBuffers);
2456
2457     numBuffersInSwQ = ixEthAccDataStats.addToSwQ -
2458         ixEthAccDataStats.removeFromSwQ;
2459
2460     printf("    Buffers in S/W Qs         : %u\n",
2461            numBuffersInSwQ);
2462     printf("    Buffers in H/W Qs or NPEs : %u\n",
2463            totalBuffers - numBuffersInSwQ);
2464 #endif
2465
2466     printf("Rx QoS Discipline             : %s\n",
2467            (ixEthAccDataInfo.schDiscipline ==
2468             FIFO_PRIORITY ) ? "Enabled" : "Disabled");
2469
2470     for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2471     {
2472         printf("Tx QoS Discipline port %u      : %s\n",
2473                portId,
2474                (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
2475                 FIFO_PRIORITY ) ? "Enabled" : "Disabled");
2476     }
2477     printf("\n");
2478 }
2479
2480
2481
2482
2483