/***************************************************************** * * Interface query functions * */ IxEthAccStatus ixEthAccMdioShow (void) { UINT32 regval; if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) { return (IX_ETH_ACC_FAIL); } ixOsalMutexLock(&miiAccessLock, IX_OSAL_WAIT_FOREVER); ixEthAccMdioCmdRead(®val); ixOsalMutexUnlock(&miiAccessLock); printf("MDIO command register\n"); printf(" Go bit : 0x%x\n", (regval & BIT(31)) >> 31); printf(" MDIO Write : 0x%x\n", (regval & BIT(26)) >> 26); printf(" PHY address : 0x%x\n", (regval >> 21) & 0x1f); printf(" Reg address : 0x%x\n", (regval >> 16) & 0x1f); ixOsalMutexLock(&miiAccessLock, IX_OSAL_WAIT_FOREVER); ixEthAccMdioStatusRead(®val); ixOsalMutexUnlock(&miiAccessLock); printf("MDIO status register\n"); printf(" Read OK : 0x%x\n", (regval & BIT(31)) >> 31); printf(" Read Data : 0x%x\n", (regval >> 16) & 0xff); return IX_ETH_ACC_SUCCESS; }
/********************************************************************* * ixEthAccMiiWriteRtn - write a 16 bit value to a PHY */ IxEthAccStatus ixEthAccMiiWriteRtn (UINT8 phyAddr, UINT8 phyReg, UINT16 value) { UINT32 mdioCommand; UINT32 regval; UINT16 readVal; UINT32 miiTimeout; if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) { return (IX_ETH_ACC_FAIL); } if ((phyAddr >= IXP425_ETH_ACC_MII_MAX_ADDR) || (phyReg >= IXP425_ETH_ACC_MII_MAX_REG)) { return (IX_ETH_ACC_FAIL); } /* ensure that a PHY is present at this address */ if(ixEthAccMiiReadRtn(phyAddr, IX_ETH_ACC_MII_CTRL_REG, &readVal) != IX_ETH_ACC_SUCCESS) { return (IX_ETH_ACC_FAIL); } ixOsalMutexLock(&miiAccessLock, IX_OSAL_WAIT_FOREVER); mdioCommand = phyReg << IX_ETH_ACC_MII_REG_SHL | phyAddr << IX_ETH_ACC_MII_ADDR_SHL ; mdioCommand |= IX_ETH_ACC_MII_GO | IX_ETH_ACC_MII_WRITE | value; ixEthAccMdioCmdWrite(mdioCommand); miiTimeout = ixEthAccMiiRetryCount; while(miiTimeout) { ixEthAccMdioCmdRead(®val); /*The "GO" bit is reset to 0 when the write completes*/ if((regval & IX_ETH_ACC_MII_GO) == 0x0) { break; } /* Sleep for a while */ ixOsalSleep(ixEthAccMiiAccessTimeout); miiTimeout--; } ixOsalMutexUnlock(&miiAccessLock); if(miiTimeout == 0) { return IX_ETH_ACC_FAIL; } return IX_ETH_ACC_SUCCESS; }
PRIVATE void ixEthAccCodeletDispatcherPoll (void* arg, void** ptrRetObj) { if (ixOsalMutexLock (&ixEthAccCodeletDispatcherPollRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("Dispatcher: Error starting QMgr Dispatcher thread! Failed to lock mutex.\n"); return; } ixEthAccCodeletDispatcherPollStopTrigger = FALSE; while (1) { if (ixEthAccCodeletDispatcherPollStopTrigger) { break; /* Exit the loop */ } ixOsalYield(); (*ixEthAccCodeletDispatcherFunc) (IX_QMGR_QUELOW_GROUP); } ixOsalMutexUnlock (&ixEthAccCodeletDispatcherPollRunning); /* Exit the thread */ }
IX_STATUS ixEthAccCodeletDispatcherStop(BOOL useInterrupt) { if(useInterrupt) /* Interrupt mode */ { /* * Unhook the QM QLOW dispatcher to the interrupt controller. */ if (ixOsalIrqUnbind(IX_ETH_CODELET_QMGR_IRQ) != IX_SUCCESS) { printf("Dispatcher: Failed to unbind to QM1 interrupt\n"); return (IX_FAIL); } } else { if (!ixEthAccCodeletDispatcherPollStopTrigger) { ixEthAccCodeletDispatcherPollStopTrigger = TRUE; if (ixOsalMutexLock (&ixEthAccCodeletDispatcherPollRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("Dispatcher: Error stopping QMgr Dispatcher thread!\n"); return (IX_FAIL); } ixOsalMutexUnlock (&ixEthAccCodeletDispatcherPollRunning); ixOsalMutexDestroy(&ixEthAccCodeletDispatcherPollRunning); } } ixEthAccCodeletDispatcherInitialized = FALSE; return (IX_SUCCESS); }
/* * Function definition: ixEthAccCodeletDBMaintenanceStop() * * Stop the EDB Maintenance task */ IX_STATUS ixEthAccCodeletDBMaintenanceStop(void) { if (!(ixEthAccCodeletDBMaintenanceTaskStopTrigger)) { ixEthAccCodeletDBMaintenanceTaskStopTrigger = TRUE; if (ixOsalMutexLock (&ixEthAccCodeletDBMaintenanceTaskRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("DBLearning: Error stopping Database Maintenance thread!\n"); return (IX_FAIL); } ixOsalMutexUnlock (&ixEthAccCodeletDBMaintenanceTaskRunning); ixOsalMutexDestroy(&ixEthAccCodeletDBMaintenanceTaskRunning); } ixEthAccCodeletDBMaintenanceInitialized = FALSE; return (IX_SUCCESS); }
PRIVATE void ixEthAccCodeletDBMaintenanceTask (void* arg, void** ptrRetObj) { UINT32 count; ixEthAccCodeletDBMaintenanceTaskStopTrigger = FALSE; if (ixOsalMutexLock (&ixEthAccCodeletDBMaintenanceTaskRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("DbLearning: Error starting Database Maintenance thread! Failed to lock mutex.\n"); return; } while (1) { /* * The Database maintenance function must be called at a period * of approximately IX_ETH_DB_MAINTENANCE_TIME seconds * regardless of whether learning is enabled or not. */ for (count = 0; count < IX_ETH_DB_MAINTENANCE_TIME; count++) { ixOsalSleep(1000); /* 1000 milliseconds */ if (ixEthAccCodeletDBMaintenanceTaskStopTrigger) { break; /* Exit the delay loop */ } } if (ixEthAccCodeletDBMaintenanceTaskStopTrigger) { break; /* Exit the thread loop */ } ixEthDBDatabaseMaintenance(); } ixOsalMutexUnlock (&ixEthAccCodeletDBMaintenanceTaskRunning); }
/** * @brief initializes the event queue and the event processor * * This function is called by the component initialization * function, ixEthDBInit(). * * @warning do not call directly * * @return IX_ETH_DB_SUCCESS if the operation completed * successfully or IX_ETH_DB_FAIL otherwise * * @internal */ IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void) { IxOsalThread eventProcessorThread; IxOsalThreadAttr threadAttr; threadAttr.name = "EthDB event thread"; threadAttr.stackSize = 32 * 1024; /* 32kbytes */ threadAttr.priority = 128; /* reset event queue */ ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER); RESET_QUEUE(&eventQueue); ixOsalMutexUnlock(&eventQueueLock); /* init event queue semaphore */ if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS) { return IX_ETH_DB_FAIL; } ixEthDBLearningShutdown = FALSE; /* create processor loop thread */ if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS) { return IX_ETH_DB_FAIL; } /* start event processor */ ixOsalThreadStart(&eventProcessorThread); return IX_ETH_DB_SUCCESS; }
/** * @brief Locks learning tree updates and port disable * * * This function locks portUpdateLock single mutex. It is primarily used * to avoid executing 'port disable' during ELT maintenance. * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBUpdateLock(void) { ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER); }
/** * @brief Ethernet event processor loop * * Extracts at most EVENT_PROCESSING_LIMIT batches of events and * sends them for processing to @ref ixEthDBProcessEvent(). * Triggers port updates which normally follow learning events. * * @warning do not call directly, executes in separate thread * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *unused1) { IxEthDBPortMap triggerPorts; IxEthDBPortId portIndex; ixEthDBEventProcessorRunning = TRUE; IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n"); while (!ixEthDBLearningShutdown) { BOOL keepProcessing = TRUE; UINT32 processedEvents = 0; if (ixEthDBEventProcessorPausing == TRUE) { /* 100 ms*/ ixOsalSleep(100); continue; } IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n"); ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER); IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n"); if (!ixEthDBLearningShutdown) { /* port update handling */ SET_EMPTY_DEPENDENCY_MAP(triggerPorts); while (keepProcessing) { PortEvent local_event; UINT32 intLockKey; /* lock queue */ ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER); /* lock NPE interrupts */ intLockKey = ixOsalIrqLock(); /* extract event */ local_event = *(QUEUE_TAIL(&eventQueue)); SHIFT_UPDATE_QUEUE(&eventQueue); ixOsalIrqUnlock(intLockKey); ixOsalMutexUnlock(&eventQueueLock); IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType); ixEthDBProcessEvent(&local_event, triggerPorts); processedEvents++; if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */ || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */ { keepProcessing = FALSE; } } /* Added a pause check here to prevent NPE message * from being sent from ixEthDBUpdatePortLearningTrees() */ while (ixEthDBEventProcessorPausing == TRUE) { /* 100 ms*/ ixOsalSleep(100); } ixEthDBUpdatePortLearningTrees(triggerPorts); } } /* turn off automatic updates */ for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) { ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = FALSE; } ixEthDBEventProcessorRunning = FALSE; }
/* * Attempt to get mutex, return immediately, * no error info because users expect some failures * when using this API. */ PUBLIC IX_STATUS ixOsalMutexTryLock (IxOsalMutex * mutex) { return ixOsalMutexLock(mutex, IX_OSAL_WAIT_NONE); }
IX_STATUS ixQMgrQConfig (char *qName, IxQMgrQId qId, IxQMgrQSizeInWords qSizeInWords, IxQMgrQEntrySizeInWords qEntrySizeInWords) { UINT32 aqmLocalBaseAddress; if (!cfgInitialized) { return IX_FAIL; } if (!IX_QMGR_QID_IS_VALID(qId)) { return IX_QMGR_INVALID_Q_ID; } else if (NULL == qName) { return IX_QMGR_PARAMETER_ERROR; } else if (strlen (qName) > IX_QMGR_MAX_QNAME_LEN) { return IX_QMGR_PARAMETER_ERROR; } else if (!qSizeInWordsIsOk (qSizeInWords)) { return IX_QMGR_INVALID_QSIZE; } else if (!qEntrySizeInWordsIsOk (qEntrySizeInWords)) { return IX_QMGR_INVALID_Q_ENTRY_SIZE; } else if (cfgQueueInfo[qId].isConfigured) { return IX_QMGR_Q_ALREADY_CONFIGURED; } ixOsalMutexLock(&ixQMgrQCfgMutex, IX_OSAL_WAIT_FOREVER); /* Write the config register */ ixQMgrAqmIfQueCfgWrite (qId, qSizeInWords, qEntrySizeInWords, freeSramAddress); strcpy (cfgQueueInfo[qId].qName, qName); cfgQueueInfo[qId].qSizeInWords = qSizeInWords; cfgQueueInfo[qId].qEntrySizeInWords = qEntrySizeInWords; /* store pre-computed information in the same cache line * to facilitate inlining of QRead and QWrite functions * in IxQMgr.h */ ixQMgrQInlinedReadWriteInfo[qId].qReadCount = 0; ixQMgrQInlinedReadWriteInfo[qId].qWriteCount = 0; ixQMgrQInlinedReadWriteInfo[qId].qEntrySizeInWords = qEntrySizeInWords; ixQMgrQInlinedReadWriteInfo[qId].qSizeInEntries = (UINT32)qSizeInWords / (UINT32)qEntrySizeInWords; /* Calculate the new freeSramAddress from the size of the queue * currently being configured. */ freeSramAddress += (qSizeInWords * IX_QMGR_NUM_BYTES_PER_WORD); /* Get the virtual SRAM address */ ixQMgrAqmIfBaseAddressGet (&aqmLocalBaseAddress); IX_OSAL_ASSERT((freeSramAddress - (aqmLocalBaseAddress + (IX_QMGR_QUEBUFFER_SPACE_OFFSET))) <= IX_QMGR_QUE_BUFFER_SPACE_SIZE); /* The queue is now configured */ cfgQueueInfo[qId].isConfigured = TRUE; ixOsalMutexUnlock(&ixQMgrQCfgMutex); #ifndef NDEBUG /* Update statistics */ stats.qStats[qId].isConfigured = TRUE; stats.qStats[qId].qName = cfgQueueInfo[qId].qName; #endif return IX_SUCCESS; }
/** * @brief scans the capabilities of the loaded NPE images * * This function MUST be called by the ixEthDBInit() function. * No EthDB features (including learning and filtering) are enabled * before this function is called. * * @return none * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBFeatureCapabilityScan(void) { IxNpeDlImageId imageId, npeAImageId; IxEthDBPortId portIndex; PortInfo *portInfo; IxEthDBPriorityTable defaultPriorityTable; IX_STATUS result; UINT32 queueIndex; UINT32 queueStructureIndex; UINT32 trafficClassDefinitionIndex; /* read version of NPE A - required to set the AQM queues for B and C */ npeAImageId.functionalityId = 0; ixNpeDlLoadedImageGet(IX_NPEDL_NPEID_NPEA, &npeAImageId); for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) { IxNpeMhMessage msg; portInfo = &ixEthDBPortInfo[portIndex]; /* check and bypass if NPE B or C is fused out */ if (ixEthDBSingleEthNpeCheck(portIndex) != IX_ETH_DB_SUCCESS) continue; /* all ports are capable of LEARNING by default */ portInfo->featureCapability |= IX_ETH_DB_LEARNING; portInfo->featureStatus |= IX_ETH_DB_LEARNING; if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE) { if (ixNpeDlLoadedImageGet(IX_ETH_DB_PORT_ID_TO_NPE(portIndex), &imageId) != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) NpeDl did not provide the image ID for NPE port %d\n", portIndex); } else { /* initialize and empty NPE response mutex */ ixOsalMutexInit(&portInfo->npeAckLock); ixOsalMutexLock(&portInfo->npeAckLock, IX_OSAL_WAIT_FOREVER); /* check NPE response to GetStatus */ msg.data[0] = IX_ETHNPE_NPE_GETSTATUS << 24; msg.data[1] = 0; IX_ETHDB_SEND_NPE_MSG(IX_ETH_DB_PORT_ID_TO_NPE(portIndex), msg, result); if (result != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, could not send message to the NPE\n"); continue; } if (imageId.functionalityId == 0x00 || imageId.functionalityId == 0x03 || imageId.functionalityId == 0x04 || imageId.functionalityId == 0x80) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; } else if (imageId.functionalityId == 0x01 || imageId.functionalityId == 0x81) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (imageId.functionalityId == 0x02 || imageId.functionalityId == 0x82) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } /* reset AQM queues */ memset(portInfo->ixEthDBTrafficClassAQMAssignments, 0, sizeof (portInfo->ixEthDBTrafficClassAQMAssignments)); /* ensure there's at least one traffic class record in the definition table, otherwise we have no default case, hence no queues */ IX_ENSURE(sizeof (ixEthDBTrafficClassDefinitions) != 0, "DB: no traffic class definitions found, check IxEthDBQoS.h"); /* find the traffic class definition index compatible with the current NPE A functionality ID */ for (trafficClassDefinitionIndex = 0 ; trafficClassDefinitionIndex < sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0]); trafficClassDefinitionIndex++) { if (ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_NPE_A_FUNCTIONALITY_ID_INDEX] == npeAImageId.functionalityId) { /* found it */ break; } } /* select the default case if we went over the array boundary */ if (trafficClassDefinitionIndex == sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0])) { trafficClassDefinitionIndex = 0; /* the first record is the default case */ } /* select queue assignment structure based on the traffic class configuration index */ queueStructureIndex = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_QUEUE_ASSIGNMENT_INDEX]; /* only traffic class 0 is active at initialization time */ portInfo->ixEthDBTrafficClassCount = 1; /* enable port, VLAN and Firewall feature bits to initialize QoS/VLAN/Firewall configuration */ portInfo->featureStatus |= IX_ETH_DB_VLAN_QOS; portInfo->featureStatus |= IX_ETH_DB_FIREWALL; portInfo->enabled = TRUE; #define CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ #ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ /* set VLAN initial configuration (permissive) */ if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0) /* QoS-enabled image */ { /* QoS capable */ portInfo->ixEthDBTrafficClassAvailable = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_TRAFFIC_CLASS_COUNT_INDEX]; /* set AQM queues */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][queueIndex]; } /* set default PVID (0) and default traffic class 0 */ ixEthDBPortVlanTagSet(portIndex, 0); /* enable reception of all frames */ ixEthDBAcceptableFrameTypeSet(portIndex, IX_ETH_DB_ACCEPT_ALL_FRAMES); /* clear full VLAN membership */ ixEthDBPortVlanMembershipRangeRemove(portIndex, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID); /* clear TTI table - no VLAN tagged frames will be transmitted */ ixEthDBEgressVlanRangeTaggingEnabledSet(portIndex, 0, 4094, FALSE); /* set membership on 0, otherwise no Tx or Rx is working */ ixEthDBPortVlanMembershipAdd(portIndex, 0); } else /* QoS not available in this image */ #endif /* test-only */ { /* initialize traffic class availability (only class 0 is available) */ portInfo->ixEthDBTrafficClassAvailable = 1; /* point all AQM queues to traffic class 0 */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][0]; } } #ifdef CONFIG_WITH_VLAN /* test-only: VLAN support not included to save space!!! */ /* download priority mapping table and Rx queue configuration */ memset (defaultPriorityTable, 0, sizeof (defaultPriorityTable)); ixEthDBPriorityMappingTableSet(portIndex, defaultPriorityTable); #endif /* by default we turn off invalid source MAC address filtering */ ixEthDBFirewallInvalidAddressFilterEnable(portIndex, FALSE); /* disable port, VLAN, Firewall feature bits */ portInfo->featureStatus &= ~IX_ETH_DB_VLAN_QOS; portInfo->featureStatus &= ~IX_ETH_DB_FIREWALL; portInfo->enabled = FALSE; /* enable filtering by default if present */ if ((portInfo->featureCapability & IX_ETH_DB_FILTERING) != 0) { portInfo->featureStatus |= IX_ETH_DB_FILTERING; } } } } }
/** * @brief scans the capabilities of the loaded NPE images * * This function MUST be called by the ixEthDBInit() function. * No EthDB features (including learning and filtering) are enabled * before this function is called. * * @return none * * @internal */ IX_ETH_DB_PUBLIC void ixEthDBFeatureCapabilityScan(void) { UINT8 functionalityId, npeAFunctionalityId; IxEthDBPortId portIndex; PortInfo *portInfo; IxEthDBPriorityTable defaultPriorityTable; IX_STATUS result; UINT32 queueIndex; UINT32 queueStructureIndex; UINT32 trafficClassDefinitionIndex, totalTrafficClass; totalTrafficClass = sizeof (ixEthDBTrafficClassDefinitions) / sizeof (ixEthDBTrafficClassDefinitions[0]); /* ensure there's at least 2 traffic class records in the definition table, otherwise we have no default cases, hence no queues */ IX_ENSURE(totalTrafficClass >= 2, "DB: no traffic class definitions found, check IxEthDBQoS.h"); /* read version of NPE A - required to set the AQM queues for B and C */ npeAFunctionalityId = 0; if(IX_FAIL == ixNpeDlLoadedImageFunctionalityGet(IX_NPEDL_NPEID_NPEA, &npeAFunctionalityId)) { /* IX_FAIL is returned when there is no image loaded in NPEA. Then we can use all 8 queues */ trafficClassDefinitionIndex = 1; /* the second record is the default if no image loaded */ } else { /* find the traffic class definition index compatible with the current NPE A functionality ID */ for (trafficClassDefinitionIndex = 0 ; trafficClassDefinitionIndex < totalTrafficClass ; trafficClassDefinitionIndex++) { if (ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_NPE_A_FUNCTIONALITY_ID_INDEX] == npeAFunctionalityId) { /* found it */ break; } } /* select the default case if we went over the array boundary */ if (trafficClassDefinitionIndex == totalTrafficClass) { trafficClassDefinitionIndex = 0; /* the first record is the default case */ } } /* To decide port definition for NPE A - IX_ETH_NPE or IX_ETH_GENERIC IX_ETH_NPE will be set for NPE A when the functionality id is ranged from 0x80 to 0x8F and ethernet + hss co-exists images range from 0x90 to 0x9F. For the rest of functionality Ids, the port type will be set to IX_ETH_GENERIC. */ if ((npeAFunctionalityId & 0xF0) != 0x80 && (npeAFunctionalityId & 0xF0) != 0x90) { /* NPEA is not Ethernet capable. Override default port definition */ ixEthDBPortDefinitions[IX_NPEA_PORT].type = IX_ETH_GENERIC; } /* select queue assignment structure based on the traffic class configuration index */ queueStructureIndex = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_QUEUE_ASSIGNMENT_INDEX]; for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++) { IxNpeMhMessage msg; portInfo = &ixEthDBPortInfo[portIndex]; /* check and bypass if NPE A, B or C is fused out */ if (ixEthDBSingleEthNpeCheck(portIndex) != IX_ETH_DB_SUCCESS) continue; /* all ports are capable of LEARNING by default */ portInfo->featureCapability = IX_ETH_DB_LEARNING; portInfo->featureStatus = IX_ETH_DB_LEARNING; if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE) { if (IX_SUCCESS != ixNpeDlLoadedImageFunctionalityGet(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portIndex), &functionalityId)) { WARNING_LOG("DB: (FeatureScan) NpeDl did not provide the image ID for NPE port %d\n", portIndex); } else { /* initialize and empty NPE response mutex */ ixOsalMutexInit(&portInfo->npeAckLock); ixOsalMutexLock(&portInfo->npeAckLock, IX_OSAL_WAIT_FOREVER); /* check NPE response to GetStatus */ msg.data[0] = IX_ETHNPE_NPE_GETSTATUS << 24; msg.data[1] = 0; IX_ETHDB_SEND_NPE_MSG(IX_ETHNPE_PHYSICAL_ID_TO_NODE(portIndex), msg, result); if (result != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, %d port could not send message to the NPE\n", portIndex); continue; } if (functionalityId == 0x00 || functionalityId == 0x03 || functionalityId == 0x04 || functionalityId == 0x80) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; } else if (functionalityId == 0x01 || functionalityId == 0x81 || functionalityId == 0x0B || functionalityId == 0x8B || functionalityId == 0x90) { portInfo->featureCapability |= IX_ETH_DB_FILTERING; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (functionalityId == 0x02 || functionalityId == 0x82 || functionalityId == 0x0D || functionalityId == 0x8D || functionalityId == 0x91) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_FIREWALL; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } else if (functionalityId == 0x0C || functionalityId == 0x8C) { portInfo->featureCapability |= IX_ETH_DB_WIFI_HEADER_CONVERSION; portInfo->featureCapability |= IX_ETH_DB_SPANNING_TREE_PROTOCOL; portInfo->featureCapability |= IX_ETH_DB_VLAN_QOS; } /* check if image supports mask based firewall */ if (functionalityId == 0x0B || functionalityId == 0x8B || functionalityId == 0x0D || functionalityId == 0x8D || functionalityId == 0x90 || functionalityId == 0x91) { /* this feature is always on and is based on the NPE */ portInfo->featureStatus |= IX_ETH_DB_ADDRESS_MASKING; portInfo->featureCapability |= IX_ETH_DB_ADDRESS_MASKING; } /* reset AQM queues */ ixOsalMemSet(portInfo->ixEthDBTrafficClassAQMAssignments, 0, sizeof (portInfo->ixEthDBTrafficClassAQMAssignments)); /* only traffic class 0 is active at initialization time */ portInfo->ixEthDBTrafficClassCount = 1; /* enable port, VLAN and Firewall feature bits to initialize QoS/VLAN/Firewall configuration */ portInfo->featureStatus |= IX_ETH_DB_VLAN_QOS; portInfo->featureStatus |= IX_ETH_DB_FIREWALL; portInfo->enabled = TRUE; /* set VLAN initial configuration (permissive) */ if ((portInfo->featureCapability & IX_ETH_DB_VLAN_QOS) != 0) /* QoS-enabled image */ { /* QoS capable */ portInfo->ixEthDBTrafficClassAvailable = ixEthDBTrafficClassDefinitions[trafficClassDefinitionIndex][IX_ETH_DB_TRAFFIC_CLASS_COUNT_INDEX]; /* set AQM queues */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][queueIndex]; } /* set default PVID (0) and default traffic class 0 */ ixEthDBPortVlanTagSet(portIndex, 0); /* enable reception of all frames */ ixEthDBAcceptableFrameTypeSet(portIndex, IX_ETH_DB_ACCEPT_ALL_FRAMES); /* clear full VLAN membership */ ixEthDBPortVlanMembershipRangeRemove(portIndex, 0, IX_ETH_DB_802_1Q_MAX_VLAN_ID); /* clear TTI table - no VLAN tagged frames will be transmitted */ ixEthDBEgressVlanRangeTaggingEnabledSet(portIndex, 0, 4094, FALSE); /* set membership on 0, otherwise no Tx or Rx is working */ ixEthDBPortVlanMembershipAdd(portIndex, 0); } else /* QoS not available in this image */ { /* initialize traffic class availability (only class 0 is available) */ portInfo->ixEthDBTrafficClassAvailable = 1; /* point all AQM queues to traffic class 0 */ for (queueIndex = 0 ; queueIndex < IX_IEEE802_1Q_QOS_PRIORITY_COUNT ; queueIndex++) { portInfo->ixEthDBTrafficClassAQMAssignments[queueIndex] = ixEthDBQueueAssignments[queueStructureIndex][0]; } } /* download priority mapping table and Rx queue configuration */ ixOsalMemSet (defaultPriorityTable, 0, sizeof (defaultPriorityTable)); ixEthDBPriorityMappingTableSet(portIndex, defaultPriorityTable); /* by default we turn on invalid source MAC address filtering */ ixEthDBFirewallInvalidAddressFilterEnable(portIndex, TRUE); /* Notify VLAN tagging is disabled */ if (ixEthDBIngressVlanTaggingEnabledSet(portIndex, IX_ETH_DB_DISABLE_VLAN) != IX_SUCCESS) { WARNING_LOG("DB: (FeatureScan) warning, %d port could not disable VLAN \n", portIndex); continue; } /* disable port, VLAN, Firewall feature bits */ portInfo->featureStatus &= ~IX_ETH_DB_VLAN_QOS; portInfo->featureStatus &= ~IX_ETH_DB_FIREWALL; portInfo->enabled = FALSE; /* enable filtering by default if present */ if ((portInfo->featureCapability & IX_ETH_DB_FILTERING) != 0) { portInfo->featureStatus |= IX_ETH_DB_FILTERING; } } } } }
/********************************************************************* * ixEthAccMiiReadRtn - read a 16 bit value from a PHY */ IxEthAccStatus ixEthAccMiiReadRtn (UINT8 phyAddr, UINT8 phyReg, UINT16 *value) { UINT32 mdioCommand; UINT32 regval; UINT32 miiTimeout; if (!IX_ETH_ACC_IS_SERVICE_INITIALIZED()) { return (IX_ETH_ACC_FAIL); } if ((phyAddr >= IXP425_ETH_ACC_MII_MAX_ADDR) || (phyReg >= IXP425_ETH_ACC_MII_MAX_REG)) { return (IX_ETH_ACC_FAIL); } if (value == NULL) { return (IX_ETH_ACC_FAIL); } ixOsalMutexLock(&miiAccessLock, IX_OSAL_WAIT_FOREVER); mdioCommand = phyReg << IX_ETH_ACC_MII_REG_SHL | phyAddr << IX_ETH_ACC_MII_ADDR_SHL; mdioCommand |= IX_ETH_ACC_MII_GO; ixEthAccMdioCmdWrite(mdioCommand); miiTimeout = ixEthAccMiiRetryCount; while(miiTimeout) { ixEthAccMdioCmdRead(®val); if((regval & IX_ETH_ACC_MII_GO) == 0x0) { break; } /* Sleep for a while */ ixOsalSleep(ixEthAccMiiAccessTimeout); miiTimeout--; } if(miiTimeout == 0) { ixOsalMutexUnlock(&miiAccessLock); *value = 0xffff; return IX_ETH_ACC_FAIL; } ixEthAccMdioStatusRead(®val); if(regval & IX_ETH_ACC_MII_READ_FAIL) { ixOsalMutexUnlock(&miiAccessLock); *value = 0xffff; return IX_ETH_ACC_FAIL; } *value = regval & 0xffff; ixOsalMutexUnlock(&miiAccessLock); return IX_ETH_ACC_SUCCESS; }
IX_STATUS ixEthAccCodeletUninit(void) { IxEthAccPortId portId; IxEthAccStatus status; if(!ixEthAccCodeletInitialised) { /* already uninitialized */ return(IX_SUCCESS); } if (!ixEthAccCodeletStatsPollTaskStop) { ixEthAccCodeletStatsPollTaskStop = TRUE; if (ixOsalMutexLock (&ixEthAccCodeletStatsPollTaskRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("CodeletMain: Error stopping Statistics Polling thread!\n"); return (IX_FAIL); } ixOsalMutexUnlock (&ixEthAccCodeletStatsPollTaskRunning); } for (portId = IX_ETH_PORT_1; portId < IX_ETHACC_CODELET_MAX_PORT; portId++) { status = ixEthAccPortDisable (portId); if (IX_ETH_ACC_SUCCESS != status) { printf("CodeletMain: Failed to disable port %d, error code %d\n", portId, status); return (IX_FAIL); } } if (ixEthAccCodeletDBMaintenanceStop() != IX_SUCCESS) { printf("CodeletMain: Error stopping DB Maintenance task!\n"); return (IX_FAIL); } if (ixEthAccUninit() != IX_SUCCESS) { printf("CodeletMain: Failed to uninitialize Ethernet Access Layer!\n"); return (IX_FAIL); } #ifdef __ixp46X if (ixNpeDlNpeStopAndReset(IX_NPEDL_NPEID_NPEA) != IX_SUCCESS) { printf("CodeletMain: Failed to stop and reset NPE A!\n"); return (IX_FAIL); } #endif if (ixNpeDlNpeStopAndReset(IX_NPEDL_NPEID_NPEB) != IX_SUCCESS) { printf("CodeletMain: Failed to stop and reset NPE B!\n"); return (IX_FAIL); } if (ixNpeDlNpeStopAndReset(IX_NPEDL_NPEID_NPEC) != IX_SUCCESS) { printf("CodeletMain: Failed to stop and reset NPE C!\n"); return (IX_FAIL); } if (ixNpeDlUnload() != IX_SUCCESS) { printf("CodeletMain: Failed to unload NPE Downloader!\n"); return (IX_FAIL); } if (ixNpeMhUnload() != IX_SUCCESS) { printf("CodeletMain: Failed to unload NPE Message Handler!\n"); return (IX_FAIL); } if (ixEthAccCodeletDispatcherStop(IX_ETH_CODELET_QMGR_DISPATCH_MODE) != IX_SUCCESS) { printf("CodeletMain: Error stopping QMgr Dispatcher loop!\n"); return (IX_FAIL); } if (ixQMgrUnload() != IX_SUCCESS) { printf("CodeletMain: Failed to unload QMgr!\n"); return (IX_FAIL); } if (ixEthAccCodeletMemPoolFree() != IX_SUCCESS) { printf("CodeletMain: Failed to free memory pool!\n"); return (IX_FAIL); } ixEthAccCodeletInitialised = FALSE; return (IX_SUCCESS); }
/** * @fn void ixEthAccCodeletStatsPollTask * * This task polls the Codelet Stats and displays the rate of Rx and * Tx packets per second. * */ PRIVATE void ixEthAccCodeletStatsPollTask(void* arg, void** ptrRetObj) { int portNo = 0; static char stillRunning[] = "|/-\\"; static int stillRunningIndex = 0; static char displayString[20 + (21 * IX_ETHACC_CODELET_MAX_PORT)]; static char *stringPtr; static UINT32 busTimestampEnd = 0; static UINT32 busTimestampStart = 0; static UINT32 pTimeCycles = 0; static UINT64 rxCount = 0; static UINT64 txCount = 0; static UINT64 pTimeUsecs = 0; ixEthAccCodeletStatsPollTaskStop = FALSE; if (ixOsalMutexLock (&ixEthAccCodeletStatsPollTaskRunning, IX_OSAL_WAIT_FOREVER) != IX_SUCCESS) { printf("CodeletMain: Error starting Stats thread! Failed to lock mutex.\n"); return; } while (1) { while (ixEthAccCodeletTrafficPollEnabled == FALSE) { /* Sleep 1 sec */ ixOsalSleep(1000); if (ixEthAccCodeletStatsPollTaskStop) { break; /* Exit the thread */ } } if (ixEthAccCodeletStatsPollTaskStop) { break; /* Exit the thread */ } printf("\n"); #ifdef __wince printf("\r"); #endif for(portNo=0; portNo<IX_ETHACC_CODELET_MAX_PORT; portNo++) { printf("Port%d Rates: |",portNo); } printf("\n"); #ifdef __wince printf("\r"); #endif for(portNo=0; portNo<IX_ETHACC_CODELET_MAX_PORT; portNo++) { printf("====================="); } printf("=\n"); #ifdef __wince printf("\r"); #endif /* reset the stats */ for(portNo=0; portNo<IX_ETHACC_CODELET_MAX_PORT; portNo++) { ixEthAccCodeletStats[portNo].rxCount=0; ixEthAccCodeletStats[portNo].txCount=0; } while (ixEthAccCodeletTrafficPollEnabled) { busTimestampStart = ixOsalTimestampGet(); /* Sleep approximatively 1 sec */ ixOsalSleep(1000); /* check if the task should stop */ if (ixEthAccCodeletStatsPollTaskStop) { break; /* Exit the thread */ } if (ixEthAccCodeletTrafficPollEnabled) { /* \r : reset print curser to beginning of line */ stringPtr = displayString; *stringPtr++ = '\r'; for(portNo=0; portNo<IX_ETHACC_CODELET_MAX_PORT; portNo++) { /* get a snapshot */ busTimestampEnd = ixOsalTimestampGet(); rxCount = ixEthAccCodeletStats[portNo].rxCount; txCount = ixEthAccCodeletStats[portNo].txCount; /* Got stats, now clear counters */ ixEthAccCodeletStats[portNo].rxCount=0; ixEthAccCodeletStats[portNo].txCount=0; /* get the measurement interval using a unsigned * subtraction in order to handle wrap-around. The time unit * is in APB bus cycles. */ pTimeCycles = busTimestampEnd - busTimestampStart; /* convert the time in APB bus cycles to microseconds * * multiplications are done before divisions and * will not overflow the UINT64. */ pTimeUsecs = (UINT64)pTimeCycles; pTimeUsecs = IX_ETHACC_CODELET_MULDIV(pTimeUsecs, IX_ETHACC_CODELET_PCLOCK_DIVIDER, IX_ETHACC_CODELET_XCLOCK_FREQ); if (!pTimeUsecs) { /* time may be 0 as the result of the previous operation * In this case (very unlikely to occur), * just skip the remaining of this loop. * The display will not be updated before the next * loop. */ continue; } /* convert from the packet count to a rate in pkts per second * * rate = pkts * usecsPerSec / timeUsec * * multiplications are done before divisions and * will not overflow the UINT64. */ rxCount = IX_ETHACC_CODELET_MULDIV(rxCount, IX_ETHACC_CODELET_USEC_PER_SEC, pTimeUsecs); txCount = IX_ETHACC_CODELET_MULDIV(txCount, IX_ETHACC_CODELET_USEC_PER_SEC, pTimeUsecs); /* print stats */ stringPtr += sprintf(stringPtr, "Rx:%6u Tx:%6u |", (unsigned)rxCount, (unsigned)txCount); } *stringPtr++ = stillRunning[stillRunningIndex++ & 3]; *stringPtr = 0; printf("%s", displayString); } } printf("\n"); #ifdef __wince printf("\r"); #endif } ixOsalMutexUnlock (&ixEthAccCodeletStatsPollTaskRunning); }