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