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