blob: e46fc9b25a94b7171cdea1dd1948f6d34a2da925 [file] [log] [blame]
Wolfgang Denk4646d2a2006-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
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