]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxEthDBEvents.c
doc: SPI: Add qspi test details on AM43xx
[karo-tx-uboot.git] / drivers / net / npe / IxEthDBEvents.c
1 /**
2  * @file IxEthDBEvents.c
3  *
4  * @brief Implementation of the event processor component
5  * 
6  * @par
7  * IXP400 SW Release version 2.0
8  * 
9  * -- Copyright Notice --
10  * 
11  * @par
12  * Copyright 2001-2005, Intel Corporation.
13  * All rights reserved.
14  * 
15  * @par
16  * SPDX-License-Identifier:     BSD-3-Clause
17  * @par
18  * -- End of Copyright Notice --
19  */
20
21 #include <IxNpeMh.h>
22 #include <IxFeatureCtrl.h>
23
24 #include "IxEthDB_p.h"
25
26 /* forward prototype declarations */
27 IX_ETH_DB_PUBLIC void ixEthDBEventProcessorLoop(void *); 
28 IX_ETH_DB_PUBLIC void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg);
29 IX_ETH_DB_PRIVATE void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts);
30 IX_ETH_DB_PRIVATE IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry);
31 IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStartLearningFunction(void);
32 IX_ETH_DB_PUBLIC IxEthDBStatus ixEthDBStopLearningFunction(void);
33
34 /* data */
35 IX_ETH_DB_PRIVATE IxOsalSemaphore eventQueueSemaphore;
36 IX_ETH_DB_PRIVATE PortEventQueue eventQueue;
37 IX_ETH_DB_PRIVATE IxOsalMutex eventQueueLock;
38 IX_ETH_DB_PRIVATE IxOsalMutex portUpdateLock;
39
40 IX_ETH_DB_PRIVATE BOOL ixEthDBLearningShutdown      = false;
41 IX_ETH_DB_PRIVATE BOOL ixEthDBEventProcessorRunning = false;
42
43 /* imported data */
44 extern HashTable dbHashtable;
45
46 /**
47  * @brief initializes the event processor
48  *
49  * Initializes the event processor queue and processing thread.
50  * Called from ixEthDBInit() DB-subcomponent master init function.
51  *
52  * @warning do not call directly
53  *
54  * @retval IX_ETH_DB_SUCCESS initialization was successful
55  * @retval IX_ETH_DB_FAIL initialization failed (OSAL or mutex init failure)
56  *
57  * @internal
58  */
59 IX_ETH_DB_PUBLIC
60 IxEthDBStatus ixEthDBEventProcessorInit(void)
61 {
62     if (ixOsalMutexInit(&portUpdateLock) != IX_SUCCESS)
63     {
64         return IX_ETH_DB_FAIL;
65     }
66
67     if (ixOsalMutexInit(&eventQueueLock) != IX_SUCCESS)
68     {
69         return IX_ETH_DB_FAIL;
70     }
71
72     if (IX_FEATURE_CTRL_SWCONFIG_ENABLED ==
73         ixFeatureCtrlSwConfigurationCheck (IX_FEATURECTRL_ETH_LEARNING))
74     {
75
76         /* start processor loop thread */
77         if (ixEthDBStartLearningFunction() != IX_ETH_DB_SUCCESS)
78         {
79             return IX_ETH_DB_FAIL;
80         }
81     }
82
83     return IX_ETH_DB_SUCCESS;
84 }
85
86 /**
87  * @brief initializes the event queue and the event processor
88  *
89  * This function is called by the component initialization
90  * function, ixEthDBInit().
91  *
92  * @warning do not call directly
93  *
94  * @return IX_ETH_DB_SUCCESS if the operation completed
95  * successfully or IX_ETH_DB_FAIL otherwise
96  *
97  * @internal
98  */
99 IX_ETH_DB_PUBLIC
100 IxEthDBStatus ixEthDBStartLearningFunction(void)
101 {
102     IxOsalThread eventProcessorThread;
103     IxOsalThreadAttr threadAttr;
104
105     threadAttr.name      = "EthDB event thread";
106     threadAttr.stackSize = 32 * 1024; /* 32kbytes */
107     threadAttr.priority  = 128;
108
109     /* reset event queue */
110     ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
111
112     RESET_QUEUE(&eventQueue);
113
114     ixOsalMutexUnlock(&eventQueueLock);
115
116     /* init event queue semaphore */
117     if (ixOsalSemaphoreInit(&eventQueueSemaphore, 0) != IX_SUCCESS)
118     {
119         return IX_ETH_DB_FAIL;
120     }
121
122     ixEthDBLearningShutdown = false;
123
124     /* create processor loop thread */
125     if (ixOsalThreadCreate(&eventProcessorThread, &threadAttr, ixEthDBEventProcessorLoop, NULL) != IX_SUCCESS)
126     {
127         return IX_ETH_DB_FAIL;
128     }
129
130     /* start event processor */
131     ixOsalThreadStart(&eventProcessorThread);
132
133     return IX_ETH_DB_SUCCESS;
134 }
135
136 /**
137  * @brief stops the event processor
138  *
139  * Stops the event processor and frees the event queue semaphore
140  * Called by the component de-initialization function, ixEthDBUnload()
141  *
142  * @warning do not call directly
143  *
144  * @return IX_ETH_DB_SUCCESS if the operation completed 
145  * successfully or IX_ETH_DB_FAIL otherwise;
146  *
147  * @internal
148  */
149 IX_ETH_DB_PUBLIC
150 IxEthDBStatus ixEthDBStopLearningFunction(void)
151 {
152     ixEthDBLearningShutdown = true;
153
154     /* wake up event processing loop to actually process the shutdown event */
155     ixOsalSemaphorePost(&eventQueueSemaphore);
156
157     if (ixOsalSemaphoreDestroy(&eventQueueSemaphore) != IX_SUCCESS)
158     {
159         return IX_ETH_DB_FAIL;
160     }
161
162     return IX_ETH_DB_SUCCESS;
163 }
164
165 /**
166  * @brief default NPE event processing callback
167  *
168  * @param npeID ID of the NPE that generated the event
169  * @param msg NPE message (encapsulated event)
170  *
171  * Creates an event object on the Ethernet event processor queue
172  * and signals the new event by incrementing the event queue semaphore.
173  * Events are processed by @ref ixEthDBEventProcessorLoop() which runs
174  * at user level.
175  *
176  * @see ixEthDBEventProcessorLoop()
177  *
178  * @warning do not call directly
179  *
180  * @internal
181  */
182 IX_ETH_DB_PUBLIC
183 void ixEthDBNPEEventCallback(IxNpeMhNpeId npeID, IxNpeMhMessage msg)
184 {
185     PortEvent *local_event;
186
187     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);
188
189     if (CAN_ENQUEUE(&eventQueue))
190     {
191         TEST_FIXTURE_LOCK_EVENT_QUEUE;
192
193         local_event = QUEUE_HEAD(&eventQueue);
194
195         /* create event structure on queue */
196         local_event->eventType = NPE_MSG_ID(msg);
197         local_event->portID    = IX_ETH_DB_NPE_TO_PORT_ID(npeID);
198         
199         /* update queue */
200         PUSH_UPDATE_QUEUE(&eventQueue);
201
202         TEST_FIXTURE_UNLOCK_EVENT_QUEUE;
203
204         IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Waking up main processor loop...\n", 0, 0, 0, 0, 0, 0);
205
206         /* increment event queue semaphore */
207         ixOsalSemaphorePost(&eventQueueSemaphore);
208     }
209     else
210     {
211         IX_ETH_DB_IRQ_EVENTS_TRACE("DB: (Events) Warning: could not enqueue event (overflow)\n", 0, 0, 0, 0, 0, 0);
212     }
213 }
214
215 /**
216  * @brief Ethernet event processor loop
217  *
218  * Extracts at most EVENT_PROCESSING_LIMIT batches of events and
219  * sends them for processing to @ref ixEthDBProcessEvent().
220  * Triggers port updates which normally follow learning events.
221  *
222  * @warning do not call directly, executes in separate thread
223  *
224  * @internal
225  */
226 IX_ETH_DB_PUBLIC
227 void ixEthDBEventProcessorLoop(void *unused1)
228 {
229     IxEthDBPortMap triggerPorts;
230     IxEthDBPortId portIndex;
231
232     ixEthDBEventProcessorRunning = true;
233
234     IX_ETH_DB_EVENTS_TRACE("DB: (Events) Event processor loop was started\n");
235
236     while (!ixEthDBLearningShutdown)
237     {
238         BOOL keepProcessing    = true;
239         UINT32 processedEvents = 0;
240
241         IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Waiting for new learning event...\n");
242
243         ixOsalSemaphoreWait(&eventQueueSemaphore, IX_OSAL_WAIT_FOREVER);
244
245         IX_ETH_DB_EVENTS_VERBOSE_TRACE("DB: (Events) Received new event\n");
246
247         if (!ixEthDBLearningShutdown)
248         {
249             /* port update handling */
250             SET_EMPTY_DEPENDENCY_MAP(triggerPorts);
251
252             while (keepProcessing)
253             {
254                 PortEvent local_event;
255                 UINT32 intLockKey;
256
257                 /* lock queue */
258                 ixOsalMutexLock(&eventQueueLock, IX_OSAL_WAIT_FOREVER);
259
260                 /* lock NPE interrupts */
261                 intLockKey = ixOsalIrqLock();
262
263                 /* extract event */
264                 local_event = *(QUEUE_TAIL(&eventQueue));
265
266                 SHIFT_UPDATE_QUEUE(&eventQueue);
267
268                 ixOsalIrqUnlock(intLockKey);
269
270                 ixOsalMutexUnlock(&eventQueueLock);
271
272                 IX_ETH_DB_EVENTS_TRACE("DB: (Events) Processing event with ID 0x%X\n", local_event.eventType);
273
274                 ixEthDBProcessEvent(&local_event, triggerPorts);
275
276                 processedEvents++;
277
278                 if (processedEvents > EVENT_PROCESSING_LIMIT /* maximum burst reached? */
279                     || ixOsalSemaphoreTryWait(&eventQueueSemaphore) != IX_SUCCESS) /* or empty queue? */
280                 {
281                     keepProcessing = false;
282                 }
283             }
284
285             ixEthDBUpdatePortLearningTrees(triggerPorts);
286         }
287     }
288
289     /* turn off automatic updates */
290     for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
291     {
292         ixEthDBPortInfo[portIndex].updateMethod.updateEnabled = false;
293     }
294
295     ixEthDBEventProcessorRunning = false;
296 }
297
298 /**
299  * @brief event processor routine
300  *
301  * @param event event to be processed
302  * @param triggerPorts port map accumulating ports to be updated
303  *
304  * Processes learning events by synchronizing the database with
305  * newly learnt data. Called only by @ref ixEthDBEventProcessorLoop().
306  *
307  * @warning do not call directly
308  *
309  * @internal
310  */
311 IX_ETH_DB_PRIVATE
312 void ixEthDBProcessEvent(PortEvent *local_event, IxEthDBPortMap triggerPorts)
313 {
314     MacDescriptor recordTemplate;
315
316     switch (local_event->eventType)
317     {
318         case IX_ETH_DB_ADD_FILTERING_RECORD:
319             /* add record */
320             memset(&recordTemplate, 0, sizeof (recordTemplate));
321             memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
322             
323             recordTemplate.type   = IX_ETH_DB_FILTERING_RECORD;
324             recordTemplate.portID = local_event->portID;
325             recordTemplate.recordData.filteringData.staticEntry = local_event->staticEntry;
326             
327             ixEthDBAdd(&recordTemplate, triggerPorts);
328
329             IX_ETH_DB_EVENTS_TRACE("DB: (Events) Added record on port %d\n", local_event->portID);
330
331             break;
332
333         case IX_ETH_DB_REMOVE_FILTERING_RECORD:
334             /* remove record */
335             memset(&recordTemplate, 0, sizeof (recordTemplate));
336             memcpy(recordTemplate.macAddress, local_event->macAddr.macAddress, sizeof (IxEthDBMacAddr));
337             
338             recordTemplate.type = IX_ETH_DB_FILTERING_RECORD | IX_ETH_DB_FILTERING_VLAN_RECORD;
339             
340             ixEthDBRemove(&recordTemplate, triggerPorts);
341             
342             IX_ETH_DB_EVENTS_TRACE("DB: (Events) Removed record on port %d\n", local_event->portID);
343
344             break;
345
346         default:
347             /* can't handle/not interested in this event type */
348             ERROR_LOG("DB: (Events) Event processor received an unknown event type (0x%X)\n", local_event->eventType);
349
350             return;
351     }
352 }
353
354 /**
355  * @brief asynchronously adds a filtering record
356  * by posting an ADD_FILTERING_RECORD event to the event queue
357  *
358  * @param macAddr MAC address of the new record
359  * @param portID port ID of the new record
360  * @param staticEntry true if record is static, false if dynamic
361  *
362  * @return IX_ETH_DB_SUCCESS if the event creation was
363  * successfull or IX_ETH_DB_BUSY if the event queue is full
364  *
365  * @internal
366  */
367 IX_ETH_DB_PUBLIC
368 IxEthDBStatus ixEthDBTriggerAddPortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
369 {
370     MacDescriptor reference;
371     
372     TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
373
374     /* fill search fields */
375     memcpy(reference.macAddress, macAddr, sizeof (IxEthDBMacAddr));
376     reference.portID = portID;
377     
378     /* set acceptable record types */
379     reference.type = IX_ETH_DB_ALL_FILTERING_RECORDS;
380
381     if (ixEthDBPeekHashEntry(&dbHashtable, IX_ETH_DB_MAC_PORT_KEY, &reference) == IX_ETH_DB_SUCCESS)
382     {
383         /* already have an identical record */
384         return IX_ETH_DB_SUCCESS;
385     }
386     else
387     {
388         return ixEthDBTriggerPortUpdate(IX_ETH_DB_ADD_FILTERING_RECORD, macAddr, portID, staticEntry);
389     }
390 }
391
392 /**
393  * @brief asynchronously removes a filtering record
394  * by posting a REMOVE_FILTERING_RECORD event to the event queue
395  *
396  * @param macAddr MAC address of the record to remove
397  * @param portID port ID of the record to remove
398  *
399  * @return IX_ETH_DB_SUCCESS if the event creation was
400  * successfull or IX_ETH_DB_BUSY if the event queue is full
401  *
402  * @internal
403  */
404 IX_ETH_DB_PUBLIC
405 IxEthDBStatus ixEthDBTriggerRemovePortUpdate(IxEthDBMacAddr *macAddr, IxEthDBPortId portID)
406 {
407     if (ixEthDBPeek(macAddr, IX_ETH_DB_ALL_FILTERING_RECORDS) != IX_ETH_DB_NO_SUCH_ADDR)
408     {
409         return ixEthDBTriggerPortUpdate(IX_ETH_DB_REMOVE_FILTERING_RECORD, macAddr, portID, false);
410     }
411     else
412     {
413         return IX_ETH_DB_NO_SUCH_ADDR;
414     }
415 }
416
417 /**
418  * @brief adds an ADD or REMOVE event to the main event queue
419  *
420  * @param eventType event type - IX_ETH_DB_ADD_FILTERING_RECORD 
421  * to add and IX_ETH_DB_REMOVE_FILTERING_RECORD to remove a
422  * record.
423  *
424  * @return IX_ETH_DB_SUCCESS if the event was successfully
425  * sent or IX_ETH_DB_BUSY if the event queue is full
426  *
427  * @internal
428  */
429 IX_ETH_DB_PRIVATE
430 IxEthDBStatus ixEthDBTriggerPortUpdate(UINT32 eventType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, BOOL staticEntry)
431 {
432     UINT32 intLockKey;
433
434     /* lock interrupts to protect queue */
435     intLockKey = ixOsalIrqLock();
436
437     if (CAN_ENQUEUE(&eventQueue))
438     {
439         PortEvent *queueEvent = QUEUE_HEAD(&eventQueue);
440
441         /* update fields on the queue */
442         memcpy(queueEvent->macAddr.macAddress, macAddr->macAddress, sizeof (IxEthDBMacAddr));
443         
444         queueEvent->eventType     = eventType;
445         queueEvent->portID        = portID;
446         queueEvent->staticEntry   = staticEntry;
447
448         PUSH_UPDATE_QUEUE(&eventQueue);
449
450         /* imcrement event queue semaphore */
451         ixOsalSemaphorePost(&eventQueueSemaphore);
452         
453         /* unlock interrupts */
454         ixOsalIrqUnlock(intLockKey);
455
456         return IX_ETH_DB_SUCCESS;
457     }
458     else /* event queue full */
459     {
460         /* unlock interrupts */
461         ixOsalIrqUnlock(intLockKey);
462
463         return IX_ETH_DB_BUSY;
464     }
465 }
466
467 /**
468  * @brief Locks learning tree updates and port disable
469  *
470  *
471  * This function locks portUpdateLock single mutex. It is primarily used
472  * to avoid executing 'port disable' during ELT maintenance.
473  *
474  * @internal
475  */
476 IX_ETH_DB_PUBLIC
477 void ixEthDBUpdateLock(void)
478 {
479     ixOsalMutexLock(&portUpdateLock, IX_OSAL_WAIT_FOREVER);
480 }
481
482 /**
483  * @brief Unlocks learning tree updates and port disable
484  *
485  *
486  * This function unlocks a portUpdateLock mutex. It is primarily used
487  * to avoid executing 'port disable' during ELT maintenance.
488  *
489  * @internal
490  */
491 IX_ETH_DB_PUBLIC
492 void ixEthDBUpdateUnlock(void)
493 {
494     ixOsalMutexUnlock(&portUpdateLock);
495 }
496