diff --git a/src/rm.c b/src/rm.c
index d3ab4932ba66e2c1677bf1b3d2d905dae3133c12..cfa937e2e484e7d095aa58c78b8470d51bc550bd 100644 (file)
--- a/src/rm.c
+++ b/src/rm.c
-/**\r
- * @file rm.c\r
- *\r
- * @brief \r
- * This is the Resource Manager source.\r
- *\r
- * \par\r
- * ============================================================================\r
- * @n (C) Copyright 2012, Texas Instruments, Inc.\r
- * \r
- * Redistribution and use in source and binary forms, with or without \r
- * modification, are permitted provided that the following conditions \r
- * are met:\r
- *\r
- * Redistributions of source code must retain the above copyright \r
- * notice, this list of conditions and the following disclaimer.\r
- *\r
- * Redistributions in binary form must reproduce the above copyright\r
- * notice, this list of conditions and the following disclaimer in the \r
- * documentation and/or other materials provided with the \r
- * distribution.\r
- *\r
- * Neither the name of Texas Instruments Incorporated nor the names of\r
- * its contributors may be used to endorse or promote products derived\r
- * from this software without specific prior written permission.\r
- *\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- *\r
- * \par\r
-*/\r
-\r
-/* RM Types */\r
-#include <ti/drv/rm/rm_types.h>\r
-\r
-/* RM external includes */\r
-#include <ti/drv/rm/rm.h>\r
-#include <ti/drv/rm/rm_services.h>\r
-#include <ti/drv/rm/rm_transport.h>\r
-#include <ti/drv/rm/rm_policy.h>\r
-\r
-/* RM internal includes */\r
-#include <ti/drv/rm/include/rm_loc.h>\r
-#include <ti/drv/rm/include/rm_transportloc.h>\r
-#include <ti/drv/rm/include/rm_servicesloc.h>\r
-#include <ti/drv/rm/include/rm_nameserverloc.h>\r
-#include <ti/drv/rm/include/rm_dtb_utilloc.h>\r
-\r
-/* RM LIBFDT includes */\r
-#include <ti/drv/rm/src/libfdt/libfdt.h>\r
-\r
-/* AVL BBST includes */\r
-#include <ti/drv/rm/include/tree.h>\r
-\r
-/* RM OSAL layer */\r
-#include <rm_osal.h>\r
-\r
-/**********************************************************************\r
- ************************** Globals ***********************************\r
- **********************************************************************/\r
-char rmIntegerAllocator[] = "integer";\r
-char rmTreeAllocator[] = "tree";\r
-\r
-extern char rmDtbStartingNode[];\r
-\r
-/** @brief Global Variable which describes the RM Version Information */\r
-const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__;\r
-\r
-/**********************************************************************\r
- ************** Red-Black BBST Tree Allocator Functions ***************\r
- **********************************************************************/\r
-\r
-/* Prototype for function that allocates new tree nodes */\r
-Rm_ResourceTreeNode *Rm_newResourceTreeNode(uint32_t resourceBase, uint32_t resourceLength, \r
- char *allocatedTo)\r
-{\r
- Rm_ResourceTreeNode *newNode = NULL;\r
-\r
- newNode = Rm_osalMalloc(sizeof(Rm_ResourceTreeNode));\r
-\r
- /* Populate the RM relevant fields */\r
- newNode->base = resourceBase;\r
- newNode->length = resourceLength;\r
- strcpy(newNode->allocatedTo, allocatedTo);\r
-\r
- return(newNode);\r
-}\r
-\r
-/* Prototype for function that frees new tree nodes */\r
-void Rm_freeResourceTreeNode(Rm_ResourceTreeNode *treeNode)\r
-{\r
- /* Free the memory associated with the tree node. */\r
- Rm_osalFree((void *)treeNode, sizeof(Rm_ResourceTreeNode));\r
-}\r
-\r
-/* Prototype for tree node comparison function\r
- * element1 < element2 --> return < 0\r
- * element1 = element2 --> return 0\r
- * element1 > element2 --> return > 0 */\r
-int Rm_ResourceTreeNodeCompare(Rm_ResourceTreeNode *element1, Rm_ResourceTreeNode *element2)\r
-{\r
- uint32_t element1End = element1->base + element1->length - 1;\r
- uint32_t element2End = element2->base + element2->length - 1;\r
-\r
- if (element1End < element2->base)\r
- {\r
- /* End of element1 range is less than the start of element2's range. Return a negative\r
- * value */\r
- return (-1);\r
- }\r
- else if (element1->base > element2End)\r
- {\r
- /* Start of element1 range is after end of element2's range. Return a positive value */\r
- return (1);\r
- }\r
- else\r
- {\r
- /* If neither of the latter conditions were satisfied there is some overlap between\r
- * element1 and element2. Return 0 since the application must handle this overlap. */\r
- return (0);\r
- }\r
-}\r
-\r
-/* Generate the red-black tree manipulation functions */\r
-RB_GENERATE(_Rm_ResourceTree, _Rm_ResourceTreeNode, linkage, Rm_ResourceTreeNodeCompare);\r
-\r
-/**********************************************************************\r
- ********************** Internal Functions ****************************\r
- **********************************************************************/\r
-\r
-Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst)\r
-{\r
- Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
- Rm_Transaction *newTransaction = NULL;\r
- void *key;\r
-\r
- /* Lock access to the RM instance's transaction queue */\r
- key = Rm_osalMtCsEnter();\r
-\r
- /* Get memory for a new transaction from local memory */\r
- newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));\r
-\r
- /* Return if the memory allocated for the transaction entry is NULL */\r
- if (newTransaction != NULL)\r
- {\r
- /* Clear the transaction */\r
- memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
-\r
- /* Create an ID for the new transaction. The ID will be used for two purposes:\r
- * 1) Matching responses from higher level RM agents to requests\r
- * 2) Provided to the component that requested the service so that it can match its\r
- * request with the response it receives via its callback function it provided */\r
- newTransaction->localId = Rm_transactionGetSequenceNum(rmInst);\r
- /* New transaction's nextTransaction pointer will always be NULL */\r
- newTransaction->nextTransaction = NULL; \r
-\r
- /* Check if there are any transactions in the transaction queue */\r
- if (transactionQueue)\r
- {\r
- /* At least one transaction in the transaction queue. Add the new entry to the \r
- * end of the transaction queue */\r
- while (transactionQueue->nextTransaction != NULL)\r
- {\r
- /* Traverse the list until arriving at the last transaction */\r
- transactionQueue = transactionQueue->nextTransaction;\r
- }\r
-\r
- /* Add the new transaction to the end of the queue */\r
- transactionQueue->nextTransaction = newTransaction;\r
- }\r
- else\r
- {\r
- /* The transaction queue does not currently exist. The new transaction is the \r
- * first transaction */\r
- rmInst->transactionQueue = newTransaction;\r
- }\r
- }\r
-\r
- Rm_osalMtCsExit(key);\r
- return (newTransaction);\r
-}\r
-\r
-Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
-{\r
- Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
-\r
- /* Make sure there is at least one transaction in the transaction queue */\r
- if (transaction != NULL)\r
- {\r
- /* Find the transaction ID within the specified RM instance's transaction queue.\r
- * If the end of the transaction queue is reached without finding the transaction the \r
- * transaction pointer will be NULL */\r
- while (transaction != NULL)\r
- {\r
- if (transaction->localId == transactionId)\r
- {\r
- /* Match: break out of loop and return the transaction */\r
- break; \r
- }\r
- transaction = transaction->nextTransaction;\r
- }\r
- }\r
-\r
- return (transaction);\r
-}\r
-\r
-int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
-{\r
- Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
- Rm_Transaction *prevTransaction = NULL;\r
- int32_t retVal = RM_SERVICE_STATE_OKAY;\r
- void *key;\r
-\r
- /* Lock access to the RM instance's transaction queue */\r
- key = Rm_osalMtCsEnter();\r
-\r
- /* Find the transaction ID within the specified RM instance's transaction queue. */\r
- while (transaction != NULL)\r
- {\r
- if (transaction->localId == transactionId)\r
- {\r
- /* Match: break out of loop and delete the transaction */\r
- break; \r
- }\r
-\r
- prevTransaction = transaction;\r
- transaction = transaction->nextTransaction;\r
- }\r
-\r
- /* Traversed entire queue but did not find transaction */\r
- if (transaction == NULL)\r
- {\r
- retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST;\r
- }\r
- else\r
- {\r
- /* Delete the transaction */\r
- if (prevTransaction == NULL)\r
- {\r
- /* Transaction to be deleted exists at start of transaction queue. Map second\r
- * transaction to be start of transaction queue as long as there are more than\r
- * one transactions. */\r
- rmInst->transactionQueue = transaction->nextTransaction;\r
- }\r
- else\r
- {\r
- /* Transaction to be deleted is in the middle or at end of the queue. Adjust \r
- * adjacent transaction pointers. This covers the case where the transaction to be \r
- * removed is at the end of the queue. */\r
- prevTransaction->nextTransaction = transaction->nextTransaction;\r
- }\r
-\r
- /* Free the memory associated with the transaction. */\r
- Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));\r
- }\r
-\r
- Rm_osalMtCsExit(key);\r
- return (retVal);\r
-}\r
-\r
-uint32_t Rm_transactionInitSequenceNum(void)\r
-{\r
- /* Sequence number can never have a value of zero so that there are no conflicts\r
- * with transactions that have a remoteOriginatingId of zero */\r
- return (1);\r
-}\r
-\r
-uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
-{\r
- uint32_t sequenceNum = 0;\r
-\r
- /* Get the next sequence number and then increment. If there's an overflow\r
- * assign the initial value instead of incrementing. */\r
- if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum)\r
- {\r
- /* Overflow */\r
- sequenceNum = rmInst->transactionSeqNum;\r
- rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
- }\r
- else\r
- {\r
- sequenceNum = rmInst->transactionSeqNum++;\r
- } \r
-\r
- return (sequenceNum);\r
-}\r
-\r
-Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName)\r
-{\r
- Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators;\r
- Rm_Allocator *newAllocator = NULL;\r
- void *key;\r
-\r
- /* Lock access to the RM instance's allocator list */\r
- key = Rm_osalMtCsEnter();\r
-\r
- /* Get memory for a new allocator from local memory */\r
- newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
-\r
- /* Return if the memory allocated for the allocator is NULL */\r
- if (newAllocator != NULL)\r
- {\r
- /* Clear the allocator */\r
- memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
-\r
- /* Populate the allocator */\r
- strcpy(newAllocator->resourceName, resourceName);\r
- /* allocator's root entry will be created by the invoking function */\r
- newAllocator->allocatorRootEntry = NULL;\r
- /* New allocator's nextAllocator pointer will always be NULL */\r
- newAllocator->nextAllocator = NULL; \r
-\r
- /* Check if there are any allocators in the allocator list */\r
- if (allocators)\r
- {\r
- /* At least one allocator in the allocator list. Add the new allocator to the \r
- * end of the allocator list */\r
- while (allocators->nextAllocator != NULL)\r
- {\r
- /* Traverse the list until arriving at the last allocator */\r
- allocators = allocators->nextAllocator;\r
- }\r
-\r
- /* Add the new allocator to the end of the list */\r
- allocators->nextAllocator = newAllocator;\r
- }\r
- else\r
- {\r
- /* The allocator list does not currently exist. The new allocator is the \r
- * first allocator */\r
- rmInst->allocators = newAllocator;\r
- }\r
- }\r
-\r
- Rm_osalMtCsExit(key);\r
- return (newAllocator);\r
-}\r
-\r
-Rm_Allocator *Rm_allocatorFind(Rm_Inst *rmInst, char *resourceName)\r
-{\r
- Rm_Allocator *allocator = (Rm_Allocator *)rmInst->allocators;\r
-\r
- /* Make sure there is at least one allocator in the allocator list */\r
- if (allocator != NULL)\r
- {\r
- /* Find the resource name within the allocator list. If the end of the\r
- * allocator list is reached without finding the resource name the \r
- * allocator pointer will be NULL */\r
- while (allocator != NULL)\r
- {\r
- if (strcmp(allocator->resourceName, resourceName) == 0)\r
- {\r
- /* Match: break out of loop and return the allocator */\r
- break; \r
- }\r
- allocator = allocator->nextAllocator;\r
- }\r
- }\r
-\r
- return (allocator);\r
-}\r
-\r
-int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
-{\r
- Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
- Rm_Allocator *prevAllocator = NULL;\r
- int32_t retVal = RM_SERVICE_STATE_OKAY;\r
- void *key;\r
-\r
- /* Lock access to the RM instance's allocator list */\r
- key = Rm_osalMtCsEnter();\r
-\r
- /* Find the resource within the specified RM instance's allocator list. */\r
- while (allocator != NULL)\r
- {\r
- if (strcmp(allocator->resourceName, resourceName) == 0)\r
- {\r
- /* Match: break out of loop and delete the transaction */\r
- break; \r
- }\r
-\r
- prevAllocator = allocator;\r
- allocator = allocator->nextAllocator;\r
- }\r
-\r
- /* Traversed entire list but did not find allocator. */\r
- if (allocator == NULL)\r
- {\r
- retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
- else\r
- {\r
- /* Delete the allocator */\r
- if (prevAllocator == NULL)\r
- {\r
- /* Allocator to be deleted exists at start of allocator list. Map second\r
- * allocator to be start of allocator list as long as there are more than\r
- * one allocators. */\r
- rmInst->allocators = allocator->nextAllocator;\r
- }\r
- else\r
- {\r
- /* Allocator to be deleted is in the middle or at end of the list. Adjust \r
- * adjacent allocator pointers. This covers the case where the allocator to be \r
- * removed is at the end of the list. */\r
- prevAllocator->nextAllocator = allocator->nextAllocator;\r
- }\r
-\r
- /* Free the memory associated with the allocator. */\r
- Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
- }\r
-\r
- Rm_osalMtCsExit(key);\r
- return (retVal);\r
-}\r
-\r
-int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
-{\r
- Rm_Allocator *allocator = NULL;\r
- Rm_ResourceTree *treeRootEntry = NULL;\r
- Rm_ResourceTreeNode *treeNode = NULL;\r
- Rm_ResourceTreeNode *collidingNode = NULL;\r
-\r
- /* Create the new base integer allocator */\r
- allocator = Rm_allocatorAdd(rmInst, resourceName);\r
-\r
- /* Create the tree root entry and initialize it */\r
- treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));\r
- RB_INIT(treeRootEntry);\r
-\r
- /* Create a node in the tree for resource range and insert them into the tree. */\r
- while (range != NULL)\r
- {\r
- treeNode = Rm_newResourceTreeNode(range->base, range->length, RM_NOT_ALLOCATED_STRING);\r
-\r
- /* Insert the node into the tree */\r
- collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
-\r
- if (collidingNode)\r
- {\r
- Rm_ResourceTreeNode *nextNode = NULL;\r
- \r
- /* Node that was inserted colliding with an existing node. Clean up the tree\r
- * that's been allocated thus far and return an error since there should be no\r
- * collisions */\r
- for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode)\r
- {\r
- nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
- RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode);\r
- Rm_freeResourceTreeNode(treeNode);\r
- }\r
- /* Delete the tree root entry and the allocator */\r
- Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));\r
- Rm_allocatorDelete(rmInst, allocator->resourceName);\r
- return (-24); /* TODO FIX RETURN */\r
- }\r
-\r
- range = range->nextRange;\r
- }\r
-\r
- /* Assign the tree's root to the allocator */\r
- allocator->allocatorRootEntry = treeRootEntry;\r
-\r
- return(0); /* TODO: FIX THIS RETURN */\r
-}\r
-\r
-/* Called when an allocate request is made but the base is unspecified. RM must preallocate\r
- * resources which then must be checked against the RM policy for the instance. If the\r
- * policy does not agree another resource(s) must be preallocated and tested against the \r
- * policy. Policy will provide initialize the preallocate with the base that it allows\r
- * for the rm instance for the specified resource. */\r
-int32_t Rm_treePreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
-{\r
- Rm_ResourceTreeNode findNode;\r
- Rm_ResourceTreeNode *matchingNode = NULL;\r
- uint32_t policyRangeEnd = opInfo->policyBase + opInfo->policyLength - 1;\r
- uint32_t index;\r
- bool resourceFound = FALSE;\r
- int32_t retVal = RM_SERVICE_PROCESSING;\r
-\r
- /* Find the tree node that contains the first value in the specified policy range. */\r
- if (opInfo->policyBase)\r
- {\r
- findNode.base = opInfo->policyBase;\r
- }\r
- else\r
- {\r
- matchingNode = RB_MIN(_Rm_ResourceTree, allocator->allocatorRootEntry);\r
- findNode.base = matchingNode->base;\r
- }\r
- \r
- findNode.length = 1;\r
- matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
-\r
- if (matchingNode != NULL)\r
- {\r
- /* Begin searching for an available range of resources starting from the\r
- * matching node */\r
- for (index = matchingNode->base; index <= policyRangeEnd;)\r
- {\r
- /* Is the matchingNode free? */\r
- if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
- {\r
- uint32_t matchEnd = matchingNode->base + matchingNode->length - 1;\r
-\r
- /* Move index to the first resource satisfying the alignment property */\r
- if ((index % opInfo->policyAlignment) != 0)\r
- {\r
- index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
- }\r
- \r
- /* Move through the node's resource range looking for a contiguous set of resources\r
- * that satisfy the request. */\r
- while ((index <= matchEnd) && (index <= policyRangeEnd))\r
- {\r
- if (((index + opInfo->resourceInfo->length - 1) <= matchEnd) &&\r
- ((index + opInfo->resourceInfo->length - 1) <= policyRangeEnd))\r
- {\r
- /* Found a resource range in the node that satisfies the requirements */\r
- opInfo->resourceInfo->base = index;\r
- resourceFound = TRUE;\r
- break;\r
- }\r
-\r
- /* Move index to the next resource value that satisfies the alignment property */\r
- index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
- }\r
- }\r
- \r
- if (!resourceFound)\r
- {\r
- /* Move to the next tree node */\r
- matchingNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- if (matchingNode == NULL)\r
- {\r
- /* Reached end of tree. Resource range does not exist. Leave the search\r
- * loop */\r
- break;\r
- }\r
- else\r
- {\r
- index = matchingNode->base;\r
- }\r
- }\r
- else\r
- {\r
- /* Found a resource range that satisfies the request properties. Break out of the\r
- * search loop */\r
- break;\r
- }\r
- }\r
-\r
- if (!resourceFound)\r
- {\r
- retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
- }\r
- }\r
- else\r
- {\r
- retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
- }\r
-\r
- return(retVal); \r
-}\r
-\r
-/* Assume the policy has already approved of the allocation */\r
-int32_t Rm_treeAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
-{\r
- Rm_ResourceTreeNode findNode;\r
- Rm_ResourceTreeNode *matchingNode = NULL;\r
- Rm_ResourceTreeNode *leftNode = NULL;\r
- Rm_ResourceTreeNode *rightNode = NULL; \r
- uint32_t findEnd, matchingEnd;\r
- int32_t retVal;\r
-\r
- /* Find the tree node that contains the specified resource range */\r
- findNode.base = opInfo->resourceInfo->base;\r
- findNode.length = opInfo->resourceInfo->length;\r
- matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
-\r
- if (matchingNode != NULL)\r
- {\r
- findEnd = findNode.base + findNode.length - 1;\r
- matchingEnd = matchingNode->base + matchingNode->length - 1;\r
- \r
- /* Does the request range fit within the matching nodes entire range? */\r
- if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
- {\r
- /* Handle node create, combine, deletion based on the request range if\r
- * resources are available. */\r
- if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
- {\r
- /* Handle case where the findNode range matches the matchingNode\r
- * range exactly.\r
- *\r
- * base0 base0+length0-1\r
- * |<---------------length0------------------->| => existing node\r
- * |<---------------length1------------------->| => requested resources\r
- * base1 base1+length1-1\r
- */ \r
- if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
- {\r
- /* Can reserve matchingNode's resources in-place */\r
- strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
- }\r
- /* Handle case where the findNode range is a subset of the matchingNode\r
- * range and neither of the boundaries of the two ranges are equivalent.\r
- *\r
- * base0 base0+length0-1\r
- * |<---------------length0------------------->| => existing node\r
- * |<---------length1---------->| => requested resources\r
- * base1 base1+length1-1\r
- */ \r
- else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
- {\r
- /* Split the matching node into three nodes:\r
- * left node - free resources to left of newly allocated resources\r
- * middle node - newly allocated resources that satisfy the request\r
- * right node - free resources to the right of newly allocated resources */\r
-\r
- /* Remove the matching node from the tree for modification. */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
-\r
- /* New left node attributes:\r
- * base: base of the matching node\r
- * length: base of requested resources - base of matching node */\r
- leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
- RM_NOT_ALLOCATED_STRING);\r
- /* New right node attributes:\r
- * base: base of the requested resources + length of requested resources\r
- * length: right bound of matching node - right bound of request resources */\r
- rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
- matchingEnd - findEnd, RM_NOT_ALLOCATED_STRING);\r
-\r
- /* Base and length of matching node become the base and length of the\r
- * requested resources */\r
- matchingNode->base = findNode.base; \r
- matchingNode->length = findNode.length;\r
- /* Reserve the resources */\r
- strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
-\r
- /* Insert all the nodes */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
- }\r
- /* Handle cases where one of findNode range boundaries is equivalent to\r
- * one of the matchingNode range boundaries.\r
- *\r
- * base0 base0+length0-1\r
- * |<---------------length0------------------->| => existing node\r
- * |<---------length1---------->| => requested resources\r
- * base1 base1+length1-1\r
- *\r
- * OR\r
- *\r
- * base0 base0+length0-1\r
- * |<---------------length0------------------->| => existing node\r
- * |<---------length1---------->| => requested resources\r
- * base1 base1+length1-1 \r
- */ \r
- else\r
- { \r
- /* Remove the matchingNode from the tree since it will be edited */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- if (findNode.base == matchingNode->base)\r
- {\r
- /* There may be a combine possibility to the left. Extract leftNode to check */\r
- leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- /* Can the node to the left of the matchingNode be combined with the \r
- * findNode's range? */\r
- if (leftNode && (strcmp(leftNode->allocatedTo, opInfo->srcInstName) == 0))\r
- {\r
- /* Remove the leftNode from the tree for editing */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
-\r
- /* Combine the leftNode and the findNode */\r
- leftNode->length += findNode.length;\r
- }\r
- else\r
- {\r
- /* Allocate a new leftNode that will take the place of the findNode\r
- * range in tree. */\r
- leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
- opInfo->srcInstName);\r
- }\r
-\r
- /* Account for the leftNode in the matchingNode */\r
- matchingNode->base = findNode.base + findNode.length;\r
- matchingNode->length = matchingEnd - findEnd; \r
-\r
- /* Insert the left node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- }\r
- else if (findEnd == matchingEnd)\r
- {\r
- /* There may be a combine possibility to the right. Extract rightNode to check */\r
- rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- /* Can the node to the right of the matchingNode be combined with the \r
- * findNode's range? */\r
- if (rightNode && (strcmp(rightNode->allocatedTo, opInfo->srcInstName) == 0))\r
- {\r
- /* Remove the rightNode from the tree for editing */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
-\r
- /* Combine the rightNode and the findNode */\r
- rightNode->base = findNode.base;\r
- rightNode->length += findNode.length;\r
- }\r
- else\r
- {\r
- /* Allocate a new rightNode that will take the place of the findNode\r
- * range in tree. */\r
- rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
- opInfo->srcInstName);\r
- }\r
-\r
- /* Account for the rightNode in the matchingNode */\r
- matchingNode->length -= findNode.length; \r
-\r
- /* Insert the right node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
- }\r
-\r
- /* Reinsert the edited matching node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- }\r
- \r
- retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
- }\r
- else\r
- {\r
- /* A resource superset containing the requested range has\r
- * already been allocated. */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
- }\r
- }\r
- else\r
- {\r
- /* Request ranges that span multiple nodes signify resources are\r
- * not available because nodes are combined into larger contiguous ranges\r
- * on resource free operations. */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
- }\r
- }\r
- else\r
- {\r
- /* The requested resources could not be found in the allocator */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
- }\r
-\r
- return(retVal); \r
-}\r
-\r
-/* Assume policy has already approved of the free */\r
-int32_t Rm_treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
-{\r
- Rm_ResourceTreeNode findNode;\r
- Rm_ResourceTreeNode *matchingNode = NULL;\r
- Rm_ResourceTreeNode *leftNode = NULL;\r
- Rm_ResourceTreeNode *rightNode = NULL;\r
- bool combineLeft = FALSE;\r
- bool combineRight = FALSE;\r
- uint32_t findEnd, matchingEnd;\r
- int32_t retVal;\r
-\r
- /* Find the tree node that contains the specified resource range */\r
- findNode.base = opInfo->resourceInfo->base;\r
- findNode.length = opInfo->resourceInfo->length;\r
- matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
-\r
- if (matchingNode != NULL)\r
- {\r
- findEnd = findNode.base + findNode.length - 1;\r
- matchingEnd = matchingNode->base + matchingNode->length - 1;\r
- \r
- /* Does the free range fit within the matching nodes entire range? It should\r
- * either be the entire range or a subset set of the found range. (the latter\r
- * satisfies the case where an entity allocated a contiguous block of resources\r
- * then attempts to free a contiguous subset of the allocated block. */\r
- if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
- { \r
- if (strcmp(matchingNode->allocatedTo, opInfo->srcInstName) == 0)\r
- {\r
- /* Resources can be freed */\r
-\r
- if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
- {\r
- /* Case 1: free range equals allocated matched node exactly. Attempt to combine \r
- * the range to be freed with the resource nodes to the left and\r
- * right of the free range.\r
- *\r
- * |<--left node-->||<---matched node--->||<--right node-->|\r
- * |<---free request--->|\r
- */ \r
-\r
- leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
-\r
- /* Remove the matching node from the tree and the nodes to the left and\r
- * right of the matching node. Removing from tree will not\r
- * wipe any of the base+length data in the node. Can reuse since they won't\r
- * be freed */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
-\r
- /* See if the left or right or both nodes can be combined with the matching\r
- * node that will be freed. */\r
- if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
- {\r
- /* Combine the left node and the matching node */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- combineLeft = TRUE;\r
- }\r
- if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
- {\r
- /* Combine the right node and the matching node */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
- combineRight = TRUE;\r
- }\r
-\r
- /* Perform any combines, insert the leftover nodes, and free any memory associated\r
- * with any nodes that weren't reinserted into the tree */\r
- if (combineLeft && combineRight)\r
- {\r
- /* Combine all three nodes into the matchingNode. Insert the freed cumulative\r
- * matching node and delete the memory for the old left and right nodes */\r
- matchingNode->base = leftNode->base;\r
- matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
-\r
- Rm_freeResourceTreeNode(leftNode);\r
- Rm_freeResourceTreeNode(rightNode); \r
- }\r
- else if (combineLeft)\r
- {\r
- /* Combine the left and matching nodes. Reinsert the right. */\r
- matchingNode->base = leftNode->base;\r
- matchingNode->length += leftNode->length;\r
- \r
- Rm_freeResourceTreeNode(leftNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); \r
- }\r
- else if (combineRight)\r
- {\r
- /* Combine the right and matching nodes. Reinsert the left. */\r
- matchingNode->length += rightNode->length;\r
- \r
- Rm_freeResourceTreeNode(rightNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- }\r
- else\r
- {\r
- /* Combine cannot be performed. Reinsert the left and right nodes then\r
- * free the matching node and reinsert it */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
- }\r
-\r
- /* No matter the combine route taken the matching node will always be declared\r
- * free and reinserted */\r
- strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); \r
- }\r
- else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
- {\r
- /* Case 2: free range is less than range in matched node. Need to split\r
- * the matched node into three nodes.\r
- *\r
- * |<----------matched node---------->|\r
- * |<---free request--->|\r
- */ \r
-\r
- /* Remove matching node for editing. */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
-\r
- /* New left node attributes:\r
- * base: base of the matching node\r
- * length: base of requested resources - base of matching node */\r
- leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
- matchingNode->allocatedTo); \r
- /* New right node attributes:\r
- * base: base of the requested resources + length of requested resources\r
- * length: right bound of matching node - right bound of request resources */\r
- rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
- matchingEnd - findEnd, matchingNode->allocatedTo);\r
-\r
- /* Insert the left and right nodes into the tree. */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
-\r
- /* Base and length of matching node become the base and length of the freed resources */\r
- matchingNode->base = findNode.base; \r
- matchingNode->length = findNode.length;\r
- /* Free the resources and insert them into the tree */\r
- strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- }\r
- else\r
- {\r
- /* Remove the matchingNode from the tree since it will be edited */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- if (findNode.base == matchingNode->base)\r
- {\r
- /* Case 3: Free range is on left boundary of matched node. Try to \r
- * combine the free range with the left node if free.\r
- *\r
- * |<---left node (free)--->||<----------matched node---------->|\r
- * |<---findNode (free req)--->|\r
- */ \r
- \r
- /* There may be a combine possibility to the left. Extract leftNode to check */\r
- leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- /* Can the node to the left of the matchingNode be combined with the \r
- * findNode's range? */\r
- if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
- {\r
- /* Remove the leftNode from the tree for editing */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
-\r
- /* Combine the leftNode and the findNode */\r
- leftNode->length += findNode.length;\r
- }\r
- else\r
- {\r
- /* Allocate a new leftNode that will take the place of the findNode\r
- * range in tree. */\r
- leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
- RM_NOT_ALLOCATED_STRING);\r
- }\r
-\r
- /* Account for the leftNode in the matchingNode */\r
- matchingNode->base = findNode.base + findNode.length;\r
- matchingNode->length = matchingEnd - findEnd; \r
-\r
- /* Insert the left node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
- }\r
- else if (findEnd == matchingEnd)\r
- {\r
- /* Case 4: Free range is on right boundary of matched node. Try to \r
- * combine the free range with the right node if free.\r
- *\r
- * |<----------matched node---------->||<---right node (free)--->|\r
- * |<---findNode (free req)--->|\r
- */ \r
- \r
- /* There may be a combine possibility to the right. Extract rightNode to check */\r
- rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- \r
- /* Can the node to the right of the matchingNode be combined with the \r
- * findNode's range? */\r
- if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
- {\r
- /* Remove the rightNode from the tree for editing */\r
- RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
-\r
- /* Combine the rightNode and the findNode */\r
- rightNode->base = findNode.base;\r
- rightNode->length += findNode.length;\r
- }\r
- else\r
- {\r
- /* Allocate a new rightNode that will take the place of the findNode\r
- * range in tree. */\r
- rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
- RM_NOT_ALLOCATED_STRING);\r
- }\r
-\r
- /* Account for the rightNode in the matchingNode */\r
- matchingNode->length -= findNode.length; \r
-\r
- /* Insert the right node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
- }\r
-\r
- /* Reinsert the edited matching node */\r
- RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
- }\r
-\r
- retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
- }\r
- else\r
- {\r
- /* The matching allocated range to be freed was allocated to a different instance. */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
- }\r
- }\r
- else\r
- {\r
- /* Free resource range crosses over node boundaries. This signifies a\r
- * free of both allocated and unallocated resources since nodes are combined\r
- * on allocate and free operations if possible. */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
- }\r
- }\r
- else\r
- {\r
- /* The free resources could not be found in the allocator */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
- }\r
-\r
- return(retVal); \r
-}\r
-\r
-int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)\r
-{\r
- Rm_Allocator *allocator = NULL;\r
- int32_t retVal;\r
- void *key;\r
-\r
- /* Lock access to the RM instance's transaction queue */\r
- key = Rm_osalMtCsEnter();\r
-\r
- /* Get the specified resource's allocator */\r
- allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name);\r
-\r
- if (allocator)\r
- {\r
- /* Call the allocator's function */\r
- if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
- {\r
- retVal = Rm_treePreAllocate(allocator, opInfo);\r
- } \r
- else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
- {\r
- retVal = Rm_treeAllocate(allocator, opInfo);\r
- }\r
- else if (opInfo->operation == Rm_allocatorOp_FREE)\r
- {\r
- retVal = Rm_treeFree(allocator, opInfo);\r
- } \r
- }\r
- else\r
- {\r
- /* Allocator could not be found for resource */\r
- retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST;\r
- }\r
-\r
- Rm_osalMtCsExit(key);\r
- return(retVal);\r
-}\r
-\r
-void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
-{\r
- Rm_AllocatorOpInfo opInfo;\r
- int32_t retVal = transaction->state;\r
-\r
- /* Initialize the opInfo structure */\r
- memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
- \r
- if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
- {\r
- /* TEMP: For now forward all allocations to the RM Server */\r
- Rm_transactionForwarder(rmInst, transaction);\r
- \r
-#if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
- if (resourceBase is unspecified)\r
- {\r
- while (policy does not approve)\r
- {\r
- Rm_policy check get allowed base as starting point for prealloc\r
- preallocate resource based on the range and alignment\r
- Rm_policy...check\r
- }\r
- }\r
- else\r
- {\r
- /* Check local policy to see if the request can be satisfied with the\r
- * resources stored locally */\r
- Rm_policy...API()\r
-\r
- if (policy check approves the resource)\r
- {\r
- /* call the allocator to allocate the resource */\r
- if (allocator returns resource)\r
- {\r
- /* Populate the transaction with the allocated resources and the result */\r
- transaction->state = approve reason;\r
- return ...\r
- }\r
- else\r
- {\r
- /* allocator ran out of resources, need to contact Server for more\r
- * resources */\r
- Rm_resourcePoolModRequest(...);\r
- }\r
- }\r
- else if (policy check denies resource)\r
- {\r
- /* Policy check denied resource. */\r
- transaction->state= deny reason;\r
- return ...\r
- }\r
- else if (policy check says forward to Server for validation)\r
- {\r
- /* Forward the transaction to the Server */\r
- Rm_transactionForwarder(rmInst, transaction);\r
- }\r
- }\r
-#endif \r
- }\r
- else if (rmInst->instType == Rm_instType_SERVER)\r
- {\r
- /* TEMP: If resource properties are unspecified allocate the next available.\r
- * If resource properties are specified allocate if they are available. */\r
-\r
- /* Fill out the allocator operation general information */\r
- opInfo.resourceInfo = &transaction->resourceInfo;\r
- opInfo.srcInstName = transaction->sourceInstName;\r
-\r
- if (strlen(transaction->resourceInfo.nsName) > 0)\r
- {\r
- /* See if a NameServer name is being used to allocate a resource */\r
- if (transaction->resourceInfo.base != 0)\r
- {\r
- /* A name and a value cannot be specified for the request. It's one\r
- * or the other. */\r
- retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
- }\r
- else\r
- {\r
- /* Get the resource information from the NameServer */\r
- retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
- }\r
- }\r
- else if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED)\r
- {\r
- /* Execute the allocator pre-allocate operation to get the next available resources.\r
- * NORMALLY CHECKED AGAINST THE POLICY */\r
- opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;\r
- \r
- if (transaction->resourceInfo.alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED)\r
- { \r
- /* TEMP: Default resource alignment of 1 if the resource alignment is not\r
- * specified */\r
- opInfo.policyAlignment = 1;\r
- }\r
- else\r
- {\r
- opInfo.policyAlignment = transaction->resourceInfo.alignment;\r
- }\r
-\r
- /* opInfo.policyBase = comes from policy once implemented */\r
- opInfo.policyLength = transaction->resourceInfo.length;\r
-\r
- /* If the pre-allocate operation succeeds the resourceInfo field pointed to\r
- * by opInfo will contain the next available resources taht satisfy the\r
- * resource properties */\r
- retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
- }\r
-\r
- /* Call allocator as long as an error or denial hasn't occurred */\r
- if (retVal == RM_SERVICE_PROCESSING)\r
- {\r
- opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
-\r
- retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
- }\r
-\r
- transaction->state = retVal;\r
-\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- /* Source of allocation was not the server instance, provide the transaction\r
- * to the transaction responder */\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- /* Otherwise let the return stack return the transaction to the serviceHandler */ \r
-\r
-#if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
- if (resourceBase is unspecified)\r
- {\r
- while (policy does not approve)\r
- {\r
- Rm_policy check get allowed base as starting point for prealloc\r
- preallocate resource based on the range and alignment\r
- Rm_policy...check\r
- }\r
- }\r
- else\r
- {\r
- /* Check global policy to see if resource can be allocated. return result\r
- * no matter what */\r
- Rm_policy...API()\r
-\r
- if (policy approves)\r
- {\r
- /* call allocator to allocate resource */\r
- }\r
-\r
- transaction->state = approve or deny reason;\r
- transaction->resourceInfo.base = ...;\r
- transaction->resourceInfo.length = ...;\r
-\r
- /* If source instance name does not match the current instance\r
- * name the allocation request came from a Client. The result\r
- * must be sent back to the Client */\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- /* Names don't match. Send the transaction back to the Client */\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- else\r
- {\r
- /* Resource allocation request originated locally on the active\r
- * instance. Send the response via the service responder. */ \r
- Rm_serviceResponder(rmInst, transaction); \r
- }\r
- }\r
-#endif \r
- } \r
-}\r
-\r
-void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
-{\r
- Rm_AllocatorOpInfo opInfo;\r
- int32_t retVal = transaction->state;\r
- \r
- if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
- {\r
- /* TEMP: Forward all free requests to the Server */\r
- Rm_transactionForwarder(rmInst, transaction);\r
- \r
-#if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
- /* Check local policy to see if the request can be satisfied with the\r
- * resources stored locally */\r
- Rm_policy...API()\r
-\r
- if (policy check approves the free)\r
- {\r
- /* call the allocator to free the resource */\r
- /* Run a resource pool check to see if the free combined a resource block\r
- * that can be returned to the server */\r
- if (resource block has been combined)\r
- {\r
- /* allocator ran out of resources, need to contact Server for more\r
- * resources */\r
- Rm_resourcePoolModRequest(free pool block to server...);\r
- }\r
- else\r
- {\r
- /* Populate the receipt with the freed resources and the result */\r
- transaction->state = approve reason;\r
- return ...\r
- }\r
- }\r
- else if (policy check denies resource free)\r
- {\r
- /* Policy check denied resource. */\r
- transaction->state = deny reason;\r
- return ...\r
- }\r
- else if (policy check says forward to Server for validation)\r
- {\r
- /* Forward the transaction to the Server */\r
- Rm_transactionForwarder(rmInst, transaction);\r
- }\r
-#endif \r
- }\r
- else if (rmInst->instType == Rm_instType_SERVER)\r
- {\r
- /* TEMP: Free the resources if resources are allocated to the source instance. */\r
-\r
- /* Fill out the allocator operation general information */\r
- opInfo.resourceInfo = &transaction->resourceInfo;\r
- opInfo.srcInstName = transaction->sourceInstName;\r
-\r
- if (strlen(transaction->resourceInfo.nsName) > 0)\r
- {\r
- /* See if a NameServer name is being used to allocate a resource */\r
- if (transaction->resourceInfo.base != 0)\r
- {\r
- /* A name and a value cannot be specified for the request. It's one\r
- * or the other. */\r
- retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
- }\r
- else\r
- {\r
- /* Get the resource information from the NameServer */\r
- retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
- }\r
- }\r
- \r
- /* Call allocator as long as an error or denial hasn't occurred */\r
- if (retVal == RM_SERVICE_PROCESSING)\r
- {\r
- opInfo.operation = Rm_allocatorOp_FREE;\r
-\r
- retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
- }\r
-\r
- transaction->state = retVal;\r
-\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- /* Source of allocation was not the server instance, provide the transaction\r
- * to the transaction responder */\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- /* Otherwise let the return stack return the transaction to the serviceHandler */ \r
- \r
-#if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
- /* Check global policy to see if resource can be freed. return result\r
- * no matter what */\r
- Rm_policy...API()\r
- if (policy approves)\r
- {\r
- /* call allocator to free resources */\r
- }\r
- \r
- transaction->state = approve or deny reason;\r
- transaction->resourceInfo.base = ...;\r
- transaction->resourceInfo.length = ...;\r
-\r
- /* If source instance name does not match the current instance\r
- * name the allocation request came from a client. The result\r
- * must be sent back to the Client */\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- /* Names don't match. Send the transaction back to the Client Delegate or Client */\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- else\r
- {\r
- /* Resource allocation request originated locally on the active\r
- * instance. Send the response via the service responder. */\r
- Rm_serviceResponder(rmInst, transaction); \r
- }\r
-#endif \r
- } \r
-}\r
-\r
-/* Function used to send RM response transactions to lower level agents */\r
-void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
-{\r
- Rm_TransportNode *dstTransportNode = NULL;\r
- Rm_Packet *rmPkt = NULL;\r
-\r
- /* Find the transport for the RM instance that sent the request. */\r
- dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
-\r
- /* Create a RM packet using the service information */\r
- switch (transaction->type)\r
- {\r
- case Rm_service_RESOURCE_ALLOCATE:\r
- case Rm_service_RESOURCE_FREE:\r
- case Rm_service_RESOURCE_GET_BY_NAME:\r
- rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
- transaction);\r
- break;\r
- case Rm_service_RESOURCE_MAP_TO_NAME:\r
- case Rm_service_RESOURCE_UNMAP_NAME:\r
- rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
- transaction);\r
- break;\r
- default:\r
- /* Invalid service type. Flag the error and return */\r
- transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
- break;\r
- }\r
-\r
- if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
- {\r
- /* Delete the transaction and return immediately because an error occurred \r
- * allocating the packet */\r
- Rm_transactionQueueDelete(rmInst, transaction->localId);\r
- return;\r
- }\r
-\r
- /* Send the RM packet to the application transport */\r
- if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
- {\r
- /* Negative value returned by transport send. An error occurred\r
- * in the transport while attempting to send the packet.*/\r
- transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
- /* Clean up the packet */\r
- if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
- {\r
- /* Non-NULL value returned by transport packet free. Flag the\r
- * error */\r
- transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
- }\r
- return;\r
- }\r
-\r
- /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD. CREATE\r
- * NEW TRANSACTION WITH DATA FROM ORIGINAL? THEN TRY TO SEND FAILED REQUEST BACK\r
- * TO REQUESTER??? KEEP RETRYING SEND OF RESPONSE??? */\r
-\r
- /* Delete the transaction */\r
- Rm_transactionQueueDelete(rmInst, transaction->localId);\r
-}\r
-\r
-/* Function used to forward RM transactions to higher level agents */\r
-void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
-{\r
- Rm_TransportNode *dstTransportNode = NULL;\r
- Rm_Packet *rmPkt = NULL;\r
-\r
- /* Make sure the RM instance has a transport registered with a higher level agent */\r
- if (rmInst->registeredWithDelegateOrServer == false)\r
- {\r
- transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
- return;\r
- }\r
-\r
- /* Find the transport for the higher level agent. Check for a connection to a Client Delegate\r
- * or a Server. Clients will be connected to either a Client Delegate or a Server. Client\r
- * Delegates will be connected to a Server. */\r
- if (rmInst->instType == Rm_instType_CLIENT)\r
- {\r
- dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
-\r
- if (!dstTransportNode)\r
- {\r
- /* No Client Delegate connection found. Check for a Server connection */\r
- dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
- }\r
- } \r
- else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
- {\r
- dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
- }\r
-\r
- /* Create a RM packet using the service information */\r
- switch (transaction->type)\r
- {\r
- case Rm_service_RESOURCE_ALLOCATE:\r
- case Rm_service_RESOURCE_FREE:\r
- case Rm_service_RESOURCE_GET_BY_NAME:\r
- rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
- transaction);\r
- break;\r
- case Rm_service_RESOURCE_MAP_TO_NAME:\r
- case Rm_service_RESOURCE_UNMAP_NAME:\r
- rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
- transaction);\r
- break;\r
- default:\r
- /* Invalid service type. Flag the error and return */\r
- transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
- break;\r
- }\r
-\r
- if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
- {\r
- /* Return immediately because an error occurred allocating the packet */\r
- return;\r
- }\r
-\r
- /* Send the RM packet to the application transport */\r
- if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
- {\r
- /* Negative value returned by transport send. An error occurred\r
- * in the transport while attempting to send the packet.*/\r
- transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
- /* Clean up the packet */\r
- if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
- {\r
- /* Non-NULL value returned by transport packet free. Flag the\r
- * error */\r
- transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
- }\r
- return;\r
- }\r
-\r
- /* Transaction is not deleted because it is awaiting a response from the higher level\r
- * RM instance */\r
-}\r
-\r
-void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
-{\r
- /* Handle auto-forwarded transactions. These transactions include:\r
- * - All request transactions received on Clients are forwarded to the Client Delegate\r
- * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
- if ((rmInst->instType == Rm_instType_CLIENT) ||\r
- ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
- ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
- (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||\r
- (transaction->type == Rm_service_RESOURCE_UNMAP_NAME))))\r
- { \r
- /* Check if the transaction is a transaction that received a response to its\r
- * request. */\r
- if (transaction->state != RM_SERVICE_PROCESSING)\r
- {\r
-\r
- /* A transaction has received a response. Send the response to either the \r
- * transaction or service responder based on the source instance */\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- /* Transaction originated from another instance. Use the \r
- * transaction responder to send the result to the source instance. This\r
- * is not possible on RM Clients since they can't forward RM services */\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- else\r
- {\r
- /* Transaction originated on this instance. Send to the\r
- * service responder */\r
- Rm_serviceResponder(rmInst, transaction);\r
- }\r
- }\r
- else\r
- {\r
- /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
- Rm_transactionForwarder(rmInst, transaction);\r
- }\r
- }\r
- else\r
- {\r
- /* Client Delegate and Server transaction processors. */\r
- switch (transaction->type)\r
- {\r
- case Rm_service_RESOURCE_ALLOCATE:\r
- case Rm_service_RESOURCE_FREE: \r
- /* Check if the transaction is fulfilled request */\r
- if (transaction->state != RM_SERVICE_PROCESSING)\r
- {\r
- /* If source instance name does not match the current instance\r
- * name the allocation request came from a client. The result\r
- * must be sent back to the Client */\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- else\r
- {\r
- /* Resource allocation request originated locally. Send the response\r
- * via the service responder. */\r
- Rm_serviceResponder(rmInst, transaction); \r
- }\r
- }\r
- else\r
- {\r
- /* This is a new transaction request originating from an RM instance with fewer\r
- * allocate/free privileges. Run the allocation or free handler to see if the resource\r
- * request can be handled locally or if it needs to be forwarded to a higher level\r
- * agent */\r
- if (transaction->type == Rm_service_RESOURCE_ALLOCATE)\r
- {\r
- Rm_allocationHandler(rmInst, transaction);\r
- }\r
- else\r
- {\r
- Rm_freeHandler(rmInst, transaction);\r
- }\r
- }\r
- break;\r
- case Rm_service_RESOURCE_MAP_TO_NAME:\r
- case Rm_service_RESOURCE_GET_BY_NAME:\r
- case Rm_service_RESOURCE_UNMAP_NAME: \r
- /* Server is the only RM instance capable of adding NameServer objects */\r
- if (rmInst->instType == Rm_instType_SERVER)\r
- {\r
- if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
- {\r
- /* Create a new NameServer object with the request transaction information.\r
- * Transaction will contain the state result of the NameServer addition. */\r
- if (Rm_nsAddObject(rmInst, &transaction->resourceInfo) == RM_NS_ACTION_APPROVED)\r
- {\r
- transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
- }\r
- else\r
- {\r
- /* TEMP: UPDATE THIS STATE VALUE */\r
- transaction->state = RM_SERVICE_DENIED_BEGIN;\r
- }\r
- }\r
- else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)\r
- {\r
- /* Create a new NameServer object with the request transaction information.\r
- * Transaction will contain the state result of the NameServer addition. */\r
- if (Rm_nsFindObject(rmInst, &transaction->resourceInfo) == RM_NS_ACTION_APPROVED)\r
- {\r
- transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
- }\r
- else\r
- {\r
- /* TEMP: UPDATE THIS STATE VALUE */\r
- transaction->state = RM_SERVICE_DENIED_BEGIN;\r
- } \r
- }\r
- else\r
- {\r
- /* Delete an existing NameServer object with the request transaction information\r
- * Transaction will contain the state result of the NameServer addition. */\r
- if (Rm_nsDeleteObject(rmInst, &transaction->resourceInfo) == \r
- RM_NS_ACTION_APPROVED)\r
- {\r
- transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
- }\r
- else\r
- {\r
- /* TEMP: UPDATE THIS STATE VALUE */\r
- transaction->state = RM_SERVICE_DENIED_BEGIN;\r
- }\r
- }\r
-\r
- /* If source instance name does not match the local instance\r
- * name the NameServer request came from a Client or Client Delegate. The \r
- * result must be sent back to the Client or Client Delegate. Just return if it does\r
- * match since the NameServer transaction result can be returned immediately by the\r
- * Rm_serviceHandler. */\r
- if (strcmp(transaction->sourceInstName, rmInst->name))\r
- {\r
- Rm_transactionResponder(rmInst, transaction);\r
- }\r
- }\r
- else\r
- {\r
- transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
- }\r
- break;\r
- }\r
- }\r
-}\r
-\r
-int32_t Rm_reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, \r
- Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)\r
-{\r
- int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
- bool baseFound = FALSE;\r
- bool lengthFound = FALSE;\r
- uint32_t valueIndex = 0;\r
-\r
- while ((linuxValues != NULL) && (!baseFound || !lengthFound))\r
- {\r
- if (linuxAlias->baseOffset == valueIndex)\r
- {\r
- /* Found the resource base. Store it in the operation info structure */\r
- opInfo->resourceInfo->base = linuxValues->value;\r
- baseFound = TRUE;\r
-\r
- /* length will always be 1 if there is no length specified in the Linux DTB */\r
- if (linuxAlias->lengthOffset == RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET)\r
- {\r
- opInfo->resourceInfo->length = 1;\r
- lengthFound = TRUE;\r
- }\r
- }\r
- else if (linuxAlias->lengthOffset == valueIndex)\r
- {\r
- /* Found the resource length. Store it in the operation info structure */\r
- opInfo->resourceInfo->length = linuxValues->value;\r
- lengthFound = TRUE;\r
- }\r
-\r
- linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;\r
- valueIndex++;\r
- }\r
-\r
- if (!baseFound || !lengthFound)\r
- {\r
- retVal = -33; /* TODO: ERROR BASE OR LENGTH OFFSET IN LINUX DTB WAS INCORRECT */\r
- }\r
- else\r
- {\r
- /* Allocate the resource to Linux */\r
- retVal = Rm_allocatorOperation(rmInst, opInfo);\r
- }\r
-\r
- return (retVal);\r
-}\r
-\r
-int32_t Rm_findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, \r
- Rm_LinuxAlias *linuxAlias)\r
-{\r
- Rm_AllocatorOpInfo opInfo;\r
- Rm_ResourceInfo resourceInfo;\r
- uint32_t pathOffset;\r
- int32_t propOffset;\r
- int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
- int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
- int32_t depth;\r
- int32_t propertyLen;\r
- const char *propertyName;\r
- const void *propertyData; \r
- Rm_LinuxValueRange *linuxValueRange;\r
- int32_t retVal = RM_DTB_UTIL_RESULT_OKAY; \r
-\r
- /* Initialize the allocator opInfo and resourceInfo structures that will be used to \r
- * reserve the resources taken by the Linux kernel */\r
- memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
- memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
-\r
- strcpy(resourceInfo.name, resourceName);\r
-\r
- /* Set the source instance name for allocation to be the Linux Kernel */\r
- opInfo.srcInstName = RM_ALLOCATED_TO_LINUX;\r
- opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
- opInfo.resourceInfo = &resourceInfo; \r
-\r
- /* Find each resource specified in the Linux resource alias list and reserve that \r
- * resource as used */\r
- while(linuxAlias != NULL)\r
- {\r
- /* Reset the parsing variables */\r
- pathOffset = 0;\r
- nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
- prevDepth = RM_DTB_UTIL_STARTING_DEPTH; \r
- resourceInfo.base = 0;\r
- resourceInfo.length = 0;\r
- \r
- while(pathOffset < linuxAlias->pathListLenBytes)\r
- {\r
- /* Move through the DTB nodes until the next alias path node is found */\r
- if (strcmp(linuxAlias->pathList + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL)))\r
- {\r
- nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);\r
-\r
- if (depth < prevDepth)\r
- {\r
- /* Returning from subnode that matched part of alias path without finding\r
- * the resource values */\r
- retVal = (-31); /* TODO: COULD NOT FIND RESOURCE AT ALIAS PATH */\r
- break;\r
- }\r
- }\r
- else\r
- {\r
- /* Found the next alias path node */\r
- pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
- prevDepth = fdt_node_depth(linuxDtb, nodeOffset);\r
-\r
- /* Check the properties of the node to see if they match the next alias\r
- * path string */\r
- propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);\r
- \r
- /* Search the properties for the next alias path string */\r
- while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&\r
- (pathOffset < linuxAlias->pathListLenBytes))\r
- {\r
- propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, \r
- &propertyName, &propertyLen);\r
-\r
- if (strcmp(linuxAlias->pathList + pathOffset, propertyName) == 0)\r
- {\r
- pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
- /* Found the alias property. Extract the values that will\r
- * contain the resource information that must be reserved. */\r
- linuxValueRange = Rm_linuxExtractValues(propertyData, propertyLen);\r
- /* Use the values to reserve resources for the Linux kernel */\r
- retVal = Rm_reserveLinuxResource(rmInst, linuxAlias, \r
- linuxValueRange, &opInfo);\r
- \r
- /* Free the memory used to store the values */\r
- Rm_linuxFreeValues(linuxValueRange);\r
- }\r
- \r
- propOffset = fdt_next_property_offset(linuxDtb, propOffset);\r
- } \r
-\r
- if (propOffset < -FDT_ERR_NOTFOUND)\r
- {\r
- /* Error was returned by LIBFDT when parsing the properties */\r
- retVal = propOffset;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- if (retVal < RM_DTB_UTIL_RESULT_OKAY)\r
- {\r
- /* Error occurred during parsing of Linux DTB. Return the error */\r
- break;\r
- }\r
- linuxAlias = (Rm_LinuxAlias *) linuxAlias->nextLinuxAlias;\r
- }\r
-\r
- return (retVal);\r
-}\r
-\r
-int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
- Rm_ResourceProperties *resourceProperties, void *linuxDtb)\r
-{\r
- Rm_ResourceRange *range = NULL;\r
- Rm_ResourceRange *rangeBasePtr = NULL;\r
- Rm_NsAssignment *nsAssignments = NULL;\r
- Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
- Rm_LinuxAlias *linuxAlias = NULL;\r
- Rm_ResourceInfo resourceInfo;\r
- int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
-\r
- if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0))\r
- {\r
- /* Extract the resource properties from the DTB */\r
- range = rangeBasePtr = Rm_resourceExtractRange(resourceProperties->rangeData, \r
- resourceProperties->rangeLen);\r
-\r
- /* Create a tree allocator using the resource properties */\r
- retVal = Rm_createTreeAllocator(rmInst, resourceName, range); \r
-\r
- if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
- {\r
- if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen)\r
- {\r
- /* Reserve the resources taken by the Linux kernel specified in the Linux DTB */\r
- linuxAlias = Rm_resourceExtractLinuxAlias(resourceProperties->linuxAliasData,\r
- resourceProperties->linuxAliasLen);\r
-\r
- retVal = Rm_findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias); \r
- }\r
- }\r
- }\r
- \r
- if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
- {\r
- /* Create entries in the NameServer if any NameServer assignments were specified */\r
- if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
- {\r
- nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
- resourceProperties->nsAssignLen);\r
-\r
- /* Cycle through the list of assignments and add them to the NameServer */\r
- nsAssignmentBasePtr = nsAssignments;\r
- while (nsAssignments)\r
- {\r
- memset((void *)&resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
-\r
- resourceInfo.base = nsAssignments->resourceBase;\r
- resourceInfo.length = nsAssignments->resourceLength;\r
- strcpy(resourceInfo.nsName, nsAssignments->nsName);\r
- \r
- /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
- Rm_nsAddObject(rmInst, &resourceInfo);\r
- nsAssignments = nsAssignments->nextNsAssignment;\r
- }\r
- /* Free the memory allocated for the NameServer assignments */\r
- Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
- }\r
- }\r
-\r
- /* Free the memory allocated for the resource properties */\r
- Rm_resourceFreeRange(rangeBasePtr);\r
- Rm_resourceFreeLinuxAlias(linuxAlias);\r
-\r
- return(retVal);\r
-}\r
-\r
-int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
-{\r
- int32_t propertyLen;\r
- const char *propertyName;\r
- const void *propertyData;\r
- Rm_ResourcePropType propertyType;\r
- int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
-\r
- /* Get the property data and store it in the corresponding propertyInfo field */\r
- propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
- if (propertyData)\r
- {\r
- propertyType = Rm_resourceGetPropertyType(propertyName);\r
- if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
- {\r
- if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
- {\r
- /* The range fields have already been populated. Return an error.\r
- * The resource list has specified a property field more than once\r
- * for a resource node */\r
- retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
- else\r
- {\r
- propertyInfo->rangeData = propertyData;\r
- propertyInfo->rangeLen = propertyLen;\r
- }\r
- }\r
- else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
- {\r
- if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
- {\r
- /* The nsAssign fields have already been populated. Return an error.\r
- * The resource list has specified a property field more than once\r
- * for a resource node */\r
- retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
- else\r
- {\r
- propertyInfo->nsAssignData = propertyData;\r
- propertyInfo->nsAssignLen = propertyLen;\r
- }\r
- }\r
- else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS)\r
- {\r
- if (propertyInfo->linuxAliasData || propertyInfo->linuxAliasLen)\r
- {\r
- /* The linuxAlias fields have already been populated. Return an error.\r
- * The resource list has specified a property field more than once\r
- * for a resource node */\r
- retVal = -28; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
- else\r
- {\r
- propertyInfo->linuxAliasData = propertyData;\r
- propertyInfo->linuxAliasLen = propertyLen;\r
- }\r
- } \r
- else\r
- {\r
- retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
- }\r
- else\r
- {\r
- retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
- }\r
-\r
- /* Don't get anymore properties if error occurred */\r
- if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
- {\r
- offset = fdt_next_property_offset(globalResourceDtb, offset);\r
- if (offset >= 0)\r
- {\r
- retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
- }\r
- else if (offset != -FDT_ERR_NOTFOUND)\r
- {\r
- /* Error was returned by LIBFDT when parsing the properties */\r
- retVal = offset;\r
- }\r
- }\r
- \r
- return (retVal);\r
-}\r
-\r
-int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,\r
- void *linuxDtb)\r
-{\r
- const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
- Rm_ResourceProperties resourceProperties;\r
- int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
- int32_t offset;\r
-\r
- /* Initialize the resource properties structure */\r
- memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
-\r
- /* Ignore properties of the base node */\r
- if (strcmp(resourceName, rmDtbStartingNode))\r
- {\r
- /* Get the properties for the resource node if any exist */\r
- offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
- if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
- {\r
- /* Since at least one property exists attempt to parse the property nodes and \r
- * use them to create and initialize a resource allocator */\r
- error = Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
- if (error < -FDT_ERR_NOTFOUND)\r
- {\r
- return (error);\r
- }\r
- \r
- /* Initialize an allocator with the resource properties if no error was returned */\r
- Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb);\r
- }\r
- else if (offset != -FDT_ERR_NOTFOUND)\r
- {\r
- /* Error was returned by LIBFDT when parsing the properties */\r
- return (offset);\r
- }\r
- }\r
- \r
- /* Get the next resource node */\r
- offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
- /* Check the offset and depth of the next node to make sure the current node\r
- * wasn't the last node in the Resource List. A depth less than the depth set\r
- * at the start of the recursion will signal the end of the resource list */\r
- if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
- {\r
- error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);\r
- if (error < -FDT_ERR_NOTFOUND)\r
- {\r
- return (error);\r
- }\r
- }\r
- else if (offset != -FDT_ERR_NOTFOUND)\r
- {\r
- /* Error was returned by LIBFDT when parsing the nodes */\r
- return (offset);\r
- }\r
-\r
- return (RM_DTB_UTIL_RESULT_OKAY);\r
-}\r
-\r
-int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)\r
-{\r
- int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
- int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
- int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
-\r
- /* Recursively parse the Global Resource List, creating an allocator for\r
- * each resource as specified in the node */\r
- result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);\r
-\r
- return(result);\r
-}\r
- \r
-/**********************************************************************\r
- ********************** Application visible APIs **********************\r
- **********************************************************************/\r
-\r
-/* Server Only */\r
-void Rm_printResourceStatus(Rm_Handle *rmHandle)\r
-{\r
- Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
- Rm_Allocator *allocator = rmInst->allocators;\r
- Rm_ResourceTree *treeRoot;\r
- Rm_ResourceTreeNode *treeNode;\r
- uint32_t numLinuxResources;\r
-\r
- while (allocator != NULL)\r
- {\r
- numLinuxResources = 0;\r
-\r
- Rm_osalLog("Resource: %s\n", allocator->resourceName);\r
-\r
- treeRoot = allocator->allocatorRootEntry;\r
-\r
- RB_FOREACH(treeNode, _Rm_ResourceTree, treeRoot)\r
- { \r
- Rm_osalLog(" %10d - %10d ", treeNode->base, \r
- treeNode->base + treeNode->length -1);\r
- \r
- if (strcmp(treeNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
- {\r
- Rm_osalLog("NOT ALLOCATED\n");\r
- }\r
- else\r
- {\r
- Rm_osalLog("allocated to %s\n", treeNode->allocatedTo);\r
- }\r
-\r
- if (strcmp(treeNode->allocatedTo, RM_ALLOCATED_TO_LINUX) == 0)\r
- {\r
- numLinuxResources += treeNode->length;\r
- }\r
- }\r
- \r
- Rm_osalLog("Total allocated to Linux: %d\n", numLinuxResources);\r
- \r
- allocator = allocator->nextAllocator;\r
- }\r
-\r
- Rm_nsPrintObjects(rmInst);\r
-}\r
-\r
-Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
-{\r
- Rm_Inst *rmInst;\r
- void *globalResourceDtb = NULL;\r
- void *linuxResourceDtb = NULL;\r
-\r
- /* Instance creation checks. Add one to strlen calculation for null character */\r
- if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
- {\r
- /* Failure: Instance name is too big */\r
- return (NULL);\r
- }\r
- \r
- /* Get memory for RM instance from local memory */\r
- rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
- /* Populate instance based on input parameters */\r
- strcpy (&rmInst->name[0], initCfg->instName);\r
- rmInst->instType = initCfg->instType;\r
- rmInst->registeredWithDelegateOrServer = false;\r
- rmInst->policyDtb = NULL;\r
-\r
- /* Initialize the transport routing map linked list pointer to NULL. The linked list\r
- * nodes will be created when the application registers transports */\r
- rmInst->routeMap = NULL;\r
-\r
- /* Initialize the allocators linked list pointer to NULL. The linked list nodes will\r
- * be created on the Server instance when the application reads in the resource list.\r
- * Nodes will also be created on Client Delegates when blocks of resources are requested\r
- * for allocation to clients. */\r
- rmInst->allocators = NULL;\r
-\r
- /* Initialize the NameServer pointer to NULL. The NameServer should only be located\r
- * on the RM Server */\r
- rmInst->nameServer = NULL;\r
-\r
- /* Initialize the transaction queue elements. */\r
- rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
- rmInst->transactionQueue= NULL;\r
-\r
- /* RM Server specific actions */\r
- if (rmInst->instType == Rm_instType_SERVER)\r
- {\r
- /* Initialize the NameServer */\r
- Rm_nsInit(rmInst);\r
- \r
- /* Open the ResourceList file and provide it to the resource initializer. The Linux\r
- * DTB will be parsed simultaneously for resource's consumed by the kernel. The resources\r
- * used by the kernel will be marked as used in the resource allocators. */\r
- if (initCfg->globalResourceList)\r
- {\r
- globalResourceDtb = initCfg->globalResourceList;\r
- fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));\r
-\r
- if (initCfg->linuxDtb)\r
- {\r
- linuxResourceDtb = initCfg->linuxDtb;\r
- fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb)); \r
- }\r
- \r
- Rm_initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb);\r
- }\r
- }\r
-\r
- /* Instance startup policies are only used for Servers and Client Delegates */\r
- if (rmInst->instType != Rm_instType_CLIENT)\r
- {\r
- /* Open the instance's policy and store it */\r
- if (initCfg->startupPolicy)\r
- {\r
- rmInst->policyDtb = initCfg->startupPolicy;\r
- fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb)); \r
- }\r
-\r
- /* Store policy via policy APIs ... */\r
- }\r
-\r
- /* Return the RM Handle */\r
- return ((Rm_Handle) rmInst);\r
-}\r
-\r
-uint32_t Rm_getVersion (void)\r
-{\r
- return RM_VERSION_ID;\r
-}\r
-\r
-\r
-const char* Rm_getVersionStr (void)\r
-{\r
- return rmVersionStr;\r
-}\r
-\r
-/**\r
-@}\r
-*/\r
+/**
+ * @file rm.c
+ *
+ * @brief
+ * This is the Resource Manager source.
+ *
+ * \par
+ * ============================================================================
+ * @n (C) Copyright 2012-2013, Texas Instruments, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 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.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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
+*/
+
+/* Standard includes */
+#include <stdint.h>
+#include <string.h>
+
+/* RM external includes */
+#include <ti/drv/rm/rm.h>
+#include <ti/drv/rm/rmver.h>
+#include <ti/drv/rm/rm_services.h>
+#include <ti/drv/rm/rm_transport.h>
+
+/* RM internal includes */
+#include <ti/drv/rm/include/rm_internal.h>
+#include <ti/drv/rm/include/rm_loc.h>
+#include <ti/drv/rm/include/rm_allocatorloc.h>
+#include <ti/drv/rm/include/rm_transportloc.h>
+#include <ti/drv/rm/include/rm_nameserverloc.h>
+#include <ti/drv/rm/include/rm_servicesloc.h>
+
+/* RM LIBFDT includes */
+#include <ti/drv/rm/util/libfdt/libfdt.h>
+
+/* RM OSAL layer */
+#include <rm_osal.h>
+
+/**********************************************************************
+ ************************** Globals ***********************************
+ **********************************************************************/
+
+/* Global Variable which describes the RM Version Information */
+const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__;
+
+/**********************************************************************
+ ************************ Local Functions *****************************
+ **********************************************************************/
+
+/* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number
+ ***********************************************************************
+ * DESCRIPTION: The RM instance transaction sequence number can never
+ * have a value of 0 to avoid conflicts with transactions
+ * that have a remoteOriginatingId of 0 (transaction ID
+ * will be used as the remoteOriginatingId for
+ * transactions that are responses to requests).
+ */
+static uint32_t transactionInitSequenceNum(void)
+{
+ return (1);
+}
+
+/* FUNCTION PURPOSE: Provides a sequence number for new transactions
+ ***********************************************************************
+ * DESCRIPTION: Returns a sequence number for a new transaction
+ * specific to a RM instance. Handles rollover of
+ * sequence number.
+ */
+static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst)
+{
+ rmInst->transactionSeqNum++;
+ if (!rmInst->transactionSeqNum) {
+ rmInst->transactionSeqNum++;
+ }
+ return (rmInst->transactionSeqNum);
+}
+
+/* FUNCTION PURPOSE: Creates a resource request packet
+ ***********************************************************************
+ * DESCRIPTION: Returns a RM packet handle that points to a RM
+ * resource request packet that has been prepared
+ * for sending to another RM instance. The packet
+ * is allocated via the rmAllocPkt API using the
+ * appTransport handle provided by the application
+ */
+void createResourceReqPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction)
+{
+ Rm_ResourceRequestPkt *resourceReqPkt = NULL;
+
+ rmPkt->pktType = Rm_pktType_RESOURCE_REQUEST;
+ resourceReqPkt = (Rm_ResourceRequestPkt *) rmPkt->data;
+ resourceReqPkt->requestId = transaction->localId;
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_USE;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_STATUS) {
+ resourceReqPkt->resourceReqType = Rm_resReqPktType_GET_STATUS;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_FREE) {
+ resourceReqPkt->resourceReqType = Rm_resReqPktType_FREE;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
+ resourceReqPkt->resourceReqType = Rm_resReqPktType_GET_NAMED;
+ }
+ strncpy(resourceReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS);
+ strncpy(resourceReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS);
+ memcpy ((void *)&(resourceReqPkt->resourceInfo), (void *)&(transaction->resourceInfo),
+ sizeof(Rm_ResourceInfo));
+}
+
+/* FUNCTION PURPOSE: Creates a resource response packet
+ ***********************************************************************
+ * DESCRIPTION: Returns a RM packet handle that points to a RM
+ * resource response packet that has been prepared
+ * for sending to another RM instance. The packet
+ * is allocated via the rmAllocPkt API using the
+ * appTransport handle provided by the application
+ */
+void createResourceResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction)
+{
+ Rm_ResourceResponsePkt *resourceRespPkt = NULL;
+
+ rmPkt->pktType = Rm_pktType_RESOURCE_RESPONSE;
+ resourceRespPkt = (Rm_ResourceResponsePkt *)rmPkt->data;
+ resourceRespPkt->responseId = transaction->remoteOriginatingId;
+ resourceRespPkt->requestState = transaction->state;
+ memcpy ((void *)&(resourceRespPkt->resourceInfo), (void *)&(transaction->resourceInfo),
+ sizeof(Rm_ResourceInfo));
+}
+
+/* FUNCTION PURPOSE: Creates a NameServer request packet
+ ***********************************************************************
+ * DESCRIPTION: Returns a RM packet handle that points to a RM
+ * NameServer request packet that has been prepared
+ * for sending to another RM instance. The packet
+ * is allocated via the rmAllocPkt API using the
+ * appTransport handle provided by the application
+ */
+void createNsRequestPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction)
+{
+ Rm_NsRequestPkt *nsReqPkt = NULL;
+
+ rmPkt->pktType = Rm_pktType_NAMESERVER_REQUEST;
+ nsReqPkt = (Rm_NsRequestPkt *)rmPkt->data;
+ nsReqPkt->requestId = transaction->localId;
+ if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
+ nsReqPkt->nsRequestType = Rm_nsReqPktType_MAP_RESOURCE;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
+ nsReqPkt->nsRequestType = Rm_nsReqPktType_UNMAP_RESOURCE;
+ }
+ strncpy(nsReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS);
+ strncpy(nsReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS);
+ memcpy ((void *)&(nsReqPkt->resourceInfo), (void *)&(transaction->resourceInfo),
+ sizeof(Rm_ResourceInfo));
+}
+
+/* FUNCTION PURPOSE: Creates a NameServer response packet
+ ***********************************************************************
+ * DESCRIPTION: Returns a RM packet handle that points to a RM
+ * NameServer response packet that has been prepared
+ * for sending to another RM instance. The packet
+ * is allocated via the rmAllocPkt API using the
+ * appTransport handle provided by the application
+ */
+void createNsResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction)
+{
+ Rm_NsResponsePkt *nsRespPkt = NULL;
+
+ rmPkt->pktType = Rm_pktType_NAMESERVER_RESPONSE;
+ nsRespPkt = (Rm_NsResponsePkt *)rmPkt->data;
+ nsRespPkt->responseId = transaction->remoteOriginatingId;
+ nsRespPkt->requestState = transaction->state;
+}
+
+/* FUNCTION PURPOSE: Issues a service response to application
+ ***********************************************************************
+ * DESCRIPTION: Provides a service response back to the application
+ * using the service callback function provided to
+ * the RM instance at the time of the service request.
+ */
+static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_ServiceRespInfo serviceResponse;
+
+ serviceResponse.rmHandle = (Rm_Handle)rmInst;
+ /* The responseTransaction will contain the resultant state details of
+ * the requestTransaction's service request */
+ serviceResponse.serviceState = transaction->state;
+ /* Pass back the ID that was provided to the component when it requested
+ * the service */
+ serviceResponse.serviceId = transaction->localId;
+ /* Owner count will only be set within RM under certain circumstances. Most of time
+ * it will be RM_RESOURCE_NUM_OWNERS_INVALID */
+ serviceResponse.resourceNumOwners = transaction->resourceInfo.ownerCount;
+
+ /* Service was approved and service was an allocate request. The resource
+ * data is passed back to the component */
+ if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) &&
+ ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
+ (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
+ (transaction->type == Rm_service_RESOURCE_FREE) ||
+ (transaction->type == Rm_service_RESOURCE_STATUS) ||
+ (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)))
+ {
+ strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
+ serviceResponse.resourceBase = transaction->resourceInfo.base;
+ serviceResponse.resourceLength = transaction->resourceInfo.length;
+ }
+
+ if (transaction->u.callback.serviceCallback) {
+ /* Issue the callback to the requesting component with the response information */
+ transaction->u.callback.serviceCallback(&serviceResponse);
+ /* Delete the transaction from the transaction queue */
+ rmTransactionQueueDelete(rmInst, transaction->localId);
+ }
+ else {
+ rmServiceInternalCallback((Rm_Handle)rmInst);
+ }
+
+ return;
+}
+
+/* FUNCTION PURPOSE: Sends RM response packets
+ ***********************************************************************
+ * DESCRIPTION: Sends RM response packets to RM instance's that sent
+ * RM request packets to the RM instance. The response
+ * is sent via the RM transport API which is plugged
+ * with an application created transport path.
+ */
+static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_Transport *dstTransport = transaction->u.respTrans;
+ Rm_Packet *rmPkt = NULL;
+ Rm_PacketHandle pktHandle = NULL;
+
+ rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle,
+ sizeof(Rm_Packet), &pktHandle);
+ if (!rmPkt || !pktHandle) {
+ transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR;
+ goto errorExit;
+ }
+
+ switch (transaction->type) {
+ case Rm_service_RESOURCE_ALLOCATE_INIT:
+ case Rm_service_RESOURCE_ALLOCATE_USE:
+ case Rm_service_RESOURCE_STATUS:
+ case Rm_service_RESOURCE_FREE:
+ case Rm_service_RESOURCE_GET_BY_NAME:
+ createResourceResponsePkt(rmPkt, transaction);
+ break;
+ case Rm_service_RESOURCE_MAP_TO_NAME:
+ case Rm_service_RESOURCE_UNMAP_NAME:
+ createNsResponsePkt(rmPkt, transaction);
+ break;
+ }
+ if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
+ transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
+ goto errorExit;
+ }
+
+ /* Response packet sent: Delete transaction from queue */
+ rmTransactionQueueDelete(rmInst, transaction->localId);
+
+errorExit:
+ /* Do not delete transaction on transport error. Transport error transactions should be visible
+ * from Rm_printInstanceStatus() */
+ return;
+}
+
+/* FUNCTION PURPOSE: Sends RM request packets
+ ***********************************************************************
+ * DESCRIPTION: Sends RM request packets to RM instance's that are
+ * capable of forwarding or validating service requests.
+ * The request is sent via the RM transport API which is
+ * plugged with an application created transport path.
+ */
+static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_Transport *dstTransport = NULL;
+ Rm_Packet *rmPkt = NULL;
+ Rm_PacketHandle pktHandle = NULL;
+
+ if (rmInst->instType == Rm_instType_CLIENT) {
+ dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_CLIENT_DELEGATE);
+
+ if (!dstTransport) {
+ dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER);
+ }
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER);
+ }
+
+ /* Just queue transaction if transport hasn't been registered. Do not return error */
+ if (dstTransport) {
+ rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle,
+ sizeof(Rm_Packet), &pktHandle);
+ if (!rmPkt || !pktHandle) {
+ transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR;
+ goto errorExit;
+ }
+
+ switch (transaction->type) {
+ case Rm_service_RESOURCE_ALLOCATE_INIT:
+ case Rm_service_RESOURCE_ALLOCATE_USE:
+ case Rm_service_RESOURCE_STATUS:
+ case Rm_service_RESOURCE_FREE:
+ case Rm_service_RESOURCE_GET_BY_NAME:
+ createResourceReqPkt(rmPkt, rmInst->instName, transaction);
+ break;
+ case Rm_service_RESOURCE_MAP_TO_NAME:
+ case Rm_service_RESOURCE_UNMAP_NAME:
+ createNsRequestPkt(rmPkt, rmInst->instName, transaction);
+ break;
+ }
+
+ if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
+ transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
+ goto errorExit;
+ }
+ transaction->hasBeenForwarded = RM_TRUE;
+ /* Transaction not deleted. Waiting for response from RM CD or Server */
+ }
+errorExit:
+ /* Do not delete transaction on transport error. Transport error transactions should be visible
+ * from Rm_printInstanceStatus() */
+ return;
+}
+
+/* FUNCTION PURPOSE: Handles static allocation requests
+ ***********************************************************************
+ * DESCRIPTION: Validates allocation requests received on CDs and
+ * Clients prior to the instance's registering
+ * with a Server. The allocation request is validated
+ * against a static policy.
+ */
+static void staticAllocationHandler (Rm_Handle rmHandle, Rm_Transaction *transaction)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ void *staticPolicy = rmPolicyGetPolicy(rmHandle);
+ Rm_PolicyCheckCfg privCheckCfg;
+ int32_t result;
+
+ if (staticPolicy) {
+ if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
+ (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
+ /* Check request against static policy */
+ memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
+
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ privCheckCfg.type = Rm_policyCheck_INIT;
+ }
+ else {
+ privCheckCfg.type = Rm_policyCheck_USE;
+ }
+ privCheckCfg.policyDtb = staticPolicy;
+ privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmHandle, rmInst->instName);
+ privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(staticPolicy,
+ transaction->resourceInfo.name);
+ privCheckCfg.resourceBase = transaction->resourceInfo.base;
+ privCheckCfg.resourceLength = transaction->resourceInfo.length;
+
+ if (rmPolicyCheckPrivilege(&privCheckCfg, &result)) {
+ transaction->state = RM_SERVICE_APPROVED_STATIC;
+ }
+ else if (result == RM_OK) {
+ /* Privilege check returned false without error */
+ transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY;
+ }
+ else {
+ /* Privilege check returned false with error */
+ transaction->state = result;
+ }
+ }
+ else {
+ transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST;
+ }
+ }
+ else {
+ transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY;
+ }
+}
+
+/* FUNCTION PURPOSE: Requests resources from Server for CD
+ ***********************************************************************
+ * DESCRIPTION: Function creates a service request to allocate resources
+ * from the Server for local management by the CD. The
+ * transaction which causes this request is put in the
+ * pending state in order to wait for the response from the
+ * Server
+ */
+static int32_t cdRequestServerResources(Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_Transaction *newTrans = NULL;
+ void * policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
+ int32_t resourceOffsetInPolicy;
+ uint32_t allocSize = 0;
+ int32_t retVal;
+
+ resourceOffsetInPolicy = rmPolicyGetResourceOffset(policy, transaction->resourceInfo.name);
+ if (resourceOffsetInPolicy > 0) {
+ if (allocSize = rmPolicyGetResourceAllocSize(policy, resourceOffsetInPolicy)) {
+ if (newTrans = rmTransactionQueueAdd(rmInst)) {
+ newTrans->type = transaction->type;
+ strncpy(newTrans->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS);
+ newTrans->state = RM_SERVICE_PROCESSING;
+ strncpy(newTrans->resourceInfo.name, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
+ newTrans->resourceInfo.base = RM_RESOURCE_BASE_UNSPECIFIED;
+ /* Make sure request length will satisfy transaction length */
+ newTrans->resourceInfo.length = allocSize;
+ while (newTrans->resourceInfo.length < transaction->resourceInfo.length) {
+ newTrans->resourceInfo.length += allocSize;
+ }
+ newTrans->resourceInfo.alignment = transaction->resourceInfo.alignment;
+ newTrans->pendingTransactionId = transaction->localId;
+ transactionForwarder(rmInst, newTrans);
+
+ retVal = RM_SERVICE_PENDING_SERVER_RESPONSE;
+ }
+ else {
+ retVal = RM_ERROR_TRANS_REQ_TO_SERVER_NOT_CREATED;
+ }
+ }
+ else {
+ /* Forward request to Server for completion if policy has
+ * no allocation size for resource */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ }
+ else {
+ /* Resource could not be found in policy */
+ retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
+ }
+ return (retVal);
+}
+
+/* FUNCTION PURPOSE: Frees local resources to Server from CD
+ ***********************************************************************
+ * DESCRIPTION: Function creates a service request to free locally
+ * managed resources that are now localized back to
+ * the Server.
+ */
+static int32_t cdFreeResourcesToServer(Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ int32_t baseToFree = transaction->resourceInfo.base;
+ uint32_t lenToFree = transaction->resourceInfo.length;
+ Rm_Transaction *newTrans = NULL;
+ /* This function should only be called after a free was approved */
+ int32_t retVal = RM_SERVICE_APPROVED;
+
+ /* Did free result in a localized free node that can be given back to Server? If
+ * so create transaction to Server to free localized resource node */
+ if (rmAllocatorGetNodeLocalization((Rm_Handle)rmInst, transaction->resourceInfo.name,
+ &baseToFree, &lenToFree)) {
+ if (newTrans = rmTransactionQueueAdd(rmInst)) {
+ newTrans->type = transaction->type;
+ strncpy(newTrans->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS);
+ newTrans->state = RM_SERVICE_PROCESSING;
+ strncpy(newTrans->resourceInfo.name, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
+ newTrans->resourceInfo.base = baseToFree;
+ newTrans->resourceInfo.length = lenToFree;
+ newTrans->pendingTransactionId = transaction->localId;
+ transactionForwarder(rmInst, newTrans);
+
+ retVal = RM_SERVICE_PENDING_SERVER_RESPONSE;
+ }
+ else {
+ /* Error: Need to re-allocate what was freed */
+ retVal = RM_ERROR_TRANS_REQ_TO_SERVER_NOT_CREATED;
+ }
+ }
+ return (retVal);
+}
+
+/* FUNCTION PURPOSE: Arbitrates allocation service requests
+ ***********************************************************************
+ * DESCRIPTION: Issues a set of allocator operations in order to
+ * handle a received allocation request. Allocation
+ * requests are always forwarded to the Server on Client
+ * CD instances. If a request is made with a NameServer
+ * name the resource base and length parameters are
+ * retrieved from the NameServer prior to the allocation
+ * attempt.
+ */
+static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_AllocatorOpInfo opInfo;
+ Rm_NameServerObjCfg nameServerObjCfg;
+ int32_t retVal = transaction->state;
+
+ memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
+ opInfo.policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
+ opInfo.resourceInfo = &transaction->resourceInfo;
+ opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, transaction->serviceSrcInstName);
+ if (opInfo.serviceSrcInstNode == NULL) {
+ retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
+ goto errorExit;
+ }
+
+ if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ if (transaction->resourceInfo.base != RM_RESOURCE_BASE_UNSPECIFIED) {
+ if (rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name)) {
+ /* Attempt to allocate from local resources that were provided by Server */
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_USE;
+ }
+ else {
+ retVal = RM_ERROR_INVALID_SERVICE_TYPE;
+ goto errorExit;
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+
+ if (retVal == RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST) {
+ /* Request resource range was not found within local resources
+ * provided by Server. Set back to PROCESSING so request is forwarded to
+ * Server */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ }
+ }
+ else {
+ if (rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name)) {
+ int32_t oldAlign = transaction->resourceInfo.alignment;
+
+ /* Attempt to allocate from local resources that were provided by Server */
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE_USE;
+ }
+ else {
+ retVal = RM_ERROR_INVALID_SERVICE_TYPE;
+ goto errorExit;
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+
+ if (retVal == RM_SERVICE_PROCESSING) {
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_USE;
+ }
+ else {
+ retVal = RM_ERROR_INVALID_SERVICE_TYPE;
+ goto errorExit;
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+
+ if (retVal == RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST) {
+ /* Request resource range was not found within local resources
+ * provided by Server. Set back to PROCESSING so request is forwarded to
+ * Server */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ }
+ else if (retVal == RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET) {
+ if (transaction->pendingTransactionId) {
+ /* Request to Server for resources to complete transaction locally
+ * performed once already. Forward transaction to Server for completion */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ else {
+ /* Restore base and alignment since they were replaced in pre-allocate routine */
+ transaction->resourceInfo.base = RM_RESOURCE_BASE_UNSPECIFIED;
+ transaction->resourceInfo.alignment = oldAlign;
+
+ retVal = cdRequestServerResources(rmInst, transaction);
+ }
+ }
+ }
+ else {
+ retVal = cdRequestServerResources(rmInst, transaction);
+ }
+ }
+ }
+ else if ((rmInst->instType == Rm_instType_SERVER)||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ /* Populated NameServer name has precedence over base */
+ if (strlen(transaction->resourceInfo.nameServerName) > 0) {
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmNameServerTreeInv(rmInst->u.server.nameServer);
+ }
+ memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
+ nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
+ nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
+ if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
+ strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
+ transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
+ transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
+ }
+ else {
+ goto errorExit;
+ }
+ }
+
+ if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE_USE;
+ }
+ else {
+ retVal = RM_ERROR_INVALID_SERVICE_TYPE;
+ goto errorExit;
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+ }
+
+ if (retVal == RM_SERVICE_PROCESSING) {
+ if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_USE;
+ }
+ else {
+ retVal = RM_ERROR_INVALID_SERVICE_TYPE;
+ goto errorExit;
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+ }
+ }
+errorExit:
+ transaction->state = retVal;
+}
+
+/* FUNCTION PURPOSE: Handles resource status service requests
+ ***********************************************************************
+ * DESCRIPTION: Issues a set of allocator operations to retrieve the
+ * current status (currently just owner reference count)
+ * for the resource specified in the transaction
+ */
+static void statusHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_AllocatorOpInfo opInfo;
+ Rm_NameServerObjCfg nameServerObjCfg;
+ int32_t retVal = transaction->state;
+
+ memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
+ opInfo.operation = Rm_allocatorOp_GET_STATUS;
+ opInfo.policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
+ opInfo.resourceInfo = &transaction->resourceInfo;
+ opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, transaction->serviceSrcInstName);
+ if (opInfo.serviceSrcInstNode == NULL) {
+ retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
+ goto errorExit;
+ }
+
+ if ((strlen(transaction->resourceInfo.nameServerName) == 0) &&
+ ((transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) ||
+ (transaction->resourceInfo.length == 0))) {
+ retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
+ goto errorExit;
+ }
+
+ if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ if (rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name)) {
+ /* Attempt to get status from local resources that were provided by Server */
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+
+ if (retVal == RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST) {
+ /* Request resource range was not found within local allocator resources
+ * provided by Server. Set back to PROCESSING so request is forwarded to
+ * Server */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ }
+ }
+ else if ((rmInst->instType == Rm_instType_SERVER)||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ /* Populated NameServer name has precedence over base and length values */
+ if (strlen(transaction->resourceInfo.nameServerName) > 0) {
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmNameServerTreeInv(rmInst->u.server.nameServer);
+ }
+ memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
+ nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
+ nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
+ if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
+ strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
+ transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
+ transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
+ }
+ else {
+ goto errorExit;
+ }
+ }
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+ }
+errorExit:
+ transaction->state = retVal;
+}
+
+/* FUNCTION PURPOSE: Arbitrates free service requests
+ ***********************************************************************
+ * DESCRIPTION: Issues a set of allocator operations in order to
+ * handle a received free request. Free
+ * requests are always forwarded to the Server on Client
+ * CD instances. If a request is made with a NameServer
+ * name the resource base and length parameters are
+ * retrieved from the NameServer prior to the free
+ * attempt.
+ */
+static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_AllocatorOpInfo opInfo;
+ Rm_NameServerObjCfg nameServerObjCfg;
+ int32_t retVal = transaction->state;
+
+ memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
+ opInfo.operation = Rm_allocatorOp_FREE;
+ opInfo.policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
+ opInfo.resourceInfo = &transaction->resourceInfo;
+ opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, transaction->serviceSrcInstName);
+ if (opInfo.serviceSrcInstNode == NULL) {
+ retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
+ goto errorExit;
+ }
+
+ if ((strlen(transaction->resourceInfo.nameServerName) == 0) &&
+ ((transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) ||
+ (transaction->resourceInfo.length == 0))) {
+ retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
+ goto errorExit;
+ }
+
+ if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ if (rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name)) {
+ /* Attempt to free from local resources that were provided by Server */
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+
+ if (retVal == RM_SERVICE_APPROVED) {
+ /* Check if free allows local resources to be freed back to Server */
+ retVal = cdFreeResourcesToServer(rmInst, transaction);
+ }
+ else if (retVal == RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST) {
+ /* Request resource range was not found within local allocator resources
+ * provided by Server. Set back to PROCESSING so request is forwarded to
+ * Server */
+ retVal = RM_SERVICE_PROCESSING;
+ }
+ }
+ }
+ else if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ /* Populated NameServer name has precedence over base */
+ if (strlen(transaction->resourceInfo.nameServerName) > 0) {
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmNameServerTreeInv(rmInst->u.server.nameServer);
+ }
+ memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
+ nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
+ nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
+ if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
+ strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
+ transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
+ transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
+ }
+ else {
+ goto errorExit;
+ }
+ }
+
+ retVal = rmAllocatorOperation((Rm_Handle)rmInst, &opInfo);
+ }
+errorExit:
+ transaction->state = retVal;
+}
+
+/* FUNCTION PURPOSE: Client transaction handling process
+ ***********************************************************************
+ * DESCRIPTION: Client process for handling transactions created
+ * from services received via the service handle or the
+ * transport. The Client process:
+ * - Performs static allocations if no transport
+ * to CD or Server has been registered
+ * - Forwards all service requests to CD or Server
+ * once transport has been registered
+ */
+static void clientProcess (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_Transaction *transQ = rmInst->transactionQueue;
+
+ if (!rmInst->registeredWithDelegateOrServer) {
+ staticAllocationHandler((Rm_Handle)rmInst, transaction);
+ }
+ else {
+ if (transaction->state == RM_SERVICE_PROCESSING) {
+ /* Forward all new transactions to CD or Server */
+ transactionForwarder(rmInst, transaction);
+ }
+ else {
+ /* Transaction validated. Return result. */
+ serviceResponder(rmInst, transaction);
+ }
+
+ /* Forward any queued static requests that weren't forwarded */
+ while(transQ) {
+ if ((transQ->state == RM_SERVICE_APPROVED_STATIC) &&
+ (!transQ->hasBeenForwarded)) {
+ transactionForwarder(rmInst, transQ);
+ }
+ transQ = transQ->nextTransaction;
+ }
+ }
+ /* Let call stack return transaction result app via Rm_serviceHandler */
+}
+
+/* FUNCTION PURPOSE: Client Delegate transaction handling process
+ ***********************************************************************
+ * DESCRIPTION: Client Delegate process for handling transactions created
+ * from services received via the service handle or the
+ * transport. The Client Delegate process:
+ * - Performs static allocations if no transport
+ * to Server has been registered
+ * - Forwards all NameServer related service requests
+ * to Server once transport has been registered
+ * - Attempts to complete resource service requests
+ * received from registered Clients
+ */
+static void cdProcess (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_Transaction *newTrans = NULL;
+ Rm_Allocator *allocator = NULL;
+ Rm_Transaction *transQ = rmInst->transactionQueue;
+
+ if (!rmInst->registeredWithDelegateOrServer) {
+ if ((transaction->state == RM_SERVICE_PROCESSING) &&
+ (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) {
+ /* Attempt static allocation of requests originating from CD inst */
+ staticAllocationHandler((Rm_Handle)rmInst, transaction);
+ }
+ /* Everything else left in transaction queue for forwarding once transport to
+ * Server is registered */
+ }
+ else {
+ if (transaction->pendingTransactionId) {
+ Rm_Transaction *pendingTrans = rmTransactionQueueFind(rmInst, transaction->pendingTransactionId);
+
+ /* Transaction is response from Server for transaction sent to get
+ * information in order to complete pending transaction */
+ if (transaction->state == RM_SERVICE_APPROVED) {
+ if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
+ /* Transfer resource data tied to name to pending transaction */
+ strncpy(pendingTrans->resourceInfo.name, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
+ pendingTrans->resourceInfo.base = transaction->resourceInfo.base;
+ pendingTrans->resourceInfo.length = transaction->resourceInfo.length;
+ /* Delete NS name from pending transaction so Server isn't queried again */
+ memset(pendingTrans->resourceInfo.nameServerName, 0, RM_NAME_MAX_CHARS);
+ /* Now that resource values have been retrieved clear pending transaction ID so
+ * CD doesn't think a resource request was sent to Server already for more local resources */
+ pendingTrans->pendingTransactionId = 0;
+
+ /* Return original transaction to processing state to attempt completion. */
+ pendingTrans->state = RM_SERVICE_PROCESSING;
+ }
+ else if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
+ (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
+ /* Add resources provided by Server to those managed by CD */
+ if (allocator = rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name)) {
+ Rm_ResourceNode *treeNode = NULL;
+
+ treeNode = rmResourceNodeNew(transaction->resourceInfo.base, transaction->resourceInfo.length);
+ RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, treeNode);
+ }
+ else {
+ Rm_ResourceRange resRange;
+
+ memset((void *)&resRange, 0, sizeof(resRange));
+ resRange.base = transaction->resourceInfo.base;
+ resRange.length = transaction->resourceInfo.length;
+
+ rmAllocatorCreate((Rm_Handle)rmInst, transaction->resourceInfo.name, &resRange);
+ }
+
+ /* Return original transaction to processing state to attempt completion */
+ pendingTrans->state = RM_SERVICE_PROCESSING;
+ }
+ else if (transaction->type == Rm_service_RESOURCE_FREE) {
+ /* Local resource freed on Server. Need to remove from local allocator. */
+ rmAllocatorDeleteNode((Rm_Handle)rmInst, transaction->resourceInfo.name,
+ transaction->resourceInfo.base, transaction->resourceInfo.length);
+
+ /* Delete the allocator if there are no nodes left in the tree */
+ allocator = rmAllocatorFind((Rm_Handle)rmInst, transaction->resourceInfo.name);
+ if (RB_MIN(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry) == NULL) {
+ rmAllocatorDelete((Rm_Handle)rmInst, transaction->resourceInfo.name);
+ }
+
+ /* Allow original free to complete */
+ pendingTrans->state = RM_SERVICE_APPROVED;
+ }
+ }
+ else {
+ if (transaction->type == Rm_service_RESOURCE_FREE) {
+ /* Error occurred when trying to free local resource on Server. Reinsert local
+ * resources freed by original request */
+ Rm_AllocatorOpInfo opInfo;
+
+ memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
+ opInfo.policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
+ opInfo.resourceInfo = &pendingTrans->resourceInfo;
+ opInfo.serviceSrcInstNode = rmPolicyGetValidInstNode((Rm_Handle)rmInst, pendingTrans->serviceSrcInstName);
+ /* Can't regain the original type of allocate. Default to init */
+ opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
+ if (rmAllocatorOperation((Rm_Handle)rmInst, &opInfo) != RM_SERVICE_APPROVED) {
+ transaction->state = RM_ERROR_LOST_RESOURCES_ON_CD;
+ }
+ }
+ /* Transfer error or denial to pending transaction */
+ pendingTrans->state = transaction->state;
+ }
+ rmTransactionQueueDelete(rmInst, transaction->localId);
+ /* Switch to pending transaction */
+ transaction = pendingTrans;
+ }
+
+ if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
+ (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
+ (transaction->type == Rm_service_RESOURCE_STATUS) ||
+ (transaction->type == Rm_service_RESOURCE_FREE)) {
+ if ((transaction->state == RM_SERVICE_PROCESSING) &&
+ (strlen(transaction->resourceInfo.nameServerName) > 0)) {
+ /* Create and forward new transaction to Server to
+ * retrieve resource data mapped to name */
+ if (newTrans = rmTransactionQueueAdd(rmInst)) {
+ newTrans->type = Rm_service_RESOURCE_GET_BY_NAME;
+ strncpy(newTrans->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS);
+ newTrans->state = RM_SERVICE_PROCESSING;
+ strncpy(newTrans->resourceInfo.nameServerName, transaction->resourceInfo.nameServerName,
+ RM_NAME_MAX_CHARS);
+ newTrans->pendingTransactionId = transaction->localId;
+ transactionForwarder(rmInst, newTrans);
+
+ transaction->state = RM_SERVICE_PENDING_SERVER_RESPONSE;
+ }
+ else {
+ transaction->state = RM_ERROR_TRANS_REQ_TO_SERVER_NOT_CREATED;
+ }
+ }
+ }
+
+ if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
+ (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
+ if (transaction->state == RM_SERVICE_PROCESSING) {
+ allocationHandler(rmInst, transaction);
+ }
+ }
+ else if (transaction->type == Rm_service_RESOURCE_STATUS) {
+ if (transaction->state == RM_SERVICE_PROCESSING) {
+ statusHandler(rmInst, transaction);
+ }
+ }
+ else if (transaction->type == Rm_service_RESOURCE_FREE) {
+ if (transaction->state == RM_SERVICE_PROCESSING) {
+ freeHandler(rmInst, transaction);
+ }
+ }
+ /* Forward all NameServer-based transactions */
+
+ if (transaction->state == RM_SERVICE_PROCESSING) {
+ /* CD could not complete transaction. Forward to Server */
+ transactionForwarder(rmInst, transaction);
+ }
+ else if (transaction->state != RM_SERVICE_PENDING_SERVER_RESPONSE) {
+ /* Transaction completed by CD or completed response received from Server. Return result */
+ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
+ /* Transaction did not originate on this instance */
+ transactionResponder(rmInst, transaction);
+ }
+ else {
+ /* Transaction originated on this instance */
+ serviceResponder(rmInst, transaction);
+ }
+ }
+
+ /* Attempt allocation of any queued static requests:
+ * RM_SERVICE_APPROVED_STATIC - Originated locally
+ * RM_SERVICE_PROCESSING - Received from any registered Clients */
+ while(transQ) {
+ if (((transQ->state == RM_SERVICE_PROCESSING) ||
+ (transQ->state == RM_SERVICE_APPROVED_STATIC)) &&
+ (!transQ->hasBeenForwarded)) {
+ transactionForwarder(rmInst, transQ);
+ }
+ transQ = transQ->nextTransaction;
+ }
+ }
+}
+
+/* FUNCTION PURPOSE: Server transaction handling process
+ ***********************************************************************
+ * DESCRIPTION: Server process for handling transactions created
+ * from services received via the service handle or the
+ * transport. The Server process:
+ * - Validates all service requests received from
+ * the service handle and registered CDs and
+ * Clients
+ */
+static void serverProcess (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ Rm_NameServerObjCfg nameServerObjCfg;
+
+ switch (transaction->type) {
+ case Rm_service_RESOURCE_STATUS:
+ statusHandler(rmInst, transaction);
+ break;
+ case Rm_service_RESOURCE_ALLOCATE_INIT:
+ case Rm_service_RESOURCE_ALLOCATE_USE:
+ allocationHandler(rmInst, transaction);
+ break;
+ case Rm_service_RESOURCE_FREE:
+ freeHandler(rmInst, transaction);
+ break;
+ case Rm_service_RESOURCE_MAP_TO_NAME:
+ case Rm_service_RESOURCE_GET_BY_NAME:
+ case Rm_service_RESOURCE_UNMAP_NAME:
+ if (rmInst->u.server.nameServer) {
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmNameServerTreeInv(rmInst->u.server.nameServer);
+ }
+ memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
+ nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
+ nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
+ if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
+ nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name;
+ nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base;
+ nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length;
+ transaction->state = rmNameServerAddObject(&nameServerObjCfg);
+ }
+ else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
+ if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) ==
+ RM_SERVICE_PROCESSING) {
+ strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
+ transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
+ transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
+ transaction->state = RM_SERVICE_APPROVED;
+ }
+ }
+ else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
+ transaction->state = rmNameServerDeleteObject(&nameServerObjCfg);
+ }
+
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmNameServerTreeWb(rmInst->u.server.nameServer);
+ }
+ }
+ else {
+ transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST;
+ }
+ break;
+ }
+
+ /* Source of shared server transaction will always be local. */
+ if (rmInst->instType != Rm_instType_SHARED_SERVER) {
+ if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
+ /* Source of transaction was not Server, return transaction via responder */
+ transactionResponder(rmInst, transaction);
+ }
+ }
+ /* Otherwise let call stack return transaction result app via Rm_serviceHandler */
+}
+
+/**********************************************************************
+ ********************** Internal Functions ****************************
+ **********************************************************************/
+
+/* FUNCTION PURPOSE: Adds a transaction
+ ***********************************************************************
+ * DESCRIPTION: Returns a pointer to a newly created transaction.
+ * The transaction is created based on a new service
+ * request received via the service API or the
+ * transport API (service forwarded from another instance)
+ */
+Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst)
+{
+ Rm_Transaction *transactionQueue = rmInst->transactionQueue;
+ Rm_Transaction *newTransaction = NULL;
+
+ newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));
+ if (newTransaction) {
+ memset((void *)newTransaction, 0, sizeof(Rm_Transaction));
+
+ newTransaction->localId = transactionGetSequenceNum(rmInst);
+ newTransaction->nextTransaction = NULL;
+ if (transactionQueue) {
+ while (transactionQueue->nextTransaction) {
+ transactionQueue = transactionQueue->nextTransaction;
+ }
+ transactionQueue->nextTransaction = newTransaction;
+ }
+ else {
+ rmInst->transactionQueue = newTransaction;
+ }
+ }
+ return (newTransaction);
+}
+
+/* FUNCTION PURPOSE: Finds a transaction
+ ***********************************************************************
+ * DESCRIPTION: Returns a pointer to a transaction resident
+ * in the transaction queue that matches the provided
+ * transaction ID.
+ */
+Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)
+{
+ Rm_Transaction *transaction = rmInst->transactionQueue;
+
+ while (transaction) {
+ if (transaction->localId == transactionId) {
+ break;
+ }
+ transaction = transaction->nextTransaction;
+ }
+
+ return (transaction);
+}
+
+/* FUNCTION PURPOSE: Deletes a transaction
+ ***********************************************************************
+ * DESCRIPTION: Deletes the transaction with the provided transaction
+ * ID from the instance's transaction queue.
+ */
+int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)
+{
+ Rm_Transaction *transaction = rmInst->transactionQueue;
+ Rm_Transaction *prevTransaction = NULL;
+ int32_t retVal = RM_OK;
+
+ while (transaction) {
+ if (transaction->localId == transactionId) {
+ break;
+ }
+
+ prevTransaction = transaction;
+ transaction = transaction->nextTransaction;
+ }
+
+ if (transaction) {
+ if (prevTransaction == NULL) {
+ /* Transaction at start of queue. Map second transaction to start of queue
+ * as long as more than one transactions. */
+ rmInst->transactionQueue = transaction->nextTransaction;
+ }
+ else {
+ /* Transaction in middle or end of queue. */
+ prevTransaction->nextTransaction = transaction->nextTransaction;
+ }
+ Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));
+ }
+ else {
+ retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST;
+ }
+ return (retVal);
+}
+
+/* FUNCTION PURPOSE: Routes a transaction for processing
+ ***********************************************************************
+ * DESCRIPTION: Routes a received transaction to the appropriate
+ * instance processing routine
+ */
+void rmProcessRouter (Rm_Inst *rmInst, Rm_Transaction *transaction)
+{
+ if (rmInst->instType == Rm_instType_CLIENT) {
+ clientProcess(rmInst, transaction);
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ cdProcess(rmInst, transaction);
+ }
+ else if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ serverProcess(rmInst, transaction);
+ }
+}
+
+/**********************************************************************
+ ********************** Application visible APIs **********************
+ **********************************************************************/
+
+/* FUNCTION PURPOSE: Display status of managed resources
+ ***********************************************************************
+ * DESCRIPTION: Prints the status (allocate/free status, as well as
+ * owners) for all resources managed by the RM
+ * instance network. Also, prints the NameServer name
+ * entries. The number of resource range owners is
+ * returned as well. This function is only available on
+ * Server and CD instances.
+ */
+int32_t Rm_resourceStatus(Rm_Handle rmHandle, int printResources)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ Rm_Allocator *allocator = NULL;
+ Rm_Owner *owners;
+ Rm_ResourceTree *treeRoot;
+ Rm_ResourceNode *treeNode;
+ int32_t totalResOwners = 0;
+ void *key;
+
+ RM_SS_INST_INV_ENTER_CS(key);
+ RM_SC_INST_INV_ENTER_CS(key);
+
+ if (rmInst->instType != Rm_instType_CLIENT) {
+ Rm_osalLog("Instance name: %s\n", rmInst->instName);
+ Rm_osalLog("Handle: 0x%08x\n", rmHandle);
+ if (rmInst->instType == Rm_instType_SERVER) {
+ Rm_osalLog("Type: Server\n");
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ Rm_osalLog("Type: Client Delegate\n");
+ }
+ else if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ Rm_osalLog("Type: Shared Server\n");
+ }
+ else if (rmInst->instType == Rm_instType_SHARED_CLIENT) {
+ Rm_osalLog("Type: Shared Client\n");
+ }
+
+ Rm_osalLog("\nResource Status:\n\n");
+ }
+
+ if (rmInst->instType == Rm_instType_SHARED_CLIENT) {
+ /* Transfer control to shared server instance */
+ rmInst = rmInst->u.sharedClient.sharedServerHandle;
+ }
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER) ||
+ (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) {
+ allocator = rmAllocatorGetAllocatorList(rmHandle);
+
+ if (!allocator) {
+ Rm_osalLog("No resources managed by instance at the moment\n\n");
+ }
+
+ while (allocator) {
+ RM_SS_OBJ_INV(allocator, Rm_Allocator);
+ if (printResources) {
+ Rm_osalLog("Resource: %s\n", allocator->resourceName);
+ }
+
+ treeRoot = allocator->allocatorRootEntry;
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ rmResourceTreeInv(treeRoot);
+ }
+ RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) {
+ if (printResources) {
+ if ((treeNode->base >= 65536) ||
+ ((treeNode->base + treeNode->length - 1) >= 65536)) {
+ /* Print in hex if number is very large */
+ Rm_osalLog(" 0x%08x - 0x%08x ", treeNode->base,
+ treeNode->base + treeNode->length - 1);
+ }
+ else {
+ Rm_osalLog(" %10d - %10d ", treeNode->base,
+ treeNode->base + treeNode->length - 1);
+ }
+ }
+
+ if (treeNode->allocationCount == 0) {
+ if (printResources) {
+ Rm_osalLog("FREE\n");
+ }
+ }
+ else {
+ owners = treeNode->ownerList;
+ while (owners) {
+ RM_SS_OBJ_INV(owners, Rm_Owner);
+ if (printResources) {
+ Rm_osalLog("%s ", owners->instNameNode->name);
+ }
+ totalResOwners++;
+ owners = owners->nextOwner;
+ }
+ if (printResources) {
+ Rm_osalLog("\n");
+ }
+ }
+ }
+ allocator = allocator->nextAllocator;
+ }
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ if (printResources) {
+ rmNameServerPrintObjects((Rm_Handle)rmInst);
+ }
+ }
+ }
+ else {
+ totalResOwners = RM_ERROR_INVALID_RES_STATUS_INSTANCE;
+ }
+
+ RM_SS_INST_WB_EXIT_CS(key);
+ return(totalResOwners);
+}
+
+/* FUNCTION PURPOSE: Display status of a RM instance
+ ***********************************************************************
+ * DESCRIPTION: Prints the current status of various RM instance
+ * properties such as the state of all transactions
+ * in the transaction queue and registered transports
+ */
+void Rm_instanceStatus(Rm_Handle rmHandle)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ Rm_Transport *transportList = NULL;
+ Rm_Transaction *transactionQ = NULL;
+ void *key;
+
+ RM_SS_INST_INV_ENTER_CS(key);
+ RM_SC_INST_INV_ENTER_CS(key);
+
+ Rm_osalLog("Instance name: %s\n", rmInst->instName);
+ Rm_osalLog("Handle: 0x%08x\n", rmHandle);
+ if (rmInst->instType == Rm_instType_SERVER) {
+ Rm_osalLog("Type: Server\n");
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ Rm_osalLog("Type: Client Delegate\n");
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT) {
+ Rm_osalLog("Type: Client\n");
+ }
+ else if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ Rm_osalLog("Type: Shared Server\n");
+ }
+ else if (rmInst->instType == Rm_instType_SHARED_CLIENT) {
+ Rm_osalLog("Type: Shared Client\n");
+
+ Rm_osalLog("\nShared Server Properties:\n");
+ /* Transfer to Shared Server instance to print out transport and
+ * transaction status */
+ rmInst = rmInst->u.sharedClient.sharedServerHandle;
+ Rm_osalLog("Instance name: %s\n", rmInst->instName);
+ Rm_osalLog("Handle: 0x%08x\n", rmHandle);
+ }
+
+ transportList = rmInst->transports;
+ if (transportList) {
+ Rm_osalLog("\nRegistered Transports:\n");
+ while (transportList) {
+ RM_SS_OBJ_INV(transportList, Rm_Transport);
+ if (transportList->remoteInstType == Rm_instType_SERVER) {
+ Rm_osalLog(" Remote instType: Server\n");
+ }
+ else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) {
+ Rm_osalLog(" Remote instType: Client Delegate\n");
+ }
+ else {
+ Rm_osalLog(" Remote instType: Client\n");
+ }
+ Rm_osalLog(" appTransportHandle: 0x%08x\n", transportList->appTransportHandle);
+ Rm_osalLog("\n");
+ transportList = transportList->nextTransport;
+ }
+ }
+
+ transactionQ = rmInst->transactionQueue;
+ if (transactionQ) {
+ Rm_osalLog("\nQueued Service Transactions:\n");
+ while (transactionQ) {
+ RM_SS_OBJ_INV(transactionQ, Rm_Transaction);
+ Rm_osalLog(" Service type: %d\n", transactionQ->type);
+ Rm_osalLog(" Service ID: %d\n", transactionQ->localId);
+ Rm_osalLog(" Service srcInstName %s\n", transactionQ->serviceSrcInstName);
+ Rm_osalLog(" Service state: %d\n", transactionQ->state);
+ Rm_osalLog(" Resource name: %s\n", transactionQ->resourceInfo.name);
+ Rm_osalLog(" Resource base: %d\n", transactionQ->resourceInfo.base);
+ Rm_osalLog(" Resource length: %d\n", transactionQ->resourceInfo.length);
+ Rm_osalLog(" Resource alignment: %d\n", transactionQ->resourceInfo.alignment);
+ Rm_osalLog(" Resource NS name: %s\n", transactionQ->resourceInfo.nameServerName);
+ Rm_osalLog("\n");
+ transactionQ = transactionQ->nextTransaction;
+ }
+ }
+ RM_SS_INST_WB_EXIT_CS(key);
+}
+
+/* FUNCTION PURPOSE: RM instance creation and initialization
+ ***********************************************************************
+ * DESCRIPTION: Returns a new RM instance created and initialized
+ * using the parameters provided via the initCfg
+ * structure.
+ */
+Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result)
+{
+ Rm_Inst *rmInst = NULL;
+ Rm_Inst *sharedServerInst = NULL;
+ uint32_t policySize;
+ void *globalResourceDtb = NULL;
+ void *linuxResourceDtb = NULL;
+ int addLinux = RM_FALSE;
+ void *key;
+
+ *result = RM_OK;
+
+ if ((initCfg->instName == NULL) ||
+ ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) {
+ *result = RM_ERROR_INVALID_INST_NAME;
+ goto errorExit;
+ }
+
+ if (initCfg->instType >= Rm_instType_LAST) {
+ *result = RM_ERROR_INVALID_INST_TYPE;
+ goto errorExit;
+ }
+
+ /* Create and initialize instance */
+ rmInst = Rm_osalMalloc(sizeof(*rmInst));
+ memset ((void *)rmInst, 0, sizeof(*rmInst));
+ rmInst->isLocked = RM_FALSE;
+ rmInst->registeredWithDelegateOrServer = RM_FALSE;
+ rmInst->transactionSeqNum = transactionInitSequenceNum();
+
+ rmInst->instType = initCfg->instType;
+ strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS);
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ if (!initCfg->instCfg.serverCfg.globalResourceList ||
+ !initCfg->instCfg.serverCfg.globalPolicy) {
+ *result = RM_ERROR_INVALID_SERVER_CONFIGURATION;
+ goto errorExit;
+ }
+
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ /* Shared Server makes copy of policy in shared memory for Shared Clients
+ * on other cores */
+ policySize = fdt_totalsize(initCfg->instCfg.serverCfg.globalPolicy);
+ /* Align policy size to cache boundary */
+ if (policySize % RM_MAX_CACHE_ALIGN) {
+ policySize += (RM_MAX_CACHE_ALIGN - (policySize % RM_MAX_CACHE_ALIGN));
+ }
+ rmInst->u.server.policySize = policySize;
+ rmInst->u.server.globalPolicy = Rm_osalMalloc(rmInst->u.server.policySize);
+ memcpy(rmInst->u.server.globalPolicy, initCfg->instCfg.serverCfg.globalPolicy, rmInst->u.server.policySize);
+ }
+ else {
+ rmInst->u.server.globalPolicy = initCfg->instCfg.serverCfg.globalPolicy;
+ }
+
+ if (initCfg->instCfg.serverCfg.linuxDtb) {
+ linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb;
+ addLinux = RM_TRUE;
+ }
+
+ /* Create valid instance list from policy. Must be done prior to parsing
+ * GRL so that Linux resources can be reserved correctly */
+ rmInst->u.server.globalValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result);
+ if (*result == RM_OK) {
+ *result = rmPolicyValidatePolicy((Rm_Handle)rmInst);
+ }
+
+ if (*result != RM_OK) {
+ if (rmInst->u.server.globalValidInstTree) {
+ rmPolicyFreeValidInstTree((Rm_Handle)rmInst);
+ }
+ goto errorExit;
+ }
+ else {
+ rmNameServerInit((Rm_Handle)rmInst);
+
+ globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList;
+
+ if ((*result = rmAllocatorInitializeResources((Rm_Handle) rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) {
+ *result = rmPolicyValidatePolicyResourceNames((Rm_Handle)rmInst);
+ }
+
+ if (*result != RM_OK) {
+ rmAllocatorDeleteResources((Rm_Handle)rmInst);
+ rmNameServerDelete((Rm_Handle)rmInst);
+ goto errorExit;
+ }
+ }
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ if (!initCfg->instCfg.cdCfg.cdPolicy) {
+ *result = RM_ERROR_INVALID_CD_CONFIGURATION;
+ goto errorExit;
+ }
+
+ rmInst->u.cd.cdPolicy = initCfg->instCfg.cdCfg.cdPolicy;
+ rmInst->u.cd.cdValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result);
+ if (*result == RM_OK) {
+ *result = rmPolicyValidatePolicy((Rm_Handle)rmInst);
+ }
+
+ if (*result != RM_OK) {
+ if (rmInst->u.cd.cdValidInstTree) {
+ rmPolicyFreeValidInstTree((Rm_Handle)rmInst);
+ }
+ goto errorExit;
+ }
+
+ rmInst->u.cd.allocators = NULL;
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT) {
+ if (initCfg->instCfg.clientCfg.staticPolicy) {
+ rmInst->u.client.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy;
+ rmInst->u.client.staticValidInstTree = rmPolicyCreateValidInstTree((Rm_Handle)rmInst, addLinux, result);
+ if (*result == RM_OK) {
+ *result = rmPolicyValidatePolicy((Rm_Handle)rmInst);
+ }
+
+ if (*result != RM_OK) {
+ if (rmInst->u.client.staticValidInstTree) {
+ rmPolicyFreeValidInstTree((Rm_Handle)rmInst);
+ }
+ goto errorExit;
+ }
+ }
+ }
+ else if (rmInst->instType == Rm_instType_SHARED_CLIENT) {
+ if (initCfg->instCfg.sharedClientCfg.sharedServerHandle) {
+ rmInst->u.sharedClient.sharedServerHandle = initCfg->instCfg.sharedClientCfg.sharedServerHandle;
+ /* Invalidate the Shared server instance structure on this core to get the latest
+ * instance data. */
+ key = Rm_osalCsEnter();
+ Rm_osalBeginMemAccess((void *)rmInst->u.sharedClient.sharedServerHandle, sizeof(Rm_Inst));
+ sharedServerInst = rmInst->u.sharedClient.sharedServerHandle;
+ if (sharedServerInst->instType != Rm_instType_SHARED_SERVER) {
+ *result = RM_ERROR_INVALID_SHARED_SERVER_HANDLE;
+ Rm_osalCsExit(key);
+ goto errorExit;
+ }
+ else {
+ /* Invalidate the policy */
+ Rm_osalBeginMemAccess((void *)sharedServerInst->u.server.globalPolicy,
+ sharedServerInst->u.server.policySize);
+ }
+ Rm_osalCsExit(key);
+ }
+ else {
+ *result = RM_ERROR_INVALID_SHARED_SERVER_HANDLE;
+ goto errorExit;
+ }
+ }
+
+ if (initCfg->instType == Rm_instType_SHARED_SERVER) {
+ /* Writeback the instance and policy for other cores */
+ Rm_osalEndMemAccess ((void *)rmInst, sizeof(Rm_Inst));
+ Rm_osalEndMemAccess ((void *)rmInst->u.server.globalPolicy, rmInst->u.server.policySize);
+ }
+ else if (rmInst->instType != Rm_instType_SHARED_CLIENT) {
+ /* Create the instance's task blocking mechanism */
+ rmInst->blockHandle = Rm_osalTaskBlockCreate();
+ }
+
+ return ((Rm_Handle) rmInst);
+errorExit:
+ if (rmInst) {
+ Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
+ }
+ return (NULL);
+}
+
+/* FUNCTION PURPOSE: Deletes an RM instance
+ ***********************************************************************
+ * DESCRIPTION: Frees all memory associated with an RM instance
+ * as long as all transports have been unregistered
+ * and the service handle has been closed
+ */
+int32_t Rm_delete(Rm_Handle rmHandle, int ignorePendingServices)
+{
+ Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
+ void *key;
+
+ key = Rm_osalCsEnter();
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ Rm_osalBeginMemAccess((void *)rmInst, sizeof(Rm_Inst));
+ }
+
+ if (rmInst->serviceHandle) {
+ return (RM_ERROR_CANT_DELETE_WITH_OPEN_SERV_HNDL);
+ }
+ else if (rmInst->transports) {
+ return (RM_ERROR_CANT_DELETE_WITH_REGD_TRANSPORT);
+ }
+ else if (rmInst->transactionQueue && !ignorePendingServices) {
+ return (RM_ERROR_CANT_DELETE_PENDING_TRANSACTIONS);
+ }
+
+ if ((rmInst->instType == Rm_instType_SERVER) ||
+ (rmInst->instType == Rm_instType_SHARED_SERVER)) {
+ rmAllocatorDeleteResources(rmHandle);
+ rmNameServerDelete(rmHandle);
+ rmInst->u.server.allocators = NULL;
+
+ if (rmInst->instType == Rm_instType_SHARED_SERVER) {
+ Rm_osalFree((void *)rmInst->u.server.globalPolicy, rmInst->u.server.policySize);
+ }
+ }
+ else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
+ rmAllocatorDeleteResources(rmHandle);
+ rmInst->u.cd.allocators = NULL;
+ }
+
+ if (rmInst->instType != Rm_instType_SHARED_CLIENT) {
+ /* Delete valid instance tree */
+ rmPolicyFreeValidInstTree(rmHandle);
+
+ /* Delete any transactions */
+ while(rmInst->transactionQueue) {
+ rmTransactionQueueDelete(rmInst, rmInst->transactionQueue->localId);
+ }
+
+ if (rmInst->instType != Rm_instType_SHARED_SERVER) {
+ /* Delete the instance's task blocking mechanism */
+ Rm_osalTaskBlockDelete(rmInst->blockHandle);
+ }
+ else {
+ Rm_osalEndMemAccess((void *)rmInst, sizeof(Rm_Inst));
+ }
+ }
+
+ Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
+
+ Rm_osalCsExit(key);
+ return (RM_OK);
+}
+
+/* FUNCTION PURPOSE: Returns RM version information
+ ***********************************************************************
+ */
+uint32_t Rm_getVersion(void)
+{
+ return RM_VERSION_ID;
+}
+
+/* FUNCTION PURPOSE: Returns RM version string
+ ***********************************************************************
+ */
+const char* Rm_getVersionStr(void)
+{
+ return rmVersionStr;
+}
+