📄 ixethacccommon.c
字号:
#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_PUBLICvoid 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_PUBLICIxEthAccStatus 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_PUBLICIxEthAccStatus 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();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -