]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxEthDBMem.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / net / npe / IxEthDBMem.c
1 /**
2  * @file IxEthDBDBMem.c
3  *
4  * @brief Memory handling routines for the MAC address database
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
22 #include "IxEthDB_p.h"
23
24 IX_ETH_DB_PRIVATE HashNode *nodePool     = NULL;
25 IX_ETH_DB_PRIVATE MacDescriptor *macPool = NULL;
26 IX_ETH_DB_PRIVATE MacTreeNode *treePool  = NULL;
27
28 IX_ETH_DB_PRIVATE HashNode nodePoolArea[NODE_POOL_SIZE];
29 IX_ETH_DB_PRIVATE MacDescriptor macPoolArea[MAC_POOL_SIZE];
30 IX_ETH_DB_PRIVATE MacTreeNode treePoolArea[TREE_POOL_SIZE];
31
32 IX_ETH_DB_PRIVATE IxOsalMutex nodePoolLock;
33 IX_ETH_DB_PRIVATE IxOsalMutex macPoolLock;
34 IX_ETH_DB_PRIVATE IxOsalMutex treePoolLock;
35
36 #define LOCK_NODE_POOL   { ixOsalMutexLock(&nodePoolLock, IX_OSAL_WAIT_FOREVER); }
37 #define UNLOCK_NODE_POOL { ixOsalMutexUnlock(&nodePoolLock); }
38
39 #define LOCK_MAC_POOL    { ixOsalMutexLock(&macPoolLock, IX_OSAL_WAIT_FOREVER); }
40 #define UNLOCK_MAC_POOL  { ixOsalMutexUnlock(&macPoolLock); }
41
42 #define LOCK_TREE_POOL   { ixOsalMutexLock(&treePoolLock, IX_OSAL_WAIT_FOREVER); }
43 #define UNLOCK_TREE_POOL { ixOsalMutexUnlock(&treePoolLock); }
44
45 /* private function prototypes */
46 IX_ETH_DB_PRIVATE MacDescriptor* ixEthDBPoolAllocMacDescriptor(void);
47 IX_ETH_DB_PRIVATE void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor);
48
49 /**
50  * @addtogroup EthMemoryManagement
51  *
52  * @{
53  */
54
55 /**
56  * @brief initializes the memory pools used by the ethernet database component
57  *
58  * Initializes the hash table node, mac descriptor and mac tree node pools.
59  * Called at initialization time by @ref ixEthDBInit().
60  *
61  * @internal
62  */
63 IX_ETH_DB_PUBLIC
64 void ixEthDBInitMemoryPools(void)
65 {
66     int local_index;
67
68     /* HashNode pool */
69     ixOsalMutexInit(&nodePoolLock);
70
71     for (local_index = 0 ; local_index < NODE_POOL_SIZE ; local_index++)
72     {
73         HashNode *freeNode = &nodePoolArea[local_index];
74
75         freeNode->nextFree = nodePool;
76         nodePool           = freeNode;
77     }
78
79     /* MacDescriptor pool */
80     ixOsalMutexInit(&macPoolLock);
81
82     for (local_index = 0 ; local_index < MAC_POOL_SIZE ; local_index++)
83     {
84         MacDescriptor *freeDescriptor = &macPoolArea[local_index];
85
86         freeDescriptor->nextFree = macPool;
87         macPool                  = freeDescriptor;
88     }
89
90     /* MacTreeNode pool */
91     ixOsalMutexInit(&treePoolLock);
92
93     for (local_index = 0 ; local_index < TREE_POOL_SIZE ; local_index++)
94     {
95         MacTreeNode *freeNode = &treePoolArea[local_index];
96
97         freeNode->nextFree = treePool;
98         treePool           = freeNode;
99     }
100 }
101
102 /**
103  * @brief allocates a hash node from the pool
104  *
105  * Allocates a hash node and resets its value.
106  *
107  * @return the allocated hash node or NULL if the pool is empty
108  *
109  * @internal
110  */
111 IX_ETH_DB_PUBLIC
112 HashNode* ixEthDBAllocHashNode(void)
113 {
114     HashNode *allocatedNode = NULL;
115
116     if (nodePool != NULL)
117     {
118         LOCK_NODE_POOL;
119
120         allocatedNode = nodePool;
121         nodePool      = nodePool->nextFree;
122
123         UNLOCK_NODE_POOL;
124
125         memset(allocatedNode, 0, sizeof(HashNode));
126     }
127
128     return allocatedNode;
129 }
130
131 /**
132  * @brief frees a hash node into the pool
133  *
134  * @param hashNode node to be freed
135  *
136  * @internal
137  */
138 IX_ETH_DB_PUBLIC
139 void ixEthDBFreeHashNode(HashNode *hashNode)
140 {
141     if (hashNode != NULL)
142     {
143         LOCK_NODE_POOL;
144
145         hashNode->nextFree = nodePool;
146         nodePool           = hashNode;
147
148         UNLOCK_NODE_POOL;
149     }
150 }
151
152 /**
153  * @brief allocates a mac descriptor from the pool
154  *
155  * Allocates a mac descriptor and resets its value.
156  * This function is not used directly, instead @ref ixEthDBAllocMacDescriptor()
157  * is used, which keeps track of the pointer reference count.
158  *
159  * @see ixEthDBAllocMacDescriptor()
160  * 
161  * @warning this function is not used directly by any other function
162  * apart from ixEthDBAllocMacDescriptor()
163  *
164  * @return the allocated mac descriptor or NULL if the pool is empty
165  *
166  * @internal
167  */
168 IX_ETH_DB_PRIVATE
169 MacDescriptor* ixEthDBPoolAllocMacDescriptor(void)
170 {
171     MacDescriptor *allocatedDescriptor = NULL;
172
173     if (macPool != NULL)
174     {
175         LOCK_MAC_POOL;
176
177         allocatedDescriptor = macPool;
178         macPool             = macPool->nextFree;
179
180         UNLOCK_MAC_POOL;
181
182         memset(allocatedDescriptor, 0, sizeof(MacDescriptor));
183     }
184
185     return allocatedDescriptor;
186 }
187
188 /**
189  * @brief allocates and initializes a mac descriptor smart pointer
190  *
191  * Uses @ref ixEthDBPoolAllocMacDescriptor() to allocate a mac descriptor
192  * from the pool and initializes its reference count.
193  *
194  * @see ixEthDBPoolAllocMacDescriptor()
195  *
196  * @return the allocated mac descriptor or NULL if the pool is empty
197  *
198  * @internal
199  */
200 IX_ETH_DB_PUBLIC
201 MacDescriptor* ixEthDBAllocMacDescriptor(void)
202 {
203     MacDescriptor *allocatedDescriptor = ixEthDBPoolAllocMacDescriptor();
204
205     if (allocatedDescriptor != NULL)
206     {
207         LOCK_MAC_POOL;
208
209         allocatedDescriptor->refCount++;
210
211         UNLOCK_MAC_POOL;
212     }
213
214     return allocatedDescriptor;
215 }
216
217 /**
218  * @brief frees a mac descriptor back into the pool
219  *
220  * @param macDescriptor mac descriptor to be freed
221  *
222  * @warning this function is not to be called by anyone but
223  * ixEthDBFreeMacDescriptor()
224  *
225  * @see ixEthDBFreeMacDescriptor()
226  *
227  * @internal
228  */
229 IX_ETH_DB_PRIVATE
230 void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor)
231 {
232     LOCK_MAC_POOL;
233
234     macDescriptor->nextFree = macPool;
235     macPool                 = macDescriptor;
236
237     UNLOCK_MAC_POOL;
238 }
239
240 /**
241  * @brief frees or reduces the usage count of a mac descriptor smart pointer
242  *
243  * If the reference count reaches 0 (structure is no longer used anywhere)
244  * then the descriptor is freed back into the pool using ixEthDBPoolFreeMacDescriptor().
245  *
246  * @see ixEthDBPoolFreeMacDescriptor()
247  *
248  * @internal
249  */
250 IX_ETH_DB_PUBLIC
251 void ixEthDBFreeMacDescriptor(MacDescriptor *macDescriptor)
252 {
253     if (macDescriptor != NULL)
254     {
255         LOCK_MAC_POOL;
256
257         if (macDescriptor->refCount > 0)
258         {
259             macDescriptor->refCount--;
260
261             if (macDescriptor->refCount == 0)
262             {
263                 UNLOCK_MAC_POOL;
264
265                 ixEthDBPoolFreeMacDescriptor(macDescriptor);
266             }
267             else
268             {
269                 UNLOCK_MAC_POOL;
270             }
271         }
272         else
273         {
274             UNLOCK_MAC_POOL;
275         }
276     }
277 }
278
279 /**
280  * @brief clones a mac descriptor smart pointer
281  *
282  * @param macDescriptor mac descriptor to clone
283  *
284  * Increments the usage count of the smart pointer
285  *
286  * @returns the cloned smart pointer
287  *
288  * @internal
289  */
290 IX_ETH_DB_PUBLIC
291 MacDescriptor* ixEthDBCloneMacDescriptor(MacDescriptor *macDescriptor)
292 {
293     LOCK_MAC_POOL;
294
295     if (macDescriptor->refCount == 0)
296     {
297         UNLOCK_MAC_POOL;
298
299         return NULL;
300     }
301
302     macDescriptor->refCount++;
303
304     UNLOCK_MAC_POOL;
305
306     return macDescriptor;
307 }
308
309 /**
310  * @brief allocates a mac tree node from the pool
311  *
312  * Allocates and initializes a mac tree node from the pool.
313  *
314  * @return the allocated mac tree node or NULL if the pool is empty
315  *
316  * @internal
317  */
318 IX_ETH_DB_PUBLIC
319 MacTreeNode* ixEthDBAllocMacTreeNode(void)
320 {
321     MacTreeNode *allocatedNode = NULL;
322
323     if (treePool != NULL)
324     {
325         LOCK_TREE_POOL;
326
327         allocatedNode = treePool;
328         treePool      = treePool->nextFree;
329
330         UNLOCK_TREE_POOL;
331
332         memset(allocatedNode, 0, sizeof(MacTreeNode));
333     }
334
335     return allocatedNode;
336 }
337
338 /**
339  * @brief frees a mac tree node back into the pool
340  *
341  * @param macNode mac tree node to be freed
342  *
343  * @warning not to be used except from ixEthDBFreeMacTreeNode().
344  *
345  * @see ixEthDBFreeMacTreeNode()
346  *
347  * @internal
348  */
349 void ixEthDBPoolFreeMacTreeNode(MacTreeNode *macNode)
350 {
351     if (macNode != NULL)
352     {
353         LOCK_TREE_POOL;
354
355         macNode->nextFree = treePool;
356         treePool          = macNode;
357
358         UNLOCK_TREE_POOL;
359     }
360 }
361
362 /**
363  * @brief frees or reduces the usage count of a mac tree node smart pointer
364  *
365  * @param macNode mac tree node to free
366  *
367  * Reduces the usage count of the given mac node. If the usage count
368  * reaches 0 the node is freed back into the pool using ixEthDBPoolFreeMacTreeNode()
369  *
370  * @internal
371  */
372 IX_ETH_DB_PUBLIC
373 void ixEthDBFreeMacTreeNode(MacTreeNode *macNode)
374 {
375     if (macNode->descriptor != NULL)
376     {
377         ixEthDBFreeMacDescriptor(macNode->descriptor);
378     }
379
380     if (macNode->left != NULL)
381     {
382         ixEthDBFreeMacTreeNode(macNode->left);
383     }
384
385     if (macNode->right != NULL)
386     {
387         ixEthDBFreeMacTreeNode(macNode->right);
388     }
389
390     ixEthDBPoolFreeMacTreeNode(macNode);
391 }
392
393 /**
394  * @brief clones a mac tree node
395  *
396  * @param macNode mac tree node to be cloned
397  *
398  * Increments the usage count of the node, <i>its associated descriptor 
399  * and <b>recursively</b> of all its child nodes</i>.
400  *
401  * @warning this function is recursive and clones whole trees/subtrees, use only for
402  * root nodes
403  *
404  * @internal
405  */
406 IX_ETH_DB_PUBLIC
407 MacTreeNode* ixEthDBCloneMacTreeNode(MacTreeNode *macNode)
408 {
409     if (macNode != NULL)
410     {
411         MacTreeNode *clonedMacNode = ixEthDBAllocMacTreeNode();
412
413         if (clonedMacNode != NULL)
414         {
415             if (macNode->right != NULL)
416             {
417                 clonedMacNode->right = ixEthDBCloneMacTreeNode(macNode->right);
418             }
419
420             if (macNode->left != NULL)
421             {
422                 clonedMacNode->left = ixEthDBCloneMacTreeNode(macNode->left);
423             }
424
425             if (macNode->descriptor != NULL)
426             {
427                 clonedMacNode->descriptor = ixEthDBCloneMacDescriptor(macNode->descriptor);
428             }
429         }
430
431         return clonedMacNode;
432     }
433     else
434     {
435         return NULL;
436     }
437 }
438
439 #ifndef NDEBUG
440 /* Debug statistical functions for memory usage */
441
442 extern HashTable dbHashtable;
443 int ixEthDBNumHashElements(void);
444
445 int ixEthDBNumHashElements(void)
446 {   
447     UINT32 bucketIndex;
448     int numElements = 0;
449     HashTable *hashTable = &dbHashtable;
450
451     for (bucketIndex = 0 ; bucketIndex < hashTable->numBuckets ; bucketIndex++)
452     {
453         if (hashTable->hashBuckets[bucketIndex] != NULL)
454         {
455             HashNode *node = hashTable->hashBuckets[bucketIndex];
456
457             while (node != NULL)
458             {
459                 numElements++;
460
461                 node = node->next;
462             }
463         }
464     }
465
466     return numElements;
467 }
468
469 UINT32 ixEthDBSearchTreeUsageGet(MacTreeNode *tree)
470 {
471     if (tree == NULL)
472     {
473         return 0;
474     }
475     else
476     {
477         return 1 /* this node */ + ixEthDBSearchTreeUsageGet(tree->left) + ixEthDBSearchTreeUsageGet(tree->right);
478     }
479 }
480
481 int ixEthDBShowMemoryStatus(void)
482 {
483     MacDescriptor *mac;
484     MacTreeNode *tree;
485     HashNode *node;
486
487     int macCounter  = 0;
488     int treeCounter = 0;
489     int nodeCounter = 0;
490
491     int totalTreeUsage            = 0;
492     int totalDescriptorUsage      = 0;
493     int totalCloneDescriptorUsage = 0;
494     int totalNodeUsage            = 0;
495
496     UINT32 portIndex;
497
498     LOCK_NODE_POOL;
499     LOCK_MAC_POOL;
500     LOCK_TREE_POOL;
501
502     mac  = macPool;
503     tree = treePool;
504     node = nodePool;
505
506     while (mac != NULL)
507     {
508         macCounter++;
509
510         mac = mac->nextFree;
511
512         if (macCounter > MAC_POOL_SIZE)
513         {
514             break;
515         }
516     }
517
518     while (tree != NULL)
519     {
520         treeCounter++;
521
522         tree = tree->nextFree;
523
524         if (treeCounter > TREE_POOL_SIZE)
525         {
526             break;
527         }
528     }
529
530     while (node != NULL)
531     {
532         nodeCounter++;
533
534         node = node->nextFree;
535
536         if (nodeCounter > NODE_POOL_SIZE)
537         {
538             break;
539         }
540     }
541
542     for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
543     {
544         int treeUsage = ixEthDBSearchTreeUsageGet(ixEthDBPortInfo[portIndex].updateMethod.searchTree);
545
546         totalTreeUsage            += treeUsage;
547         totalCloneDescriptorUsage += treeUsage; /* each tree node contains a descriptor */
548     }
549
550     totalNodeUsage        = ixEthDBNumHashElements();
551     totalDescriptorUsage += totalNodeUsage; /* each hash table entry contains a descriptor */
552
553     UNLOCK_NODE_POOL;
554     UNLOCK_MAC_POOL;
555     UNLOCK_TREE_POOL;
556
557     printf("Ethernet database memory usage stats:\n\n");
558
559     if (macCounter <= MAC_POOL_SIZE)
560     {
561         printf("\tMAC descriptor pool  : %d free out of %d entries (%d%%)\n", macCounter, MAC_POOL_SIZE, macCounter * 100 / MAC_POOL_SIZE);
562     }
563     else
564     {
565         printf("\tMAC descriptor pool  : invalid state (ring within the pool), normally %d entries\n", MAC_POOL_SIZE);
566     }
567
568     if (treeCounter <= TREE_POOL_SIZE)
569     {
570         printf("\tTree node pool       : %d free out of %d entries (%d%%)\n", treeCounter, TREE_POOL_SIZE, treeCounter * 100 / TREE_POOL_SIZE);
571     }
572     else
573     {
574         printf("\tTREE descriptor pool  : invalid state (ring within the pool), normally %d entries\n", TREE_POOL_SIZE);
575     }
576
577     if (nodeCounter <= NODE_POOL_SIZE)
578     {
579         printf("\tHash node pool       : %d free out of %d entries (%d%%)\n", nodeCounter, NODE_POOL_SIZE, nodeCounter * 100 / NODE_POOL_SIZE);
580     }
581     else
582     {
583         printf("\tNODE descriptor pool  : invalid state (ring within the pool), normally %d entries\n", NODE_POOL_SIZE);
584     }
585
586     printf("\n");
587     printf("\tMAC descriptor usage : %d entries, %d cloned\n", totalDescriptorUsage, totalCloneDescriptorUsage);
588     printf("\tTree node usage      : %d entries\n", totalTreeUsage);
589     printf("\tHash node usage      : %d entries\n", totalNodeUsage);
590     printf("\n");
591
592     /* search for duplicate nodes in the mac pool */
593     {
594         MacDescriptor *reference = macPool;
595
596         while (reference != NULL)
597         {
598             MacDescriptor *comparison = reference->nextFree;
599
600             while (comparison != NULL)
601             {
602                 if (reference == comparison)
603                 {
604                     printf("Warning: reached a duplicate (%p), invalid MAC pool state\n", reference);
605
606                     return 1;
607                 }
608
609                 comparison = comparison->nextFree;
610             }
611
612             reference = reference->nextFree;
613         }
614     }
615
616     printf("No duplicates found in the MAC pool (sanity check ok)\n");
617
618     return 0;
619 }
620
621 #endif /* NDEBUG */
622
623 /**
624  * @} EthMemoryManagement
625  */