Merge branch 'mpc86xx'
[oweals/u-boot.git] / cpu / ixp / npe / IxEthDBCore.c
1 /**
2  * @file IxEthDBDBCore.c
3  *
4  * @brief Database support functions
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 "IxEthDB_p.h"
46
47 /* list of database hashtables */
48 IX_ETH_DB_PUBLIC HashTable dbHashtable;
49 IX_ETH_DB_PUBLIC MatchFunction matchFunctions[IX_ETH_DB_MAX_KEY_INDEX + 1];
50 IX_ETH_DB_PUBLIC BOOL ixEthDBPortUpdateRequired[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1];
51 IX_ETH_DB_PUBLIC UINT32 ixEthDBKeyType[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1];
52
53 /* private initialization flag */
54 IX_ETH_DB_PRIVATE BOOL ethDBInitializationComplete = FALSE;
55
56 /**
57  * @brief initializes EthDB
58  *
59  * This function must be called to initialize the component.
60  *
61  * It does the following things:
62  * - checks the port definition structure
63  * - scans the capabilities of the NPE images and sets the
64  *   capabilities of the ports accordingly
65  * - initializes the memory pools internally used in EthDB
66  *   for storing database records and handling data
67  * - registers automatic update handlers for add and remove
68  *   operations
69  * - registers hashing match functions, depending on key sets
70  * - initializes the main database hashtable
71  * - allocates contiguous memory zones to be used for NPE
72  *   updates
73  * - registers the serialize methods used to convert data
74  *   into NPE-readable format
75  * - starts the event processor
76  *
77  * Note that this function is documented in the public
78  * component header file, IxEthDB.h.
79  *
80  * @return IX_ETH_DB_SUCCESS or an appropriate error if the
81  * component failed to initialize correctly
82  */
83 IX_ETH_DB_PUBLIC
84 IxEthDBStatus ixEthDBInit(void)
85 {
86     IxEthDBStatus result;
87
88     if (ethDBInitializationComplete)
89     {
90         /* redundant */
91         return IX_ETH_DB_SUCCESS;
92     }
93
94     /* trap an invalid port definition structure */
95     IX_ETH_DB_PORTS_ASSERTION;
96
97     /* memory management */
98     ixEthDBInitMemoryPools();
99
100     /* register hashing search methods */
101     ixEthDBMatchMethodsRegister(matchFunctions);
102
103     /* register type-based automatic port updates */
104     ixEthDBUpdateTypeRegister(ixEthDBPortUpdateRequired);
105
106     /* register record to key type mappings */
107     ixEthDBKeyTypeRegister(ixEthDBKeyType);
108
109     /* hash table */
110     ixEthDBInitHash(&dbHashtable, NUM_BUCKETS, ixEthDBEntryXORHash, matchFunctions, (FreeFunction) ixEthDBFreeMacDescriptor);
111
112     /* NPE update zones */
113     ixEthDBNPEUpdateAreasInit();
114
115     /* register record serialization methods */
116     ixEthDBRecordSerializeMethodsRegister();
117
118     /* start the event processor */
119     result = ixEthDBEventProcessorInit();
120
121     /* scan NPE features */
122     if (result == IX_ETH_DB_SUCCESS)
123     {
124         ixEthDBFeatureCapabilityScan();
125     }
126
127     ethDBInitializationComplete = TRUE;
128
129     return result;
130 }
131
132 /**
133  * @brief prepares EthDB for unloading
134  *
135  * This function must be called before removing the
136  * EthDB component from memory (e.g. doing rmmod in
137  * Linux) if the component is to be re-initialized again
138  * without rebooting the platform.
139  *
140  * All the EthDB ports must be disabled before this
141  * function is to be called. Failure to disable all
142  * the ports will return the IX_ETH_DB_BUSY error.
143  *
144  * This function will destroy mutexes, deallocate
145  * memory and stop the event processor.
146  *
147  * Note that this function is fully documented in the
148  * main component header file, IxEthDB.h.
149  *
150  * @return IX_ETH_DB_SUCCESS if de-initialization
151  * completed successfully or an appropriate error
152  * message otherwise
153  */
154 IX_ETH_DB_PUBLIC
155 IxEthDBStatus ixEthDBUnload(void)
156 {
157     IxEthDBPortId portIndex;
158
159     if (!ethDBInitializationComplete)
160     {
161         /* redundant */
162         return IX_ETH_DB_SUCCESS;
163     }
164
165     /* check if any ports are enabled */
166     for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
167     {
168         if (ixEthDBPortInfo[portIndex].enabled)
169         {
170             return IX_ETH_DB_BUSY;
171         }
172     }
173
174     /* free port resources */
175     for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
176     {
177         if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE)
178         {
179             ixOsalMutexDestroy(&ixEthDBPortInfo[portIndex].npeAckLock);
180         }
181
182         ixEthDBPortInfo[portIndex].initialized = FALSE;
183     }
184
185     /* shutdown event processor */
186     ixEthDBStopLearningFunction();
187
188     /* deallocate NPE update zones */
189     ixEthDBNPEUpdateAreasUnload();
190
191     ethDBInitializationComplete = FALSE;
192
193     return IX_ETH_DB_SUCCESS;
194 }
195
196 /**
197  * @brief adds a new entry to the Ethernet database
198  *
199  * @param newRecordTemplate address of the record template to use
200  * @param updateTrigger port map containing the update triggers
201  * resulting from this update operation
202  *
203  * Creates a new database entry, populates it with the data
204  * copied from the given template and adds the record to the
205  * database hash table.
206  * It also checks whether the new record type is registered to trigger
207  * automatic updates; if it is, the update trigger will contain the
208  * port on which the record insertion was performed, as well as the
209  * old port in case the addition was a record migration (from one port
210  * to the other). The caller can use the updateTrigger to trigger
211  * automatic updates on the ports changed as a result of this addition.
212  *
213  * @retval IX_ETH_DB_SUCCESS addition successful
214  * @retval IX_ETH_DB_NOMEM insertion failed, no memory left in the mac descriptor memory pool
215  * @retval IX_ETH_DB_BUSY database busy, cannot insert due to locking
216  *
217  * @internal
218  */
219 IX_ETH_DB_PUBLIC
220 IxEthDBStatus ixEthDBAdd(MacDescriptor *newRecordTemplate, IxEthDBPortMap updateTrigger)
221 {
222     IxEthDBStatus result;
223     MacDescriptor *newDescriptor;
224     IxEthDBPortId originalPortID;
225     HashNode *node = NULL;
226
227     BUSY_RETRY(ixEthDBSearchHashEntry(&dbHashtable, ixEthDBKeyType[newRecordTemplate->type], newRecordTemplate, &node));
228
229     TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
230
231     if (node == NULL)
232     {
233         /* not found, create a new one */
234         newDescriptor = ixEthDBAllocMacDescriptor();
235
236         if (newDescriptor == NULL)
237         {
238             return IX_ETH_DB_NOMEM; /* no memory */
239         }
240
241         /* old port does not exist, avoid unnecessary updates */
242         originalPortID = newRecordTemplate->portID;
243     }
244     else
245     {
246         /* a node with the same key exists, will update node */
247         newDescriptor = (MacDescriptor *) node->data;
248
249         /* save original port id */
250         originalPortID = newDescriptor->portID;
251     }
252
253     /* copy/update fields into new record */
254     memcpy(newDescriptor->macAddress, newRecordTemplate->macAddress, sizeof (IxEthDBMacAddr));
255     memcpy(&newDescriptor->recordData, &newRecordTemplate->recordData, sizeof (IxEthDBRecordData));
256
257     newDescriptor->type   = newRecordTemplate->type;
258     newDescriptor->portID = newRecordTemplate->portID;
259     newDescriptor->user   = newRecordTemplate->user;
260
261     if (node == NULL)
262     {
263         /* new record, insert into hashtable */
264         BUSY_RETRY_WITH_RESULT(ixEthDBAddHashEntry(&dbHashtable, newDescriptor), result);
265
266         if (result != IX_ETH_DB_SUCCESS)
267         {
268             ixEthDBFreeMacDescriptor(newDescriptor);
269
270             return result; /* insertion failed */
271         }
272     }
273
274     if (node != NULL)
275     {
276         /* release access */
277         ixEthDBReleaseHashNode(node);
278     }
279
280     /* trigger add/remove update if required by type */
281     if (updateTrigger != NULL &&
282         ixEthDBPortUpdateRequired[newRecordTemplate->type])
283     {
284         /* add new port to update list */
285         JOIN_PORT_TO_MAP(updateTrigger, newRecordTemplate->portID);
286
287         /* check if record has moved, we'll need to update the old port as well */
288         if (originalPortID != newDescriptor->portID)
289         {
290             JOIN_PORT_TO_MAP(updateTrigger, originalPortID);
291         }
292     }
293
294     return IX_ETH_DB_SUCCESS;
295 }
296
297 /**
298  * @brief remove a record from the Ethernet database
299  *
300  * @param templateRecord template record used to determine
301  * what record is to be removed
302  * @param updateTrigger port map containing the update triggers
303  * resulting from this update operation
304  *
305  * This function will examine the template record it receives
306  * and attempts to delete a record of the same type and containing
307  * the same keys as the template record. If deletion is successful
308  * and the record type is registered for automatic port updates the
309  * port will also be set in the updateTrigger port map, so that the
310  * client can perform an update of the port.
311  *
312  * @retval IX_ETH_DB_SUCCESS removal was successful
313  * @retval IX_ETH_DB_NO_SUCH_ADDR the record with the given MAC address was not found
314  * @retval IX_ETH_DB_BUSY database busy, cannot remove due to locking
315  *
316  * @internal
317  */
318 IX_ETH_DB_PUBLIC
319 IxEthDBStatus ixEthDBRemove(MacDescriptor *templateRecord, IxEthDBPortMap updateTrigger)
320 {
321     IxEthDBStatus result;
322
323     TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
324
325     BUSY_RETRY_WITH_RESULT(ixEthDBRemoveHashEntry(&dbHashtable, ixEthDBKeyType[templateRecord->type], templateRecord), result);
326
327     if (result != IX_ETH_DB_SUCCESS)
328     {
329         return IX_ETH_DB_NO_SUCH_ADDR; /* not found */
330     }
331
332     /* trigger add/remove update if required by type */
333     if (updateTrigger != NULL
334         &&ixEthDBPortUpdateRequired[templateRecord->type])
335     {
336         /* add new port to update list */
337         JOIN_PORT_TO_MAP(updateTrigger, templateRecord->portID);
338     }
339
340     return IX_ETH_DB_SUCCESS;
341 }
342
343 /**
344  * @brief register record key types
345  *
346  * This function registers the appropriate key types,
347  * depending on record types.
348  *
349  * All filtering records use the MAC address as the key.
350  * WiFi and Firewall records use a compound key consisting
351  * in both the MAC address and the port ID.
352  *
353  * @return the number of registered record types
354  */
355 IX_ETH_DB_PUBLIC
356 UINT32 ixEthDBKeyTypeRegister(UINT32 *keyType)
357 {
358     /* safety */
359     memset(keyType, 0, sizeof (keyType));
360
361     /* register all known record types */
362     keyType[IX_ETH_DB_FILTERING_RECORD]      = IX_ETH_DB_MAC_KEY;
363     keyType[IX_ETH_DB_FILTERING_VLAN_RECORD] = IX_ETH_DB_MAC_KEY;
364     keyType[IX_ETH_DB_ALL_FILTERING_RECORDS] = IX_ETH_DB_MAC_KEY;
365     keyType[IX_ETH_DB_WIFI_RECORD]           = IX_ETH_DB_MAC_PORT_KEY;
366     keyType[IX_ETH_DB_FIREWALL_RECORD]       = IX_ETH_DB_MAC_PORT_KEY;
367
368     return 5;
369 }
370
371 /**
372  * @brief Sets a user-defined field into a database record
373  *
374  * Note that this function is fully documented in the main component
375  * header file.
376  */
377 IX_ETH_DB_PUBLIC
378 IxEthDBStatus ixEthDBUserFieldSet(IxEthDBRecordType recordType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, IxEthDBVlanId vlanID, void *field)
379 {
380     HashNode *result = NULL;
381
382     if (macAddr == NULL)
383     {
384         return IX_ETH_DB_INVALID_ARG;
385     }
386
387     if (recordType == IX_ETH_DB_FILTERING_RECORD)
388     {
389         result = ixEthDBSearch(macAddr, recordType);
390     }
391     else if (recordType == IX_ETH_DB_FILTERING_VLAN_RECORD)
392     {
393         result = ixEthDBVlanSearch(macAddr, vlanID, recordType);
394     }
395     else if (recordType == IX_ETH_DB_WIFI_RECORD || recordType == IX_ETH_DB_FIREWALL_RECORD)
396     {
397         IX_ETH_DB_CHECK_PORT_EXISTS(portID);
398
399         result = ixEthDBPortSearch(macAddr, portID, recordType);
400     }
401     else
402     {
403         return IX_ETH_DB_INVALID_ARG;
404     }
405
406     if (result == NULL)
407     {
408         return IX_ETH_DB_NO_SUCH_ADDR;
409     }
410
411     ((MacDescriptor *) result->data)->user = field;
412
413     ixEthDBReleaseHashNode(result);
414
415     return IX_ETH_DB_SUCCESS;
416 }
417
418 /**
419  * @brief Retrieves a user-defined field from a database record
420  *
421  * Note that this function is fully documented in the main component
422  * header file.
423  */
424 IX_ETH_DB_PUBLIC
425 IxEthDBStatus ixEthDBUserFieldGet(IxEthDBRecordType recordType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, IxEthDBVlanId vlanID, void **field)
426 {
427     HashNode *result = NULL;
428
429     if (macAddr == NULL || field == NULL)
430     {
431         return IX_ETH_DB_INVALID_ARG;
432     }
433
434     if (recordType == IX_ETH_DB_FILTERING_RECORD)
435     {
436         result = ixEthDBSearch(macAddr, recordType);
437     }
438     else if (recordType == IX_ETH_DB_FILTERING_VLAN_RECORD)
439     {
440         result = ixEthDBVlanSearch(macAddr, vlanID, recordType);
441     }
442     else if (recordType == IX_ETH_DB_WIFI_RECORD || recordType == IX_ETH_DB_FIREWALL_RECORD)
443     {
444         IX_ETH_DB_CHECK_PORT_EXISTS(portID);
445
446         result = ixEthDBPortSearch(macAddr, portID, recordType);
447     }
448     else
449     {
450         return IX_ETH_DB_INVALID_ARG;
451     }
452
453     if (result == NULL)
454     {
455         return IX_ETH_DB_NO_SUCH_ADDR;
456     }
457
458     *field = ((MacDescriptor *) result->data)->user;
459
460     ixEthDBReleaseHashNode(result);
461
462     return IX_ETH_DB_SUCCESS;
463 }