diff options
Diffstat (limited to 'cpu/ixp/npe/IxEthAccCommon.c')
-rw-r--r-- | cpu/ixp/npe/IxEthAccCommon.c | 1049 |
1 files changed, 1049 insertions, 0 deletions
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(); +} + + + |