blob: 78fce4bd9247593c2ccc0d78cb8eebf174682f70 [file] [log] [blame]
Wolfgang Denk4646d2a2006-05-30 15:56:48 +02001/**
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
Wolfgang Denkc57eadc2013-07-28 22:12:47 +020016 * SPDX-License-Identifier: BSD-3-Clause
Wolfgang Denk4646d2a2006-05-30 15:56:48 +020017 * @par
18 * -- End of Copyright Notice --
19 */
20
21
22#include "IxEthDB_p.h"
23
24IX_ETH_DB_PRIVATE HashNode *nodePool = NULL;
25IX_ETH_DB_PRIVATE MacDescriptor *macPool = NULL;
26IX_ETH_DB_PRIVATE MacTreeNode *treePool = NULL;
27
28IX_ETH_DB_PRIVATE HashNode nodePoolArea[NODE_POOL_SIZE];
29IX_ETH_DB_PRIVATE MacDescriptor macPoolArea[MAC_POOL_SIZE];
30IX_ETH_DB_PRIVATE MacTreeNode treePoolArea[TREE_POOL_SIZE];
31
32IX_ETH_DB_PRIVATE IxOsalMutex nodePoolLock;
33IX_ETH_DB_PRIVATE IxOsalMutex macPoolLock;
34IX_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 */
46IX_ETH_DB_PRIVATE MacDescriptor* ixEthDBPoolAllocMacDescriptor(void);
47IX_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 */
63IX_ETH_DB_PUBLIC
64void 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 */
111IX_ETH_DB_PUBLIC
112HashNode* 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 */
138IX_ETH_DB_PUBLIC
139void 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 */
168IX_ETH_DB_PRIVATE
169MacDescriptor* 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 */
200IX_ETH_DB_PUBLIC
201MacDescriptor* 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 */
229IX_ETH_DB_PRIVATE
230void 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 */
250IX_ETH_DB_PUBLIC
251void 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 */
290IX_ETH_DB_PUBLIC
291MacDescriptor* 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 */
318IX_ETH_DB_PUBLIC
319MacTreeNode* 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 */
349void 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 */
372IX_ETH_DB_PUBLIC
373void 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 */
406IX_ETH_DB_PUBLIC
407MacTreeNode* 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
442extern HashTable dbHashtable;
443int ixEthDBNumHashElements(void);
444
445int 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
469UINT32 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
481int 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 */