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 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
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.
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
48 * -- End of Copyright Notice --
55 #include "IxEthDBPortDefs.h"
56 #include "IxFeatureCtrl.h"
57 #include "IxEthAcc_p.h"
58 #include "IxEthAccQueueAssign_p.h"
60 extern PUBLIC IxEthAccMacState ixEthAccMacState[];
61 extern PUBLIC UINT32 ixEthAccNewSrcMask;
64 * private functions prototype
66 PRIVATE IX_OSAL_MBUF *
67 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
70 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
73 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
75 PRIVATE IxEthAccStatus
76 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
77 IxEthAccTxPriority *priorityPtr);
79 PRIVATE IxEthAccStatus
80 ixEthAccTxFromSwQ(IxEthAccPortId portId,
81 IxEthAccTxPriority priority);
83 PRIVATE IxEthAccStatus
84 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
87 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
90 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
93 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
97 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
101 ixEthAccQmgrTxWrite(IxEthAccPortId portId,
106 * @addtogroup IxEthAccPri
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)
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++
122 PRIVATE IxEthAccDataPlaneStats ixEthAccDataStats;
124 extern IxEthAccPortDataInfo ixEthAccPortData[];
125 extern IxEthAccInfo ixEthAccDataInfo;
127 PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
128 PRIVATE IxOsalFastMutex rxWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
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.
137 #if defined(__wince) && !defined(IN_KERNEL)
138 #define PTR_VIRT2NPE(ptrSrc,dst) \
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); } \
146 #define PTR_NPE2VIRT(type,src,ptrDst) \
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); } \
155 #define PTR_VIRT2NPE(ptrSrc,dst) \
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); } \
163 #define PTR_NPE2VIRT(type,src,ptrDst) \
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); } \
175 * @brief Mbuf payload pointer conversion macros : Wince has its own
176 * method to convert the buffer pointers
178 #if defined(__wince) && !defined(IN_KERNEL)
179 #define DATAPTR_VIRT2NPE(ptrSrc,dst) \
181 temp = (UINT32)IX_OSAL_MBUF_DATA_VIRTUAL_TO_PHYSICAL_TRANSLATION(ptrSrc); \
182 (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
186 #define DATAPTR_VIRT2NPE(ptrSrc,dst) PTR_VIRT2NPE(IX_OSAL_MBUF_MDATA(ptrSrc),dst)
190 /* Flush the shared part of the mbuf header */
191 #define IX_ETHACC_NE_CACHE_FLUSH(mbufPtr) \
193 IX_OSAL_CACHE_FLUSH(IX_ETHACC_NE_SHARED(mbufPtr), \
194 sizeof(IxEthAccNe)); \
198 /* Invalidate the shared part of the mbuf header */
199 #define IX_ETHACC_NE_CACHE_INVALIDATE(mbufPtr) \
201 IX_OSAL_CACHE_INVALIDATE(IX_ETHACC_NE_SHARED(mbufPtr), \
202 sizeof(IxEthAccNe)); \
206 /* Preload one cache line (shared mbuf headers are aligned
207 * and their size is 1 cache line)
209 * IX_OSAL_CACHED is defined when the mbuf headers are
210 * allocated from cached memory.
212 * Other processor on emulation environment may not implement
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)); \
223 /* preload not implemented on different processor */
224 #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
225 do { /* nothing */ } while (0)
228 /* preload not needed if cache is not enabled */
229 #define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
230 do { /* nothing */ } while (0)
235 * @brief function to retrieve the correct pointer from
236 * a queue entry posted by the NPE
238 * @param qEntry : entry from qmgr queue
239 * mask : applicable mask for this queue
240 * (4 most significant bits are used for additional informations)
242 * @return IX_OSAL_MBUF * pointer to mbuf header
246 PRIVATE IX_OSAL_MBUF *
247 ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask)
249 IX_OSAL_MBUF *mbufPtr;
253 /* mask NPE bits (e.g. priority, port ...) */
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);
260 /* get the mbuf pointer address from the npe-shared address */
261 qEntry -= offsetof(IX_OSAL_MBUF,ix_ne);
264 mbufPtr = (IX_OSAL_MBUF *)IX_OSAL_MMU_PHYS_TO_VIRT(qEntry);
266 /* preload the cacheline shared with NPE */
267 IX_ACC_DATA_CACHE_PRELOAD(IX_ETHACC_NE_SHARED(mbufPtr));
269 /* preload the cacheline used by xscale */
270 IX_ACC_DATA_CACHE_PRELOAD(mbufPtr);
280 /* Convert the mbuf header for NPE transmission */
282 ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf)
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));
292 /* test for unchained mbufs */
293 if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
295 /* "best case" scenario : unchained mbufs */
296 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxMBufs);
298 /* payload pointer conversion */
299 DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
301 /* unchained mbufs : the frame length is the mbuf length
302 * and the 2 identical lengths are stored in the same
305 len = IX_OSAL_MBUF_MLEN(mbuf);
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);
311 /* unchained mbufs : next contains 0 */
312 IX_ETHACC_NE_NEXT(mbuf) = 0;
314 /* flush shared header after all address conversions */
315 IX_ETHACC_NE_CACHE_FLUSH(mbuf);
320 IX_OSAL_MBUF *ptr = mbuf;
321 IX_OSAL_MBUF *nextPtr;
324 /* get the frame length from the header of the first buffer */
325 frmLen = IX_OSAL_MBUF_PKT_LEN(mbuf);
329 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxMBufs);
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);
338 /* get the virtual next chain pointer */
339 nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
342 /* shared pointer of the next buffer is chained */
343 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
344 IX_ETHACC_NE_NEXT(ptr));
348 IX_ETHACC_NE_NEXT(ptr) = 0;
351 /* flush shared header after all address conversions */
352 IX_ETHACC_NE_CACHE_FLUSH(ptr);
354 /* move to next buffer */
357 /* the frame length field is set only in the first buffer
358 * and is zeroed in the next buffers
366 /* virt2phys mbuf itself */
367 qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
368 IX_ETHACC_NE_SHARED(mbuf));
370 /* Ensure the bits which are reserved to exchange information with
371 * the NPE are cleared
373 * If the mbuf address is not correctly aligned, or from an
374 * incompatible memory range, there is no point to continue
376 IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_TXENET_ADDR_MASK) == 0),
377 "Invalid address range");
382 /* Convert the mbuf header for NPE reception */
384 ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf)
389 if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
391 /* "best case" scenario : unchained mbufs */
392 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxFreeMBufs);
394 /* unchained mbufs : payload pointer */
395 DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
397 /* unchained mbufs : set the buffer length
398 * and the frame length field is zeroed
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);
403 /* unchained mbufs : next pointer is null */
404 IX_ETHACC_NE_NEXT(mbuf) = 0;
406 /* flush shared header after all address conversions */
407 IX_ETHACC_NE_CACHE_FLUSH(mbuf);
409 /* remove shared header cache line */
410 IX_ETHACC_NE_CACHE_INVALIDATE(mbuf);
415 IX_OSAL_MBUF *ptr = mbuf;
416 IX_OSAL_MBUF *nextPtr;
421 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxFreeMBufs);
423 /* we must save virtual next chain pointer */
424 nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
428 /* chaining pointer for NPE */
429 PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
430 IX_ETHACC_NE_NEXT(ptr));
434 IX_ETHACC_NE_NEXT(ptr) = 0;
437 /* payload pointer */
438 DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
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);
444 /* flush shared header after all address conversions */
445 IX_ETHACC_NE_CACHE_FLUSH(ptr);
447 /* remove shared header cache line */
448 IX_ETHACC_NE_CACHE_INVALIDATE(ptr);
450 /* next mbuf in the chain */
456 /* virt2phys mbuf itself */
457 qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
458 IX_ETHACC_NE_SHARED(mbuf));
460 /* Ensure the bits which are reserved to exchange information with
461 * the NPE are cleared
463 * If the mbuf address is not correctly aligned, or from an
464 * incompatible memory range, there is no point to continue
466 IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0),
467 "Invalid address range");
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
478 ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf)
481 /* test for unchained mbufs */
482 if (IX_ETHACC_NE_NEXT(mbuf) == 0)
484 /* unchained mbufs : update the stats */
485 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs);
489 /* chained mbufs : walk the chain and update the stats */
490 IX_OSAL_MBUF *ptr = mbuf;
494 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs);
495 ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
502 /* Convert the mbuf header after NPE reception */
504 ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf)
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));
513 /* test for unchained mbufs */
514 if (IX_ETHACC_NE_NEXT(mbuf) == 0)
516 /* unchained mbufs */
517 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs);
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;
524 /* clears the next packet field */
525 IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL;
529 IX_OSAL_MBUF *ptr = mbuf;
530 IX_OSAL_MBUF *nextPtr;
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);
540 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs);
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);
546 /* get the next pointer */
547 PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr);
550 nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne));
552 /* set the next pointer */
553 IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr;
555 /* move to the next buffer */
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.
567 ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer)
570 if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS)
572 qStatus = ixQMgrQWrite(
573 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
576 if (qStatus != IX_SUCCESS)
578 TX_STATS_INC(portId, txOverflow);
581 ixOsalFastMutexUnlock(&txWriteMutex[portId]);
585 TX_STATS_INC(portId, txLock);
586 qStatus = IX_QMGR_Q_OVERFLOW;
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.
596 ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer)
599 if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS)
601 qStatus = ixQMgrQWrite(
602 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
605 if (qStatus != IX_SUCCESS)
607 RX_STATS_INC(portId, rxFreeOverflow);
610 ixOsalFastMutexUnlock(&rxWriteMutex[portId]);
614 RX_STATS_INC(portId, rxFreeLock);
615 qStatus = IX_QMGR_Q_OVERFLOW;
621 * Set the priority and write to a qmgr queue.
624 ixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority)
626 /* fill the priority field */
627 qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R);
629 return ixEthAccQmgrLockTxWrite(portId, qBuffer);
634 * @brief This function will discover the highest priority S/W Tx Q that
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
641 * @return IX_ETH_ACC_SUCCESS if an occupied Q is found
642 * IX_ETH_ACC_FAIL if no Q has entries
646 PRIVATE IxEthAccStatus
647 ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
648 IxEthAccTxPriority *priorityPtr)
650 if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline
653 if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
654 ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY]))
656 return IX_ETH_ACC_FAIL;
660 *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
661 TX_STATS_INC(portId,txPriority[*priorityPtr]);
662 return IX_ETH_ACC_SUCCESS;
667 IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7;
670 if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
671 ixEthAccTxData.txQ[highestPriority]))
674 *priorityPtr = highestPriority;
675 TX_STATS_INC(portId,txPriority[highestPriority]);
676 return IX_ETH_ACC_SUCCESS;
679 if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0)
681 return IX_ETH_ACC_FAIL;
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
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
698 PRIVATE IxEthAccStatus
699 ixEthAccTxFromSwQ(IxEthAccPortId portId,
700 IxEthAccTxPriority priority)
705 IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority");
707 IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
708 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
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().
718 qStatus = ixEthAccQmgrTxWrite(
720 IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)),
723 if (qStatus == IX_SUCCESS)
725 TX_STATS_INC(portId,txFromSwQOK);
728 else if (qStatus == IX_QMGR_Q_OVERFLOW)
731 * H/W Q overflow, need to save the buffer
733 * we must put it back on the head of the q to avoid
734 * reordering packet tx
736 TX_STATS_INC(portId,txFromSwQDelayed);
737 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
738 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
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));
746 if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING)
748 TX_INC(portId,txUnexpectedError);
749 IX_ETH_ACC_FATAL_LOG(
750 "ixEthAccTxFromSwQ:Unexpected Error: %u\n",
751 qStatus, 0, 0, 0, 0, 0);
756 TX_INC(portId,txUnexpectedError);
758 /* recovery attempt */
759 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
760 ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
763 IX_ETH_ACC_FATAL_LOG(
764 "ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n",
765 qStatus, 0, 0, 0, 0, 0);
770 /* sw queue is empty */
772 return IX_ETH_ACC_FAIL;
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
780 * @param portId - the port whose RXFree queue is to be written to
784 PRIVATE IxEthAccStatus
785 ixEthAccRxFreeFromSwQ(IxEthAccPortId portId)
788 IX_STATUS qStatus = IX_SUCCESS;
790 IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
791 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
796 * Add The Rx Buffer to the H/W Free buffer Q if possible
798 qStatus = ixEthAccQmgrLockRxWrite(portId,
799 IX_OSAL_MMU_VIRT_TO_PHYS(
800 (UINT32)IX_ETHACC_NE_SHARED(mbuf)));
802 if (qStatus == IX_SUCCESS)
804 RX_STATS_INC(portId,rxFreeRepFromSwQOK);
806 * Buffer added to h/w Q.
810 else if (qStatus == IX_QMGR_Q_OVERFLOW)
813 * H/W Q overflow, need to save the buffer back on the s/w Q.
815 RX_STATS_INC(portId,rxFreeRepFromSwQDelayed);
817 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
818 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
823 /* unexpected qmgr error */
824 RX_INC(portId,rxUnexpectedError);
826 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
827 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
830 IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n",
831 qStatus, 0, 0, 0, 0, 0);
836 /* sw queue is empty */
838 return IX_ETH_ACC_FAIL;
843 IxEthAccStatus ixEthAccInitDataPlane()
848 * Initialize the service and register callback to other services.
851 IX_ETH_ACC_MEMSET(&ixEthAccDataStats,
853 sizeof(ixEthAccDataStats));
855 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
857 ixOsalFastMutexInit(&txWriteMutex[portId]);
858 ixOsalFastMutexInit(&rxWriteMutex[portId]);
860 IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId],
862 sizeof(ixEthAccPortData[portId]));
864 ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY;
867 return (IX_ETH_ACC_SUCCESS);
872 IxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId,
873 IxEthAccPortTxDoneCallback
877 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
879 return (IX_ETH_ACC_FAIL);
881 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
883 return (IX_ETH_ACC_INVALID_PORT);
886 /* HACK: removing this code to enable NPE-A preliminary testing
887 * if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
894 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
896 return (IX_ETH_ACC_PORT_UNINITIALIZED);
898 if (txCallbackFn == 0)
899 /* Check for null function pointer here. */
901 return (IX_ETH_ACC_INVALID_ARG);
903 ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn;
904 ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag;
905 return (IX_ETH_ACC_SUCCESS);
910 IxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId,
911 IxEthAccPortRxCallback
917 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
919 return (IX_ETH_ACC_FAIL);
921 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
923 return (IX_ETH_ACC_INVALID_PORT);
926 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
932 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
934 return (IX_ETH_ACC_PORT_UNINITIALIZED);
937 /* Check for null function pointer here. */
938 if (rxCallbackFn == NULL)
940 return (IX_ETH_ACC_INVALID_ARG);
943 /* Check the user is not changing the callback type
944 * when the port is enabled.
946 if (ixEthAccMacState[portId].portDisableState == ACTIVE)
948 for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
950 if ((ixEthAccMacState[port].portDisableState == ACTIVE)
951 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == true))
953 /* one of the active ports has a different rx callback type.
954 * Changing the callback type when the port is enabled
957 return (IX_ETH_ACC_INVALID_ARG);
962 /* update the callback pointer : this is done before
963 * registering the new qmgr callback
965 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = rxCallbackFn;
966 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = callbackTag;
968 /* update the qmgr callback for rx queues */
969 if (ixEthAccQMgrRxCallbacksRegister(ixEthRxFrameQMCallback)
970 != IX_ETH_ACC_SUCCESS)
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);
976 RX_INC(portId,rxUnexpectedError);
977 return (IX_ETH_ACC_INVALID_ARG);
980 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = false;
982 return (IX_ETH_ACC_SUCCESS);
986 IxEthAccStatus ixEthAccPortMultiBufferRxCallbackRegister(
987 IxEthAccPortId portId,
988 IxEthAccPortMultiBufferRxCallback
994 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
996 return (IX_ETH_ACC_FAIL);
998 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1000 return (IX_ETH_ACC_INVALID_PORT);
1003 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1009 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1011 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1014 /* Check for null function pointer here. */
1015 if (rxCallbackFn == NULL)
1017 return (IX_ETH_ACC_INVALID_ARG);
1020 /* Check the user is not changing the callback type
1021 * when the port is enabled.
1023 if (ixEthAccMacState[portId].portDisableState == ACTIVE)
1025 for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
1027 if ((ixEthAccMacState[port].portDisableState == ACTIVE)
1028 && (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == false))
1030 /* one of the active ports has a different rx callback type.
1031 * Changing the callback type when the port is enabled
1034 return (IX_ETH_ACC_INVALID_ARG);
1039 /* update the callback pointer : this is done before
1040 * registering the new qmgr callback
1042 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = rxCallbackFn;
1043 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = callbackTag;
1045 /* update the qmgr callback for rx queues */
1046 if (ixEthAccQMgrRxCallbacksRegister(ixEthRxMultiBufferQMCallback)
1047 != IX_ETH_ACC_SUCCESS)
1049 /* unexpected qmgr error */
1050 RX_INC(portId,rxUnexpectedError);
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);
1055 return (IX_ETH_ACC_INVALID_ARG);
1058 ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = true;
1060 return (IX_ETH_ACC_SUCCESS);
1064 IxEthAccStatus ixEthAccPortTxFrameSubmit(IxEthAccPortId portId,
1065 IX_OSAL_MBUF *buffer,
1066 IxEthAccTxPriority priority)
1068 IX_STATUS qStatus = IX_SUCCESS;
1070 IxEthAccTxPriority highestPriority;
1071 IxQMgrQStatus txQStatus;
1076 return (IX_ETH_ACC_FAIL);
1078 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1080 return (IX_ETH_ACC_FAIL);
1082 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1084 return (IX_ETH_ACC_INVALID_PORT);
1087 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1094 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1096 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1098 if ((UINT32)priority > (UINT32)IX_ETH_ACC_TX_PRIORITY_7)
1100 return (IX_ETH_ACC_INVALID_ARG);
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.
1108 qBuffer = ixEthAccMbufTxQPrepare(buffer);
1111 * If no fifo priority set on Xscale ...
1113 if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
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)
1122 qStatus = ixEthAccQmgrTxWrite(portId,
1124 IX_ETH_ACC_TX_DEFAULT_PRIORITY);
1126 if (qStatus == IX_SUCCESS)
1128 TX_STATS_INC(portId,txQOK);
1131 * "best case" scenario : Buffer added to h/w Q.
1133 return (IX_SUCCESS);
1135 else if (qStatus == IX_QMGR_Q_OVERFLOW)
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
1143 priority = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
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);
1155 else if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
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
1163 ixQMgrQStatusGet(IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &txQStatus);
1164 if((txQStatus & IX_QMGR_Q_STATUS_E_BIT_MASK) != 0)
1166 /*The tx queue is empty, check whether there are buffers on the s/w queues*/
1167 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1170 /*there are buffers on the s/w queues, submit them*/
1171 ixEthAccTxFromSwQ(portId, highestPriority);
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
1178 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1181 ixEthAccTxFromSwQ(portId, highestPriority);
1183 * and force the buffer supplied to be placed
1184 * on a priority queue
1186 qStatus = IX_QMGR_Q_OVERFLOW;
1190 /*there are no buffers in the s/w queues, submit directly*/
1191 qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1196 /*there are no buffers in the s/w queues, submit directly*/
1197 qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
1202 qStatus = IX_QMGR_Q_OVERFLOW;
1207 TX_INC(portId,txUnexpectedError);
1208 IX_ETH_ACC_FATAL_LOG(
1209 "ixEthAccPortTxFrameSubmit:Error: wrong schedule discipline setup\n",
1211 return (IX_ETH_ACC_FAIL);
1214 if(qStatus == IX_SUCCESS )
1216 TX_STATS_INC(portId,txQOK);
1217 return IX_ETH_ACC_SUCCESS;
1219 else if(qStatus == IX_QMGR_Q_OVERFLOW)
1221 TX_STATS_INC(portId,txQDelayed);
1223 * We were unable to write the buffer to the
1224 * appropriate H/W Q, Save it in a s/w Q.
1226 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1227 ixEthAccPortData[portId].
1228 ixEthAccTxData.txQ[priority],
1231 qStatus = ixQMgrNotificationEnable(
1232 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
1233 IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
1235 if (qStatus != IX_SUCCESS)
1237 if (qStatus == IX_QMGR_WARNING)
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
1243 TX_STATS_INC(portId,txLateNotificationEnabled);
1245 /* pull a buffer from the sw queue */
1246 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority)
1249 /*there are buffers on the s/w queues, submit from them*/
1250 ixEthAccTxFromSwQ(portId, highestPriority);
1255 TX_INC(portId,txUnexpectedError);
1256 IX_ETH_ACC_FATAL_LOG(
1257 "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
1258 qStatus, 0, 0, 0, 0, 0);
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);
1271 return (IX_ETH_ACC_SUCCESS);
1277 * @brief replenish: convert a chain of mbufs to the format
1278 * expected by the NPE
1283 IxEthAccStatus ixEthAccPortRxFreeReplenish(IxEthAccPortId portId,
1284 IX_OSAL_MBUF *buffer)
1286 IX_STATUS qStatus = IX_SUCCESS;
1290 * Check buffer is valid.
1294 /* check parameter value */
1297 return (IX_ETH_ACC_FAIL);
1299 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
1301 return (IX_ETH_ACC_FAIL);
1303 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1305 return (IX_ETH_ACC_INVALID_PORT);
1308 /* check initialisation is done */
1309 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1315 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1317 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1319 /* check boundaries and constraints */
1320 if (IX_OSAL_MBUF_MLEN(buffer) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
1322 return (IX_ETH_ACC_FAIL);
1326 qBuffer = ixEthAccMbufRxQPrepare(buffer);
1329 * Add The Rx Buffer to the H/W Free buffer Q if possible
1331 qStatus = ixEthAccQmgrLockRxWrite(portId, qBuffer);
1333 if (qStatus == IX_SUCCESS)
1335 RX_STATS_INC(portId,rxFreeRepOK);
1337 * Buffer added to h/w Q.
1339 return (IX_SUCCESS);
1341 else if (qStatus == IX_QMGR_Q_OVERFLOW)
1343 RX_STATS_INC(portId,rxFreeRepDelayed);
1345 * We were unable to write the buffer to the approprate H/W Q,
1346 * Save it in a s/w Q.
1348 IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
1349 ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
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));
1356 if (qStatus != IX_SUCCESS)
1358 if (qStatus == IX_QMGR_WARNING)
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);
1369 RX_INC(portId,rxUnexpectedError);
1370 IX_ETH_ACC_FATAL_LOG(
1371 "ixEthAccRxPortFreeReplenish:Error: %u\n",
1372 qStatus, 0, 0, 0, 0, 0);
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);
1384 return (IX_ETH_ACC_SUCCESS);
1389 IxEthAccStatus ixEthAccTxSchedulingDisciplineSetPriv(IxEthAccPortId portId,
1390 IxEthAccSchedulerDiscipline
1393 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1395 return (IX_ETH_ACC_INVALID_PORT);
1398 if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
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 ;
1404 if (!IX_ETH_IS_PORT_INITIALIZED(portId))
1406 return (IX_ETH_ACC_PORT_UNINITIALIZED);
1409 if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1411 return (IX_ETH_ACC_INVALID_ARG);
1414 ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = sched;
1415 return (IX_ETH_ACC_SUCCESS);
1419 IxEthAccStatus ixEthAccRxSchedulingDisciplineSetPriv(IxEthAccSchedulerDiscipline
1422 if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
1424 return (IX_ETH_ACC_INVALID_ARG);
1427 ixEthAccDataInfo.schDiscipline = sched;
1429 return (IX_ETH_ACC_SUCCESS);
1434 * @fn ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1436 * @brief process incoming frame :
1438 * @param @ref IxQMgrCallback IxQMgrMultiBufferCallback
1445 IX_ETH_ACC_PRIVATE BOOL
1446 ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
1449 IxEthDBStatus result;
1452 /* Prudent to at least check the port is within range */
1453 if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
1455 ixEthAccDataStats.unexpectedError++;
1456 IX_ETH_ACC_FATAL_LOG(
1457 "ixEthRxFrameProcess: Illegal port: %u\n",
1458 (UINT32)portId, 0, 0, 0, 0, 0);
1463 /* convert fields from mbuf header */
1464 ixEthAccMbufFromRxQ(mbufPtr);
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)
1470 /* "best case" scenario : nothing special to do for this frame */
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.
1478 if ((flags & IX_ETHACC_NE_NEWSRCMASK & ixEthAccNewSrcMask) != 0)
1480 result = ixEthDBFilteringDynamicEntryProvision(portId,
1481 (IxEthDBMacAddr *) IX_ETHACC_NE_SOURCEMAC(mbufPtr));
1483 if (result != IX_ETH_DB_SUCCESS && result != IX_ETH_DB_FEATURE_UNAVAILABLE)
1485 if ((ixEthAccMacState[portId].portDisableState == ACTIVE) && (result != IX_ETH_DB_BUSY))
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);
1493 /* we expect this to fail during PortDisable, as EthDB is disabled for
1494 * that port and will refuse to learn new addresses
1500 RX_STATS_INC(portId, rxUnlearnedMacAddress);
1505 /* check if this frame should have been filtered
1506 * by the NPE and take the appropriate action
1508 if (((flags & IX_ETHACC_NE_FILTERMASK) != 0)
1509 && (ixEthAccMacState[portId].portDisableState == ACTIVE))
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
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)) )
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;
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)) );
1533 /* replenish from here */
1534 if (ixEthAccPortRxFreeReplenish(portId, mbufPtr) != IX_ETH_ACC_SUCCESS)
1536 IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to replenish with filtered frame\
1537 on port %d\n", portId, 0, 0, 0, 0, 0);
1540 RX_STATS_INC(portId, rxFiltered);
1542 /* indicate that frame should not be subjected to further processing */
1551 * @fn ixEthRxFrameQMCallback
1553 * @brief receive callback for Frame receive Q from NPE
1555 * Frames are passed one-at-a-time to the user
1557 * @param @ref IxQMgrCallback
1563 * Design note : while processing the entry X, entry X+1 is preloaded
1564 * into memory to reduce the number of stall cycles
1567 void ixEthRxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1569 IX_OSAL_MBUF *mbufPtr;
1570 IX_OSAL_MBUF *nextMbufPtr;
1577 UINT32 rxQReadStatus;
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.
1584 UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
1587 * Indication of the number of times the callback is used.
1589 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1594 * Indication of the number of times the queue is drained
1596 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
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;
1602 rxQReadStatus = ixQMgrQBurstRead(qId,
1603 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1607 if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1608 && (rxQReadStatus != IX_SUCCESS))
1610 ixEthAccDataStats.unexpectedError++;
1612 IX_ETH_ACC_FATAL_LOG(
1613 "ixEthRxFrameQMCallback:Error: %u\n",
1614 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
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)
1623 nextQEntry = *qEntryPtr;
1624 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1625 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1627 while(nextQEntry != 0)
1629 /* get the next entry */
1630 qEntry = nextQEntry;
1631 mbufPtr = nextMbufPtr;
1634 if (mbufPtr == NULL)
1636 ixEthAccDataStats.unexpectedError++;
1637 IX_ETH_ACC_FATAL_LOG(
1638 "ixEthRxFrameQMCallback: Null Mbuf Ptr\n",
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)
1648 nextQEntry = *(++qEntryPtr);
1649 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1650 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1653 * Get Port and Npe ID from message.
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);
1659 /* process frame, check the return code and skip the remaining of
1660 * the loop if the frame is to be filtered out
1662 if (ixEthRxFrameProcess(portId, mbufPtr))
1664 /* destination portId for this packet */
1665 destPortId = IX_ETHACC_NE_DESTPORTID(mbufPtr);
1667 if (destPortId != IX_ETH_DB_UNKNOWN_PORT)
1669 destPortId = IX_ETH_DB_NPE_LOGICAL_ID_TO_PORT_ID(destPortId);
1672 /* test if QoS is enabled in ethAcc
1674 if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1676 /* check if there is a higher priority queue
1677 * which may require processing and then process it.
1679 if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1681 ixEthRxFrameQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1687 * increment priority stats
1689 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1692 * increment callback count stats
1694 RX_STATS_INC(portId,rxFrameClientCallback);
1697 * Call user level callback.
1699 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn(
1700 ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag,
1705 } while (rxQReadStatus == IX_SUCCESS);
1709 * @fn ixEthRxMultiBufferQMCallback
1711 * @brief receive callback for Frame receive Q from NPE
1713 * Frames are passed as an array to the user
1715 * @param @ref IxQMgrCallback
1721 * Design note : while processing the entry X, entry X+1 is preloaded
1722 * into memory to reduce the number of stall cycles
1725 void ixEthRxMultiBufferQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1727 IX_OSAL_MBUF *mbufPtr;
1728 IX_OSAL_MBUF *nextMbufPtr;
1734 UINT32 rxQReadStatus;
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.
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];
1744 for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1746 rxMbufPtr[portId] = rxMbufPortArray[portId];
1750 * Indication of the number of times the callback is used.
1752 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
1757 * Indication of the number of times the queue is drained
1759 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
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;
1765 rxQReadStatus = ixQMgrQBurstRead(qId,
1766 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
1770 if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
1771 && (rxQReadStatus != IX_SUCCESS))
1773 ixEthAccDataStats.unexpectedError++;
1775 IX_ETH_ACC_FATAL_LOG(
1776 "ixEthRxFrameMultiBufferQMCallback:Error: %u\n",
1777 (UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
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)
1786 nextQEntry = *qEntryPtr;
1787 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1788 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1790 while(nextQEntry != 0)
1792 /* get the next entry */
1793 qEntry = nextQEntry;
1794 mbufPtr = nextMbufPtr;
1797 if (mbufPtr == NULL)
1799 ixEthAccDataStats.unexpectedError++;
1800 IX_ETH_ACC_FATAL_LOG(
1801 "ixEthRxFrameMultiBufferQMCallback:Error: Null Mbuf Ptr\n",
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)
1811 nextQEntry = *(++qEntryPtr);
1812 nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
1813 IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
1816 * Get Port and Npe ID from message.
1818 npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
1820 IX_ETHNPE_QM_Q_FIELD_NPEID_R);
1821 portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
1823 /* skip the remaining of the loop if the frame is
1824 * to be filtered out
1826 if (ixEthRxFrameProcess(portId, mbufPtr))
1828 /* store a mbuf pointer in an array */
1829 *rxMbufPtr[portId]++ = mbufPtr;
1832 * increment priority stats
1834 RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
1837 /* test for QoS enabled in ethAcc */
1838 if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
1840 /* check if there is a higher priority queue
1841 * which may require processing and then process it.
1843 if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
1845 ixEthRxMultiBufferQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
1851 /* check if any of the the arrays contains any entry */
1852 for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
1854 if (rxMbufPtr[portId] != rxMbufPortArray[portId])
1856 /* add a last NULL pointer at the end of the
1857 * array of mbuf pointers
1859 *rxMbufPtr[portId] = NULL;
1862 * increment callback count stats
1864 RX_STATS_INC(portId,rxFrameClientCallback);
1867 * Call user level callback with an array of
1868 * buffers (NULL terminated)
1870 ixEthAccPortData[portId].ixEthAccRxData.
1871 rxMultiBufferCallbackFn(
1872 ixEthAccPortData[portId].ixEthAccRxData.
1873 rxMultiBufferCallbackTag,
1874 rxMbufPortArray[portId]);
1876 /* reset the buffer pointer to the beginning of
1879 rxMbufPtr[portId] = rxMbufPortArray[portId];
1883 } while (rxQReadStatus == IX_SUCCESS);
1888 * @brief rxFree low event handler
1891 void ixEthRxFreeQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1893 IxEthAccPortId portId = (IxEthAccPortId) callbackId;
1895 UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_RX_FREE_BUFFERS_LOAD;
1896 IX_STATUS qStatus = IX_SUCCESS;
1899 * We have reached a low threshold on one of the Rx Free Qs
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
1906 RX_STATS_INC(portId,rxFreeLowCallback);
1909 * Get buffers from approprite S/W Rx freeBufferList Q.
1913 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
1915 ixEthAccDataStats.unexpectedError++;
1916 IX_ETH_ACC_FATAL_LOG(
1917 "ixEthRxFreeQMCallback:Error: Invalid Port 0x%08X\n",
1918 portId, 0, 0, 0, 0, 0);
1922 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1923 if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1924 ixEthAccRxData.freeBufferList))
1927 * Turn off Q callback notification for Q in Question.
1929 qStatus = ixQMgrNotificationDisable(
1930 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1933 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1935 if (qStatus != IX_SUCCESS)
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);
1946 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1948 * Load the H/W Q with buffers from the s/w Q.
1954 * Consume Q entries. - Note Q contains Physical addresss,
1955 * and have already been flushed to memory,
1956 * And endianess converted if required.
1958 if (ixEthAccRxFreeFromSwQ(portId) != IX_SUCCESS)
1961 * No more entries in s/w Q.
1962 * Turn off Q callback indication
1965 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
1966 if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
1967 ixEthAccRxData.freeBufferList))
1969 qStatus = ixQMgrNotificationDisable(
1970 IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
1972 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
1976 while (--maxQWritesToPerform);
1980 * @fn Tx queue low event handler
1984 ixEthTxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
1986 IxEthAccPortId portId = (IxEthAccPortId) callbackId;
1988 UINT32 maxQWritesToPerform = IX_ETH_ACC_MAX_TX_FRAME_TX_CONSUME_PER_CALLBACK;
1989 IX_STATUS qStatus = IX_SUCCESS;
1990 IxEthAccTxPriority highestPriority;
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
1997 TX_STATS_INC(portId,txLowThreshCallback);
2000 * Get buffers from approprite Q.
2004 if (!IX_ETH_ACC_IS_PORT_VALID(portId))
2006 ixEthAccDataStats.unexpectedError++;
2007 IX_ETH_ACC_FATAL_LOG(
2008 "ixEthTxFrameQMCallback:Error: Invalid Port 0x%08X\n",
2009 portId, 0, 0, 0, 0, 0);
2017 * Consume Q entries. - Note Q contains Physical addresss,
2018 * and have already been flushed to memory,
2019 * and endianess already sone if required.
2022 IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
2024 if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) ==
2028 * No more entries in s/w Q.
2029 * Turn off Q callback indication
2031 qStatus = ixQMgrNotificationDisable(
2032 IX_ETH_ACC_PORT_TO_TX_Q_ID(portId));
2034 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2036 if (qStatus != IX_SUCCESS)
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);
2048 IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
2049 if (ixEthAccTxFromSwQ(portId,highestPriority)!=IX_SUCCESS)
2051 /* nothing left in the sw queue or the hw queues are
2052 * full. There is no point to continue to drain the
2059 while (--maxQWritesToPerform);
2063 * @brief TxDone event handler
2065 * Design note : while processing the entry X, entry X+1 is preloaded
2066 * into memory to reduce the number of stall cycles
2071 ixEthTxFrameDoneQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
2073 IX_OSAL_MBUF *mbufPtr;
2076 UINT32 txDoneQReadStatus;
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.
2085 static UINT32 txDoneQEntry[IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK + 1];
2088 * Indication that Tx frames have been transmitted from the NPE.
2091 IX_ETH_ACC_STATS_INC(ixEthAccDataStats.txDoneCallbackCounter);
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,
2100 if (txDoneQReadStatus != IX_QMGR_Q_UNDERFLOW
2101 && (txDoneQReadStatus != IX_SUCCESS))
2104 ixEthAccDataStats.unexpectedError++;
2105 IX_ETH_ACC_FATAL_LOG(
2106 "ixEthTxFrameDoneQMCallback:Error: %u\n",
2107 (UINT32)txDoneQReadStatus, 0, 0, 0, 0, 0);
2112 qEntry = *qEntryPtr;
2116 mbufPtr = ixEthAccEntryFromQConvert(qEntry,
2117 IX_ETHNPE_QM_Q_TXENET_ADDR_MASK);
2120 if (mbufPtr == NULL)
2122 ixEthAccDataStats.unexpectedError++;
2123 IX_ETH_ACC_FATAL_LOG(
2124 "ixEthTxFrameDoneQMCallback:Error: Null Mbuf Ptr\n",
2130 /* endianness conversions and stats updates */
2131 ixEthAccMbufFromTxQ(mbufPtr);
2134 * Get NPE id from message, then convert to portId.
2136 npeId = ((IX_ETHNPE_QM_Q_TXENETDONE_NPEID_MASK &
2138 IX_ETHNPE_QM_Q_FIELD_NPEID_R);
2139 portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
2142 /* Prudent to at least check the port is within range */
2143 if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
2145 ixEthAccDataStats.unexpectedError++;
2146 IX_ETH_ACC_FATAL_LOG(
2147 "ixEthTxFrameDoneQMCallback: Illegal port: %u\n",
2148 (UINT32)portId, 0, 0, 0, 0, 0);
2153 TX_STATS_INC(portId,txDoneClientCallback);
2156 * Call user level callback.
2158 ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn(
2159 ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag,
2162 /* move to next queue entry */
2163 qEntry = *(++qEntryPtr);
2166 } while( txDoneQReadStatus == IX_SUCCESS );
2170 void ixEthAccDataPlaneShow(void)
2172 UINT32 numTx0Entries;
2173 UINT32 numTx1Entries;
2174 UINT32 numTxDoneEntries;
2175 UINT32 numRxEntries;
2176 UINT32 numRxFree0Entries;
2177 UINT32 numRxFree1Entries;
2180 UINT32 numTx2Entries;
2181 UINT32 numRxFree2Entries;
2185 UINT32 numBuffersInRx=0;
2186 UINT32 numBuffersInTx=0;
2187 UINT32 numBuffersInSwQ=0;
2188 UINT32 totalBuffers=0;
2189 UINT32 rxFreeCallbackCounter = 0;
2190 UINT32 txCallbackCounter = 0;
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;
2199 if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
2204 /* get a reliable snapshot */
2205 key = ixOsalIrqLock();
2208 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET0_Q, &numTx0Entries);
2210 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET1_Q, &numTx1Entries);
2211 numTxDoneEntries = 0;
2212 ixQMgrQNumEntriesGet( IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, &numTxDoneEntries);
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);
2222 ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET2_Q, &numTx2Entries);
2223 numRxFree2Entries = 0;
2224 ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q, &numRxFree2Entries);
2227 for(portId=IX_ETH_PORT_1; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2230 &ixEthAccPortData[portId].ixEthAccTxData.stats,
2231 sizeof(tx[portId]));
2233 &ixEthAccPortData[portId].ixEthAccRxData.stats,
2234 sizeof(rx[portId]));
2236 memcpy(&stats, &ixEthAccDataStats, sizeof(stats));
2238 ixOsalIrqUnlock(key);
2241 printf("Detailed statistics collection not supported in this load\n");
2244 /* print snapshot */
2245 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
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 ()))
2252 if ((IX_ETH_PORT_1 == portId) &&
2253 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
2254 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2258 if ((IX_ETH_PORT_2 == portId) &&
2259 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
2260 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2264 if ((IX_ETH_PORT_3 == portId) &&
2265 (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) ==
2266 IX_FEATURE_CTRL_COMPONENT_DISABLED))
2272 printf("PORT %u --------------------------------\n",
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",
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",
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;
2305 if (tx[portId].txPriority[priority])
2307 printf("Tx Priority %u : %u\n",
2309 tx[portId].txPriority[priority]);
2313 printf("Tx unexpected errors : %u (should be 0)\n",
2314 tx[portId].txUnexpectedError);
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);
2348 for (priority = IX_ETH_ACC_TX_PRIORITY_0;
2349 priority <= IX_ETH_ACC_TX_PRIORITY_7;
2352 if (rx[portId].rxPriority[priority])
2354 printf("Rx Priority %u : %u\n",
2356 rx[portId].rxPriority[priority]);
2360 printf("Rx unexpected errors : %u (should be 0)\n",
2361 rx[portId].rxUnexpectedError);
2364 numBuffersInTx = tx[portId].txQOK +
2365 tx[portId].txQDelayed -
2366 tx[portId].txDoneClientCallback -
2367 tx[portId].txDoneSwQDuringDisable -
2368 tx[portId].txDoneDuringDisable;
2370 printf("# Tx Buffers currently for transmission : %u\n",
2373 numBuffersInRx = rx[portId].rxFreeRepOK +
2374 rx[portId].rxFreeRepDelayed -
2375 rx[portId].rxFrameClientCallback -
2376 rx[portId].rxSwQDuringDisable -
2377 rx[portId].rxDuringDisable;
2379 printf("# Rx Buffers currently for reception : %u\n",
2382 totalBuffers += numBuffersInRx + numBuffersInTx;
2386 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);
2409 printf("Software queue usage :\n");
2410 printf("Buffers added to S/W Q : %u\n",
2412 printf("Buffers removed from S/W Q : %u\n",
2413 stats.removeFromSwQ);
2416 printf("Hardware queues callbacks :\n");
2418 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2420 rxFreeCallbackCounter += rx[portId].rxFreeLowCallback;
2421 txCallbackCounter += tx[portId].txLowThreshCallback;
2423 printf("Tx Done QM Callback invoked : %u\n",
2424 stats.txDoneCallbackCounter);
2425 printf("Tx QM Callback invoked : %u\n",
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);
2434 printf("Unexpected errors in CB : %u (should be 0)\n",
2435 stats.unexpectedError);
2438 printf("Hardware queues levels :\n");
2439 printf("Transmit Port 1 Q : %u \n",numTx0Entries);
2440 printf("Transmit Port 2 Q : %u \n",numTx1Entries);
2442 printf("Transmit Port 3 Q : %u \n",numTx2Entries);
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);
2449 printf("Receive Free Port 3 Q : %u \n",numRxFree2Entries);
2454 printf("# Total Buffers accounted for : %u\n",
2457 numBuffersInSwQ = ixEthAccDataStats.addToSwQ -
2458 ixEthAccDataStats.removeFromSwQ;
2460 printf(" Buffers in S/W Qs : %u\n",
2462 printf(" Buffers in H/W Qs or NPEs : %u\n",
2463 totalBuffers - numBuffersInSwQ);
2466 printf("Rx QoS Discipline : %s\n",
2467 (ixEthAccDataInfo.schDiscipline ==
2468 FIFO_PRIORITY ) ? "Enabled" : "Disabled");
2470 for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
2472 printf("Tx QoS Discipline port %u : %s\n",
2474 (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
2475 FIFO_PRIORITY ) ? "Enabled" : "Disabled");