| /** |
| * @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(); |
| } |
| |
| |
| |