mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
84ad688473
Signed-off-by: Peter Tyser <ptyser@xes-inc.com>
1049 lines
29 KiB
C
1049 lines
29 KiB
C
/**
|
|
* @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();
|
|
}
|
|
|
|
|
|
|