blob: c0b82d99b7f51fca63e390f6a1f70ea9baa2bd71 [file] [log] [blame]
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001/**
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
Wolfgang Denkcb3761e2013-07-28 22:12:47 +020022 * SPDX-License-Identifier: BSD-3-Clause
Wolfgang Denkba94a1b2006-05-30 15:56:48 +020023 * @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
36extern PUBLIC IxEthAccMacState ixEthAccMacState[];
37extern PUBLIC UINT32 ixEthAccNewSrcMask;
38
39/**
40 * private functions prototype
41 */
42PRIVATE IX_OSAL_MBUF *
43ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
44
45PRIVATE UINT32
46ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
47
48PRIVATE UINT32
49ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
50
51PRIVATE IxEthAccStatus
52ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
53 IxEthAccTxPriority *priorityPtr);
54
55PRIVATE IxEthAccStatus
56ixEthAccTxFromSwQ(IxEthAccPortId portId,
57 IxEthAccTxPriority priority);
58
59PRIVATE IxEthAccStatus
60ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
61
62PRIVATE void
63ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
64
65PRIVATE void
66ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
67
68PRIVATE IX_STATUS
69ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
70 UINT32 qBuffer);
71
72PRIVATE IX_STATUS
73ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
74 UINT32 qBuffer);
75
76PRIVATE IX_STATUS
77ixEthAccQmgrTxWrite(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
98PRIVATE IxEthAccDataPlaneStats ixEthAccDataStats;
99
100extern IxEthAccPortDataInfo ixEthAccPortData[];
101extern IxEthAccInfo ixEthAccDataInfo;
102
103PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
104PRIVATE 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 */
222PRIVATE IX_OSAL_MBUF *
223ixEthAccEntryFromQConvert(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 */
257PRIVATE UINT32
258ixEthAccMbufTxQPrepare(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 */
359PRIVATE UINT32
360ixEthAccMbufRxQPrepare(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*/
453PRIVATE void
454ixEthAccMbufFromTxQ(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 */
479PRIVATE void
480ixEthAccMbufFromRxQ(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 */
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200523 PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200524 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 */
542PRIVATE IX_STATUS
543ixEthAccQmgrLockTxWrite(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 */
571PRIVATE IX_STATUS
572ixEthAccQmgrLockRxWrite(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 */
599PRIVATE IX_STATUS
600ixEthAccQmgrTxWrite(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 */
622PRIVATE IxEthAccStatus
623ixEthAccTxSwQHighestPriorityGet(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 */
674PRIVATE IxEthAccStatus
675ixEthAccTxFromSwQ(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 */
760PRIVATE IxEthAccStatus
761ixEthAccRxFreeFromSwQ(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
818IX_ETH_ACC_PUBLIC
819IxEthAccStatus 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
847IX_ETH_ACC_PUBLIC
848IxEthAccStatus 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
885IX_ETH_ACC_PUBLIC
886IxEthAccStatus 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)
York Sun472d5462013-04-01 11:29:11 -0700927 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == true))
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200928 {
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
York Sun472d5462013-04-01 11:29:11 -0700956 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = false;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200957
958 return (IX_ETH_ACC_SUCCESS);
959}
960
961IX_ETH_ACC_PUBLIC
962IxEthAccStatus 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)
York Sun472d5462013-04-01 11:29:11 -07001004 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == false))
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001005 {
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
York Sun472d5462013-04-01 11:29:11 -07001034 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = true;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001035
1036 return (IX_ETH_ACC_SUCCESS);
1037}
1038
1039IX_ETH_ACC_PUBLIC
1040IxEthAccStatus 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
1258IX_ETH_ACC_PUBLIC
1259IxEthAccStatus 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
1364IX_ETH_ACC_PUBLIC
1365IxEthAccStatus 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
1394IX_ETH_ACC_PUBLIC
1395IxEthAccStatus 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 */
1421IX_ETH_ACC_PRIVATE BOOL
1422ixEthRxFrameProcess(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);
York Sun472d5462013-04-01 11:29:11 -07001435 return false;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001436 }
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 */
York Sun472d5462013-04-01 11:29:11 -07001447 return true;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001448 }
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 */
York Sun472d5462013-04-01 11:29:11 -07001519 return false;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001520 }
1521
York Sun472d5462013-04-01 11:29:11 -07001522 return true;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001523}
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 */
1543void 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 */
1701void 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 */
1867void 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 */
1959void
1960ixEthTxFrameQMCallback(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
2046void
2047ixEthTxFrameDoneQMCallback(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
2145IX_ETH_ACC_PUBLIC
2146void 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