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