* 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/IxEthAccCommon.c b/cpu/ixp/npe/IxEthAccCommon.c
new file mode 100644
index 0000000..bda2c44
--- /dev/null
+++ b/cpu/ixp/npe/IxEthAccCommon.c
@@ -0,0 +1,1049 @@
+/**
+ * @file IxEthAccCommon.c
+ *
+ * @author Intel Corporation
+ * @date 12-Feb-2002
+ *
+ * @brief This file contains the implementation common support routines for the 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 --
+ */
+
+/*
+ * Component header files
+ */
+
+#include "IxOsal.h"
+#include "IxEthAcc.h"
+#include "IxEthDB.h"
+#include "IxNpeMh.h"
+#include "IxEthDBPortDefs.h"
+#include "IxFeatureCtrl.h"
+#include "IxEthAcc_p.h"
+#include "IxEthAccQueueAssign_p.h"
+
+#include "IxEthAccDataPlane_p.h"
+#include "IxEthAccMii_p.h"
+
+/**
+ * @addtogroup IxEthAccPri
+ *@{
+ */
+
+extern IxEthAccInfo ixEthAccDataInfo;
+
+/**
+ *
+ * @brief Maximum number of RX queues set to be the maximum number
+ * of traffic calsses.
+ *
+ */
+#define IX_ETHACC_MAX_RX_QUEUES \
+ (IX_ETH_DB_QOS_TRAFFIC_CLASS_7_RX_QUEUE_PROPERTY \
+ - IX_ETH_DB_QOS_TRAFFIC_CLASS_0_RX_QUEUE_PROPERTY \
+ + 1)
+
+/**
+ *
+ * @brief Maximum number of 128 entry RX queues
+ *
+ */
+#define IX_ETHACC_MAX_LARGE_RX_QUEUES 4
+
+/**
+ *
+ * @brief Data structure template for Default RX Queues
+ *
+ */
+IX_ETH_ACC_PRIVATE
+IxEthAccQregInfo ixEthAccQmgrRxDefaultTemplate =
+ {
+ IX_ETH_ACC_RX_FRAME_ETH_Q, /**< Queue ID */
+ "Eth Rx Q",
+ ixEthRxFrameQMCallback, /**< Functional callback */
+ (IxQMgrCallbackId) 0, /**< Callback tag */
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ TRUE, /**< Enable Q notification at startup */
+ IX_ETH_ACC_RX_FRAME_ETH_Q_SOURCE,/**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL1, /**< Q High water mark - needed by NPE */
+ };
+
+/**
+ *
+ * @brief Data structure template for Small RX Queues
+ *
+ */
+IX_ETH_ACC_PRIVATE
+IxEthAccQregInfo ixEthAccQmgrRxSmallTemplate =
+ {
+ IX_ETH_ACC_RX_FRAME_ETH_Q, /**< Queue ID */
+ "Eth Rx Q",
+ ixEthRxFrameQMCallback, /**< Functional callback */
+ (IxQMgrCallbackId) 0, /**< Callback tag */
+ IX_QMGR_Q_SIZE64, /**< Allocate Smaller Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ TRUE, /**< Enable Q notification at startup */
+ IX_ETH_ACC_RX_FRAME_ETH_Q_SOURCE,/**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL1, /**< Q High water mark - needed by NPE */
+ };
+
+
+/**
+ *
+ * @brief Data structure used to register & initialize the Queues
+ *
+ */
+IX_ETH_ACC_PRIVATE
+IxEthAccQregInfo ixEthAccQmgrStaticInfo[]=
+{
+ {
+ IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q,
+ "Eth Rx Fr Q 1",
+ ixEthRxFreeQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_1,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ FALSE, /**< Disable Q notification at startup */
+ IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /***< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL64, /**< Q High water mark */
+ },
+
+ {
+ IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q,
+ "Eth Rx Fr Q 2",
+ ixEthRxFreeQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_2,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ FALSE, /**< Disable Q notification at startup */
+ IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL64, /**< Q High water mark */
+ },
+#ifdef __ixp46X
+ {
+ IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q,
+ "Eth Rx Fr Q 3",
+ ixEthRxFreeQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_3,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ FALSE, /**< Disable Q notification at startup */
+ IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL64, /**< Q High water mark */
+ },
+#endif
+ {
+ IX_ETH_ACC_TX_FRAME_ENET0_Q,
+ "Eth Tx Q 1",
+ ixEthTxFrameQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_1,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ FALSE, /**< Disable Q notification at startup */
+ IX_ETH_ACC_TX_FRAME_ENET0_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL64, /**< Q High water mark */
+ },
+
+ {
+ IX_ETH_ACC_TX_FRAME_ENET1_Q,
+ "Eth Tx Q 2",
+ ixEthTxFrameQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_2,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ FALSE, /**< Disable Q notification at startup */
+ IX_ETH_ACC_TX_FRAME_ENET1_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL64, /**< Q High water mark */
+ },
+#ifdef __ixp46X
+ {
+ IX_ETH_ACC_TX_FRAME_ENET2_Q,
+ "Eth Tx Q 3",
+ ixEthTxFrameQMCallback,
+ (IxQMgrCallbackId) IX_ETH_PORT_3,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /** Queue Entry Sizes - all Q entries are single ord entries */
+ FALSE, /** Disable Q notification at startup */
+ IX_ETH_ACC_TX_FRAME_ENET2_Q_SOURCE, /** Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /* No queues use almost empty */
+ IX_QMGR_Q_WM_LEVEL64, /** Q High water mark - needed used */
+ },
+#endif
+ {
+ IX_ETH_ACC_TX_FRAME_DONE_ETH_Q,
+ "Eth Tx Done Q",
+ ixEthTxFrameDoneQMCallback,
+ (IxQMgrCallbackId) 0,
+ IX_QMGR_Q_SIZE128, /**< Allocate Max Size Q */
+ IX_QMGR_Q_ENTRY_SIZE1, /**< Queue Entry Sizes - all Q entries are single word entries */
+ TRUE, /**< Enable Q notification at startup */
+ IX_ETH_ACC_TX_FRAME_DONE_ETH_Q_SOURCE, /**< Q Condition to drive callback */
+ IX_QMGR_Q_WM_LEVEL0, /**< Q Low water mark */
+ IX_QMGR_Q_WM_LEVEL2, /**< Q High water mark - needed by NPE */
+ },
+
+ { /* Null Termination entry
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }
+
+};
+
+/**
+ *
+ * @brief Data structure used to register & initialize the Queues
+ *
+ * The structure will be filled at run time depending on the NPE
+ * image already loaded and the QoS configured in ethDB.
+ *
+ */
+IX_ETH_ACC_PRIVATE
+IxEthAccQregInfo ixEthAccQmgrRxQueuesInfo[IX_ETHACC_MAX_RX_QUEUES+1]=
+{
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* PlaceHolder for rx queues
+ * depending on the QoS configured
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+
+ { /* Null Termination entry
+ */
+ (IxQMgrQId)0,
+ (char *) NULL,
+ (IxQMgrCallback) NULL,
+ (IxQMgrCallbackId) 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }
+
+};
+
+/* forward declarations */
+IX_ETH_ACC_PRIVATE IxEthAccStatus
+ixEthAccQMgrQueueSetup(IxEthAccQregInfo *qInfoDes);
+
+/**
+ * @fn ixEthAccQMgrQueueSetup(void)
+ *
+ * @brief Setup one queue and its event, and register the callback required
+ * by this component to the QMgr
+ *
+ * @internal
+ */
+IX_ETH_ACC_PRIVATE IxEthAccStatus
+ixEthAccQMgrQueueSetup(IxEthAccQregInfo *qInfoDes)
+{
+ /*
+ * Configure each Q.
+ */
+ if ( ixQMgrQConfig( qInfoDes->qName,
+ qInfoDes->qId,
+ qInfoDes->qSize,
+ qInfoDes->qWords) != IX_SUCCESS)
+ {
+ return IX_ETH_ACC_FAIL;
+ }
+
+ if ( ixQMgrWatermarkSet( qInfoDes->qId,
+ qInfoDes->AlmostEmptyThreshold,
+ qInfoDes->AlmostFullThreshold
+ ) != IX_SUCCESS)
+ {
+ return IX_ETH_ACC_FAIL;
+ }
+
+ /*
+ * Set dispatcher priority.
+ */
+ if ( ixQMgrDispatcherPrioritySet( qInfoDes->qId,
+ IX_ETH_ACC_QM_QUEUE_DISPATCH_PRIORITY)
+ != IX_SUCCESS)
+ {
+ return IX_ETH_ACC_FAIL;
+ }
+
+ /*
+ * Register callbacks for each Q.
+ */
+ if ( ixQMgrNotificationCallbackSet(qInfoDes->qId,
+ qInfoDes->qCallback,
+ qInfoDes->callbackTag)
+ != IX_SUCCESS )
+ {
+ return IX_ETH_ACC_FAIL;
+ }
+
+ /*
+ * Set notification condition for Q
+ */
+ if ( qInfoDes->qNotificationEnableAtStartup == TRUE )
+ {
+ if ( ixQMgrNotificationEnable(qInfoDes->qId,
+ qInfoDes->qConditionSource)
+ != IX_SUCCESS )
+ {
+ return IX_ETH_ACC_FAIL;
+ }
+ }
+
+ return(IX_ETH_ACC_SUCCESS);
+}
+
+/**
+ * @fn ixEthAccQMgrQueuesConfig(void)
+ *
+ * @brief Setup all the queues and register all callbacks required
+ * by this component to the QMgr
+ *
+ * The RxFree queues, tx queues, rx queues are configured statically
+ *
+ * Rx queues configuration is driven by QoS setup.
+ * Many Rx queues may be required when QoS is enabled (this depends
+ * on IxEthDB setup and the images being downloaded). The configuration
+ * of the rxQueues is done in many steps as follows:
+ *
+ * @li select all Rx queues as configured by ethDB for all ports
+ * @li sort the queues by traffic class
+ * @li build the priority dependency for all queues
+ * @li fill the configuration for all rx queues
+ * @li configure all statically configured queues
+ * @li configure all dynamically configured queues
+ *
+ * @param none
+ *
+ * @return IxEthAccStatus
+ *
+ * @internal
+ */
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccQMgrQueuesConfig(void)
+{
+ struct
+ {
+ int npeCount;
+ UINT32 npeId;
+ IxQMgrQId qId;
+ IxEthDBProperty trafficClass;
+ } rxQueues[IX_ETHACC_MAX_RX_QUEUES];
+
+ UINT32 rxQueue = 0;
+ UINT32 rxQueueCount = 0;
+ IxQMgrQId ixQId =IX_QMGR_MAX_NUM_QUEUES;
+ IxEthDBStatus ixEthDBStatus = IX_ETH_DB_SUCCESS;
+ IxEthDBPortId ixEthDbPortId = 0;
+ IxEthAccPortId ixEthAccPortId = 0;
+ UINT32 ixNpeId = 0;
+ UINT32 ixHighestNpeId = 0;
+ UINT32 sortIterations = 0;
+ IxEthAccStatus ret = IX_ETH_ACC_SUCCESS;
+ IxEthAccQregInfo *qInfoDes = NULL;
+ IxEthDBProperty ixEthDBTrafficClass = IX_ETH_DB_QOS_TRAFFIC_CLASS_0_RX_QUEUE_PROPERTY;
+ IxEthDBPropertyType ixEthDBPropertyType = IX_ETH_DB_INTEGER_PROPERTY;
+ UINT32 ixEthDBParameter = 0;
+ BOOL completelySorted = FALSE;
+
+ /* Fill the corspondance between ports and queues
+ * This defines the mapping from port to queue Ids.
+ */
+
+ ixEthAccPortData[IX_ETH_PORT_1].ixEthAccRxData.rxFreeQueue
+ = IX_ETH_ACC_RX_FREE_BUFF_ENET0_Q;
+ ixEthAccPortData[IX_ETH_PORT_2].ixEthAccRxData.rxFreeQueue
+ = IX_ETH_ACC_RX_FREE_BUFF_ENET1_Q;
+#ifdef __ixp46X
+ ixEthAccPortData[IX_ETH_PORT_3].ixEthAccRxData.rxFreeQueue
+ = IX_ETH_ACC_RX_FREE_BUFF_ENET2_Q;
+#endif
+ ixEthAccPortData[IX_ETH_PORT_1].ixEthAccTxData.txQueue
+ = IX_ETH_ACC_TX_FRAME_ENET0_Q;
+ ixEthAccPortData[IX_ETH_PORT_2].ixEthAccTxData.txQueue
+ = IX_ETH_ACC_TX_FRAME_ENET1_Q;
+#ifdef __ixp46X
+ ixEthAccPortData[IX_ETH_PORT_3].ixEthAccTxData.txQueue
+ = IX_ETH_ACC_TX_FRAME_ENET2_Q;
+#endif
+ /* Fill the corspondance between ports and NPEs
+ * This defines the mapping from port to npeIds.
+ */
+
+ ixEthAccPortData[IX_ETH_PORT_1].npeId = IX_NPEMH_NPEID_NPEB;
+ ixEthAccPortData[IX_ETH_PORT_2].npeId = IX_NPEMH_NPEID_NPEC;
+#ifdef __ixp46X
+ ixEthAccPortData[IX_ETH_PORT_3].npeId = IX_NPEMH_NPEID_NPEA;
+#endif
+ /* set the default rx scheduling discipline */
+ ixEthAccDataInfo.schDiscipline = FIFO_NO_PRIORITY;
+
+ /*
+ * Queue Selection step:
+ *
+ * The following code selects all the queues and build
+ * a temporary array which contains for each queue
+ * - the queue Id,
+ * - the highest traffic class (in case of many
+ * priorities configured for the same queue on different
+ * ports)
+ * - the number of different Npes which are
+ * configured to write to this queue.
+ *
+ * The output of this loop is a temporary array of RX queues
+ * in any order.
+ *
+ */
+#ifdef CONFIG_IXP425_COMPONENT_ETHDB
+ for (ixEthAccPortId = 0;
+ (ixEthAccPortId < IX_ETH_ACC_NUMBER_OF_PORTS)
+ && (ret == IX_ETH_ACC_SUCCESS);
+ ixEthAccPortId++)
+ {
+ /* map between ethDb and ethAcc port Ids */
+ ixEthDbPortId = (IxEthDBPortId)ixEthAccPortId;
+
+ /* map between npeId and ethAcc port Ids */
+ ixNpeId = IX_ETH_ACC_PORT_TO_NPE_ID(ixEthAccPortId);
+
+ /* Iterate thru the different priorities */
+ for (ixEthDBTrafficClass = IX_ETH_DB_QOS_TRAFFIC_CLASS_0_RX_QUEUE_PROPERTY;
+ ixEthDBTrafficClass <= IX_ETH_DB_QOS_TRAFFIC_CLASS_7_RX_QUEUE_PROPERTY;
+ ixEthDBTrafficClass++)
+ {
+ ixEthDBStatus = ixEthDBFeaturePropertyGet(
+ ixEthDbPortId,
+ IX_ETH_DB_VLAN_QOS,
+ ixEthDBTrafficClass,
+ &ixEthDBPropertyType,
+ (void *)&ixEthDBParameter);
+
+ if (ixEthDBStatus == IX_ETH_DB_SUCCESS)
+ {
+ /* This port and QoS class are mapped to
+ * a RX queue.
+ */
+ if (ixEthDBPropertyType == IX_ETH_DB_INTEGER_PROPERTY)
+ {
+ /* remember the highest npe Id supporting ethernet */
+ if (ixNpeId > ixHighestNpeId)
+ {
+ ixHighestNpeId = ixNpeId;
+ }
+
+ /* search the queue in the list of queues
+ * already used by an other port or QoS
+ */
+ for (rxQueue = 0;
+ rxQueue < rxQueueCount;
+ rxQueue++)
+ {
+ if (rxQueues[rxQueue].qId == (IxQMgrQId)ixEthDBParameter)
+ {
+ /* found an existing setup, update the number of ports
+ * for this queue if the port maps to
+ * a different NPE.
+ */
+ if (rxQueues[rxQueue].npeId != ixNpeId)
+ {
+ rxQueues[rxQueue].npeCount++;
+ rxQueues[rxQueue].npeId = ixNpeId;
+ }
+ /* get the highest traffic class for this queue */
+ if (rxQueues[rxQueue].trafficClass > ixEthDBTrafficClass)
+ {
+ rxQueues[rxQueue].trafficClass = ixEthDBTrafficClass;
+ }
+ break;
+ }
+ }
+ if (rxQueue == rxQueueCount)
+ {
+ /* new queue not found in the current list,
+ * add a new entry.
+ */
+ IX_OSAL_ASSERT(rxQueueCount < IX_ETHACC_MAX_RX_QUEUES);
+ rxQueues[rxQueueCount].qId = ixEthDBParameter;
+ rxQueues[rxQueueCount].npeCount = 1;
+ rxQueues[rxQueueCount].npeId = ixNpeId;
+ rxQueues[rxQueueCount].trafficClass = ixEthDBTrafficClass;
+ rxQueueCount++;
+ }
+ }
+ else
+ {
+ /* unexpected property type (not Integer) */
+ ret = IX_ETH_ACC_FAIL;
+
+ IX_ETH_ACC_WARNING_LOG("ixEthAccQMgrQueuesConfig: unexpected property type returned by EthDB\n", 0, 0, 0, 0, 0, 0);
+
+ /* no point to continue to iterate */
+ break;
+ }
+ }
+ else
+ {
+ /* No Rx queue configured for this port
+ * and this traffic class. Do nothing.
+ */
+ }
+ }
+
+ /* notify EthDB that queue initialization is complete and traffic class allocation is frozen */
+ ixEthDBFeaturePropertySet(ixEthDbPortId,
+ IX_ETH_DB_VLAN_QOS,
+ IX_ETH_DB_QOS_QUEUE_CONFIGURATION_COMPLETE,
+ NULL /* ignored */);
+ }
+
+#else
+
+ ixNpeId = IX_ETH_ACC_PORT_TO_NPE_ID(ixEthAccPortId);
+ rxQueues[0].qId = 4;
+ rxQueues[0].npeCount = 1;
+ rxQueues[0].npeId = ixNpeId;
+ rxQueues[0].trafficClass = IX_ETH_DB_QOS_TRAFFIC_CLASS_0_RX_QUEUE_PROPERTY;
+ rxQueueCount++;
+
+#endif
+
+ /* check there is at least 1 rx queue : there is no point
+ * to continue if there is no rx queue configured
+ */
+ if ((rxQueueCount == 0) || (ret == IX_ETH_ACC_FAIL))
+ {
+ IX_ETH_ACC_WARNING_LOG("ixEthAccQMgrQueuesConfig: no queues configured, bailing out\n", 0, 0, 0, 0, 0, 0);
+ return (IX_ETH_ACC_FAIL);
+ }
+
+ /* Queue sort step:
+ *
+ * Re-order the array of queues by decreasing traffic class
+ * using a bubble sort. (trafficClass 0 is the lowest
+ * priority traffic, trafficClass 7 is the highest priority traffic)
+ *
+ * Primary sort order is traffic class
+ * Secondary sort order is npeId
+ *
+ * Note that a bubble sort algorithm is not very efficient when
+ * the number of queues grows . However, this is not a very bad choice
+ * considering the very small number of entries to sort. Also, bubble
+ * sort is extremely fast when the list is already sorted.
+ *
+ * The output of this loop is a sorted array of queues.
+ *
+ */
+ sortIterations = 0;
+ do
+ {
+ sortIterations++;
+ completelySorted = TRUE;
+ for (rxQueue = 0;
+ rxQueue < rxQueueCount - sortIterations;
+ rxQueue++)
+ {
+ /* compare adjacent elements */
+ if ((rxQueues[rxQueue].trafficClass <
+ rxQueues[rxQueue+1].trafficClass)
+ || ((rxQueues[rxQueue].trafficClass ==
+ rxQueues[rxQueue+1].trafficClass)
+ &&(rxQueues[rxQueue].npeId <
+ rxQueues[rxQueue+1].npeId)))
+ {
+ /* swap adjacent elements */
+ int npeCount = rxQueues[rxQueue].npeCount;
+ UINT32 npeId = rxQueues[rxQueue].npeId;
+ IxQMgrQId qId = rxQueues[rxQueue].qId;
+ IxEthDBProperty trafficClass = rxQueues[rxQueue].trafficClass;
+ rxQueues[rxQueue].npeCount = rxQueues[rxQueue+1].npeCount;
+ rxQueues[rxQueue].npeId = rxQueues[rxQueue+1].npeId;
+ rxQueues[rxQueue].qId = rxQueues[rxQueue+1].qId;
+ rxQueues[rxQueue].trafficClass = rxQueues[rxQueue+1].trafficClass;
+ rxQueues[rxQueue+1].npeCount = npeCount;
+ rxQueues[rxQueue+1].npeId = npeId;
+ rxQueues[rxQueue+1].qId = qId;
+ rxQueues[rxQueue+1].trafficClass = trafficClass;
+ completelySorted = FALSE;
+ }
+ }
+ }
+ while (!completelySorted);
+
+ /* Queue traffic class list:
+ *
+ * Fill an array of rx queues linked by ascending traffic classes.
+ *
+ * If the queues are configured as follows
+ * qId 6 -> traffic class 0 (lowest)
+ * qId 7 -> traffic class 0
+ * qId 8 -> traffic class 6
+ * qId 12 -> traffic class 7 (highest)
+ *
+ * Then the output of this loop will be
+ *
+ * higherPriorityQueue[6] = 8
+ * higherPriorityQueue[7] = 8
+ * higherPriorityQueue[8] = 12
+ * higherPriorityQueue[12] = Invalid queueId
+ * higherPriorityQueue[...] = Invalid queueId
+ *
+ * Note that this queue ordering does not handle all possibilities
+ * that could result from different rules associated with different
+ * ports, and inconsistencies in the rules. In all cases, the
+ * output of this algorithm is a simple linked list of queues,
+ * without closed circuit.
+
+ * This list is implemented as an array with invalid values initialized
+ * with an "invalid" queue id which is the maximum number of queues.
+ *
+ */
+
+ /*
+ * Initialise the rx queue list.
+ */
+ for (rxQueue = 0; rxQueue < IX_QMGR_MAX_NUM_QUEUES; rxQueue++)
+ {
+ ixEthAccDataInfo.higherPriorityQueue[rxQueue] = IX_QMGR_MAX_NUM_QUEUES;
+ }
+
+ /* build the linked list for this NPE.
+ */
+ for (ixNpeId = 0;
+ ixNpeId <= ixHighestNpeId;
+ ixNpeId++)
+ {
+ /* iterate thru the sorted list of queues
+ */
+ ixQId = IX_QMGR_MAX_NUM_QUEUES;
+ for (rxQueue = 0;
+ rxQueue < rxQueueCount;
+ rxQueue++)
+ {
+ if (rxQueues[rxQueue].npeId == ixNpeId)
+ {
+ ixEthAccDataInfo.higherPriorityQueue[rxQueues[rxQueue].qId] = ixQId;
+ /* iterate thru queues with the same traffic class
+ * than the current queue. (queues are ordered by descending
+ * traffic classes and npeIds).
+ */
+ while ((rxQueue < rxQueueCount - 1)
+ && (rxQueues[rxQueue].trafficClass
+ == rxQueues[rxQueue+1].trafficClass)
+ && (ixNpeId == rxQueues[rxQueue].npeId))
+ {
+ rxQueue++;
+ ixEthAccDataInfo.higherPriorityQueue[rxQueues[rxQueue].qId] = ixQId;
+ }
+ ixQId = rxQueues[rxQueue].qId;
+ }
+ }
+ }
+
+ /* point on the first dynamic queue description */
+ qInfoDes = ixEthAccQmgrRxQueuesInfo;
+
+ /* update the list of queues with the rx queues */
+ for (rxQueue = 0;
+ (rxQueue < rxQueueCount) && (ret == IX_ETH_ACC_SUCCESS);
+ rxQueue++)
+ {
+ /* Don't utilize more than IX_ETHACC_MAX_LARGE_RX_QUEUES queues
+ * with the full 128 entries. For the lower priority queues, use
+ * a smaller number of entries. This ensures queue resources
+ * remain available for other components.
+ */
+ if( (rxQueueCount > IX_ETHACC_MAX_LARGE_RX_QUEUES) &&
+ (rxQueue < rxQueueCount - IX_ETHACC_MAX_LARGE_RX_QUEUES) )
+ {
+ /* add the small RX Queue setup template to the list of queues */
+ memcpy(qInfoDes, &ixEthAccQmgrRxSmallTemplate, sizeof(*qInfoDes));
+ } else {
+ /* add the default RX Queue setup template to the list of queues */
+ memcpy(qInfoDes, &ixEthAccQmgrRxDefaultTemplate, sizeof(*qInfoDes));
+ }
+
+ /* setup the RxQueue ID */
+ qInfoDes->qId = rxQueues[rxQueue].qId;
+
+ /* setup the RxQueue watermark level
+ *
+ * Each queue can be filled by many NPEs. To avoid the
+ * NPEs to write to a full queue, need to set the
+ * high watermark level for nearly full condition.
+ * (the high watermark level are a power of 2
+ * starting from the top of the queue)
+ *
+ * Number of watermark
+ * ports level
+ * 1 0
+ * 2 1
+ * 3 2
+ * 4 4
+ * 5 4
+ * 6 8
+ * n approx. 2**ceil(log2(n))
+ */
+ if (rxQueues[rxQueue].npeCount == 1)
+ {
+ qInfoDes->AlmostFullThreshold = IX_QMGR_Q_WM_LEVEL0;
+ }
+ else if (rxQueues[rxQueue].npeCount == 2)
+ {
+ qInfoDes->AlmostFullThreshold = IX_QMGR_Q_WM_LEVEL1;
+ }
+ else if (rxQueues[rxQueue].npeCount == 3)
+ {
+ qInfoDes->AlmostFullThreshold = IX_QMGR_Q_WM_LEVEL2;
+ }
+ else
+ {
+ /* reach the maximum number for CSR 2.0 */
+ IX_ETH_ACC_WARNING_LOG("ixEthAccQMgrQueuesConfig: maximum number of NPEs per queue reached, bailing out\n", 0, 0, 0, 0, 0, 0);
+ ret = IX_ETH_ACC_FAIL;
+ break;
+ }
+
+ /* move to next queue entry */
+ ++qInfoDes;
+ }
+
+ /* configure the static list (RxFree, Tx and TxDone queues) */
+ for (qInfoDes = ixEthAccQmgrStaticInfo;
+ (qInfoDes->qCallback != (IxQMgrCallback) NULL )
+ && (ret == IX_ETH_ACC_SUCCESS);
+ ++qInfoDes)
+ {
+ ret = ixEthAccQMgrQueueSetup(qInfoDes);
+ }
+
+ /* configure the dynamic list (Rx queues) */
+ for (qInfoDes = ixEthAccQmgrRxQueuesInfo;
+ (qInfoDes->qCallback != (IxQMgrCallback) NULL )
+ && (ret == IX_ETH_ACC_SUCCESS);
+ ++qInfoDes)
+ {
+ ret = ixEthAccQMgrQueueSetup(qInfoDes);
+ }
+
+ return(ret);
+}
+
+/**
+ * @fn ixEthAccQMgrRxQEntryGet(UINT32 *rxQueueEntries)
+ *
+ * @brief Add and return the total number of entries in all Rx queues
+ *
+ * @param UINT32 rxQueueEntries[in] number of entries in all queues
+ *
+ * @return void
+ *
+ * @note Rx queues configuration is driven by Qos Setup. There is a
+ * variable number of rx queues which are set at initialisation.
+ *
+ * @internal
+ */
+IX_ETH_ACC_PUBLIC
+void ixEthAccQMgrRxQEntryGet(UINT32 *numRxQueueEntries)
+{
+ UINT32 rxQueueLevel;
+ IxEthAccQregInfo *qInfoDes;;
+
+ *numRxQueueEntries = 0;
+
+ /* iterate thru rx queues */
+ for (qInfoDes = ixEthAccQmgrRxQueuesInfo;
+ qInfoDes->qCallback != (IxQMgrCallback)NULL;
+ ++qInfoDes)
+ {
+ /* retrieve the rx queue level */
+ rxQueueLevel = 0;
+ ixQMgrQNumEntriesGet(qInfoDes->qId, &rxQueueLevel);
+ (*numRxQueueEntries) += rxQueueLevel;
+ }
+}
+
+/**
+ * @fn ixEthAccQMgrRxCallbacksRegister(IxQMgrCallback ixQMgrCallback)
+ *
+ * @brief Change the callback registered to all rx queues.
+ *
+ * @param IxQMgrCallback ixQMgrCallback[in] QMgr callback to register
+ *
+ * @return IxEthAccStatus
+ *
+ * @note The user may decide to use different Rx mechanisms
+ * (e.g. receive many frames at the same time , or receive
+ * one frame at a time, depending on the overall application
+ * performances). A different QMgr callback is registered. This
+ * way, there is no excessive pointer checks in the datapath.
+ *
+ * @internal
+ */
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccQMgrRxCallbacksRegister(IxQMgrCallback ixQMgrCallback)
+{
+ IxEthAccQregInfo *qInfoDes;
+ IxEthAccStatus ret = IX_ETH_ACC_SUCCESS;
+
+ /* parameter check */
+ if (NULL == ixQMgrCallback)
+ {
+ ret = IX_ETH_ACC_FAIL;
+ }
+
+ /* iterate thru rx queues */
+ for (qInfoDes = ixEthAccQmgrRxQueuesInfo;
+ (qInfoDes->qCallback != (IxQMgrCallback) NULL )
+ && (ret == IX_ETH_ACC_SUCCESS);
+ ++qInfoDes)
+ {
+ /* register the rx callback for all queues */
+ if (ixQMgrNotificationCallbackSet(qInfoDes->qId,
+ ixQMgrCallback,
+ qInfoDes->callbackTag
+ ) != IX_SUCCESS)
+ {
+ ret = IX_ETH_ACC_FAIL;
+ }
+ }
+ return(ret);
+}
+
+/**
+ * @fn ixEthAccSingleEthNpeCheck(IxEthAccPortId portId)
+ *
+ * @brief Check the npe exists for this port
+ *
+ * @param IxEthAccPortId portId[in] port
+ *
+ * @return IxEthAccStatus
+ *
+ * @internal
+ */
+IX_ETH_ACC_PUBLIC
+IxEthAccStatus ixEthAccSingleEthNpeCheck(IxEthAccPortId 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_ENABLED))
+ {
+ return IX_ETH_ACC_SUCCESS;
+ }
+
+ if ((IX_ETH_PORT_2 == portId) &&
+ (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
+ IX_FEATURE_CTRL_COMPONENT_ENABLED))
+ {
+ return IX_ETH_ACC_SUCCESS;
+ }
+
+ if ((IX_ETH_PORT_3 == portId) &&
+ (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) ==
+ IX_FEATURE_CTRL_COMPONENT_ENABLED))
+ {
+ return IX_ETH_ACC_SUCCESS;
+ }
+
+ return IX_ETH_ACC_FAIL;
+ }
+
+ return IX_ETH_ACC_SUCCESS;
+}
+
+/**
+ * @fn ixEthAccStatsShow(void)
+ *
+ * @brief Displays all EthAcc stats
+ *
+ * @return void
+ *
+ */
+void ixEthAccStatsShow(IxEthAccPortId portId)
+{
+ ixEthAccMdioShow();
+
+ printf("\nPort %u\nUnicast MAC : ", portId);
+ ixEthAccPortUnicastAddressShow(portId);
+ ixEthAccPortMulticastAddressShow(portId);
+ printf("\n");
+
+ ixEthAccDataPlaneShow();
+}
+
+
+