summaryrefslogtreecommitdiff
path: root/cpu/ixp/npe/IxEthDBMem.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/ixp/npe/IxEthDBMem.c')
-rw-r--r--cpu/ixp/npe/IxEthDBMem.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/cpu/ixp/npe/IxEthDBMem.c b/cpu/ixp/npe/IxEthDBMem.c
new file mode 100644
index 0000000..133cbef
--- /dev/null
+++ b/cpu/ixp/npe/IxEthDBMem.c
@@ -0,0 +1,649 @@
+/**
+ * @file IxEthDBDBMem.c
+ *
+ * @brief Memory handling routines for the MAC address database
+ *
+ * @par
+ * IXP400 SW Release version 2.0
+ *
+ * -- Copyright Notice --
+ *
+ * @par
+ * Copyright 2001-2005, Intel Corporation.
+ * All rights reserved.
+ *
+ * @par
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * @par
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @par
+ * -- End of Copyright Notice --
+ */
+
+
+#include "IxEthDB_p.h"
+
+IX_ETH_DB_PRIVATE HashNode *nodePool = NULL;
+IX_ETH_DB_PRIVATE MacDescriptor *macPool = NULL;
+IX_ETH_DB_PRIVATE MacTreeNode *treePool = NULL;
+
+IX_ETH_DB_PRIVATE HashNode nodePoolArea[NODE_POOL_SIZE];
+IX_ETH_DB_PRIVATE MacDescriptor macPoolArea[MAC_POOL_SIZE];
+IX_ETH_DB_PRIVATE MacTreeNode treePoolArea[TREE_POOL_SIZE];
+
+IX_ETH_DB_PRIVATE IxOsalMutex nodePoolLock;
+IX_ETH_DB_PRIVATE IxOsalMutex macPoolLock;
+IX_ETH_DB_PRIVATE IxOsalMutex treePoolLock;
+
+#define LOCK_NODE_POOL { ixOsalMutexLock(&nodePoolLock, IX_OSAL_WAIT_FOREVER); }
+#define UNLOCK_NODE_POOL { ixOsalMutexUnlock(&nodePoolLock); }
+
+#define LOCK_MAC_POOL { ixOsalMutexLock(&macPoolLock, IX_OSAL_WAIT_FOREVER); }
+#define UNLOCK_MAC_POOL { ixOsalMutexUnlock(&macPoolLock); }
+
+#define LOCK_TREE_POOL { ixOsalMutexLock(&treePoolLock, IX_OSAL_WAIT_FOREVER); }
+#define UNLOCK_TREE_POOL { ixOsalMutexUnlock(&treePoolLock); }
+
+/* private function prototypes */
+IX_ETH_DB_PRIVATE MacDescriptor* ixEthDBPoolAllocMacDescriptor(void);
+IX_ETH_DB_PRIVATE void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor);
+
+/**
+ * @addtogroup EthMemoryManagement
+ *
+ * @{
+ */
+
+/**
+ * @brief initializes the memory pools used by the ethernet database component
+ *
+ * Initializes the hash table node, mac descriptor and mac tree node pools.
+ * Called at initialization time by @ref ixEthDBInit().
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+void ixEthDBInitMemoryPools(void)
+{
+ int local_index;
+
+ /* HashNode pool */
+ ixOsalMutexInit(&nodePoolLock);
+
+ for (local_index = 0 ; local_index < NODE_POOL_SIZE ; local_index++)
+ {
+ HashNode *freeNode = &nodePoolArea[local_index];
+
+ freeNode->nextFree = nodePool;
+ nodePool = freeNode;
+ }
+
+ /* MacDescriptor pool */
+ ixOsalMutexInit(&macPoolLock);
+
+ for (local_index = 0 ; local_index < MAC_POOL_SIZE ; local_index++)
+ {
+ MacDescriptor *freeDescriptor = &macPoolArea[local_index];
+
+ freeDescriptor->nextFree = macPool;
+ macPool = freeDescriptor;
+ }
+
+ /* MacTreeNode pool */
+ ixOsalMutexInit(&treePoolLock);
+
+ for (local_index = 0 ; local_index < TREE_POOL_SIZE ; local_index++)
+ {
+ MacTreeNode *freeNode = &treePoolArea[local_index];
+
+ freeNode->nextFree = treePool;
+ treePool = freeNode;
+ }
+}
+
+/**
+ * @brief allocates a hash node from the pool
+ *
+ * Allocates a hash node and resets its value.
+ *
+ * @return the allocated hash node or NULL if the pool is empty
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+HashNode* ixEthDBAllocHashNode(void)
+{
+ HashNode *allocatedNode = NULL;
+
+ if (nodePool != NULL)
+ {
+ LOCK_NODE_POOL;
+
+ allocatedNode = nodePool;
+ nodePool = nodePool->nextFree;
+
+ UNLOCK_NODE_POOL;
+
+ memset(allocatedNode, 0, sizeof(HashNode));
+ }
+
+ return allocatedNode;
+}
+
+/**
+ * @brief frees a hash node into the pool
+ *
+ * @param hashNode node to be freed
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+void ixEthDBFreeHashNode(HashNode *hashNode)
+{
+ if (hashNode != NULL)
+ {
+ LOCK_NODE_POOL;
+
+ hashNode->nextFree = nodePool;
+ nodePool = hashNode;
+
+ UNLOCK_NODE_POOL;
+ }
+}
+
+/**
+ * @brief allocates a mac descriptor from the pool
+ *
+ * Allocates a mac descriptor and resets its value.
+ * This function is not used directly, instead @ref ixEthDBAllocMacDescriptor()
+ * is used, which keeps track of the pointer reference count.
+ *
+ * @see ixEthDBAllocMacDescriptor()
+ *
+ * @warning this function is not used directly by any other function
+ * apart from ixEthDBAllocMacDescriptor()
+ *
+ * @return the allocated mac descriptor or NULL if the pool is empty
+ *
+ * @internal
+ */
+IX_ETH_DB_PRIVATE
+MacDescriptor* ixEthDBPoolAllocMacDescriptor(void)
+{
+ MacDescriptor *allocatedDescriptor = NULL;
+
+ if (macPool != NULL)
+ {
+ LOCK_MAC_POOL;
+
+ allocatedDescriptor = macPool;
+ macPool = macPool->nextFree;
+
+ UNLOCK_MAC_POOL;
+
+ memset(allocatedDescriptor, 0, sizeof(MacDescriptor));
+ }
+
+ return allocatedDescriptor;
+}
+
+/**
+ * @brief allocates and initializes a mac descriptor smart pointer
+ *
+ * Uses @ref ixEthDBPoolAllocMacDescriptor() to allocate a mac descriptor
+ * from the pool and initializes its reference count.
+ *
+ * @see ixEthDBPoolAllocMacDescriptor()
+ *
+ * @return the allocated mac descriptor or NULL if the pool is empty
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+MacDescriptor* ixEthDBAllocMacDescriptor(void)
+{
+ MacDescriptor *allocatedDescriptor = ixEthDBPoolAllocMacDescriptor();
+
+ if (allocatedDescriptor != NULL)
+ {
+ LOCK_MAC_POOL;
+
+ allocatedDescriptor->refCount++;
+
+ UNLOCK_MAC_POOL;
+ }
+
+ return allocatedDescriptor;
+}
+
+/**
+ * @brief frees a mac descriptor back into the pool
+ *
+ * @param macDescriptor mac descriptor to be freed
+ *
+ * @warning this function is not to be called by anyone but
+ * ixEthDBFreeMacDescriptor()
+ *
+ * @see ixEthDBFreeMacDescriptor()
+ *
+ * @internal
+ */
+IX_ETH_DB_PRIVATE
+void ixEthDBPoolFreeMacDescriptor(MacDescriptor *macDescriptor)
+{
+ LOCK_MAC_POOL;
+
+ macDescriptor->nextFree = macPool;
+ macPool = macDescriptor;
+
+ UNLOCK_MAC_POOL;
+}
+
+/**
+ * @brief frees or reduces the usage count of a mac descriptor smart pointer
+ *
+ * If the reference count reaches 0 (structure is no longer used anywhere)
+ * then the descriptor is freed back into the pool using ixEthDBPoolFreeMacDescriptor().
+ *
+ * @see ixEthDBPoolFreeMacDescriptor()
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+void ixEthDBFreeMacDescriptor(MacDescriptor *macDescriptor)
+{
+ if (macDescriptor != NULL)
+ {
+ LOCK_MAC_POOL;
+
+ if (macDescriptor->refCount > 0)
+ {
+ macDescriptor->refCount--;
+
+ if (macDescriptor->refCount == 0)
+ {
+ UNLOCK_MAC_POOL;
+
+ ixEthDBPoolFreeMacDescriptor(macDescriptor);
+ }
+ else
+ {
+ UNLOCK_MAC_POOL;
+ }
+ }
+ else
+ {
+ UNLOCK_MAC_POOL;
+ }
+ }
+}
+
+/**
+ * @brief clones a mac descriptor smart pointer
+ *
+ * @param macDescriptor mac descriptor to clone
+ *
+ * Increments the usage count of the smart pointer
+ *
+ * @returns the cloned smart pointer
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+MacDescriptor* ixEthDBCloneMacDescriptor(MacDescriptor *macDescriptor)
+{
+ LOCK_MAC_POOL;
+
+ if (macDescriptor->refCount == 0)
+ {
+ UNLOCK_MAC_POOL;
+
+ return NULL;
+ }
+
+ macDescriptor->refCount++;
+
+ UNLOCK_MAC_POOL;
+
+ return macDescriptor;
+}
+
+/**
+ * @brief allocates a mac tree node from the pool
+ *
+ * Allocates and initializes a mac tree node from the pool.
+ *
+ * @return the allocated mac tree node or NULL if the pool is empty
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+MacTreeNode* ixEthDBAllocMacTreeNode(void)
+{
+ MacTreeNode *allocatedNode = NULL;
+
+ if (treePool != NULL)
+ {
+ LOCK_TREE_POOL;
+
+ allocatedNode = treePool;
+ treePool = treePool->nextFree;
+
+ UNLOCK_TREE_POOL;
+
+ memset(allocatedNode, 0, sizeof(MacTreeNode));
+ }
+
+ return allocatedNode;
+}
+
+/**
+ * @brief frees a mac tree node back into the pool
+ *
+ * @param macNode mac tree node to be freed
+ *
+ * @warning not to be used except from ixEthDBFreeMacTreeNode().
+ *
+ * @see ixEthDBFreeMacTreeNode()
+ *
+ * @internal
+ */
+void ixEthDBPoolFreeMacTreeNode(MacTreeNode *macNode)
+{
+ if (macNode != NULL)
+ {
+ LOCK_TREE_POOL;
+
+ macNode->nextFree = treePool;
+ treePool = macNode;
+
+ UNLOCK_TREE_POOL;
+ }
+}
+
+/**
+ * @brief frees or reduces the usage count of a mac tree node smart pointer
+ *
+ * @param macNode mac tree node to free
+ *
+ * Reduces the usage count of the given mac node. If the usage count
+ * reaches 0 the node is freed back into the pool using ixEthDBPoolFreeMacTreeNode()
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+void ixEthDBFreeMacTreeNode(MacTreeNode *macNode)
+{
+ if (macNode->descriptor != NULL)
+ {
+ ixEthDBFreeMacDescriptor(macNode->descriptor);
+ }
+
+ if (macNode->left != NULL)
+ {
+ ixEthDBFreeMacTreeNode(macNode->left);
+ }
+
+ if (macNode->right != NULL)
+ {
+ ixEthDBFreeMacTreeNode(macNode->right);
+ }
+
+ ixEthDBPoolFreeMacTreeNode(macNode);
+}
+
+/**
+ * @brief clones a mac tree node
+ *
+ * @param macNode mac tree node to be cloned
+ *
+ * Increments the usage count of the node, <i>its associated descriptor
+ * and <b>recursively</b> of all its child nodes</i>.
+ *
+ * @warning this function is recursive and clones whole trees/subtrees, use only for
+ * root nodes
+ *
+ * @internal
+ */
+IX_ETH_DB_PUBLIC
+MacTreeNode* ixEthDBCloneMacTreeNode(MacTreeNode *macNode)
+{
+ if (macNode != NULL)
+ {
+ MacTreeNode *clonedMacNode = ixEthDBAllocMacTreeNode();
+
+ if (clonedMacNode != NULL)
+ {
+ if (macNode->right != NULL)
+ {
+ clonedMacNode->right = ixEthDBCloneMacTreeNode(macNode->right);
+ }
+
+ if (macNode->left != NULL)
+ {
+ clonedMacNode->left = ixEthDBCloneMacTreeNode(macNode->left);
+ }
+
+ if (macNode->descriptor != NULL)
+ {
+ clonedMacNode->descriptor = ixEthDBCloneMacDescriptor(macNode->descriptor);
+ }
+ }
+
+ return clonedMacNode;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+#ifndef NDEBUG
+/* Debug statistical functions for memory usage */
+
+extern HashTable dbHashtable;
+int ixEthDBNumHashElements(void);
+
+int ixEthDBNumHashElements(void)
+{
+ UINT32 bucketIndex;
+ int numElements = 0;
+ HashTable *hashTable = &dbHashtable;
+
+ for (bucketIndex = 0 ; bucketIndex < hashTable->numBuckets ; bucketIndex++)
+ {
+ if (hashTable->hashBuckets[bucketIndex] != NULL)
+ {
+ HashNode *node = hashTable->hashBuckets[bucketIndex];
+
+ while (node != NULL)
+ {
+ numElements++;
+
+ node = node->next;
+ }
+ }
+ }
+
+ return numElements;
+}
+
+UINT32 ixEthDBSearchTreeUsageGet(MacTreeNode *tree)
+{
+ if (tree == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1 /* this node */ + ixEthDBSearchTreeUsageGet(tree->left) + ixEthDBSearchTreeUsageGet(tree->right);
+ }
+}
+
+int ixEthDBShowMemoryStatus(void)
+{
+ MacDescriptor *mac;
+ MacTreeNode *tree;
+ HashNode *node;
+
+ int macCounter = 0;
+ int treeCounter = 0;
+ int nodeCounter = 0;
+
+ int totalTreeUsage = 0;
+ int totalDescriptorUsage = 0;
+ int totalCloneDescriptorUsage = 0;
+ int totalNodeUsage = 0;
+
+ UINT32 portIndex;
+
+ LOCK_NODE_POOL;
+ LOCK_MAC_POOL;
+ LOCK_TREE_POOL;
+
+ mac = macPool;
+ tree = treePool;
+ node = nodePool;
+
+ while (mac != NULL)
+ {
+ macCounter++;
+
+ mac = mac->nextFree;
+
+ if (macCounter > MAC_POOL_SIZE)
+ {
+ break;
+ }
+ }
+
+ while (tree != NULL)
+ {
+ treeCounter++;
+
+ tree = tree->nextFree;
+
+ if (treeCounter > TREE_POOL_SIZE)
+ {
+ break;
+ }
+ }
+
+ while (node != NULL)
+ {
+ nodeCounter++;
+
+ node = node->nextFree;
+
+ if (nodeCounter > NODE_POOL_SIZE)
+ {
+ break;
+ }
+ }
+
+ for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
+ {
+ int treeUsage = ixEthDBSearchTreeUsageGet(ixEthDBPortInfo[portIndex].updateMethod.searchTree);
+
+ totalTreeUsage += treeUsage;
+ totalCloneDescriptorUsage += treeUsage; /* each tree node contains a descriptor */
+ }
+
+ totalNodeUsage = ixEthDBNumHashElements();
+ totalDescriptorUsage += totalNodeUsage; /* each hash table entry contains a descriptor */
+
+ UNLOCK_NODE_POOL;
+ UNLOCK_MAC_POOL;
+ UNLOCK_TREE_POOL;
+
+ printf("Ethernet database memory usage stats:\n\n");
+
+ if (macCounter <= MAC_POOL_SIZE)
+ {
+ printf("\tMAC descriptor pool : %d free out of %d entries (%d%%)\n", macCounter, MAC_POOL_SIZE, macCounter * 100 / MAC_POOL_SIZE);
+ }
+ else
+ {
+ printf("\tMAC descriptor pool : invalid state (ring within the pool), normally %d entries\n", MAC_POOL_SIZE);
+ }
+
+ if (treeCounter <= TREE_POOL_SIZE)
+ {
+ printf("\tTree node pool : %d free out of %d entries (%d%%)\n", treeCounter, TREE_POOL_SIZE, treeCounter * 100 / TREE_POOL_SIZE);
+ }
+ else
+ {
+ printf("\tTREE descriptor pool : invalid state (ring within the pool), normally %d entries\n", TREE_POOL_SIZE);
+ }
+
+ if (nodeCounter <= NODE_POOL_SIZE)
+ {
+ printf("\tHash node pool : %d free out of %d entries (%d%%)\n", nodeCounter, NODE_POOL_SIZE, nodeCounter * 100 / NODE_POOL_SIZE);
+ }
+ else
+ {
+ printf("\tNODE descriptor pool : invalid state (ring within the pool), normally %d entries\n", NODE_POOL_SIZE);
+ }
+
+ printf("\n");
+ printf("\tMAC descriptor usage : %d entries, %d cloned\n", totalDescriptorUsage, totalCloneDescriptorUsage);
+ printf("\tTree node usage : %d entries\n", totalTreeUsage);
+ printf("\tHash node usage : %d entries\n", totalNodeUsage);
+ printf("\n");
+
+ /* search for duplicate nodes in the mac pool */
+ {
+ MacDescriptor *reference = macPool;
+
+ while (reference != NULL)
+ {
+ MacDescriptor *comparison = reference->nextFree;
+
+ while (comparison != NULL)
+ {
+ if (reference == comparison)
+ {
+ printf("Warning: reached a duplicate (%p), invalid MAC pool state\n", reference);
+
+ return 1;
+ }
+
+ comparison = comparison->nextFree;
+ }
+
+ reference = reference->nextFree;
+ }
+ }
+
+ printf("No duplicates found in the MAC pool (sanity check ok)\n");
+
+ return 0;
+}
+
+#endif /* NDEBUG */
+
+/**
+ * @} EthMemoryManagement
+ */