source: SVN/rincon/u-boot/cpu/ixp/npe/IxEthAccDataPlane.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 68.0 KB
Line 
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
60extern PUBLIC IxEthAccMacState ixEthAccMacState[];
61extern PUBLIC UINT32 ixEthAccNewSrcMask;
62
63/**
64 * private functions prototype
65 */
66PRIVATE IX_OSAL_MBUF *
67ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
68
69PRIVATE UINT32
70ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
71
72PRIVATE UINT32
73ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
74
75PRIVATE IxEthAccStatus
76ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
77                                IxEthAccTxPriority *priorityPtr);
78
79PRIVATE IxEthAccStatus
80ixEthAccTxFromSwQ(IxEthAccPortId portId,
81                  IxEthAccTxPriority priority);
82
83PRIVATE IxEthAccStatus
84ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
85
86PRIVATE void
87ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
88
89PRIVATE void
90ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
91
92PRIVATE IX_STATUS
93ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
94                        UINT32 qBuffer);
95
96PRIVATE IX_STATUS
97ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
98                        UINT32 qBuffer);
99
100PRIVATE IX_STATUS
101ixEthAccQmgrTxWrite(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
122PRIVATE IxEthAccDataPlaneStats     ixEthAccDataStats;
123
124extern IxEthAccPortDataInfo   ixEthAccPortData[];
125extern IxEthAccInfo   ixEthAccDataInfo;
126
127PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
128PRIVATE 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 */
246PRIVATE IX_OSAL_MBUF *
247ixEthAccEntryFromQConvert(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 */
281PRIVATE UINT32
282ixEthAccMbufTxQPrepare(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 */
383PRIVATE UINT32
384ixEthAccMbufRxQPrepare(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*/
477PRIVATE void
478ixEthAccMbufFromTxQ(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 */
503PRIVATE void
504ixEthAccMbufFromRxQ(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 */
566PRIVATE IX_STATUS
567ixEthAccQmgrLockTxWrite(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 */
595PRIVATE IX_STATUS
596ixEthAccQmgrLockRxWrite(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 */
623PRIVATE IX_STATUS
624ixEthAccQmgrTxWrite(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 */
646PRIVATE IxEthAccStatus
647ixEthAccTxSwQHighestPriorityGet(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 */
698PRIVATE IxEthAccStatus
699ixEthAccTxFromSwQ(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 */
784PRIVATE IxEthAccStatus
785ixEthAccRxFreeFromSwQ(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
842IX_ETH_ACC_PUBLIC
843IxEthAccStatus 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
871IX_ETH_ACC_PUBLIC
872IxEthAccStatus 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
909IX_ETH_ACC_PUBLIC
910IxEthAccStatus 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
985IX_ETH_ACC_PUBLIC
986IxEthAccStatus 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
1063IX_ETH_ACC_PUBLIC
1064IxEthAccStatus 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
1282IX_ETH_ACC_PUBLIC
1283IxEthAccStatus 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
1388IX_ETH_ACC_PUBLIC
1389IxEthAccStatus 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
1418IX_ETH_ACC_PUBLIC
1419IxEthAccStatus 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 */
1445IX_ETH_ACC_PRIVATE BOOL
1446ixEthRxFrameProcess(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 */
1567void 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 */
1725void 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 */
1891void 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 */
1983void
1984ixEthTxFrameQMCallback(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
2070void
2071ixEthTxFrameDoneQMCallback(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
2169IX_ETH_ACC_PUBLIC
2170void 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
Note: See TracBrowser for help on using the repository browser.