* Update Intel IXP4xx support
- Add IXP4xx NPE ethernet MAC support
- Add support for Intel IXDPG425 board
- Add support for Prodrive PDNB3 board
- Add IRQ support
Patch by Stefan Roese, 23 May 2006

[This patch does not include cpu/ixp/npe/IxNpeMicrocode.c which still
 sufferes from licensing issues. Blame Intel.]
diff --git a/cpu/ixp/npe/IxEthAccDataPlane.c b/cpu/ixp/npe/IxEthAccDataPlane.c
new file mode 100644
index 0000000..e46fc9b
--- /dev/null
+++ b/cpu/ixp/npe/IxEthAccDataPlane.c
@@ -0,0 +1,2483 @@
+/**
+ * @file IxEthDataPlane.c
+ *
+ * @author Intel Corporation
+ * @date 12-Feb-2002
+ *
+ * @brief This file contains the implementation of the IXPxxx
+ * Ethernet Access Data plane component
+ *
+ * Design Notes:
+ *
+ * @par
+ * IXP400 SW Release version 2.0
+ *
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright 2001-2005, Intel Corporation.
+ * All rights reserved.
+ *
+ * @par
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * @par
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+#include "IxNpeMh.h"
+#include "IxEthAcc.h"
+#include "IxEthDB.h"
+#include "IxOsal.h"
+#include "IxEthDBPortDefs.h"
+#include "IxFeatureCtrl.h"
+#include "IxEthAcc_p.h"
+#include "IxEthAccQueueAssign_p.h"
+
+extern PUBLIC IxEthAccMacState ixEthAccMacState[];
+extern PUBLIC UINT32 ixEthAccNewSrcMask;
+
+/**
+ * private functions prototype
+ */
+PRIVATE IX_OSAL_MBUF *
+ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask);
+
+PRIVATE UINT32
+ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf);
+
+PRIVATE UINT32
+ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf);
+
+PRIVATE IxEthAccStatus
+ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
+				IxEthAccTxPriority *priorityPtr);
+
+PRIVATE IxEthAccStatus
+ixEthAccTxFromSwQ(IxEthAccPortId portId,
+		  IxEthAccTxPriority priority);
+
+PRIVATE IxEthAccStatus
+ixEthAccRxFreeFromSwQ(IxEthAccPortId portId);
+
+PRIVATE void
+ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf);
+
+PRIVATE void
+ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf);
+
+PRIVATE IX_STATUS
+ixEthAccQmgrLockTxWrite(IxEthAccPortId portId,
+			UINT32 qBuffer);
+
+PRIVATE IX_STATUS
+ixEthAccQmgrLockRxWrite(IxEthAccPortId portId,
+			UINT32 qBuffer);
+
+PRIVATE IX_STATUS
+ixEthAccQmgrTxWrite(IxEthAccPortId portId,
+		    UINT32 qBuffer,
+		    UINT32 priority);
+
+/**
+ * @addtogroup IxEthAccPri
+ *@{
+ */
+
+/* increment a counter only when stats are enabled */
+#define TX_STATS_INC(port,field) \
+        IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccTxData.stats.field)
+#define RX_STATS_INC(port,field) \
+        IX_ETH_ACC_STATS_INC(ixEthAccPortData[port].ixEthAccRxData.stats.field)
+
+/* always increment the counter (mainly used for unexpected errors) */
+#define TX_INC(port,field) \
+        ixEthAccPortData[port].ixEthAccTxData.stats.field++
+#define RX_INC(port,field) \
+        ixEthAccPortData[port].ixEthAccRxData.stats.field++
+
+PRIVATE IxEthAccDataPlaneStats     ixEthAccDataStats;
+
+extern IxEthAccPortDataInfo   ixEthAccPortData[];
+extern IxEthAccInfo   ixEthAccDataInfo;
+
+PRIVATE IxOsalFastMutex txWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
+PRIVATE IxOsalFastMutex rxWriteMutex[IX_ETH_ACC_NUMBER_OF_PORTS];
+
+/**
+ *
+ * @brief Mbuf header conversion macros : they implement the
+ *  different conversions using a temporary value. They also double-check
+ *  that the parameters can be converted to/from NPE format.
+ *
+ */
+#if defined(__wince) && !defined(IN_KERNEL)
+#define PTR_VIRT2NPE(ptrSrc,dst) \
+  do { UINT32 temp; \
+      IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \
+      temp = (UINT32)IX_OSAL_MBUF_MBUF_VIRTUAL_TO_PHYSICAL_TRANSLATION((IX_OSAL_MBUF*)ptrSrc); \
+      (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
+  while(0)
+
+#define PTR_NPE2VIRT(type,src,ptrDst) \
+  do { void *temp; \
+      IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \
+      temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \
+      (ptrDst) = (type)IX_OSAL_MBUF_MBUF_PHYSICAL_TO_VIRTUAL_TRANSLATION(temp); } \
+  while(0)
+#else
+#define PTR_VIRT2NPE(ptrSrc,dst) \
+  do { UINT32 temp; \
+      IX_OSAL_ENSURE(sizeof(ptrSrc) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(dst) == sizeof(UINT32), "Wrong parameter type"); \
+      temp = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(ptrSrc); \
+      (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
+  while(0)
+
+#define PTR_NPE2VIRT(type,src,ptrDst) \
+  do { void *temp; \
+      IX_OSAL_ENSURE(sizeof(type) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(src) == sizeof(UINT32), "Wrong parameter type"); \
+      IX_OSAL_ENSURE(sizeof(ptrDst) == sizeof(UINT32), "Wrong parameter type"); \
+      temp = (void *)IX_OSAL_SWAP_BE_SHARED_LONG(src); \
+      (ptrDst) = (type)IX_OSAL_MMU_PHYS_TO_VIRT(temp); } \
+  while(0)
+#endif
+
+/**
+ *
+ * @brief Mbuf payload pointer conversion macros : Wince has its own
+ *  method to convert the buffer pointers
+ */
+#if defined(__wince) && !defined(IN_KERNEL)
+#define DATAPTR_VIRT2NPE(ptrSrc,dst) \
+  do { UINT32 temp; \
+      temp = (UINT32)IX_OSAL_MBUF_DATA_VIRTUAL_TO_PHYSICAL_TRANSLATION(ptrSrc); \
+      (dst) = IX_OSAL_SWAP_BE_SHARED_LONG(temp); } \
+  while(0)
+
+#else
+#define DATAPTR_VIRT2NPE(ptrSrc,dst) PTR_VIRT2NPE(IX_OSAL_MBUF_MDATA(ptrSrc),dst)
+#endif
+
+
+/* Flush the shared part of the mbuf header */
+#define IX_ETHACC_NE_CACHE_FLUSH(mbufPtr) \
+  do { \
+      IX_OSAL_CACHE_FLUSH(IX_ETHACC_NE_SHARED(mbufPtr), \
+			      sizeof(IxEthAccNe)); \
+    } \
+  while(0)
+
+/* Invalidate the shared part of the mbuf header */
+#define IX_ETHACC_NE_CACHE_INVALIDATE(mbufPtr) \
+  do { \
+      IX_OSAL_CACHE_INVALIDATE(IX_ETHACC_NE_SHARED(mbufPtr), \
+				   sizeof(IxEthAccNe)); \
+    } \
+  while(0)
+
+/* Preload one cache line (shared mbuf headers are aligned
+ * and their size is 1 cache line)
+ *
+ * IX_OSAL_CACHED  is defined when the mbuf headers are
+ * allocated from cached memory.
+ *
+ * Other processor on emulation environment may not implement
+ * preload function
+ */
+#ifdef IX_OSAL_CACHED
+	#if (CPU!=SIMSPARCSOLARIS) && !defined (__wince)
+		#define IX_ACC_DATA_CACHE_PRELOAD(ptr) \
+		do { /* preload a cache line (Xscale Processor) */ \
+			__asm__ (" pld [%0]\n": : "r" (ptr)); \
+		} \
+		while(0)
+	#else
+		/* preload not implemented on different processor */
+		#define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
+		do { /* nothing */ } while (0)
+	#endif
+#else
+	/* preload not needed if cache is not enabled */
+	#define IX_ACC_DATA_CACHE_PRELOAD(mbufPtr) \
+	do { /* nothing */ } while (0)
+#endif
+
+/**
+ *
+ * @brief function to retrieve the correct pointer from
+ * a queue entry posted by the NPE
+ *
+ * @param qEntry : entry from qmgr queue
+ *        mask : applicable mask for this queue
+ *        (4 most significant bits are used for additional informations)
+ *
+ * @return IX_OSAL_MBUF * pointer to mbuf header
+ *
+ * @internal
+ */
+PRIVATE IX_OSAL_MBUF *
+ixEthAccEntryFromQConvert(UINT32 qEntry, UINT32 mask)
+{
+    IX_OSAL_MBUF *mbufPtr;
+
+    if (qEntry != 0)
+    {
+        /* mask NPE bits (e.g. priority, port ...) */
+        qEntry &= mask;
+
+#if IX_ACC_DRAM_PHYS_OFFSET != 0
+        /* restore the original address pointer (if PHYS_OFFSET is not 0) */
+        qEntry |= (IX_ACC_DRAM_PHYS_OFFSET & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
+#endif
+        /* get the mbuf pointer address from the npe-shared address */
+        qEntry -= offsetof(IX_OSAL_MBUF,ix_ne);
+
+        /* phys2virt mbuf */
+        mbufPtr = (IX_OSAL_MBUF *)IX_OSAL_MMU_PHYS_TO_VIRT(qEntry);
+
+        /* preload the cacheline shared with NPE */
+        IX_ACC_DATA_CACHE_PRELOAD(IX_ETHACC_NE_SHARED(mbufPtr));
+
+        /* preload the cacheline used by xscale */
+        IX_ACC_DATA_CACHE_PRELOAD(mbufPtr);
+    }
+    else
+    {
+	mbufPtr = NULL;
+    }
+
+    return mbufPtr;
+}
+
+/* Convert the mbuf header for NPE transmission */
+PRIVATE UINT32
+ixEthAccMbufTxQPrepare(IX_OSAL_MBUF *mbuf)
+{
+    UINT32 qbuf;
+    UINT32 len;
+
+    /* endianess swap for tci and flags
+       note: this is done only once, even for chained buffers */
+    IX_ETHACC_NE_FLAGS(mbuf)   = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf));
+    IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf));
+
+    /* test for unchained mbufs */
+    if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
+    {
+	/* "best case" scenario : unchained mbufs */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxMBufs);
+
+	/* payload pointer conversion */
+	DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
+
+	/* unchained mbufs : the frame length is the mbuf length
+	 * and the 2 identical lengths are stored in the same
+	 * word.
+	 */
+	len = IX_OSAL_MBUF_MLEN(mbuf);
+
+	/* set the length in both length and pktLen 16-bits fields */
+	len |= (len << IX_ETHNPE_ACC_LENGTH_OFFSET);
+	IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
+
+	/* unchained mbufs : next contains 0 */
+	IX_ETHACC_NE_NEXT(mbuf) = 0;
+
+	/* flush shared header after all address conversions */
+	IX_ETHACC_NE_CACHE_FLUSH(mbuf);
+    }
+    else
+    {
+	/* chained mbufs */
+	IX_OSAL_MBUF *ptr = mbuf;
+	IX_OSAL_MBUF *nextPtr;
+	UINT32 frmLen;
+
+	/* get the frame length from the header of the first buffer */
+	frmLen = IX_OSAL_MBUF_PKT_LEN(mbuf);
+
+	do
+	{
+	    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxMBufs);
+
+	    /* payload pointer */
+	    DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
+	    /* Buffer length and frame length are stored in the same word */
+	    len = IX_OSAL_MBUF_MLEN(ptr);
+	    len = frmLen | (len << IX_ETHNPE_ACC_LENGTH_OFFSET);
+	    IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
+
+	    /* get the virtual next chain pointer */
+	    nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
+	    if (nextPtr != NULL)
+	    {
+		/* shared pointer of the next buffer is chained */
+		PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
+			     IX_ETHACC_NE_NEXT(ptr));
+	    }
+	    else
+	    {
+		IX_ETHACC_NE_NEXT(ptr) = 0;
+	    }
+
+	    /* flush shared header after all address conversions */
+	    IX_ETHACC_NE_CACHE_FLUSH(ptr);
+
+	    /* move to next buffer */
+	    ptr = nextPtr;
+
+	    /* the frame length field is set only in the first buffer
+	     * and is zeroed in the next buffers
+	     */
+	    frmLen = 0;
+	}
+	while(ptr != NULL);
+
+    }
+
+    /* virt2phys mbuf itself */
+    qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
+		  IX_ETHACC_NE_SHARED(mbuf));
+
+    /* Ensure the bits which are reserved to exchange information with
+     * the NPE are cleared
+     *
+     * If the mbuf address is not correctly aligned, or from an
+     * incompatible memory range, there is no point to continue
+     */
+    IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_TXENET_ADDR_MASK) == 0),
+	      "Invalid address range");
+
+    return qbuf;
+}
+
+/* Convert the mbuf header for NPE reception */
+PRIVATE UINT32
+ixEthAccMbufRxQPrepare(IX_OSAL_MBUF *mbuf)
+{
+    UINT32 len;
+    UINT32 qbuf;
+
+    if (IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) == NULL)
+    {
+	/* "best case" scenario : unchained mbufs */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxFreeMBufs);
+
+	/* unchained mbufs : payload pointer */
+	DATAPTR_VIRT2NPE(mbuf, IX_ETHACC_NE_DATA(mbuf));
+
+	/* unchained mbufs : set the buffer length
+	* and the frame length field is zeroed
+	*/
+	len = (IX_OSAL_MBUF_MLEN(mbuf) << IX_ETHNPE_ACC_LENGTH_OFFSET);
+	IX_ETHACC_NE_LEN(mbuf) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
+
+	/* unchained mbufs : next pointer is null */
+	IX_ETHACC_NE_NEXT(mbuf) = 0;
+
+	/* flush shared header after all address conversions */
+	IX_ETHACC_NE_CACHE_FLUSH(mbuf);
+
+	/* remove shared header cache line */
+	IX_ETHACC_NE_CACHE_INVALIDATE(mbuf);
+    }
+    else
+    {
+	/* chained mbufs */
+	IX_OSAL_MBUF *ptr = mbuf;
+	IX_OSAL_MBUF *nextPtr;
+
+	do
+	{
+	    /* chained mbufs */
+	    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxFreeMBufs);
+
+	    /* we must save virtual next chain pointer */
+	    nextPtr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
+
+	    if (nextPtr != NULL)
+	    {
+		/* chaining pointer for NPE */
+		PTR_VIRT2NPE(IX_ETHACC_NE_SHARED(nextPtr),
+			     IX_ETHACC_NE_NEXT(ptr));
+	    }
+	    else
+	    {
+		IX_ETHACC_NE_NEXT(ptr) = 0;
+	    }
+
+	    /* payload pointer */
+	    DATAPTR_VIRT2NPE(ptr,IX_ETHACC_NE_DATA(ptr));
+
+	    /* buffer length */
+	    len = (IX_OSAL_MBUF_MLEN(ptr) << IX_ETHNPE_ACC_LENGTH_OFFSET);
+	    IX_ETHACC_NE_LEN(ptr) = IX_OSAL_SWAP_BE_SHARED_LONG(len);
+
+	    /* flush shared header after all address conversions */
+	    IX_ETHACC_NE_CACHE_FLUSH(ptr);
+
+	    /* remove shared header cache line */
+	    IX_ETHACC_NE_CACHE_INVALIDATE(ptr);
+
+	    /* next mbuf in the chain */
+	    ptr = nextPtr;
+	}
+	while(ptr != NULL);
+    }
+
+    /* virt2phys mbuf itself */
+    qbuf = (UINT32)IX_OSAL_MMU_VIRT_TO_PHYS(
+		  IX_ETHACC_NE_SHARED(mbuf));
+
+    /* Ensure the bits which are reserved to exchange information with
+     * the NPE are cleared
+     *
+     * If the mbuf address is not correctly aligned, or from an
+     * incompatible memory range, there is no point to continue
+     */
+    IX_OSAL_ENSURE(((qbuf & ~IX_ETHNPE_QM_Q_RXENET_ADDR_MASK) == 0),
+	      "Invalid address range");
+
+    return qbuf;
+}
+
+/* Convert the mbuf header after NPE transmission
+ * Since there is nothing changed by the NPE, there is no need
+ * to process anything but the update of internal stats
+ * when they are enabled
+*/
+PRIVATE void
+ixEthAccMbufFromTxQ(IX_OSAL_MBUF *mbuf)
+{
+#ifndef NDEBUG
+    /* test for unchained mbufs */
+    if (IX_ETHACC_NE_NEXT(mbuf) == 0)
+    {
+	/* unchained mbufs : update the stats */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedTxDoneMBufs);
+    }
+    else
+    {
+	/* chained mbufs : walk the chain and update the stats */
+	IX_OSAL_MBUF *ptr = mbuf;
+
+	do
+	{
+	    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedTxDoneMBufs);
+	    ptr = IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr);
+	}
+	while (ptr != NULL);
+    }
+#endif
+}
+
+/* Convert the mbuf header after NPE reception */
+PRIVATE void
+ixEthAccMbufFromRxQ(IX_OSAL_MBUF *mbuf)
+{
+    UINT32 len;
+
+    /* endianess swap for tci and flags
+       note: this is done only once, even for chained buffers */
+    IX_ETHACC_NE_FLAGS(mbuf)   = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_FLAGS(mbuf));
+    IX_ETHACC_NE_VLANTCI(mbuf) = IX_OSAL_SWAP_BE_SHARED_SHORT(IX_ETHACC_NE_VLANTCI(mbuf));
+
+    /* test for unchained mbufs */
+    if (IX_ETHACC_NE_NEXT(mbuf) == 0)
+    {
+	/* unchained mbufs */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.unchainedRxMBufs);
+
+	/* get the frame length. it is the same than the buffer length */
+	len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf));
+	len &= IX_ETHNPE_ACC_PKTLENGTH_MASK;
+	IX_OSAL_MBUF_PKT_LEN(mbuf) = IX_OSAL_MBUF_MLEN(mbuf) = len;
+
+        /* clears the next packet field */
+	IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(mbuf) = NULL;
+    }
+    else
+    {
+	IX_OSAL_MBUF *ptr = mbuf;
+	IX_OSAL_MBUF *nextPtr;
+	UINT32 frmLen;
+
+	/* convert the frame length */
+	frmLen = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(mbuf));
+	IX_OSAL_MBUF_PKT_LEN(mbuf) = (frmLen & IX_ETHNPE_ACC_PKTLENGTH_MASK);
+
+        /* chained mbufs */
+	do
+	{
+	    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.chainedRxMBufs);
+
+	    /* convert the length */
+	    len = IX_OSAL_SWAP_BE_SHARED_LONG(IX_ETHACC_NE_LEN(ptr));
+	    IX_OSAL_MBUF_MLEN(ptr) = (len >> IX_ETHNPE_ACC_LENGTH_OFFSET);
+
+            /* get the next pointer */
+ 	    PTR_NPE2VIRT(IX_OSAL_MBUF *,IX_ETHACC_NE_NEXT(ptr), nextPtr);
+	    if (nextPtr != NULL)
+	    {
+		nextPtr = (IX_OSAL_MBUF *)((UINT8 *)nextPtr - offsetof(IX_OSAL_MBUF,ix_ne));
+	    }
+	    /* set the next pointer */
+	    IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(ptr) = nextPtr;
+
+	    /* move to the next buffer */
+	    ptr = nextPtr;
+	}
+	while (ptr != NULL);
+    }
+}
+
+/* write to qmgr if possible and report an overflow if not possible
+ * Use a fast lock to protect the queue write.
+ * This way, the tx feature is reentrant.
+ */
+PRIVATE IX_STATUS
+ixEthAccQmgrLockTxWrite(IxEthAccPortId portId, UINT32 qBuffer)
+{
+    IX_STATUS qStatus;
+    if (ixOsalFastMutexTryLock(&txWriteMutex[portId]) == IX_SUCCESS)
+    {
+	qStatus = ixQMgrQWrite(
+	       IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
+	       &qBuffer);
+#ifndef NDEBUG
+	if (qStatus != IX_SUCCESS)
+	{
+	    TX_STATS_INC(portId, txOverflow);
+	}
+#endif
+	ixOsalFastMutexUnlock(&txWriteMutex[portId]);
+    }
+    else
+    {
+	TX_STATS_INC(portId, txLock);
+	qStatus = IX_QMGR_Q_OVERFLOW;
+    }
+    return qStatus;
+}
+
+/* write to qmgr if possible and report an overflow if not possible
+ * Use a fast lock to protect the queue write.
+ * This way, the Rx feature is reentrant.
+ */
+PRIVATE IX_STATUS
+ixEthAccQmgrLockRxWrite(IxEthAccPortId portId, UINT32 qBuffer)
+{
+    IX_STATUS qStatus;
+    if (ixOsalFastMutexTryLock(&rxWriteMutex[portId]) == IX_SUCCESS)
+    {
+	qStatus = ixQMgrQWrite(
+	       IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
+	       &qBuffer);
+#ifndef NDEBUG
+	if (qStatus != IX_SUCCESS)
+	{
+	    RX_STATS_INC(portId, rxFreeOverflow);
+	}
+#endif
+	ixOsalFastMutexUnlock(&rxWriteMutex[portId]);
+    }
+    else
+    {
+	RX_STATS_INC(portId, rxFreeLock);
+	qStatus = IX_QMGR_Q_OVERFLOW;
+    }
+    return qStatus;
+}
+
+/*
+ * Set the priority and write to a qmgr queue.
+ */
+PRIVATE IX_STATUS
+ixEthAccQmgrTxWrite(IxEthAccPortId portId, UINT32 qBuffer, UINT32 priority)
+{
+    /* fill the priority field */
+    qBuffer |= (priority << IX_ETHNPE_QM_Q_FIELD_PRIOR_R);
+
+    return ixEthAccQmgrLockTxWrite(portId, qBuffer);
+}
+
+/**
+ *
+ * @brief This function will discover the highest priority S/W Tx Q that
+ *        has entries in it
+ *
+ * @param portId - (in) the id of the port whose S/W Tx queues are to be searched
+ *        priorityPtr - (out) the priority of the highest priority occupied q will be written
+ *                      here
+ *
+ * @return IX_ETH_ACC_SUCCESS if an occupied Q is found
+ *         IX_ETH_ACC_FAIL if no Q has entries
+ *
+ * @internal
+ */
+PRIVATE IxEthAccStatus
+ixEthAccTxSwQHighestPriorityGet(IxEthAccPortId portId,
+				IxEthAccTxPriority *priorityPtr)
+{
+    if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline
+	== FIFO_NO_PRIORITY)
+    {
+	if(IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
+	       ixEthAccTxData.txQ[IX_ETH_ACC_TX_DEFAULT_PRIORITY]))
+	{
+	    return IX_ETH_ACC_FAIL;
+	}
+	else
+	{
+	    *priorityPtr = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
+	    TX_STATS_INC(portId,txPriority[*priorityPtr]);
+	    return IX_ETH_ACC_SUCCESS;
+	}
+    }
+    else
+    {
+	IxEthAccTxPriority highestPriority = IX_ETH_ACC_TX_PRIORITY_7;
+	while(1)
+	{
+	    if(!IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
+	       ixEthAccTxData.txQ[highestPriority]))
+	    {
+
+		*priorityPtr = highestPriority;
+		TX_STATS_INC(portId,txPriority[highestPriority]);
+		return IX_ETH_ACC_SUCCESS;
+
+	    }
+	    if (highestPriority == IX_ETH_ACC_TX_PRIORITY_0)
+	    {
+		return IX_ETH_ACC_FAIL;
+	    }
+	    highestPriority--;
+	}
+    }
+}
+
+/**
+ *
+ * @brief This function will take a buffer from a TX S/W Q and attempt
+ *        to add it to the relevant TX H/W Q
+ *
+ * @param portId - the port whose TX queue is to be written to
+ *        priority - identifies the queue from which the entry is to be read
+ *
+ * @internal
+ */
+PRIVATE IxEthAccStatus
+ixEthAccTxFromSwQ(IxEthAccPortId portId,
+		  IxEthAccTxPriority priority)
+{
+    IX_OSAL_MBUF        *mbuf;
+    IX_STATUS	   qStatus;
+
+    IX_OSAL_ENSURE((UINT32)priority <= (UINT32)7, "Invalid priority");
+
+    IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
+	ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
+	mbuf);
+
+    if (mbuf != NULL)
+    {
+	/*
+	 * Add the Tx buffer to the H/W Tx Q
+	 * We do not need to flush here as it is already done
+	 * in TxFrameSubmit().
+	 */
+	qStatus = ixEthAccQmgrTxWrite(
+	      portId,
+	      IX_OSAL_MMU_VIRT_TO_PHYS((UINT32)IX_ETHACC_NE_SHARED(mbuf)),
+	      priority);
+
+	if (qStatus == IX_SUCCESS)
+	{
+	    TX_STATS_INC(portId,txFromSwQOK);
+	    return IX_SUCCESS;
+	}
+	else if (qStatus == IX_QMGR_Q_OVERFLOW)
+	{
+	    /*
+	     * H/W Q overflow, need to save the buffer
+	     * back on the s/w Q.
+	     * we must put it back on the head of the q to avoid
+	     * reordering packet tx
+	     */
+	    TX_STATS_INC(portId,txFromSwQDelayed);
+	    IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
+		ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
+		mbuf);
+
+	    /*enable Q notification*/
+	    qStatus = ixQMgrNotificationEnable(
+		IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
+		IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
+
+            if (qStatus != IX_SUCCESS && qStatus != IX_QMGR_WARNING)
+            {
+		TX_INC(portId,txUnexpectedError);
+		IX_ETH_ACC_FATAL_LOG(
+	            "ixEthAccTxFromSwQ:Unexpected Error: %u\n",
+	            qStatus, 0, 0, 0, 0, 0);
+            }
+	}
+	else
+	{
+	    TX_INC(portId,txUnexpectedError);
+
+	    /* recovery attempt */
+	    IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
+		ixEthAccPortData[portId].ixEthAccTxData.txQ[priority],
+		mbuf);
+
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthAccTxFromSwQ:Error: unexpected QM status 0x%08X\n",
+		qStatus, 0, 0, 0, 0, 0);
+	}
+    }
+    else
+    {
+	/* sw queue is empty */
+    }
+    return IX_ETH_ACC_FAIL;
+}
+
+/**
+ *
+ * @brief This function will take a buffer from a RXfree S/W Q and attempt
+ *        to add it to the relevant RxFree H/W Q
+ *
+ * @param portId - the port whose RXFree queue is to be written to
+ *
+ * @internal
+ */
+PRIVATE IxEthAccStatus
+ixEthAccRxFreeFromSwQ(IxEthAccPortId portId)
+{
+    IX_OSAL_MBUF        *mbuf;
+    IX_STATUS	   qStatus = IX_SUCCESS;
+
+    IX_ETH_ACC_DATAPLANE_REMOVE_MBUF_FROM_Q_HEAD(
+	  ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
+	  mbuf);
+    if (mbuf != NULL)
+    {
+	/*
+	 * Add The Rx Buffer to the H/W Free buffer Q if possible
+	 */
+	qStatus = ixEthAccQmgrLockRxWrite(portId,
+		  IX_OSAL_MMU_VIRT_TO_PHYS(
+			 (UINT32)IX_ETHACC_NE_SHARED(mbuf)));
+
+	if (qStatus == IX_SUCCESS)
+	{
+	    RX_STATS_INC(portId,rxFreeRepFromSwQOK);
+	    /*
+	     * Buffer added to h/w Q.
+	     */
+	    return IX_SUCCESS;
+	}
+	else if (qStatus == IX_QMGR_Q_OVERFLOW)
+	{
+	    /*
+	     * H/W Q overflow, need to save the buffer back on the s/w Q.
+	     */
+	    RX_STATS_INC(portId,rxFreeRepFromSwQDelayed);
+
+	    IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
+		   ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
+		   mbuf);
+	}
+	else
+	{
+	    /* unexpected qmgr error */
+	    RX_INC(portId,rxUnexpectedError);
+
+	    IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_HEAD(
+		    ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
+		    mbuf);
+
+	    IX_ETH_ACC_FATAL_LOG("IxEthAccRxFreeFromSwQ:Error: unexpected QM status 0x%08X\n",
+				 qStatus, 0, 0, 0, 0, 0);
+	}
+    }
+    else
+    {
+	/* sw queue is empty */
+    }
+    return IX_ETH_ACC_FAIL;
+}
+
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccInitDataPlane()
+{
+    UINT32 portId;
+
+    /*
+     * Initialize the service and register callback to other services.
+     */
+
+    IX_ETH_ACC_MEMSET(&ixEthAccDataStats,
+		      0,
+		      sizeof(ixEthAccDataStats));
+
+    for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+	ixOsalFastMutexInit(&txWriteMutex[portId]);
+	ixOsalFastMutexInit(&rxWriteMutex[portId]);
+
+	IX_ETH_ACC_MEMSET(&ixEthAccPortData[portId],
+			  0,
+			  sizeof(ixEthAccPortData[portId]));
+
+	ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = FIFO_NO_PRIORITY;
+    }
+
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccPortTxDoneCallbackRegister(IxEthAccPortId portId,
+						  IxEthAccPortTxDoneCallback
+						  txCallbackFn,
+						  UINT32 callbackTag)
+{
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+/* HACK: removing this code to enable NPE-A preliminary testing
+ *    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+ *    {
+ *        IX_ETH_ACC_WARNING_LOG("ixEthAccPortTxDoneCallbackRegister: Unavailable Eth %d: Cannot register TxDone Callback.\n",(INT32)portId,0,0,0,0,0);
+ *        return IX_ETH_ACC_SUCCESS ;
+ *    }
+ */
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+    if (txCallbackFn == 0)
+	/* Check for null function pointer here. */
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+    ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn = txCallbackFn;
+    ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag = callbackTag;
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccPortRxCallbackRegister(IxEthAccPortId portId,
+					      IxEthAccPortRxCallback
+					      rxCallbackFn,
+					      UINT32 callbackTag)
+{
+    IxEthAccPortId port;
+
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+    {
+        IX_ETH_ACC_WARNING_LOG("ixEthAccPortRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0);
+        return IX_ETH_ACC_SUCCESS ;
+    }
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+
+    /* Check for null function pointer here. */
+    if (rxCallbackFn == NULL)
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    /* Check the user is not changing the callback type
+     * when the port is enabled.
+    */
+    if (ixEthAccMacState[portId].portDisableState == ACTIVE)
+    {
+	for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
+	{
+	    if ((ixEthAccMacState[port].portDisableState == ACTIVE)
+		&& (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == TRUE))
+	    {
+		/* one of the active ports has a different rx callback type.
+		 * Changing the callback type when the port is enabled
+		 * is not safe
+		 */
+		return (IX_ETH_ACC_INVALID_ARG);
+	    }
+	}
+    }
+
+    /* update the callback pointer : this is done before
+     * registering the new qmgr callback
+     */
+    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn = rxCallbackFn;
+    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag = callbackTag;
+
+    /* update the qmgr callback for rx queues */
+    if (ixEthAccQMgrRxCallbacksRegister(ixEthRxFrameQMCallback)
+	!= IX_ETH_ACC_SUCCESS)
+    {
+	/* unexpected qmgr error */
+        IX_ETH_ACC_FATAL_LOG("ixEthAccPortRxCallbackRegister: unexpected QMgr error, " \
+            "could not register Rx single-buffer callback\n", 0, 0, 0, 0, 0, 0);
+
+	RX_INC(portId,rxUnexpectedError);
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = FALSE;
+
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccPortMultiBufferRxCallbackRegister(
+			 IxEthAccPortId portId,
+			 IxEthAccPortMultiBufferRxCallback
+			 rxCallbackFn,
+			 UINT32 callbackTag)
+{
+    IxEthAccPortId port;
+
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+    {
+        IX_ETH_ACC_WARNING_LOG("ixEthAccPortMultiBufferRxCallbackRegister: Unavailable Eth %d: Cannot register Rx Callback.\n",(INT32)portId,0,0,0,0,0);
+        return IX_ETH_ACC_SUCCESS ;
+    }
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+
+    /* Check for null function pointer here. */
+    if (rxCallbackFn == NULL)
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    /* Check the user is not changing the callback type
+     * when the port is enabled.
+    */
+    if (ixEthAccMacState[portId].portDisableState == ACTIVE)
+    {
+	for (port = 0; port < IX_ETH_ACC_NUMBER_OF_PORTS; port++)
+	{
+	    if ((ixEthAccMacState[port].portDisableState == ACTIVE)
+		&& (ixEthAccPortData[port].ixEthAccRxData.rxMultiBufferCallbackInUse == FALSE))
+	    {
+		/* one of the active ports has a different rx callback type.
+		 * Changing the callback type when the port is enabled
+		 * is not safe
+		 */
+		return (IX_ETH_ACC_INVALID_ARG);
+	    }
+	}
+    }
+
+    /* update the callback pointer : this is done before
+     * registering the new qmgr callback
+     */
+    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackFn = rxCallbackFn;
+    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackTag = callbackTag;
+
+    /* update the qmgr callback for rx queues */
+    if (ixEthAccQMgrRxCallbacksRegister(ixEthRxMultiBufferQMCallback)
+	!= IX_ETH_ACC_SUCCESS)
+    {
+	/* unexpected qmgr error */
+	RX_INC(portId,rxUnexpectedError);
+
+        IX_ETH_ACC_FATAL_LOG("ixEthAccPortMultiBufferRxCallbackRegister: unexpected QMgr error, " \
+            "could not register Rx multi-buffer callback\n", 0, 0, 0, 0, 0, 0);
+
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    ixEthAccPortData[portId].ixEthAccRxData.rxMultiBufferCallbackInUse = TRUE;
+
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccPortTxFrameSubmit(IxEthAccPortId portId,
+					 IX_OSAL_MBUF *buffer,
+					 IxEthAccTxPriority priority)
+{
+    IX_STATUS	qStatus = IX_SUCCESS;
+    UINT32      qBuffer;
+    IxEthAccTxPriority highestPriority;
+    IxQMgrQStatus txQStatus;
+
+#ifndef NDEBUG
+    if (buffer == NULL)
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+    {
+        IX_ETH_ACC_FATAL_LOG("ixEthAccPortTxFrameSubmit: Unavailable Eth %d: Cannot submit Tx Frame.\n",
+			     (INT32)portId,0,0,0,0,0);
+        return IX_ETH_ACC_PORT_UNINITIALIZED ;
+    }
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+    if ((UINT32)priority > (UINT32)IX_ETH_ACC_TX_PRIORITY_7)
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+#endif
+
+    /*
+     * Need to Flush the MBUF and its contents (data) as it may be
+     * read from the NPE. Convert virtual addresses to physical addresses also.
+     */
+    qBuffer = ixEthAccMbufTxQPrepare(buffer);
+
+    /*
+     * If no fifo priority set on Xscale ...
+     */
+    if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
+	FIFO_NO_PRIORITY)
+    {
+	/*
+	 * Add The Tx Buffer to the H/W Tx Q if possible
+	 * (the priority is passed to the NPE, because
+	 * the NPE is able to reorder the frames
+	 * before transmission to the underlying hardware)
+	 */
+	qStatus = ixEthAccQmgrTxWrite(portId,
+				      qBuffer,
+				      IX_ETH_ACC_TX_DEFAULT_PRIORITY);
+
+	if (qStatus == IX_SUCCESS)
+	{
+	    TX_STATS_INC(portId,txQOK);
+
+	    /*
+	     * "best case" scenario : Buffer added to h/w Q.
+	     */
+	    return (IX_SUCCESS);
+	}
+	else if (qStatus == IX_QMGR_Q_OVERFLOW)
+	{
+	    /*
+	     * We were unable to write the buffer to the
+	     * appropriate H/W Q,  Save it in the sw Q.
+	     * (use the default priority queue regardless of
+	     * input parameter)
+	     */
+	    priority = IX_ETH_ACC_TX_DEFAULT_PRIORITY;
+	}
+	else
+	{
+	    /* unexpected qmgr error */
+	    TX_INC(portId,txUnexpectedError);
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthAccPortTxFrameSubmit:Error: qStatus = %u\n",
+		(UINT32)qStatus, 0, 0, 0, 0, 0);
+	    return (IX_ETH_ACC_FAIL);
+	}
+    }
+    else if (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
+	     FIFO_PRIORITY)
+    {
+
+	/*
+	 * For priority transmission, put the frame directly on the H/W queue
+	 * if the H/W queue is empty, otherwise, put it in a S/W Q
+	 */
+	ixQMgrQStatusGet(IX_ETH_ACC_PORT_TO_TX_Q_ID(portId), &txQStatus);
+	if((txQStatus & IX_QMGR_Q_STATUS_E_BIT_MASK) != 0)
+	{
+	    /*The tx queue is empty, check whether there are buffers on the s/w queues*/
+	    if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
+	       !=IX_ETH_ACC_FAIL)
+	    {
+		/*there are buffers on the s/w queues, submit them*/
+		ixEthAccTxFromSwQ(portId, highestPriority);
+
+		/* the queue was empty, 1 buffer is already supplied
+		 * but is likely to be immediately transmitted and the
+		 * hw queue is likely to be empty again, so submit
+		 * more from the sw queues
+		 */
+		if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
+		   !=IX_ETH_ACC_FAIL)
+		{
+		    ixEthAccTxFromSwQ(portId, highestPriority);
+		    /*
+		     * and force the buffer supplied to be placed
+		     * on a priority queue
+		     */
+		    qStatus = IX_QMGR_Q_OVERFLOW;
+		}
+		else
+		{
+		    /*there are no buffers in the s/w queues, submit directly*/
+		    qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
+		}
+	    }
+	    else
+	    {
+		/*there are no buffers in the s/w queues, submit directly*/
+		qStatus = ixEthAccQmgrTxWrite(portId, qBuffer, priority);
+	    }
+	}
+	else
+	{
+	    qStatus = IX_QMGR_Q_OVERFLOW;
+	}
+    }
+    else
+    {
+	TX_INC(portId,txUnexpectedError);
+	IX_ETH_ACC_FATAL_LOG(
+	    "ixEthAccPortTxFrameSubmit:Error: wrong schedule discipline setup\n",
+	    0, 0, 0, 0, 0, 0);
+	return (IX_ETH_ACC_FAIL);
+    }
+
+    if(qStatus == IX_SUCCESS )
+    {
+	TX_STATS_INC(portId,txQOK);
+	return IX_ETH_ACC_SUCCESS;
+    }
+    else if(qStatus == IX_QMGR_Q_OVERFLOW)
+    {
+	TX_STATS_INC(portId,txQDelayed);
+	/*
+	 * We were unable to write the buffer to the
+	 * appropriate H/W Q,  Save it in a s/w Q.
+	 */
+	IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
+		ixEthAccPortData[portId].
+		ixEthAccTxData.txQ[priority],
+		buffer);
+
+	qStatus = ixQMgrNotificationEnable(
+		IX_ETH_ACC_PORT_TO_TX_Q_ID(portId),
+		IX_ETH_ACC_PORT_TO_TX_Q_SOURCE(portId));
+
+        if (qStatus != IX_SUCCESS)
+	{
+	    if (qStatus == IX_QMGR_WARNING)
+	    {
+		/* notification is enabled for a queue
+		 * which is already empty (the condition is already met)
+		 * and there will be no more queue event to drain the sw queue
+		 */
+		TX_STATS_INC(portId,txLateNotificationEnabled);
+
+		/* pull a buffer from the sw queue */
+		if(ixEthAccTxSwQHighestPriorityGet(portId,  &highestPriority)
+		   !=IX_ETH_ACC_FAIL)
+		{
+		    /*there are buffers on the s/w queues, submit from them*/
+		    ixEthAccTxFromSwQ(portId, highestPriority);
+		}
+	    }
+	    else
+	    {
+		TX_INC(portId,txUnexpectedError);
+		IX_ETH_ACC_FATAL_LOG(
+		     "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
+		     qStatus, 0, 0, 0, 0, 0);
+	    }
+        }
+    }
+    else
+    {
+	TX_INC(portId,txUnexpectedError);
+	IX_ETH_ACC_FATAL_LOG(
+	     "ixEthAccPortTxFrameSubmit: unexpected Error: %u\n",
+	     qStatus, 0, 0, 0, 0, 0);
+	return (IX_ETH_ACC_FAIL);
+    }
+
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+
+/**
+ *
+ * @brief replenish: convert a chain of mbufs to the format
+ *        expected by the NPE
+ *
+  */
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccPortRxFreeReplenish(IxEthAccPortId portId,
+					   IX_OSAL_MBUF *buffer)
+{
+    IX_STATUS	qStatus = IX_SUCCESS;
+    UINT32      qBuffer;
+
+    /*
+     * Check buffer is valid.
+     */
+
+#ifndef NDEBUG
+    /* check parameter value */
+    if (buffer == 0)
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+    /* check initialisation is done */
+    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+    {
+        IX_ETH_ACC_FATAL_LOG(" ixEthAccPortRxFreeReplenish: Unavailable Eth %d: Cannot replenish Rx Free Q.\n",(INT32)portId,0,0,0,0,0);
+        return IX_ETH_ACC_PORT_UNINITIALIZED ;
+    }
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+    /* check boundaries and constraints */
+    if (IX_OSAL_MBUF_MLEN(buffer) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
+    {
+	return (IX_ETH_ACC_FAIL);
+    }
+#endif
+
+    qBuffer = ixEthAccMbufRxQPrepare(buffer);
+
+    /*
+     * Add The Rx Buffer to the H/W Free buffer Q if possible
+     */
+    qStatus = ixEthAccQmgrLockRxWrite(portId, qBuffer);
+
+    if (qStatus == IX_SUCCESS)
+    {
+	RX_STATS_INC(portId,rxFreeRepOK);
+	/*
+	 * Buffer added to h/w Q.
+	 */
+	return (IX_SUCCESS);
+    }
+    else if (qStatus == IX_QMGR_Q_OVERFLOW)
+    {
+	RX_STATS_INC(portId,rxFreeRepDelayed);
+	/*
+	 * We were unable to write the buffer to the approprate H/W Q,
+	 * Save it in a s/w Q.
+	 */
+	IX_ETH_ACC_DATAPLANE_ADD_MBUF_TO_Q_TAIL(
+	    ixEthAccPortData[portId].ixEthAccRxData.freeBufferList,
+	    buffer);
+
+	qStatus = ixQMgrNotificationEnable(
+	    IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId),
+	    IX_ETH_ACC_PORT_TO_RX_FREE_Q_SOURCE(portId));
+
+        if (qStatus != IX_SUCCESS)
+	{
+	    if (qStatus == IX_QMGR_WARNING)
+	    {
+		/* notification is enabled for a queue
+		 * which is already empty (the condition is already met)
+		 * and there will be no more queue event to drain the sw queue
+		 * move an entry from the sw queue to the hw queue */
+		RX_STATS_INC(portId,rxFreeLateNotificationEnabled);
+		ixEthAccRxFreeFromSwQ(portId);
+	    }
+	    else
+	    {
+		RX_INC(portId,rxUnexpectedError);
+		IX_ETH_ACC_FATAL_LOG(
+		     "ixEthAccRxPortFreeReplenish:Error: %u\n",
+		     qStatus, 0, 0, 0, 0, 0);
+	    }
+        }
+    }
+    else
+    {
+	RX_INC(portId,rxUnexpectedError);
+	IX_ETH_ACC_FATAL_LOG(
+	    "ixEthAccRxPortFreeReplenish:Error: qStatus = %u\n",
+	    (UINT32)qStatus, 0, 0, 0, 0, 0);
+        return(IX_ETH_ACC_FAIL);
+    }
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccTxSchedulingDisciplineSetPriv(IxEthAccPortId portId,
+						 IxEthAccSchedulerDiscipline
+						 sched)
+{
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	return (IX_ETH_ACC_INVALID_PORT);
+    }
+
+    if (IX_ETH_ACC_SUCCESS != ixEthAccSingleEthNpeCheck(portId))
+    {
+        IX_ETH_ACC_WARNING_LOG("ixEthAccTxSchedulingDisciplineSet: Unavailable Eth %d: Cannot set Tx Scheduling Discipline.\n",(INT32)portId,0,0,0,0,0);
+        return IX_ETH_ACC_SUCCESS ;
+    }
+
+    if (!IX_ETH_IS_PORT_INITIALIZED(portId))
+    {
+	return (IX_ETH_ACC_PORT_UNINITIALIZED);
+    }
+
+    if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    ixEthAccPortData[portId].ixEthAccTxData.schDiscipline = sched;
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccRxSchedulingDisciplineSetPriv(IxEthAccSchedulerDiscipline
+						 sched)
+{
+    if (sched != FIFO_PRIORITY && sched != FIFO_NO_PRIORITY)
+    {
+	return (IX_ETH_ACC_INVALID_ARG);
+    }
+
+    ixEthAccDataInfo.schDiscipline = sched;
+
+    return (IX_ETH_ACC_SUCCESS);
+}
+
+
+/**
+ * @fn ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
+ *
+ * @brief process incoming frame :
+ *
+ * @param @ref IxQMgrCallback IxQMgrMultiBufferCallback
+ *
+ * @return none
+ *
+ * @internal
+ *
+ */
+IX_ETH_ACC_PRIVATE BOOL
+ixEthRxFrameProcess(IxEthAccPortId portId, IX_OSAL_MBUF *mbufPtr)
+{
+    UINT32 flags;
+    IxEthDBStatus result;
+
+#ifndef NDEBUG
+    /* Prudent to at least check the port is within range */
+    if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
+    {
+	ixEthAccDataStats.unexpectedError++;
+	IX_ETH_ACC_FATAL_LOG(
+	     "ixEthRxFrameProcess: Illegal port: %u\n",
+	     (UINT32)portId, 0, 0, 0, 0, 0);
+	return FALSE;
+    }
+#endif
+
+    /* convert fields from mbuf header */
+    ixEthAccMbufFromRxQ(mbufPtr);
+
+    /* check about any special processing for this frame */
+    flags = IX_ETHACC_NE_FLAGS(mbufPtr);
+    if ((flags & (IX_ETHACC_NE_FILTERMASK | IX_ETHACC_NE_NEWSRCMASK)) == 0)
+    {
+	/* "best case" scenario : nothing special to do for this frame */
+	return TRUE;
+    }
+
+#ifdef CONFIG_IXP425_COMPONENT_ETHDB
+    /* if a new source MAC address is detected by the NPE,
+     * update IxEthDB with the portId and the MAC address.
+     */
+    if ((flags & IX_ETHACC_NE_NEWSRCMASK & ixEthAccNewSrcMask) != 0)
+    {
+        result = ixEthDBFilteringDynamicEntryProvision(portId,
+			  (IxEthDBMacAddr *) IX_ETHACC_NE_SOURCEMAC(mbufPtr));
+
+	if (result != IX_ETH_DB_SUCCESS && result != IX_ETH_DB_FEATURE_UNAVAILABLE)
+	{
+            if ((ixEthAccMacState[portId].portDisableState == ACTIVE) && (result != IX_ETH_DB_BUSY))
+            {
+	        RX_STATS_INC(portId, rxUnexpectedError);
+                IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to add source MAC \
+                                    to the Learning/Filtering database\n", 0, 0, 0, 0, 0, 0);
+            }
+            else
+            {
+                /* we expect this to fail during PortDisable, as EthDB is disabled for
+                 * that port and will refuse to learn new addresses
+		 */
+            }
+	}
+	else
+	{
+	    RX_STATS_INC(portId, rxUnlearnedMacAddress);
+	}
+    }
+#endif
+
+    /* check if this frame should have been filtered
+     * by the NPE and take the appropriate action
+     */
+    if (((flags & IX_ETHACC_NE_FILTERMASK) != 0)
+        && (ixEthAccMacState[portId].portDisableState == ACTIVE))
+    {
+        /* If the mbuf was allocated with a small data size, or the current data pointer is not
+         * within the allocated data area, then the buffer is non-standard and has to be
+         * replenished with the minimum size only
+         */
+        if( (IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) < IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN)
+           || ((UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) > IX_OSAL_MBUF_MDATA(mbufPtr))
+           || ((UINT8 *)(IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr) +
+              IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr))
+               < IX_OSAL_MBUF_MDATA(mbufPtr)) )
+        {
+            /* set to minimum length */
+            IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) =
+                IX_ETHNPE_ACC_RXFREE_BUFFER_LENGTH_MIN;
+        }
+        else
+        {
+            /* restore original length */
+            IX_OSAL_MBUF_MLEN(mbufPtr) = IX_OSAL_MBUF_PKT_LEN(mbufPtr) =
+                ( IX_OSAL_MBUF_ALLOCATED_BUFF_LEN(mbufPtr) -
+                 (IX_OSAL_MBUF_MDATA(mbufPtr) - (UINT8 *)IX_OSAL_MBUF_ALLOCATED_BUFF_DATA(mbufPtr)) );
+        }
+
+        /* replenish from here */
+        if (ixEthAccPortRxFreeReplenish(portId, mbufPtr) != IX_ETH_ACC_SUCCESS)
+        {
+                IX_ETH_ACC_FATAL_LOG("ixEthRxFrameProcess: Failed to replenish with filtered frame\
+                                      on port %d\n", portId, 0, 0, 0, 0, 0);
+        }
+
+        RX_STATS_INC(portId, rxFiltered);
+
+        /* indicate that frame should not be subjected to further processing */
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+/**
+ * @fn ixEthRxFrameQMCallback
+ *
+ * @brief receive callback for Frame receive Q from NPE
+ *
+ * Frames are passed one-at-a-time to the user
+ *
+ * @param @ref IxQMgrCallback
+ *
+ * @return none
+ *
+ * @internal
+ *
+ * Design note : while processing the entry X, entry X+1 is preloaded
+ * into memory to reduce the number of stall cycles
+ *
+ */
+void ixEthRxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
+{
+    IX_OSAL_MBUF    *mbufPtr;
+    IX_OSAL_MBUF    *nextMbufPtr;
+    UINT32     qEntry;
+    UINT32     nextQEntry;
+    UINT32     *qEntryPtr;
+    UINT32     portId;
+    UINT32     destPortId;
+    UINT32     npeId;
+    UINT32     rxQReadStatus;
+
+    /*
+     * Design note : entries are read in a buffer, This buffer contains
+     * an extra zeroed entry so the loop will
+     * always terminate on a null entry, whatever the result of Burst read is.
+     */
+    UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
+
+    /*
+     * Indication of the number of times the callback is used.
+     */
+    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
+
+    do
+    {
+	/*
+	 * Indication of the number of times the queue is drained
+	 */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
+
+	/* ensure the last entry of the array contains a zeroed value */
+	qEntryPtr = rxQEntry;
+	qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0;
+
+	rxQReadStatus = ixQMgrQBurstRead(qId,
+		 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
+		 qEntryPtr);
+
+#ifndef NDEBUG
+	if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
+	    && (rxQReadStatus != IX_SUCCESS))
+	{
+	    ixEthAccDataStats.unexpectedError++;
+	    /*major error*/
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthRxFrameQMCallback:Error: %u\n",
+		(UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
+	    return;
+	}
+#endif
+
+	/* convert and preload the next entry
+	 * (the conversion function takes care about null pointers which
+	 * are used to mark the end of the loop)
+	 */
+	nextQEntry = *qEntryPtr;
+	nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
+			  IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
+
+	while(nextQEntry != 0)
+	{
+	    /* get the next entry */
+	    qEntry = nextQEntry;
+	    mbufPtr = nextMbufPtr;
+
+#ifndef NDEBUG
+	    if (mbufPtr == NULL)
+	    {
+		ixEthAccDataStats.unexpectedError++;
+		IX_ETH_ACC_FATAL_LOG(
+		    "ixEthRxFrameQMCallback: Null Mbuf Ptr\n",
+		    0, 0, 0, 0, 0, 0);
+		return;
+	    }
+#endif
+
+	    /* convert the next entry
+	     * (the conversion function takes care about null pointers which
+	     * are used to mark the end of the loop)
+	     */
+	    nextQEntry = *(++qEntryPtr);
+	    nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
+			      IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
+
+	    /*
+	     * Get Port and Npe ID from message.
+	     */
+	    npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
+		      qEntry) >> IX_ETHNPE_QM_Q_FIELD_NPEID_R);
+	    portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
+
+	    /* process frame, check the return code and skip the remaining of
+	     * the loop if the frame is to be filtered out
+	     */
+            if (ixEthRxFrameProcess(portId, mbufPtr))
+            {
+	        /* destination portId for this packet */
+	        destPortId = IX_ETHACC_NE_DESTPORTID(mbufPtr);
+
+                if (destPortId != IX_ETH_DB_UNKNOWN_PORT)
+                {
+                    destPortId = IX_ETH_DB_NPE_LOGICAL_ID_TO_PORT_ID(destPortId);
+                }
+
+	        /* test if QoS is enabled in ethAcc
+	        */
+	        if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
+	        {
+		    /* check if there is a higher priority queue
+		    * which may require processing and then process it.
+		    */
+		    if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
+		    {
+		        ixEthRxFrameQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
+					    callbackId);
+		    }
+	        }
+
+	        /*
+	        * increment priority stats
+	        */
+	        RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
+
+	        /*
+	        * increment callback count stats
+	        */
+	        RX_STATS_INC(portId,rxFrameClientCallback);
+
+	        /*
+	        * Call user level callback.
+	        */
+	        ixEthAccPortData[portId].ixEthAccRxData.rxCallbackFn(
+		    ixEthAccPortData[portId].ixEthAccRxData.rxCallbackTag,
+		    mbufPtr,
+		    destPortId);
+            }
+	}
+    } while (rxQReadStatus == IX_SUCCESS);
+}
+
+/**
+ * @fn ixEthRxMultiBufferQMCallback
+ *
+ * @brief receive callback for Frame receive Q from NPE
+ *
+ * Frames are passed as an array to the user
+ *
+ * @param @ref IxQMgrCallback
+ *
+ * @return none
+ *
+ * @internal
+ *
+ * Design note : while processing the entry X, entry X+1 is preloaded
+ * into memory to reduce the number of stall cycles
+ *
+ */
+void ixEthRxMultiBufferQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
+{
+    IX_OSAL_MBUF    *mbufPtr;
+    IX_OSAL_MBUF    *nextMbufPtr;
+    UINT32     qEntry;
+    UINT32     nextQEntry;
+    UINT32     *qEntryPtr;
+    UINT32     portId;
+    UINT32     npeId;
+    UINT32     rxQReadStatus;
+    /*
+     * Design note : entries are read in a static buffer, This buffer contains
+     * an extra zeroed entry so the loop will
+     * always terminate on a null entry, whatever the result of Burst read is.
+     */
+    static UINT32 rxQEntry[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
+    static IX_OSAL_MBUF *rxMbufPortArray[IX_ETH_ACC_NUMBER_OF_PORTS][IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK + 1];
+    IX_OSAL_MBUF **rxMbufPtr[IX_ETH_ACC_NUMBER_OF_PORTS];
+
+    for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+	rxMbufPtr[portId] = rxMbufPortArray[portId];
+    }
+
+    /*
+     * Indication of the number of times the callback is used.
+     */
+    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackCounter);
+
+    do
+    {
+	/*
+	 * Indication of the number of times the queue is drained
+	 */
+	IX_ETH_ACC_STATS_INC(ixEthAccDataStats.rxCallbackBurstRead);
+
+	/* ensure the last entry of the array contains a zeroed value */
+	qEntryPtr = rxQEntry;
+	qEntryPtr[IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK] = 0;
+
+	rxQReadStatus = ixQMgrQBurstRead(qId,
+		 IX_ETH_ACC_MAX_RX_FRAME_CONSUME_PER_CALLBACK,
+		 qEntryPtr);
+
+#ifndef NDEBUG
+	if ((rxQReadStatus != IX_QMGR_Q_UNDERFLOW)
+	    && (rxQReadStatus != IX_SUCCESS))
+	{
+	    ixEthAccDataStats.unexpectedError++;
+	    /*major error*/
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthRxFrameMultiBufferQMCallback:Error: %u\n",
+		(UINT32)rxQReadStatus, 0, 0, 0, 0, 0);
+	    return;
+	}
+#endif
+
+	/* convert and preload the next entry
+	 * (the conversion function takes care about null pointers which
+	 * are used to mark the end of the loop)
+	 */
+	nextQEntry = *qEntryPtr;
+	nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
+			  IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
+
+	while(nextQEntry != 0)
+	{
+	    /* get the next entry */
+	    qEntry = nextQEntry;
+	    mbufPtr = nextMbufPtr;
+
+#ifndef NDEBUG
+	    if (mbufPtr == NULL)
+	    {
+		ixEthAccDataStats.unexpectedError++;
+		IX_ETH_ACC_FATAL_LOG(
+		    "ixEthRxFrameMultiBufferQMCallback:Error: Null Mbuf Ptr\n",
+		    0, 0, 0, 0, 0, 0);
+		return;
+	    }
+#endif
+
+	    /* convert the next entry
+	     * (the conversion function takes care about null pointers which
+	     * are used to mark the end of the loop)
+	     */
+	    nextQEntry = *(++qEntryPtr);
+	    nextMbufPtr = ixEthAccEntryFromQConvert(nextQEntry,
+			      IX_ETHNPE_QM_Q_RXENET_ADDR_MASK);
+
+	    /*
+	     * Get Port and Npe ID from message.
+	     */
+	    npeId = ((IX_ETHNPE_QM_Q_RXENET_NPEID_MASK &
+		      qEntry) >>
+		     IX_ETHNPE_QM_Q_FIELD_NPEID_R);
+	    portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
+
+	    /* skip the remaining of the loop if the frame is
+	     * to be filtered out
+	     */
+	    if (ixEthRxFrameProcess(portId, mbufPtr))
+	    {
+		/* store a mbuf pointer in an array */
+		*rxMbufPtr[portId]++ = mbufPtr;
+
+		/*
+		 * increment priority stats
+		 */
+		RX_STATS_INC(portId,rxPriority[IX_ETHACC_NE_QOS(mbufPtr)]);
+	    }
+
+	    /* test for QoS enabled in ethAcc */
+	    if (ixEthAccDataInfo.schDiscipline == FIFO_PRIORITY)
+	    {
+		/* check if there is a higher priority queue
+		 * which may require processing and then process it.
+		 */
+		if (ixEthAccDataInfo.higherPriorityQueue[qId] < IX_QMGR_MAX_NUM_QUEUES)
+		{
+		    ixEthRxMultiBufferQMCallback(ixEthAccDataInfo.higherPriorityQueue[qId],
+						 callbackId);
+		}
+	    }
+	}
+
+	/* check if any of the the arrays contains any entry */
+	for (portId = 0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+	{
+	    if (rxMbufPtr[portId] != rxMbufPortArray[portId])
+	    {
+		/* add a last NULL pointer at the end of the
+		 * array of mbuf pointers
+		 */
+		*rxMbufPtr[portId] = NULL;
+
+		/*
+		 * increment callback count stats
+		 */
+		RX_STATS_INC(portId,rxFrameClientCallback);
+
+		/*
+		 * Call user level callback with an array of
+		 * buffers (NULL terminated)
+		 */
+		ixEthAccPortData[portId].ixEthAccRxData.
+		    rxMultiBufferCallbackFn(
+			    ixEthAccPortData[portId].ixEthAccRxData.
+			           rxMultiBufferCallbackTag,
+			    rxMbufPortArray[portId]);
+
+		/* reset the buffer pointer to the beginning of
+		 * the array
+		 */
+		rxMbufPtr[portId] = rxMbufPortArray[portId];
+	    }
+	}
+
+    } while (rxQReadStatus == IX_SUCCESS);
+}
+
+
+/**
+ * @brief  rxFree low event handler
+ *
+ */
+void ixEthRxFreeQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
+{
+    IxEthAccPortId	portId = (IxEthAccPortId) callbackId;
+    int		        lockVal;
+    UINT32		maxQWritesToPerform = IX_ETH_ACC_MAX_RX_FREE_BUFFERS_LOAD;
+    IX_STATUS	        qStatus = IX_SUCCESS;
+
+    /*
+     * We have reached a low threshold on one of the Rx Free Qs
+     */
+
+    /*note that due to the fact that we are working off an Empty threshold, this callback
+      need only write a single entry to the Rx Free queue in order to re-arm the notification
+    */
+
+    RX_STATS_INC(portId,rxFreeLowCallback);
+
+    /*
+     * Get buffers from approprite S/W Rx freeBufferList Q.
+     */
+
+#ifndef NDEBUG
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	ixEthAccDataStats.unexpectedError++;
+	IX_ETH_ACC_FATAL_LOG(
+	    "ixEthRxFreeQMCallback:Error: Invalid Port 0x%08X\n",
+	    portId, 0, 0, 0, 0, 0);
+	return;
+    }
+#endif
+    IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
+    if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
+					ixEthAccRxData.freeBufferList))
+    {
+	/*
+	 * Turn off Q callback notification for Q in Question.
+	 */
+	qStatus = ixQMgrNotificationDisable(
+	    IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
+
+
+	IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
+
+	if (qStatus != IX_SUCCESS)
+	{
+	    RX_INC(portId,rxUnexpectedError);
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthRxFreeQMCallback:Error: unexpected QM status 0x%08X\n",
+		qStatus, 0, 0, 0, 0, 0);
+	    return;
+	}
+    }
+    else
+    {
+	IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
+	/*
+	 * Load the H/W Q with buffers from the s/w Q.
+	 */
+
+	do
+	{
+	    /*
+	     * Consume Q entries. - Note Q contains Physical addresss,
+	     * and have already been flushed to memory,
+	     * And endianess converted if required.
+	     */
+	    if (ixEthAccRxFreeFromSwQ(portId) != IX_SUCCESS)
+	    {
+		/*
+		 * No more entries in s/w Q.
+		 * Turn off Q callback indication
+		 */
+
+		IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
+		if (IX_ETH_ACC_DATAPLANE_IS_Q_EMPTY(ixEthAccPortData[portId].
+		    ixEthAccRxData.freeBufferList))
+		{
+		    qStatus = ixQMgrNotificationDisable(
+			IX_ETH_ACC_PORT_TO_RX_FREE_Q_ID(portId));
+		}
+		IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
+		break;
+	    }
+	}
+	while (--maxQWritesToPerform);
+    }
+}
+/**
+ * @fn Tx queue low event handler
+ *
+ */
+void
+ixEthTxFrameQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
+{
+    IxEthAccPortId portId = (IxEthAccPortId) callbackId;
+    int		   lockVal;
+    UINT32	   maxQWritesToPerform = IX_ETH_ACC_MAX_TX_FRAME_TX_CONSUME_PER_CALLBACK;
+    IX_STATUS	   qStatus = IX_SUCCESS;
+    IxEthAccTxPriority highestPriority;
+
+
+    /*
+     * We have reached a low threshold on the Tx Q, and are being asked to
+     * supply a buffer for transmission from our S/W TX queues
+     */
+    TX_STATS_INC(portId,txLowThreshCallback);
+
+    /*
+     * Get buffers from approprite Q.
+     */
+
+#ifndef NDEBUG
+    if (!IX_ETH_ACC_IS_PORT_VALID(portId))
+    {
+	ixEthAccDataStats.unexpectedError++;
+	IX_ETH_ACC_FATAL_LOG(
+	    "ixEthTxFrameQMCallback:Error: Invalid Port 0x%08X\n",
+	    portId, 0, 0, 0, 0, 0);
+	return;
+    }
+#endif
+
+    do
+    {
+	/*
+	 * Consume Q entries. - Note Q contains Physical addresss,
+	 * and have already been flushed to memory,
+	 * and endianess already sone if required.
+	 */
+
+	IX_ETH_ACC_DATA_PLANE_LOCK(lockVal);
+
+	if(ixEthAccTxSwQHighestPriorityGet(portId, &highestPriority) ==
+	   IX_ETH_ACC_FAIL)
+	{
+	    /*
+	     * No more entries in s/w Q.
+	     * Turn off Q callback indication
+	     */
+	    qStatus = ixQMgrNotificationDisable(
+		IX_ETH_ACC_PORT_TO_TX_Q_ID(portId));
+
+	    IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
+
+	    if (qStatus != IX_SUCCESS)
+	    {
+		ixEthAccDataStats.unexpectedError++;
+		IX_ETH_ACC_FATAL_LOG(
+		    "ixEthTxFrameQMCallback:Error: unexpected QM status 0x%08X\n",
+		    qStatus, 0, 0, 0, 0, 0);
+	    }
+
+	    return;
+	}
+	else
+	{
+	    IX_ETH_ACC_DATA_PLANE_UNLOCK(lockVal);
+	    if (ixEthAccTxFromSwQ(portId,highestPriority)!=IX_SUCCESS)
+	    {
+                /* nothing left in the sw queue or the hw queues are
+                * full. There is no point to continue to drain the
+                * sw queues
+                */
+		return;
+	    }
+	}
+    }
+    while (--maxQWritesToPerform);
+}
+
+/**
+ * @brief TxDone event handler
+ *
+ * Design note : while processing the entry X, entry X+1 is preloaded
+ * into memory to reduce the number of stall cycles
+ *
+ */
+
+void
+ixEthTxFrameDoneQMCallback(IxQMgrQId qId, IxQMgrCallbackId callbackId)
+{
+    IX_OSAL_MBUF    *mbufPtr;
+    UINT32     qEntry;
+    UINT32     *qEntryPtr;
+    UINT32     txDoneQReadStatus;
+    UINT32     portId;
+    UINT32     npeId;
+
+    /*
+     * Design note : entries are read in a static buffer, This buffer contains
+     * an extra entyry (which is zeroed by the compiler), so the loop will
+     * always terminate on a null entry, whatever the result of Burst read is.
+     */
+    static UINT32 txDoneQEntry[IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK + 1];
+
+    /*
+     * Indication that Tx frames have been transmitted from the NPE.
+     */
+
+    IX_ETH_ACC_STATS_INC(ixEthAccDataStats.txDoneCallbackCounter);
+
+    do{
+	qEntryPtr = txDoneQEntry;
+	txDoneQReadStatus = ixQMgrQBurstRead(IX_ETH_ACC_TX_FRAME_DONE_ETH_Q,
+		     IX_ETH_ACC_MAX_TX_FRAME_DONE_CONSUME_PER_CALLBACK,
+		     qEntryPtr);
+
+#ifndef NDEBUG
+	if (txDoneQReadStatus != IX_QMGR_Q_UNDERFLOW
+	    && (txDoneQReadStatus != IX_SUCCESS))
+	{
+	    /*major error*/
+	    ixEthAccDataStats.unexpectedError++;
+	    IX_ETH_ACC_FATAL_LOG(
+		"ixEthTxFrameDoneQMCallback:Error: %u\n",
+		(UINT32)txDoneQReadStatus, 0, 0, 0, 0, 0);
+	    return;
+	}
+#endif
+
+	qEntry = *qEntryPtr;
+
+	while(qEntry != 0)
+	{
+	    mbufPtr = ixEthAccEntryFromQConvert(qEntry,
+		      IX_ETHNPE_QM_Q_TXENET_ADDR_MASK);
+
+#ifndef NDEBUG
+	    if (mbufPtr == NULL)
+	    {
+		ixEthAccDataStats.unexpectedError++;
+		IX_ETH_ACC_FATAL_LOG(
+		    "ixEthTxFrameDoneQMCallback:Error: Null Mbuf Ptr\n",
+		    0, 0, 0, 0, 0, 0);
+		return;
+	    }
+#endif
+
+	    /* endianness conversions and stats updates */
+	    ixEthAccMbufFromTxQ(mbufPtr);
+
+	    /*
+	     * Get NPE id from message, then convert to portId.
+	     */
+	    npeId = ((IX_ETHNPE_QM_Q_TXENETDONE_NPEID_MASK &
+		       qEntry) >>
+		      IX_ETHNPE_QM_Q_FIELD_NPEID_R);
+	    portId = IX_ETH_ACC_NPE_TO_PORT_ID(npeId);
+
+#ifndef NDEBUG
+	    /* Prudent to at least check the port is within range */
+	    if (portId >= IX_ETH_ACC_NUMBER_OF_PORTS)
+	    {
+		ixEthAccDataStats.unexpectedError++;
+		IX_ETH_ACC_FATAL_LOG(
+		    "ixEthTxFrameDoneQMCallback: Illegal port: %u\n",
+		    (UINT32)portId, 0, 0, 0, 0, 0);
+		return;
+	    }
+#endif
+
+	    TX_STATS_INC(portId,txDoneClientCallback);
+
+	    /*
+	     * Call user level callback.
+	     */
+	    ixEthAccPortData[portId].ixEthAccTxData.txBufferDoneCallbackFn(
+		ixEthAccPortData[portId].ixEthAccTxData.txCallbackTag,
+		mbufPtr);
+
+	    /* move to next queue entry */
+	    qEntry = *(++qEntryPtr);
+
+	}
+    } while( txDoneQReadStatus == IX_SUCCESS );
+}
+
+IX_ETH_ACC_PUBLIC
+void ixEthAccDataPlaneShow(void)
+{
+    UINT32 numTx0Entries;
+    UINT32 numTx1Entries;
+    UINT32 numTxDoneEntries;
+    UINT32 numRxEntries;
+    UINT32 numRxFree0Entries;
+    UINT32 numRxFree1Entries;
+    UINT32 portId;
+#ifdef __ixp46X
+    UINT32 numTx2Entries;
+    UINT32 numRxFree2Entries;
+#endif
+#ifndef NDEBUG
+    UINT32 priority;
+    UINT32 numBuffersInRx=0;
+    UINT32 numBuffersInTx=0;
+    UINT32 numBuffersInSwQ=0;
+    UINT32 totalBuffers=0;
+    UINT32 rxFreeCallbackCounter = 0;
+    UINT32 txCallbackCounter = 0;
+#endif
+    UINT32 key;
+
+    /* snapshot of stats */
+    IxEthAccTxDataStats tx[IX_ETH_ACC_NUMBER_OF_PORTS];
+    IxEthAccRxDataStats rx[IX_ETH_ACC_NUMBER_OF_PORTS];
+    IxEthAccDataPlaneStats stats;
+
+    if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED())
+    {
+	return;
+    }
+
+    /* get a reliable snapshot */
+    key = ixOsalIrqLock();
+
+    numTx0Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET0_Q, &numTx0Entries);
+    numTx1Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET1_Q, &numTx1Entries);
+    numTxDoneEntries = 0;
+    ixQMgrQNumEntriesGet( IX_ETH_ACC_TX_FRAME_DONE_ETH_Q, &numTxDoneEntries);
+    numRxEntries = 0;
+    ixEthAccQMgrRxQEntryGet(&numRxEntries);
+    numRxFree0Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q, &numRxFree0Entries);
+    numRxFree1Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q, &numRxFree1Entries);
+
+#ifdef __ixp46X
+    numTx2Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_TX_FRAME_ENET2_Q, &numTx2Entries);
+    numRxFree2Entries = 0;
+    ixQMgrQNumEntriesGet(IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q, &numRxFree2Entries);
+#endif
+
+    for(portId=IX_ETH_PORT_1; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+	memcpy(&tx[portId],
+	       &ixEthAccPortData[portId].ixEthAccTxData.stats,
+	       sizeof(tx[portId]));
+	memcpy(&rx[portId],
+	       &ixEthAccPortData[portId].ixEthAccRxData.stats,
+	       sizeof(rx[portId]));
+    }
+    memcpy(&stats, &ixEthAccDataStats, sizeof(stats));
+
+    ixOsalIrqUnlock(key);
+
+#ifdef NDEBUG
+    printf("Detailed statistics collection not supported in this load\n");
+#endif
+
+    /* print snapshot */
+    for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+        /* If not IXP42X A0 stepping, proceed to check for existence of coprocessors */
+        if ((IX_FEATURE_CTRL_SILICON_TYPE_A0 !=
+	     (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK))
+	    || (IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X != ixFeatureCtrlDeviceRead ()))
+        {
+                if ((IX_ETH_PORT_1 == portId) &&
+                    (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
+                     IX_FEATURE_CTRL_COMPONENT_DISABLED))
+                {
+                   continue ;
+                }
+                if ((IX_ETH_PORT_2 == portId) &&
+                    (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
+                     IX_FEATURE_CTRL_COMPONENT_DISABLED))
+                {
+                    continue ;
+                }
+                if ((IX_ETH_PORT_3 == portId) &&
+                    (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) ==
+                     IX_FEATURE_CTRL_COMPONENT_DISABLED))
+                {
+                    continue ;
+                }
+        }
+
+	printf("PORT %u --------------------------------\n",
+	       portId);
+#ifndef NDEBUG
+	printf("Tx Done Frames                : %u\n",
+	       tx[portId].txDoneClientCallback +
+	       tx[portId].txDoneSwQDuringDisable +
+	       tx[portId].txDoneDuringDisable);
+	printf("Tx Frames                     : %u\n",
+	       tx[portId].txQOK + tx[portId].txQDelayed);
+	printf("Tx H/W Q Added OK             : %u\n",
+	       tx[portId].txQOK);
+	printf("Tx H/W Q Delayed              : %u\n",
+	       tx[portId].txQDelayed);
+	printf("Tx From S/W Q Added OK        : %u\n",
+	       tx[portId].txFromSwQOK);
+	printf("Tx From S/W Q Delayed         : %u\n",
+	       tx[portId].txFromSwQDelayed);
+	printf("Tx Overflow                   : %u\n",
+	       tx[portId].txOverflow);
+	printf("Tx Mutual Lock                : %u\n",
+	       tx[portId].txLock);
+	printf("Tx Late Ntf Enabled           : %u\n",
+	       tx[portId].txLateNotificationEnabled);
+	printf("Tx Low Thresh CB              : %u\n",
+	       tx[portId].txLowThreshCallback);
+	printf("Tx Done from H/W Q (Disable)  : %u\n",
+	       tx[portId].txDoneDuringDisable);
+	printf("Tx Done from S/W Q (Disable)  : %u\n",
+	       tx[portId].txDoneSwQDuringDisable);
+	for (priority = IX_ETH_ACC_TX_PRIORITY_0;
+	     priority <= IX_ETH_ACC_TX_PRIORITY_7;
+	     priority++)
+	{
+	    if (tx[portId].txPriority[priority])
+	    {
+		printf("Tx Priority %u                 : %u\n",
+		       priority,
+		       tx[portId].txPriority[priority]);
+	    }
+	}
+#endif
+	printf("Tx unexpected errors          : %u (should be 0)\n",
+	       tx[portId].txUnexpectedError);
+
+#ifndef NDEBUG
+	printf("Rx Frames                     : %u\n",
+	       rx[portId].rxFrameClientCallback +
+	       rx[portId].rxSwQDuringDisable+
+	       rx[portId].rxDuringDisable);
+	printf("Rx Free Replenish             : %u\n",
+	       rx[portId].rxFreeRepOK + rx[portId].rxFreeRepDelayed);
+	printf("Rx Free H/W Q Added OK        : %u\n",
+	       rx[portId].rxFreeRepOK);
+	printf("Rx Free H/W Q Delayed         : %u\n",
+	       rx[portId].rxFreeRepDelayed);
+	printf("Rx Free From S/W Q Added OK   : %u\n",
+	       rx[portId].rxFreeRepFromSwQOK);
+	printf("Rx Free From S/W Q Delayed    : %u\n",
+	       rx[portId].rxFreeRepFromSwQDelayed);
+	printf("Rx Free Overflow              : %u\n",
+	       rx[portId].rxFreeOverflow);
+	printf("Rx Free Mutual Lock           : %u\n",
+	       rx[portId].rxFreeLock);
+	printf("Rx Free Late Ntf Enabled      : %u\n",
+	       rx[portId].rxFreeLateNotificationEnabled);
+	printf("Rx Free Low CB                : %u\n",
+	       rx[portId].rxFreeLowCallback);
+	printf("Rx From H/W Q (Disable)       : %u\n",
+	       rx[portId].rxDuringDisable);
+	printf("Rx From S/W Q (Disable)       : %u\n",
+	       rx[portId].rxSwQDuringDisable);
+	printf("Rx unlearned Mac Address      : %u\n",
+	       rx[portId].rxUnlearnedMacAddress);
+        printf("Rx Filtered (Rx => RxFree)    : %u\n",
+            rx[portId].rxFiltered);
+
+	for (priority = IX_ETH_ACC_TX_PRIORITY_0;
+	     priority <= IX_ETH_ACC_TX_PRIORITY_7;
+	     priority++)
+	{
+	    if (rx[portId].rxPriority[priority])
+	    {
+		printf("Rx Priority %u                 : %u\n",
+		       priority,
+		       rx[portId].rxPriority[priority]);
+	    }
+	}
+#endif
+	printf("Rx unexpected errors          : %u (should be 0)\n",
+	       rx[portId].rxUnexpectedError);
+
+#ifndef NDEBUG
+	numBuffersInTx = tx[portId].txQOK +
+	    tx[portId].txQDelayed -
+	    tx[portId].txDoneClientCallback -
+	    tx[portId].txDoneSwQDuringDisable -
+	    tx[portId].txDoneDuringDisable;
+
+	printf("# Tx Buffers currently for transmission : %u\n",
+	       numBuffersInTx);
+
+	numBuffersInRx = rx[portId].rxFreeRepOK +
+	    rx[portId].rxFreeRepDelayed -
+	    rx[portId].rxFrameClientCallback -
+	    rx[portId].rxSwQDuringDisable -
+	    rx[portId].rxDuringDisable;
+
+	printf("# Rx Buffers currently for reception    : %u\n",
+	       numBuffersInRx);
+
+	totalBuffers += numBuffersInRx + numBuffersInTx;
+#endif
+    }
+
+    printf("---------------------------------------\n");
+
+#ifndef NDEBUG
+    printf("\n");
+    printf("Mbufs :\n");
+    printf("Tx Unchained mbufs            : %u\n",
+	   stats.unchainedTxMBufs);
+    printf("Tx Chained bufs               : %u\n",
+	   stats.chainedTxMBufs);
+    printf("TxDone Unchained mbufs        : %u\n",
+	   stats.unchainedTxDoneMBufs);
+    printf("TxDone Chained bufs           : %u\n",
+	   stats.chainedTxDoneMBufs);
+    printf("RxFree Unchained mbufs        : %u\n",
+	   stats.unchainedRxFreeMBufs);
+    printf("RxFree Chained bufs           : %u\n",
+	   stats.chainedRxFreeMBufs);
+    printf("Rx Unchained mbufs            : %u\n",
+	   stats.unchainedRxMBufs);
+    printf("Rx Chained bufs               : %u\n",
+	   stats.chainedRxMBufs);
+
+    printf("\n");
+    printf("Software queue usage :\n");
+    printf("Buffers added to S/W Q        : %u\n",
+	   stats.addToSwQ);
+    printf("Buffers removed from S/W Q    : %u\n",
+	   stats.removeFromSwQ);
+
+    printf("\n");
+    printf("Hardware queues callbacks :\n");
+
+    for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+	rxFreeCallbackCounter += rx[portId].rxFreeLowCallback;
+	txCallbackCounter += tx[portId].txLowThreshCallback;
+    }
+    printf("Tx Done QM Callback invoked   : %u\n",
+	   stats.txDoneCallbackCounter);
+    printf("Tx QM Callback invoked        : %u\n",
+	   txCallbackCounter);
+    printf("Rx QM Callback invoked        : %u\n",
+	   stats.rxCallbackCounter);
+    printf("Rx QM Callback burst read     : %u\n",
+	   stats.rxCallbackBurstRead);
+    printf("Rx Free QM Callback invoked   : %u\n",
+	   rxFreeCallbackCounter);
+#endif
+    printf("Unexpected errors in CB       : %u (should be 0)\n",
+	   stats.unexpectedError);
+    printf("\n");
+
+    printf("Hardware queues levels :\n");
+    printf("Transmit Port 1 Q             : %u \n",numTx0Entries);
+    printf("Transmit Port 2 Q             : %u \n",numTx1Entries);
+#ifdef __ixp46X
+    printf("Transmit Port 3 Q             : %u \n",numTx2Entries);
+#endif
+    printf("Transmit Done Q               : %u \n",numTxDoneEntries);
+    printf("Receive Q                     : %u \n",numRxEntries);
+    printf("Receive Free Port 1 Q         : %u \n",numRxFree0Entries);
+    printf("Receive Free Port 2 Q         : %u \n",numRxFree1Entries);
+#ifdef __ixp46X
+    printf("Receive Free Port 3 Q         : %u \n",numRxFree2Entries);
+#endif
+
+#ifndef NDEBUG
+    printf("\n");
+    printf("# Total Buffers accounted for : %u\n",
+	   totalBuffers);
+
+    numBuffersInSwQ = ixEthAccDataStats.addToSwQ -
+	ixEthAccDataStats.removeFromSwQ;
+
+    printf("    Buffers in S/W Qs         : %u\n",
+	   numBuffersInSwQ);
+    printf("    Buffers in H/W Qs or NPEs : %u\n",
+	   totalBuffers - numBuffersInSwQ);
+#endif
+
+    printf("Rx QoS Discipline             : %s\n",
+	   (ixEthAccDataInfo.schDiscipline ==
+	    FIFO_PRIORITY ) ? "Enabled" : "Disabled");
+
+    for(portId=0; portId < IX_ETH_ACC_NUMBER_OF_PORTS; portId++)
+    {
+	printf("Tx QoS Discipline port %u      : %s\n",
+	       portId,
+	       (ixEthAccPortData[portId].ixEthAccTxData.schDiscipline ==
+		FIFO_PRIORITY ) ? "Enabled" : "Disabled");
+    }
+    printf("\n");
+}
+
+
+
+
+