2 * @file IxEthDataPlane.c
4 * @author Intel Corporation
7 * @brief This file contains the implementation of the IXPxxx
8 * Ethernet Access Data plane component
13 * IXP400 SW Release version 2.0
15 * -- Copyright Notice --
18 * Copyright 2001-2005, Intel Corporation.
19 * All rights reserved.
22 * SPDX-License-Identifier: BSD-3-Clause
24 * -- End of Copyright Notice --
31 #include "IxEthDBPortDefs.h"
32 #include "IxFeatureCtrl.h"
33 #include "IxEthAcc_p.h"
34 #include "IxEthAccQueueAssign_p.h"
36 extern PUBLIC IxEthAccMacState ixEthAccMacState[];
37 extern PUBLIC UINT32 ixEthAccNewSrcMask;
40 * private functions prototype
42 PRIVATE IX_OSAL_MBUF *
43 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
46 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
49 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
51 PRIVATE IxEthAccStatus
52 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
53 IxEthAccTxPriority *priorityPtr);
55 PRIVATE IxEthAccStatus
56 ixEthAccTxFromSwQ(IxEthAccPortId portId,
57 IxEthAccTxPriority priority);
59 PRIVATE IxEthAccStatus
60 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
63 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
66 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
69 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
73 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
77 ixEthAccQmgrTxWrite(IxEthAccPortId portId,
82 * @addtogroup IxEthAccPri
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)
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++
98 PRIVATE IxEthAccDataPlaneStats ixEthAccDataStats;
100 extern IxEthAccPortDataInfo ixEthAccPortData[];
101 extern IxEthAccInfo ixEthAccDataInfo;
103 PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
104 PRIVATE IxOsalFastMutex rxWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
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.
113 #if defined(__wince) && !defined(IN_KERNEL)
114 #define PTR_VIRT2NPE(ptrSrc,dst) \
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); } \
122 #define PTR_NPE2VIRT(type,src,ptrDst) \
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); } \
131 #define PTR_VIRT2NPE(ptrSrc,dst) \
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); } \
139 #define PTR_NPE2VIRT(type,src,ptrDst) \
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); } \
151 * @brief Mbuf payload pointer conversion macros : Wince has its own
152 * method to convert the buffer pointers
154 #if defined(__wince) && !defined(IN_KERNEL)
155 #define DATAPTR_VIRT2NPE(ptrSrc,dst) \
157 temp = (UINT32)IX_OSAL_MBUF_DATA_VIRTUAL_TO_PHYSICAL_TRANSLATION(ptrSrc); \
158 (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
162 #define DATAPTR_VIRT2NPE(ptrSrc,dst) PTR_VIRT2NPE(IX_OSAL_MBUF_MDATA(ptrSrc),dst)
166 /* Flush the shared part of the mbuf header */
167 #define IX_ETHACC_NE_CACHE_FLUSH(mbufPtr) \
169 IX_OSAL_CACHE_FLUSH(IX_ETHACC_NE_SHARED(mbufPtr), \
170 sizeof(IxEthAccNe)); \
174 /* Invalidate the shared part of the mbuf header */
175 #define IX_ETHACC_NE_CACHE_INVALIDATE(mbufPtr) \
177 IX_OSAL_CACHE_INVALIDATE(IX_ETHACC_NE_SHARED(mbufPtr), \
178 sizeof(IxEthAccNe)); \
182 /* Preload one cache line (shared mbuf headers are aligned
183 * and their size is 1 cache line)
185 * IX_OSAL_CACHED is defined when the mbuf headers are
186 * allocated from cached memory.
188 * Other processor on emulation environment may not implement
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)); \
199 /* preload not implemented on different processor */
200 #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
201 do { /* nothing */ } while (0)
204 /* preload not needed if cache is not enabled */
205 #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
206 do { /* nothing */ } while (0)
211 * @brief function to retrieve the correct pointer from
212 * a queue entry posted by the NPE
214 * @param qEntry : entry from qmgr queue
215 * mask : applicable mask for this queue
216 * (4 most significant bits are used for additional informations)
218 * @return IX_OSAL_MBUF * pointer to mbuf header
222 PRIVATE IX_OSAL_MBUF *
223 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask)
225 IX_OSAL_MBUF *mbufPtr;
229 /* mask NPE bits (e.g. priority, port ...) */
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);
236 /* get the mbuf pointer address from the npe-shared address */
237 qEntry -= offsetof(IX_OSAL_MBUF,ix_ne);
240 mbufPtr = (IX_OSAL_MBUF *)IX_OSAL_MMU_PHYS_TO_VIRT(qEntry);
242 /* preload the cacheline shared with NPE */
243 IX_ACC_DATA_CACHE_PRELOAD(IX_ETHACC_NE_SHARED(mbufPtr));
245 /* preload the cacheline used by xscale */
246 IX_ACC_DATA_CACHE_PRELOAD(mbufPtr);
256 /* Convert the mbuf header for NPE transmission */
258 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf)
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));
268 /* test for unchained mbufs */
269 if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
271 /* "best case" scenario : unchained mbufs */
272 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxMBufs);
274 /* payload pointer conversion */
275 DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
277 /* unchained mbufs : the frame length is the mbuf length
278 * and the 2 identical lengths are stored in the same
281 len = IX_OSAL_MBUF_MLEN(mbuf);
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);
287 /* unchained mbufs : next contains 0 */
288 IX_ETHACC_NE_NEXT(mbuf) = 0;
290 /* flush shared header after all address conversions */
291 IX_ETHACC_NE_CACHE_FLUSH(mbuf);
296 IX_OSAL_MBUF *ptr = mbuf;
297 IX_OSAL_MBUF *nextPtr;
300 /* get the frame length from the header of the first buffer */
301 frmLen = IX_OSAL_MBUF_PKT_LEN(mbuf);
305 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxMBufs);
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);
314 /* get the virtual next chain pointer */
315 nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
318 /* shared pointer of the next buffer is chained */
319 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
320 IX_ETHACC_NE_NEXT(ptr));
324 IX_ETHACC_NE_NEXT(ptr) = 0;
327 /* flush shared header after all address conversions */
328 IX_ETHACC_NE_CACHE_FLUSH(ptr);
330 /* move to next buffer */
333 /* the frame length field is set only in the first buffer
334 * and is zeroed in the next buffers
342 /* virt2phys mbuf itself */
343 qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
344 IX_ETHACC_NE_SHARED(mbuf));
346 /* Ensure the bits which are reserved to exchange information with
347 * the NPE are cleared
349 * If the mbuf address is not correctly aligned, or from an
350 * incompatible memory range, there is no point to continue
352 IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_TXENET_ADDR_MASK) == 0),
353 "Invalid address range");
358 /* Convert the mbuf header for NPE reception */
360 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf)
365 if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
367 /* "best case" scenario : unchained mbufs */
368 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxFreeMBufs);
370 /* unchained mbufs : payload pointer */
371 DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
373 /* unchained mbufs : set the buffer length
374 * and the frame length field is zeroed
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);
379 /* unchained mbufs : next pointer is null */
380 IX_ETHACC_NE_NEXT(mbuf) = 0;
382 /* flush shared header after all address conversions */
383 IX_ETHACC_NE_CACHE_FLUSH(mbuf);
385 /* remove shared header cache line */
386 IX_ETHACC_NE_CACHE_INVALIDATE(mbuf);
391 IX_OSAL_MBUF *ptr = mbuf;
392 IX_OSAL_MBUF *nextPtr;
397 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxFreeMBufs);
399 /* we must save virtual next chain pointer */
400 nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
404 /* chaining pointer for NPE */
405 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
406 IX_ETHACC_NE_NEXT(ptr));
410 IX_ETHACC_NE_NEXT(ptr) = 0;
413 /* payload pointer */
414 DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
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);
420 /* flush shared header after all address conversions */
421 IX_ETHACC_NE_CACHE_FLUSH(ptr);
423 /* remove shared header cache line */
424 IX_ETHACC_NE_CACHE_INVALIDATE(ptr);
426 /* next mbuf in the chain */
432 /* virt2phys mbuf itself */
433 qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
434 IX_ETHACC_NE_SHARED(mbuf));
436 /* Ensure the bits which are reserved to exchange information with
437 * the NPE are cleared
439 * If the mbuf address is not correctly aligned, or from an
440 * incompatible memory range, there is no point to continue
442 IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0),
443 "Invalid address range");
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
454 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf)
457 /* test for unchained mbufs */
458 if (IX_ETHACC_NE_NEXT(mbuf) == 0)
460 /* unchained mbufs : update the stats */
461 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs);
465 /* chained mbufs : walk the chain and update the stats */
466 IX_OSAL_MBUF *ptr = mbuf;
470 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs);
471 ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
478 /* Convert the mbuf header after NPE reception */
480 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf)
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));
489 /* test for unchained mbufs */
490 if (IX_ETHACC_NE_NEXT(mbuf) == 0)
492 /* unchained mbufs */
493 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs);
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;
500 /* clears the next packet field */
501 IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL;
505 IX_OSAL_MBUF *ptr = mbuf;
506 IX_OSAL_MBUF *nextPtr;
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);
516 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs);
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);
522 /* get the next pointer */
523 PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr);
526 nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne));
528 /* set the next pointer */
529 IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr;
531 /* move to the next buffer */
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.
543 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer)
546 if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS)
548 qStatus = ixQMgrQWrite(
549 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
552 if (qStatus != IX_SUCCESS)
554 TX_STATS_INC(portId, txOverflow);
557 ixOsalFastMutexUnlock(&txWriteMutex[portId]);
561 TX_STATS_INC(portId, txLock);
562 qStatus = IX_QMGR_Q_OVERFLOW;
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.
572 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer)
575 if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS)
577 qStatus = ixQMgrQWrite(
578 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
581 if (qStatus != IX_SUCCESS)
583 RX_STATS_INC(portId, rxFreeOverflow);
586 ixOsalFastMutexUnlock(&rxWriteMutex[portId]);
590 RX_STATS_INC(portId, rxFreeLock);
591 qStatus = IX_QMGR_Q_OVERFLOW;
597 * Set the priority and write to a qmgr queue.
600 ixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority)
602 /* fill the priority field */
603 qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R);
605 return ixEthAccQmgrLockTxWrite(portId, qBuffer);
610 * @brief This function will discover the highest priority S/W Tx Q that
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
617 * @return IX_ETH_ACC_SUCCESS if an occupied Q is found
618 * IX_ETH_ACC_FAIL if no Q has entries
622 PRIVATE IxEthAccStatus
623 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
624 IxEthAccTxPriority *priorityPtr)
626 if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline
629 if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
630 ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY]))
632 return IX_ETH_ACC_FAIL;
636 *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
637 TX_STATS_INC(portId,txPriority[*priorityPtr]);
638 return IX_ETH_ACC_SUCCESS;
643 IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7;
646 if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
647 ixEthAccTxData.txQ[highestPriority]))
650 *priorityPtr = highestPriority;
651 TX_STATS_INC(portId,txPriority[highestPriority]);
652 return IX_ETH_ACC_SUCCESS;
655 if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0)
657 return IX_ETH_ACC_FAIL;
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
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
674 PRIVATE IxEthAccStatus
675 ixEthAccTxFromSwQ(IxEthAccPortId portId,
676 IxEthAccTxPriority priority)
681 IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority");
683 IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
684 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
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().
694 qStatus = ixEthAccQmgrTxWrite(
696 IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)),
699 if (qStatus == IX_SUCCESS)
701 TX_STATS_INC(portId,txFromSwQOK);
704 else if (qStatus == IX_QMGR_Q_OVERFLOW)
707 * H/W Q overflow, need to save the buffer
709 * we must put it back on the head of the q to avoid
710 * reordering packet tx
712 TX_STATS_INC(portId,txFromSwQDelayed);
713 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
714 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
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));
722 if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING)
724 TX_INC(portId,txUnexpectedError);
725 IX_ETH_ACC_FATAL_LOG(
726 "ixEthAccTxFromSwQ:Unexpected Error: %u\n",
727 qStatus, 0, 0, 0, 0, 0);
732 TX_INC(portId,txUnexpectedError);
734 /* recovery attempt */
735 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
736 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
739 IX_ETH_ACC_FATAL_LOG(
740 "ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n",
741 qStatus, 0, 0, 0, 0, 0);
746 /* sw queue is empty */
748 return IX_ETH_ACC_FAIL;
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
756 * @param portId - the port whose RXFree queue is to be written to
760 PRIVATE IxEthAccStatus
761 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId)
764 IX_STATUS qStatus = IX_SUCCESS;
766 IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
767 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
772 * Add The Rx Buffer to the H/W Free buffer Q if possible
774 qStatus = ixEthAccQmgrLockRxWrite(portId,
775 IX_OSAL_MMU_VIRT_TO_PHYS(
776 (UINT32)IX_ETHACC_NE_SHARED(mbuf)));
778 if (qStatus == IX_SUCCESS)
780 RX_STATS_INC(portId,rxFreeRepFromSwQOK);
782 * Buffer added to h/w Q.
786 else if (qStatus == IX_QMGR_Q_OVERFLOW)
789 * H/W Q overflow, need to save the buffer back on the s/w Q.
791 RX_STATS_INC(portId,rxFreeRepFromSwQDelayed);
793 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
794 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
799 /* unexpected qmgr error */
800 RX_INC(portId,rxUnexpectedError);
802 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
803 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
806 IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n",
807 qStatus, 0, 0, 0, 0, 0);
812 /* sw queue is empty */
814 return IX_ETH_ACC_FAIL;
819 IxEthAccStatus ixEthAccInitDataPlane()
824 * Initialize the service and register callback to other services.
827 IX_ETH_ACC_MEMSET(&ixEthAccDataStats,
829 sizeof(ixEthAccDataStats));
831 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
833 ixOsalFastMutexInit(&txWriteMutex[portId]);
834 ixOsalFastMutexInit(&rxWriteMutex[portId]);
836 IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId],
838 sizeof(ixEthAccPortData[portId]));
840 ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY;
843 return (IX_ETH_ACC_SUCCESS);
848 IxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId,
849 IxEthAccPortTxDoneCallback
853 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
855 return (IX_ETH_ACC_FAIL);
857 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
859 return (IX_ETH_ACC_INVALID_PORT);
862 /* HACK: removing this code to enable NPE-A preliminary testing
863 * if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
870 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
872 return (IX_ETH_ACC_PORT_UNINITIALIZED);
874 if (txCallbackFn == 0)
875 /* Check for null function pointer here. */
877 return (IX_ETH_ACC_INVALID_ARG);
879 ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn;
880 ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag;
881 return (IX_ETH_ACC_SUCCESS);
886 IxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId,
887 IxEthAccPortRxCallback
893 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
895 return (IX_ETH_ACC_FAIL);
897 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
899 return (IX_ETH_ACC_INVALID_PORT);
902 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
908 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
910 return (IX_ETH_ACC_PORT_UNINITIALIZED);
913 /* Check for null function pointer here. */
914 if (rxCallbackFn == NULL)
916 return (IX_ETH_ACC_INVALID_ARG);
919 /* Check the user is not changing the callback type
920 * when the port is enabled.
922 if (ixEthAccMacState[portId].portDisableState == ACTIVE)
924 for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
926 if ((ixEthAccMacState[port].portDisableState == ACTIVE)
927 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == true))
929 /* one of the active ports has a different rx callback type.
930 * Changing the callback type when the port is enabled
933 return (IX_ETH_ACC_INVALID_ARG);
938 /* update the callback pointer : this is done before
939 * registering the new qmgr callback
941 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = rxCallbackFn;
942 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = callbackTag;
944 /* update the qmgr callback for rx queues */
945 if (ixEthAccQMgrRxCallbacksRegister(ixEthRxFrameQMCallback)
946 != IX_ETH_ACC_SUCCESS)
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);
952 RX_INC(portId,rxUnexpectedError);
953 return (IX_ETH_ACC_INVALID_ARG);
956 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = false;
958 return (IX_ETH_ACC_SUCCESS);
962 IxEthAccStatus ixEthAccPortMultiBufferRxCallbackRegister(
963 IxEthAccPortId portId,
964 IxEthAccPortMultiBufferRxCallback
970 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
972 return (IX_ETH_ACC_FAIL);
974 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
976 return (IX_ETH_ACC_INVALID_PORT);
979 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
985 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
987 return (IX_ETH_ACC_PORT_UNINITIALIZED);
990 /* Check for null function pointer here. */
991 if (rxCallbackFn == NULL)
993 return (IX_ETH_ACC_INVALID_ARG);
996 /* Check the user is not changing the callback type
997 * when the port is enabled.
999 if (ixEthAccMacState[portId].portDisableState == ACTIVE)
1001 for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
1003 if ((ixEthAccMacState[port].portDisableState == ACTIVE)
1004 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == false))
1006 /* one of the active ports has a different rx callback type.
1007 * Changing the callback type when the port is enabled
1010 return (IX_ETH_ACC_INVALID_ARG);
1015 /* update the callback pointer : this is done before
1016 * registering the new qmgr callback
1018 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = rxCallbackFn;
1019 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = callbackTag;
1021 /* update the qmgr callback for rx queues */
1022 if (ixEthAccQMgrRxCallbacksRegister(ixEthRxMultiBufferQMCallback)
1023 != IX_ETH_ACC_SUCCESS)
1025 /* unexpected qmgr error */
1026 RX_INC(portId,rxUnexpectedError);
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);
1031 return (IX_ETH_ACC_INVALID_ARG);
1034 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = true;
1036 return (IX_ETH_ACC_SUCCESS);
1040 IxEthAccStatus ixEthAccPortTxFrameSubmit(IxEthAccPortId portId,
1041 IX_OSAL_MBUF *buffer,
1042 IxEthAccTxPriority priority)
1044 IX_STATUS qStatus = IX_SUCCESS;
1046 IxEthAccTxPriority highestPriority;
1047 IxQMgrQStatus txQStatus;
1052 return (IX_ETH_ACC_FAIL);
1054 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1056 return (IX_ETH_ACC_FAIL);
1058 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1060 return (IX_ETH_ACC_INVALID_PORT);
1063 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1070 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1072 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1074 if ((UINT32)priority > (UINT32)IX_ETH_ACC_TX_PRIORITY_7)
1076 return (IX_ETH_ACC_INVALID_ARG);
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.
1084 qBuffer = ixEthAccMbufTxQPrepare(buffer);
1087 * If no fifo priority set on Xscale ...
1089 if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
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)
1098 qStatus = ixEthAccQmgrTxWrite(portId,
1100 IX_ETH_ACC_TX_DEFAULT_PRIORITY);
1102 if (qStatus == IX_SUCCESS)
1104 TX_STATS_INC(portId,txQOK);
1107 * "best case" scenario : Buffer added to h/w Q.
1109 return (IX_SUCCESS);
1111 else if (qStatus == IX_QMGR_Q_OVERFLOW)
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
1119 priority = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
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);
1131 else if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
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
1139 ixQMgrQStatusGet(IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &txQStatus);
1140 if((txQStatus & IX_QMGR_Q_STATUS_E_BIT_MASK) != 0)
1142 /*The tx queue is empty, check whether there are buffers on the s/w queues*/
1143 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1146 /*there are buffers on the s/w queues, submit them*/
1147 ixEthAccTxFromSwQ(portId, highestPriority);
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
1154 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1157 ixEthAccTxFromSwQ(portId, highestPriority);
1159 * and force the buffer supplied to be placed
1160 * on a priority queue
1162 qStatus = IX_QMGR_Q_OVERFLOW;
1166 /*there are no buffers in the s/w queues, submit directly*/
1167 qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1172 /*there are no buffers in the s/w queues, submit directly*/
1173 qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1178 qStatus = IX_QMGR_Q_OVERFLOW;
1183 TX_INC(portId,txUnexpectedError);
1184 IX_ETH_ACC_FATAL_LOG(
1185 "ixEthAccPortTxFrameSubmit:Error: wrong schedule discipline setup\n",
1187 return (IX_ETH_ACC_FAIL);
1190 if(qStatus == IX_SUCCESS )
1192 TX_STATS_INC(portId,txQOK);
1193 return IX_ETH_ACC_SUCCESS;
1195 else if(qStatus == IX_QMGR_Q_OVERFLOW)
1197 TX_STATS_INC(portId,txQDelayed);
1199 * We were unable to write the buffer to the
1200 * appropriate H/W Q, Save it in a s/w Q.
1202 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1203 ixEthAccPortData[portId].
1204 ixEthAccTxData.txQ[priority],
1207 qStatus = ixQMgrNotificationEnable(
1208 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
1209 IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
1211 if (qStatus != IX_SUCCESS)
1213 if (qStatus == IX_QMGR_WARNING)
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
1219 TX_STATS_INC(portId,txLateNotificationEnabled);
1221 /* pull a buffer from the sw queue */
1222 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1225 /*there are buffers on the s/w queues, submit from them*/
1226 ixEthAccTxFromSwQ(portId, highestPriority);
1231 TX_INC(portId,txUnexpectedError);
1232 IX_ETH_ACC_FATAL_LOG(
1233 "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
1234 qStatus, 0, 0, 0, 0, 0);
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);
1247 return (IX_ETH_ACC_SUCCESS);
1253 * @brief replenish: convert a chain of mbufs to the format
1254 * expected by the NPE
1259 IxEthAccStatus ixEthAccPortRxFreeReplenish(IxEthAccPortId portId,
1260 IX_OSAL_MBUF *buffer)
1262 IX_STATUS qStatus = IX_SUCCESS;
1266 * Check buffer is valid.
1270 /* check parameter value */
1273 return (IX_ETH_ACC_FAIL);
1275 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1277 return (IX_ETH_ACC_FAIL);
1279 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1281 return (IX_ETH_ACC_INVALID_PORT);
1284 /* check initialisation is done */
1285 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1291 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1293 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1295 /* check boundaries and constraints */
1296 if (IX_OSAL_MBUF_MLEN(buffer) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
1298 return (IX_ETH_ACC_FAIL);
1302 qBuffer = ixEthAccMbufRxQPrepare(buffer);
1305 * Add The Rx Buffer to the H/W Free buffer Q if possible
1307 qStatus = ixEthAccQmgrLockRxWrite(portId, qBuffer);
1309 if (qStatus == IX_SUCCESS)
1311 RX_STATS_INC(portId,rxFreeRepOK);
1313 * Buffer added to h/w Q.
1315 return (IX_SUCCESS);
1317 else if (qStatus == IX_QMGR_Q_OVERFLOW)
1319 RX_STATS_INC(portId,rxFreeRepDelayed);
1321 * We were unable to write the buffer to the approprate H/W Q,
1322 * Save it in a s/w Q.
1324 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1325 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
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));
1332 if (qStatus != IX_SUCCESS)
1334 if (qStatus == IX_QMGR_WARNING)
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);
1345 RX_INC(portId,rxUnexpectedError);
1346 IX_ETH_ACC_FATAL_LOG(
1347 "ixEthAccRxPortFreeReplenish:Error: %u\n",
1348 qStatus, 0, 0, 0, 0, 0);
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);
1360 return (IX_ETH_ACC_SUCCESS);
1365 IxEthAccStatus ixEthAccTxSchedulingDisciplineSetPriv(IxEthAccPortId portId,
1366 IxEthAccSchedulerDiscipline
1369 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1371 return (IX_ETH_ACC_INVALID_PORT);
1374 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1380 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1382 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1385 if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1387 return (IX_ETH_ACC_INVALID_ARG);
1390 ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = sched;
1391 return (IX_ETH_ACC_SUCCESS);
1395 IxEthAccStatus ixEthAccRxSchedulingDisciplineSetPriv(IxEthAccSchedulerDiscipline
1398 if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1400 return (IX_ETH_ACC_INVALID_ARG);
1403 ixEthAccDataInfo.schDiscipline = sched;
1405 return (IX_ETH_ACC_SUCCESS);
1410 * @fn ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1412 * @brief process incoming frame :
1414 * @param @ref IxQMgrCallback IxQMgrMultiBufferCallback
1421 IX_ETH_ACC_PRIVATE BOOL
1422 ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1425 IxEthDBStatus result;
1428 /* Prudent to at least check the port is within range */
1429 if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
1431 ixEthAccDataStats.unexpectedError++;
1432 IX_ETH_ACC_FATAL_LOG(
1433 "ixEthRxFrameProcess: Illegal port: %u\n",
1434 (UINT32)portId, 0, 0, 0, 0, 0);
1439 /* convert fields from mbuf header */
1440 ixEthAccMbufFromRxQ(mbufPtr);
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)
1446 /* "best case" scenario : nothing special to do for this frame */
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.
1454 if ((flags & IX_ETHACC_NE_NEWSRCMASK & ixEthAccNewSrcMask) != 0)
1456 result = ixEthDBFilteringDynamicEntryProvision(portId,
1457 (IxEthDBMacAddr *) IX_ETHACC_NE_SOURCEMAC(mbufPtr));
1459 if (result != IX_ETH_DB_SUCCESS && result != IX_ETH_DB_FEATURE_UNAVAILABLE)
1461 if ((ixEthAccMacState[portId].portDisableState == ACTIVE) && (result != IX_ETH_DB_BUSY))
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);
1469 /* we expect this to fail during PortDisable, as EthDB is disabled for
1470 * that port and will refuse to learn new addresses
1476 RX_STATS_INC(portId, rxUnlearnedMacAddress);
1481 /* check if this frame should have been filtered
1482 * by the NPE and take the appropriate action
1484 if (((flags & IX_ETHACC_NE_FILTERMASK) != 0)
1485 && (ixEthAccMacState[portId].portDisableState == ACTIVE))
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
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)) )
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;
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)) );
1509 /* replenish from here */
1510 if (ixEthAccPortRxFreeReplenish(portId, mbufPtr) != IX_ETH_ACC_SUCCESS)
1512 IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to replenish with filtered frame\
1513 on port %d\n", portId, 0, 0, 0, 0, 0);
1516 RX_STATS_INC(portId, rxFiltered);
1518 /* indicate that frame should not be subjected to further processing */
1527 * @fn ixEthRxFrameQMCallback
1529 * @brief receive callback for Frame receive Q from NPE
1531 * Frames are passed one-at-a-time to the user
1533 * @param @ref IxQMgrCallback
1539 * Design note : while processing the entry X, entry X+1 is preloaded
1540 * into memory to reduce the number of stall cycles
1543 void ixEthRxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1545 IX_OSAL_MBUF *mbufPtr;
1546 IX_OSAL_MBUF *nextMbufPtr;
1553 UINT32 rxQReadStatus;
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.
1560 UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
1563 * Indication of the number of times the callback is used.
1565 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1570 * Indication of the number of times the queue is drained
1572 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
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;
1578 rxQReadStatus = ixQMgrQBurstRead(qId,
1579 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1583 if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1584 && (rxQReadStatus != IX_SUCCESS))
1586 ixEthAccDataStats.unexpectedError++;
1588 IX_ETH_ACC_FATAL_LOG(
1589 "ixEthRxFrameQMCallback:Error: %u\n",
1590 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
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)
1599 nextQEntry = *qEntryPtr;
1600 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1601 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1603 while(nextQEntry != 0)
1605 /* get the next entry */
1606 qEntry = nextQEntry;
1607 mbufPtr = nextMbufPtr;
1610 if (mbufPtr == NULL)
1612 ixEthAccDataStats.unexpectedError++;
1613 IX_ETH_ACC_FATAL_LOG(
1614 "ixEthRxFrameQMCallback: Null Mbuf Ptr\n",
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)
1624 nextQEntry = *(++qEntryPtr);
1625 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1626 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1629 * Get Port and Npe ID from message.
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);
1635 /* process frame, check the return code and skip the remaining of
1636 * the loop if the frame is to be filtered out
1638 if (ixEthRxFrameProcess(portId, mbufPtr))
1640 /* destination portId for this packet */
1641 destPortId = IX_ETHACC_NE_DESTPORTID(mbufPtr);
1643 if (destPortId != IX_ETH_DB_UNKNOWN_PORT)
1645 destPortId = IX_ETH_DB_NPE_LOGICAL_ID_TO_PORT_ID(destPortId);
1648 /* test if QoS is enabled in ethAcc
1650 if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1652 /* check if there is a higher priority queue
1653 * which may require processing and then process it.
1655 if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1657 ixEthRxFrameQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1663 * increment priority stats
1665 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1668 * increment callback count stats
1670 RX_STATS_INC(portId,rxFrameClientCallback);
1673 * Call user level callback.
1675 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn(
1676 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag,
1681 } while (rxQReadStatus == IX_SUCCESS);
1685 * @fn ixEthRxMultiBufferQMCallback
1687 * @brief receive callback for Frame receive Q from NPE
1689 * Frames are passed as an array to the user
1691 * @param @ref IxQMgrCallback
1697 * Design note : while processing the entry X, entry X+1 is preloaded
1698 * into memory to reduce the number of stall cycles
1701 void ixEthRxMultiBufferQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1703 IX_OSAL_MBUF *mbufPtr;
1704 IX_OSAL_MBUF *nextMbufPtr;
1710 UINT32 rxQReadStatus;
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.
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];
1720 for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1722 rxMbufPtr[portId] = rxMbufPortArray[portId];
1726 * Indication of the number of times the callback is used.
1728 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1733 * Indication of the number of times the queue is drained
1735 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
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;
1741 rxQReadStatus = ixQMgrQBurstRead(qId,
1742 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1746 if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1747 && (rxQReadStatus != IX_SUCCESS))
1749 ixEthAccDataStats.unexpectedError++;
1751 IX_ETH_ACC_FATAL_LOG(
1752 "ixEthRxFrameMultiBufferQMCallback:Error: %u\n",
1753 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
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)
1762 nextQEntry = *qEntryPtr;
1763 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1764 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1766 while(nextQEntry != 0)
1768 /* get the next entry */
1769 qEntry = nextQEntry;
1770 mbufPtr = nextMbufPtr;
1773 if (mbufPtr == NULL)
1775 ixEthAccDataStats.unexpectedError++;
1776 IX_ETH_ACC_FATAL_LOG(
1777 "ixEthRxFrameMultiBufferQMCallback:Error: Null Mbuf Ptr\n",
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)
1787 nextQEntry = *(++qEntryPtr);
1788 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1789 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1792 * Get Port and Npe ID from message.
1794 npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
1796 IX_ETHNPE_QM_Q_FIELD_NPEID_R);
1797 portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
1799 /* skip the remaining of the loop if the frame is
1800 * to be filtered out
1802 if (ixEthRxFrameProcess(portId, mbufPtr))
1804 /* store a mbuf pointer in an array */
1805 *rxMbufPtr[portId]++ = mbufPtr;
1808 * increment priority stats
1810 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1813 /* test for QoS enabled in ethAcc */
1814 if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1816 /* check if there is a higher priority queue
1817 * which may require processing and then process it.
1819 if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1821 ixEthRxMultiBufferQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1827 /* check if any of the the arrays contains any entry */
1828 for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1830 if (rxMbufPtr[portId] != rxMbufPortArray[portId])
1832 /* add a last NULL pointer at the end of the
1833 * array of mbuf pointers
1835 *rxMbufPtr[portId] = NULL;
1838 * increment callback count stats
1840 RX_STATS_INC(portId,rxFrameClientCallback);
1843 * Call user level callback with an array of
1844 * buffers (NULL terminated)
1846 ixEthAccPortData[portId].ixEthAccRxData.
1847 rxMultiBufferCallbackFn(
1848 ixEthAccPortData[portId].ixEthAccRxData.
1849 rxMultiBufferCallbackTag,
1850 rxMbufPortArray[portId]);
1852 /* reset the buffer pointer to the beginning of
1855 rxMbufPtr[portId] = rxMbufPortArray[portId];
1859 } while (rxQReadStatus == IX_SUCCESS);
1864 * @brief rxFree low event handler
1867 void ixEthRxFreeQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1869 IxEthAccPortId portId = (IxEthAccPortId) callbackId;
1871 UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_RX_FREE_BUFFERS_LOAD;
1872 IX_STATUS qStatus = IX_SUCCESS;
1875 * We have reached a low threshold on one of the Rx Free Qs
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
1882 RX_STATS_INC(portId,rxFreeLowCallback);
1885 * Get buffers from approprite S/W Rx freeBufferList Q.
1889 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1891 ixEthAccDataStats.unexpectedError++;
1892 IX_ETH_ACC_FATAL_LOG(
1893 "ixEthRxFreeQMCallback:Error: Invalid Port 0x%08X\n",
1894 portId, 0, 0, 0, 0, 0);
1898 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1899 if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1900 ixEthAccRxData.freeBufferList))
1903 * Turn off Q callback notification for Q in Question.
1905 qStatus = ixQMgrNotificationDisable(
1906 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1909 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1911 if (qStatus != IX_SUCCESS)
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);
1922 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1924 * Load the H/W Q with buffers from the s/w Q.
1930 * Consume Q entries. - Note Q contains Physical addresss,
1931 * and have already been flushed to memory,
1932 * And endianess converted if required.
1934 if (ixEthAccRxFreeFromSwQ(portId) != IX_SUCCESS)
1937 * No more entries in s/w Q.
1938 * Turn off Q callback indication
1941 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1942 if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1943 ixEthAccRxData.freeBufferList))
1945 qStatus = ixQMgrNotificationDisable(
1946 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1948 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1952 while (--maxQWritesToPerform);
1956 * @fn Tx queue low event handler
1960 ixEthTxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1962 IxEthAccPortId portId = (IxEthAccPortId) callbackId;
1964 UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_TX_FRAME_TX_CONSUME_PER_CALLBACK;
1965 IX_STATUS qStatus = IX_SUCCESS;
1966 IxEthAccTxPriority highestPriority;
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
1973 TX_STATS_INC(portId,txLowThreshCallback);
1976 * Get buffers from approprite Q.
1980 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1982 ixEthAccDataStats.unexpectedError++;
1983 IX_ETH_ACC_FATAL_LOG(
1984 "ixEthTxFrameQMCallback:Error: Invalid Port 0x%08X\n",
1985 portId, 0, 0, 0, 0, 0);
1993 * Consume Q entries. - Note Q contains Physical addresss,
1994 * and have already been flushed to memory,
1995 * and endianess already sone if required.
1998 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
2000 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) ==
2004 * No more entries in s/w Q.
2005 * Turn off Q callback indication
2007 qStatus = ixQMgrNotificationDisable(
2008 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId));
2010 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2012 if (qStatus != IX_SUCCESS)
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);
2024 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2025 if (ixEthAccTxFromSwQ(portId,highestPriority)!=IX_SUCCESS)
2027 /* nothing left in the sw queue or the hw queues are
2028 * full. There is no point to continue to drain the
2035 while (--maxQWritesToPerform);
2039 * @brief TxDone event handler
2041 * Design note : while processing the entry X, entry X+1 is preloaded
2042 * into memory to reduce the number of stall cycles
2047 ixEthTxFrameDoneQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
2049 IX_OSAL_MBUF *mbufPtr;
2052 UINT32 txDoneQReadStatus;
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.
2061 static UINT32 txDoneQEntry[IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK + 1];
2064 * Indication that Tx frames have been transmitted from the NPE.
2067 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.txDoneCallbackCounter);
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,
2076 if (txDoneQReadStatus != IX_QMGR_Q_UNDERFLOW
2077 && (txDoneQReadStatus != IX_SUCCESS))
2080 ixEthAccDataStats.unexpectedError++;
2081 IX_ETH_ACC_FATAL_LOG(
2082 "ixEthTxFrameDoneQMCallback:Error: %u\n",
2083 (UINT32)txDoneQReadStatus, 0, 0, 0, 0, 0);
2088 qEntry = *qEntryPtr;
2092 mbufPtr = ixEthAccEntryFromQConvert(qEntry,
2093 IX_ETHNPE_QM_Q_TXENET_ADDR_MASK);
2096 if (mbufPtr == NULL)
2098 ixEthAccDataStats.unexpectedError++;
2099 IX_ETH_ACC_FATAL_LOG(
2100 "ixEthTxFrameDoneQMCallback:Error: Null Mbuf Ptr\n",
2106 /* endianness conversions and stats updates */
2107 ixEthAccMbufFromTxQ(mbufPtr);
2110 * Get NPE id from message, then convert to portId.
2112 npeId = ((IX_ETHNPE_QM_Q_TXENETDONE_NPEID_MASK &
2114 IX_ETHNPE_QM_Q_FIELD_NPEID_R);
2115 portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
2118 /* Prudent to at least check the port is within range */
2119 if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
2121 ixEthAccDataStats.unexpectedError++;
2122 IX_ETH_ACC_FATAL_LOG(
2123 "ixEthTxFrameDoneQMCallback: Illegal port: %u\n",
2124 (UINT32)portId, 0, 0, 0, 0, 0);
2129 TX_STATS_INC(portId,txDoneClientCallback);
2132 * Call user level callback.
2134 ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn(
2135 ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag,
2138 /* move to next queue entry */
2139 qEntry = *(++qEntryPtr);
2142 } while( txDoneQReadStatus == IX_SUCCESS );
2146 void ixEthAccDataPlaneShow(void)
2148 UINT32 numTx0Entries;
2149 UINT32 numTx1Entries;
2150 UINT32 numTxDoneEntries;
2151 UINT32 numRxEntries;
2152 UINT32 numRxFree0Entries;
2153 UINT32 numRxFree1Entries;
2156 UINT32 numTx2Entries;
2157 UINT32 numRxFree2Entries;
2161 UINT32 numBuffersInRx=0;
2162 UINT32 numBuffersInTx=0;
2163 UINT32 numBuffersInSwQ=0;
2164 UINT32 totalBuffers=0;
2165 UINT32 rxFreeCallbackCounter = 0;
2166 UINT32 txCallbackCounter = 0;
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;
2175 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
2180 /* get a reliable snapshot */
2181 key = ixOsalIrqLock();
2184 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET0_Q, &numTx0Entries);
2186 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET1_Q, &numTx1Entries);
2187 numTxDoneEntries = 0;
2188 ixQMgrQNumEntriesGet( IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, &numTxDoneEntries);
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);
2198 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET2_Q, &numTx2Entries);
2199 numRxFree2Entries = 0;
2200 ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q, &numRxFree2Entries);
2203 for(portId=IX_ETH_PORT_1; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2206 &ixEthAccPortData[portId].ixEthAccTxData.stats,
2207 sizeof(tx[portId]));
2209 &ixEthAccPortData[portId].ixEthAccRxData.stats,
2210 sizeof(rx[portId]));
2212 memcpy(&stats, &ixEthAccDataStats, sizeof(stats));
2214 ixOsalIrqUnlock(key);
2217 printf("Detailed statistics collection not supported in this load\n");
2220 /* print snapshot */
2221 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
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 ()))
2228 if ((IX_ETH_PORT_1 == portId) &&
2229 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
2230 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2234 if ((IX_ETH_PORT_2 == portId) &&
2235 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
2236 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2240 if ((IX_ETH_PORT_3 == portId) &&
2241 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) ==
2242 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2248 printf("PORT %u --------------------------------\n",
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",
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",
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;
2281 if (tx[portId].txPriority[priority])
2283 printf("Tx Priority %u : %u\n",
2285 tx[portId].txPriority[priority]);
2289 printf("Tx unexpected errors : %u (should be 0)\n",
2290 tx[portId].txUnexpectedError);
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);
2324 for (priority = IX_ETH_ACC_TX_PRIORITY_0;
2325 priority <= IX_ETH_ACC_TX_PRIORITY_7;
2328 if (rx[portId].rxPriority[priority])
2330 printf("Rx Priority %u : %u\n",
2332 rx[portId].rxPriority[priority]);
2336 printf("Rx unexpected errors : %u (should be 0)\n",
2337 rx[portId].rxUnexpectedError);
2340 numBuffersInTx = tx[portId].txQOK +
2341 tx[portId].txQDelayed -
2342 tx[portId].txDoneClientCallback -
2343 tx[portId].txDoneSwQDuringDisable -
2344 tx[portId].txDoneDuringDisable;
2346 printf("# Tx Buffers currently for transmission : %u\n",
2349 numBuffersInRx = rx[portId].rxFreeRepOK +
2350 rx[portId].rxFreeRepDelayed -
2351 rx[portId].rxFrameClientCallback -
2352 rx[portId].rxSwQDuringDisable -
2353 rx[portId].rxDuringDisable;
2355 printf("# Rx Buffers currently for reception : %u\n",
2358 totalBuffers += numBuffersInRx + numBuffersInTx;
2362 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);
2385 printf("Software queue usage :\n");
2386 printf("Buffers added to S/W Q : %u\n",
2388 printf("Buffers removed from S/W Q : %u\n",
2389 stats.removeFromSwQ);
2392 printf("Hardware queues callbacks :\n");
2394 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2396 rxFreeCallbackCounter += rx[portId].rxFreeLowCallback;
2397 txCallbackCounter += tx[portId].txLowThreshCallback;
2399 printf("Tx Done QM Callback invoked : %u\n",
2400 stats.txDoneCallbackCounter);
2401 printf("Tx QM Callback invoked : %u\n",
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);
2410 printf("Unexpected errors in CB : %u (should be 0)\n",
2411 stats.unexpectedError);
2414 printf("Hardware queues levels :\n");
2415 printf("Transmit Port 1 Q : %u \n",numTx0Entries);
2416 printf("Transmit Port 2 Q : %u \n",numTx1Entries);
2418 printf("Transmit Port 3 Q : %u \n",numTx2Entries);
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);
2425 printf("Receive Free Port 3 Q : %u \n",numRxFree2Entries);
2430 printf("# Total Buffers accounted for : %u\n",
2433 numBuffersInSwQ = ixEthAccDataStats.addToSwQ -
2434 ixEthAccDataStats.removeFromSwQ;
2436 printf(" Buffers in S/W Qs : %u\n",
2438 printf(" Buffers in H/W Qs or NPEs : %u\n",
2439 totalBuffers - numBuffersInSwQ);
2442 printf("Rx QoS Discipline : %s\n",
2443 (ixEthAccDataInfo.schDiscipline ==
2444 FIFO_PRIORITY ) ? "Enabled" : "Disabled");
2446 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2448 printf("Tx QoS Discipline port %u : %s\n",
2450 (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
2451 FIFO_PRIORITY ) ? "Enabled" : "Disabled");