ba94a1bba3
- Add IXP4xx NPE ethernet MAC support - Add support for Intel IXDPG425 board - Add support for Prodrive PDNB3 board - Add IRQ support Patch by Stefan Roese, 23 May 2006 [This patch does not include cpu/ixp/npe/IxNpeMicrocode.c which still sufferes from licensing issues. Blame Intel.]
521 lines
15 KiB
C
521 lines
15 KiB
C
/**
|
|
* @file IxEthDBEvents.c
|
|
*
|
|
* @brief Implementation of the event processor component
|
|
*
|
|
* @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 --
|
|
*/
|
|
|
|
#include <IxNpeMh.h>
|
|
#include <IxFeatureCtrl.h>
|
|
|
|
#include "IxEthDB_p.h"
|
|
|
|
/* forward prototype declarations */
|
|
IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *);
|
|
IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
|
|
IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts);
|
|
IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
|
|
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
|
|
IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
|
|
|
|
/* data */
|
|
IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore;
|
|
IX_ETH_DB_PRIVATE PortEventQueue eventQueue;
|
|
IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock;
|
|
IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock;
|
|
|
|
IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown = FALSE;
|
|
IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = FALSE;
|
|
|
|
/* imported data */
|
|
extern HashTable dbHashtable;
|
|
|
|
/**
|
|
* @brief initializes the event processor
|
|
*
|
|
* Initializes the event processor queue and processing thread.
|
|
* Called from ixEthDBInit() DB-subcomponent master init function.
|
|
*
|
|
* @warning do not call directly
|
|
*
|
|
* @retval IX_ETH_DB_SUCCESS initialization was successful
|
|
* @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PUBLIC
|
|
IxEthDBStatus ixEthDBEventProcessorInit(void)
|
|
{
|
|
if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS)
|
|
{
|
|
return IX_ETH_DB_FAIL;
|
|
}
|
|
|
|
if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS)
|
|
{
|
|
return IX_ETH_DB_FAIL;
|
|
}
|
|
|
|
if (IX_FEATURE_CTRL_SWCONFIG_ENABLED ==
|
|
ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
|
|
{
|
|
|
|
/* start processor loop thread */
|
|
if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS)
|
|
{
|
|
return IX_ETH_DB_FAIL;
|
|
}
|
|
}
|
|
|
|
return IX_ETH_DB_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @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 stops the event processor
|
|
*
|
|
* Stops the event processor and frees the event queue semaphore
|
|
* Called by the component de-initialization function, ixEthDBUnload()
|
|
*
|
|
* @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 ixEthDBStopLearningFunction(void)
|
|
{
|
|
ixEthDBLearningShutdown = TRUE;
|
|
|
|
/* wake up event processing loop to actually process the shutdown event */
|
|
ixOsalSemaphorePost(&eventQueueSemaphore);
|
|
|
|
if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS)
|
|
{
|
|
return IX_ETH_DB_FAIL;
|
|
}
|
|
|
|
return IX_ETH_DB_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief default NPE event processing callback
|
|
*
|
|
* @param npeID ID of the NPE that generated the event
|
|
* @param msg NPE message (encapsulated event)
|
|
*
|
|
* Creates an event object on the Ethernet event processor queue
|
|
* and signals the new event by incrementing the event queue semaphore.
|
|
* Events are processed by @ref ixEthDBEventProcessorLoop() which runs
|
|
* at user level.
|
|
*
|
|
* @see ixEthDBEventProcessorLoop()
|
|
*
|
|
* @warning do not call directly
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PUBLIC
|
|
void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg)
|
|
{
|
|
PortEvent *local_event;
|
|
|
|
IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) new event received by processor callback from port %d, id 0x%X\n", IX_ETH_DB_NPE_TO_PORT_ID(npeID), NPE_MSG_ID(msg), 0, 0, 0, 0);
|
|
|
|
if (CAN_ENQUEUE(&eventQueue))
|
|
{
|
|
TEST_FIXTURE_LOCK_EVENT_QUEUE;
|
|
|
|
local_event = QUEUE_HEAD(&eventQueue);
|
|
|
|
/* create event structure on queue */
|
|
local_event->eventType = NPE_MSG_ID(msg);
|
|
local_event->portID = IX_ETH_DB_NPE_TO_PORT_ID(npeID);
|
|
|
|
/* update queue */
|
|
PUSH_UPDATE_QUEUE(&eventQueue);
|
|
|
|
TEST_FIXTURE_UNLOCK_EVENT_QUEUE;
|
|
|
|
IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
|
|
|
|
/* increment event queue semaphore */
|
|
ixOsalSemaphorePost(&eventQueueSemaphore);
|
|
}
|
|
else
|
|
{
|
|
IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
ixEthDBUpdatePortLearningTrees(triggerPorts);
|
|
}
|
|
}
|
|
|
|
/* turn off automatic updates */
|
|
for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
|
|
{
|
|
ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = FALSE;
|
|
}
|
|
|
|
ixEthDBEventProcessorRunning = FALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief event processor routine
|
|
*
|
|
* @param event event to be processed
|
|
* @param triggerPorts port map accumulating ports to be updated
|
|
*
|
|
* Processes learning events by synchronizing the database with
|
|
* newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
|
|
*
|
|
* @warning do not call directly
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PRIVATE
|
|
void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts)
|
|
{
|
|
MacDescriptor recordTemplate;
|
|
|
|
switch (local_event->eventType)
|
|
{
|
|
case IX_ETH_DB_ADD_FILTERING_RECORD:
|
|
/* add record */
|
|
memset(&recordTemplate, 0, sizeof (recordTemplate));
|
|
memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
|
|
|
|
recordTemplate.type = IX_ETH_DB_FILTERING_RECORD;
|
|
recordTemplate.portID = local_event->portID;
|
|
recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry;
|
|
|
|
ixEthDBAdd(&recordTemplate, triggerPorts);
|
|
|
|
IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID);
|
|
|
|
break;
|
|
|
|
case IX_ETH_DB_REMOVE_FILTERING_RECORD:
|
|
/* remove record */
|
|
memset(&recordTemplate, 0, sizeof (recordTemplate));
|
|
memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
|
|
|
|
recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD;
|
|
|
|
ixEthDBRemove(&recordTemplate, triggerPorts);
|
|
|
|
IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID);
|
|
|
|
break;
|
|
|
|
default:
|
|
/* can't handle/not interested in this event type */
|
|
ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event->eventType);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief asynchronously adds a filtering record
|
|
* by posting an ADD_FILTERING_RECORD event to the event queue
|
|
*
|
|
* @param macAddr MAC address of the new record
|
|
* @param portID port ID of the new record
|
|
* @param staticEntry TRUE if record is static, FALSE if dynamic
|
|
*
|
|
* @return IX_ETH_DB_SUCCESS if the event creation was
|
|
* successfull or IX_ETH_DB_BUSY if the event queue is full
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PUBLIC
|
|
IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
|
|
{
|
|
MacDescriptor reference;
|
|
|
|
TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
|
|
|
|
/* fill search fields */
|
|
memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr));
|
|
reference.portID = portID;
|
|
|
|
/* set acceptable record types */
|
|
reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS;
|
|
|
|
if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS)
|
|
{
|
|
/* already have an identical record */
|
|
return IX_ETH_DB_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief asynchronously removes a filtering record
|
|
* by posting a REMOVE_FILTERING_RECORD event to the event queue
|
|
*
|
|
* @param macAddr MAC address of the record to remove
|
|
* @param portID port ID of the record to remove
|
|
*
|
|
* @return IX_ETH_DB_SUCCESS if the event creation was
|
|
* successfull or IX_ETH_DB_BUSY if the event queue is full
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PUBLIC
|
|
IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID)
|
|
{
|
|
if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR)
|
|
{
|
|
return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, FALSE);
|
|
}
|
|
else
|
|
{
|
|
return IX_ETH_DB_NO_SUCH_ADDR;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief adds an ADD or REMOVE event to the main event queue
|
|
*
|
|
* @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD
|
|
* to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
|
|
* record.
|
|
*
|
|
* @return IX_ETH_DB_SUCCESS if the event was successfully
|
|
* sent or IX_ETH_DB_BUSY if the event queue is full
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PRIVATE
|
|
IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
|
|
{
|
|
UINT32 intLockKey;
|
|
|
|
/* lock interrupts to protect queue */
|
|
intLockKey = ixOsalIrqLock();
|
|
|
|
if (CAN_ENQUEUE(&eventQueue))
|
|
{
|
|
PortEvent *queueEvent = QUEUE_HEAD(&eventQueue);
|
|
|
|
/* update fields on the queue */
|
|
memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr));
|
|
|
|
queueEvent->eventType = eventType;
|
|
queueEvent->portID = portID;
|
|
queueEvent->staticEntry = staticEntry;
|
|
|
|
PUSH_UPDATE_QUEUE(&eventQueue);
|
|
|
|
/* imcrement event queue semaphore */
|
|
ixOsalSemaphorePost(&eventQueueSemaphore);
|
|
|
|
/* unlock interrupts */
|
|
ixOsalIrqUnlock(intLockKey);
|
|
|
|
return IX_ETH_DB_SUCCESS;
|
|
}
|
|
else /* event queue full */
|
|
{
|
|
/* unlock interrupts */
|
|
ixOsalIrqUnlock(intLockKey);
|
|
|
|
return IX_ETH_DB_BUSY;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @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 Unlocks learning tree updates and port disable
|
|
*
|
|
*
|
|
* This function unlocks a portUpdateLock mutex. It is primarily used
|
|
* to avoid executing 'port disable' during ELT maintenance.
|
|
*
|
|
* @internal
|
|
*/
|
|
IX_ETH_DB_PUBLIC
|
|
void ixEthDBUpdateUnlock(void)
|
|
{
|
|
ixOsalMutexUnlock(&portUpdateLock);
|
|
}
|
|
|