/** * @file rm.c * * @brief * This is the Resource Manager source. * * \par * ============================================================================ * @n (C) Copyright 2012, 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 */ /* RM Types */ #include /* RM external includes */ #include #include #include #include /* RM internal includes */ #include #include #include #include #include /* RM LIBFDT includes */ #include /* AVL BBST includes */ #include /* RM OSAL layer */ #include /********************************************************************** ************************** Globals *********************************** **********************************************************************/ char rmIntegerAllocator[] = "integer"; char rmTreeAllocator[] = "tree"; extern char rmDtbStartingNode[]; /** @brief Global Variable which describes the RM Version Information */ const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__; /********************************************************************** ************** Red-Black BBST Tree Allocator Functions *************** **********************************************************************/ /* Prototype for function that allocates new tree nodes */ Rm_ResourceTreeNode *Rm_newResourceTreeNode(uint32_t resourceBase, uint32_t resourceLength, char *allocatedTo) { Rm_ResourceTreeNode *newNode = NULL; newNode = Rm_osalMalloc(sizeof(Rm_ResourceTreeNode)); /* Populate the RM relevant fields */ newNode->base = resourceBase; newNode->length = resourceLength; strcpy(newNode->allocatedTo, allocatedTo); return(newNode); } /* Prototype for function that frees new tree nodes */ void Rm_freeResourceTreeNode(Rm_ResourceTreeNode *treeNode) { /* Free the memory associated with the tree node. */ Rm_osalFree((void *)treeNode, sizeof(Rm_ResourceTreeNode)); } /* Prototype for tree node comparison function * element1 < element2 --> return < 0 * element1 = element2 --> return 0 * element1 > element2 --> return > 0 */ int Rm_ResourceTreeNodeCompare(Rm_ResourceTreeNode *element1, Rm_ResourceTreeNode *element2) { uint32_t element1End = element1->base + element1->length - 1; uint32_t element2End = element2->base + element2->length - 1; if (element1End < element2->base) { /* End of element1 range is less than the start of element2's range. Return a negative * value */ return (-1); } else if (element1->base > element2End) { /* Start of element1 range is after end of element2's range. Return a positive value */ return (1); } else { /* If neither of the latter conditions were satisfied there is some overlap between * element1 and element2. Return 0 since the application must handle this overlap. */ return (0); } } /* Generate the red-black tree manipulation functions */ RB_GENERATE(_Rm_ResourceTree, _Rm_ResourceTreeNode, linkage, Rm_ResourceTreeNodeCompare); /********************************************************************** ********************** Internal Functions **************************** **********************************************************************/ Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst) { Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue; Rm_Transaction *newTransaction = NULL; void *key; /* Lock access to the RM instance's transaction queue */ key = Rm_osalMtCsEnter(); /* Get memory for a new transaction from local memory */ newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction)); /* Return if the memory allocated for the transaction entry is NULL */ if (newTransaction == NULL) { /* Clear the transaction */ memset((void *)newTransaction, 0, sizeof(Rm_Transaction)); /* Create an ID for the new transaction. The ID will be used for two purposes: * 1) Matching responses from higher level RM agents to requests * 2) Provided to the component that requested the service so that it can match its * request with the response it receives via its callback function it provided */ newTransaction->localId = Rm_transactionGetSequenceNum(rmInst); /* New transaction's nextTransaction pointer will always be NULL */ newTransaction->nextTransaction = NULL; /* Check if there are any transactions in the transaction queue */ if (transactionQueue) { /* At least one transaction in the transaction queue. Add the new entry to the * end of the transaction queue */ while (transactionQueue->nextTransaction != NULL) { /* Traverse the list until arriving at the last transaction */ transactionQueue = transactionQueue->nextTransaction; } /* Add the new transaction to the end of the queue */ transactionQueue->nextTransaction = newTransaction; } else { /* The transaction queue does not currently exist. The new transaction is the * first transaction */ rmInst->transactionQueue = newTransaction; } } Rm_osalMtCsExit(key); return (newTransaction); } Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue; /* Make sure there is at least one transaction in the transaction queue */ if (transaction != NULL) { /* Find the transaction ID within the specified RM instance's transaction queue. * If the end of the transaction queue is reached without finding the transaction the * transaction pointer will be NULL */ while (transaction != NULL) { if (transaction->localId == transactionId) { /* Match: break out of loop and return the transaction */ break; } transaction = transaction->nextTransaction; } } return (transaction); } int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId) { Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue; Rm_Transaction *prevTransaction = NULL; int32_t retVal = RM_SERVICE_STATE_OKAY; void *key; /* Lock access to the RM instance's transaction queue */ key = Rm_osalMtCsEnter(); /* Find the transaction ID within the specified RM instance's transaction queue. */ while (transaction != NULL) { if (transaction->localId == transactionId) { /* Match: break out of loop and delete the transaction */ break; } prevTransaction = transaction; transaction = transaction->nextTransaction; } /* Traversed entire queue but did not find transaction */ if (transaction == NULL) { retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST; } else { /* Delete the transaction */ if ((prevTransaction == NULL) && transaction->nextTransaction) { /* Transaction to be deleted exists at start of transaction queue. Map second * transaction to be start of transaction queue as long as there are more than * one transactions. */ rmInst->transactionQueue = transaction->nextTransaction; } else { /* Transaction to be deleted is in the middle or at end of the queue. Adjust * adjacent transaction pointers. This covers the case where the transaction to be * removed is at the end of the queue. */ prevTransaction->nextTransaction = transaction->nextTransaction; } /* Free the memory associated with the transaction. */ Rm_osalFree((void *)transaction, sizeof(Rm_Transaction)); } Rm_osalMtCsExit(key); return (retVal); } uint32_t Rm_transactionInitSequenceNum(void) { /* Sequence number can never have a value of zero so that there are no conflicts * with transactions that have a remoteOriginatingId of zero */ return (1); } uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst) { uint32_t sequenceNum = 0; /* Get the next sequence number and then increment. If there's an overflow * assign the initial value instead of incrementing. */ if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum) { /* Overflow */ sequenceNum = rmInst->transactionSeqNum; rmInst->transactionSeqNum = Rm_transactionInitSequenceNum(); } else { sequenceNum = rmInst->transactionSeqNum++; } return (sequenceNum); } /* Function used to send RM response transactions to lower level agents */ void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_TransportNode *dstTransportNode = NULL; Rm_Packet *rmPkt = NULL; /* Find the transport for the RM instance that sent the request. */ dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName); /* Create a RM packet using the service information */ switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE: case Rm_service_RESOURCE_BLOCK_ALLOCATE: case Rm_service_RESOURCE_ALLOCATE_BY_NAME: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_BLOCK_FREE: case Rm_service_RESOURCE_FREE_BY_NAME: rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode, transaction); break; default: /* Invalid service type. Flag the error and return */ transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE; break; } if (transaction->state <= RM_SERVICE_ERROR_BASE) { /* Delete the transaction and return immediately because an error occurred * allocating the packet */ Rm_transactionQueueDelete(rmInst, transaction->localId); return; } /* Send the RM packet to the application transport */ if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL) { /* Negative value returned by transport send. An error occurred * in the transport while attempting to send the packet.*/ transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR; /* Clean up the packet */ if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt)) { /* Non-NULL value returned by transport packet free. Flag the * error */ transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR; } return; } /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD. CREATE * NEW TRANSACTION WITH DATA FROM ORIGINAL? THEN TRY TO SEND FAILED REQUEST BACK * TO REQUESTER??? KEEP RETRYING SEND OF RESPONSE??? */ /* Delete the transaction */ Rm_transactionQueueDelete(rmInst, transaction->localId); } Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName, Rm_AllocatorType type) { Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators; Rm_Allocator *newAllocator = NULL; void *key; /* Lock access to the RM instance's allocator list */ key = Rm_osalMtCsEnter(); /* Get memory for a new allocator from local memory */ newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator)); /* Return if the memory allocated for the allocator is NULL */ if (newAllocator != NULL) { /* Clear the allocator */ memset((void *)newAllocator, 0, sizeof(Rm_Allocator)); /* Populate the allocator */ newAllocator->type = type; strcpy(newAllocator->resourceName, resourceName); /* allocator's root entry will be created by the invoking function */ newAllocator->allocatorRootEntry = NULL; /* New allocator's nextAllocator pointer will always be NULL */ newAllocator->nextAllocator = NULL; /* Check if there are any allocators in the allocator list */ if (allocators) { /* At least one allocator in the allocator list. Add the new allocator to the * end of the allocator list */ while (allocators->nextAllocator != NULL) { /* Traverse the list until arriving at the last allocator */ allocators = allocators->nextAllocator; } /* Add the new allocator to the end of the list */ allocators->nextAllocator = newAllocator; } else { /* The allocator list does not currently exist. The new allocator is the * first allocator */ rmInst->allocators = newAllocator; } } Rm_osalMtCsExit(key); return (newAllocator); } Rm_Allocator *Rm_allocatorFind(Rm_Inst *rmInst, char *resourceName) { Rm_Allocator *allocator = (Rm_Allocator *)rmInst->allocators; /* Make sure there is at least one allocator in the allocator list */ if (allocator != NULL) { /* Find the resource name within the allocator list. If the end of the * allocator list is reached without finding the resource name the * allocator pointer will be NULL */ while (allocator != NULL) { if (strcmp(allocator->resourceName, resourceName) == 0) { /* Match: break out of loop and return the allocator */ break; } allocator = allocator->nextAllocator; } } return (allocator); } int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName) { Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators; Rm_Allocator *prevAllocator = NULL; int32_t retVal = RM_SERVICE_STATE_OKAY; void *key; /* Lock access to the RM instance's allocator list */ key = Rm_osalMtCsEnter(); /* Find the resource within the specified RM instance's allocator list. */ while (allocator != NULL) { if (strcmp(allocator->resourceName, resourceName) == 0) { /* Match: break out of loop and delete the transaction */ break; } prevAllocator = allocator; allocator = allocator->nextAllocator; } /* Traversed entire list but did not find allocator. */ if (allocator == NULL) { retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } else { /* Delete the allocator */ if ((prevAllocator == NULL) && allocator->nextAllocator) { /* Allocator to be deleted exists at start of allocator list. Map second * allocator to be start of allocator list as long as there are more than * one allocators. */ rmInst->allocators = allocator->nextAllocator; } else { /* Allocator to be deleted is in the middle or at end of the list. Adjust * adjacent allocator pointers. This covers the case where the allocator to be * removed is at the end of the list. */ prevAllocator->nextAllocator = allocator->nextAllocator; } /* Free the memory associated with the allocator. */ Rm_osalFree((void *)allocator, sizeof(Rm_Allocator)); } Rm_osalMtCsExit(key); return (retVal); } int32_t Rm_createIntegerAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range) { Rm_Allocator *allocator = NULL; Rm_ResourceRange *rangeBasePtr = range; Rm_IntegerAllocatorRootEntry *intRootEntry = NULL; uint16_t i, entryIndex; /* Create the new base integer allocator */ allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_INTEGER); /* Construct the integer allocator root entry */ intRootEntry = Rm_osalMalloc(sizeof(Rm_IntegerAllocatorRootEntry)); intRootEntry->numResourceElements = 0; /* Get the number of entries to allocate based on the lengths in the ranges */ while (range != NULL) { intRootEntry->numResourceElements += range->length; range = range->nextRange; } /* Initialize the entries using the range information */ if (intRootEntry->numResourceElements) { intRootEntry->resourceArrayBase = Rm_osalMalloc(sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements); memset((void *)intRootEntry->resourceArrayBase, 0, sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements); /* Reset the range pointer */ range = rangeBasePtr; entryIndex = 0; while (range != NULL) { /* Initialize each entry */ for (i = range->base; i < (range->base + range->length); i++, entryIndex++) { intRootEntry->resourceArrayBase[entryIndex].value = i; /* Initialize the allocatedTo field to the NOT_ALLOCATED string */ strcpy(intRootEntry->resourceArrayBase[entryIndex].allocatedTo, RM_NOT_ALLOCATED_STRING); } range = range->nextRange; } allocator->allocatorRootEntry = intRootEntry; } else { /* No resource entries were created. Free the memory associated with the * allocator and the root entry */ Rm_osalFree((void *)intRootEntry, sizeof(Rm_IntegerAllocatorRootEntry)); Rm_allocatorDelete(rmInst, allocator->resourceName); } return(0); /* TODO: FIX THIS RETURN */ } int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range) { Rm_Allocator *allocator = NULL; Rm_ResourceTree *treeRootEntry = NULL; Rm_ResourceTreeNode *treeNode = NULL; Rm_ResourceTreeNode *collidingNode = NULL; /* Create the new base integer allocator */ allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_TREE); /* Create the tree root entry and initialize it */ treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree)); RB_INIT(treeRootEntry); /* Create a node in the tree for resource range and insert them into the tree. */ while (range != NULL) { Rm_newResourceTreeNode(range->base, range->length, RM_NOT_ALLOCATED_STRING); /* Insert the node into the tree */ collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode); if (collidingNode) { Rm_ResourceTreeNode *nextNode = NULL; /* Node that was inserted colliding with an existing node. Clean up the tree * that's been allocated thus far and return an error since there should be no * collisions */ for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) { nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode); RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode); Rm_freeResourceTreeNode(treeNode); } /* Delete the tree root entry and the allocator */ Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree)); Rm_allocatorDelete(rmInst, allocator->resourceName); return (-24); /* TODO FIX RETURN */ } range = range->nextRange; } /* Assign the tree's root to the allocator */ allocator->allocatorRootEntry = treeRootEntry; /* Print the base values as a test */ RB_FOREACH(treeNode, _Rm_ResourceTree, (Rm_ResourceTree *) allocator->allocatorRootEntry) { Rm_osalLog("Tree node base: %d length: %d and allocated to: %s\n", treeNode->base, treeNode->length, treeNode->allocatedTo); } return(0); /* TODO: FIX THIS RETURN */ } int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceProperties *resourceProperties) { char *allocatorType = NULL; Rm_ResourceRange *range = NULL; Rm_ResourceRange *rangeBasePtr = NULL; Rm_NsAssignment *nsAssignments = NULL; Rm_NsAssignment *nsAssignmentBasePtr = NULL; int32_t retVal = RM_DTB_UTIL_RESULT_OKAY; /* TODO: NEED CHECKS FOR VALIDITY OF ALL THE resourceProperties FIELDS */ /* Extract the resource properties from the DTB */ allocatorType = Rm_resourceExtractResourceAllocator(resourceProperties->allocatorData, resourceProperties->allocatorLen); range = rangeBasePtr = Rm_resourceExtractResourceRange(resourceProperties->rangeData, resourceProperties->rangeLen); /* Create an allocator based on the allocator type specified */ if (strcmp(allocatorType, &rmIntegerAllocator[0]) == 0) { /* Create an integer allocator using the resource properties */ retVal = Rm_createIntegerAllocator(rmInst, resourceName, range); } else if (strcmp(allocatorType, &rmTreeAllocator[0]) == 0) { /* Create a tree allocator using the resource properties */ retVal = Rm_createTreeAllocator(rmInst, resourceName, range); } else { /* Allocator type not recognized. Free the resource properties and return */ retVal = -21; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } if (retVal >= RM_DTB_UTIL_RESULT_OKAY) { /* Create entries in the NameServer if any NameServer assignments were specified */ if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) { nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, resourceProperties->nsAssignLen); /* Cycle through the list of assignments and add them to the NameServer */ nsAssignmentBasePtr = nsAssignments; while (nsAssignments) { /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */ Rm_nsAddObject(rmInst, nsAssignments->nsName, nsAssignments->resourceValue); nsAssignments = nsAssignments->nextNsAssignment; } /* Free the memory allocated for the NameServer assignments */ Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr); } } /* Free the memory allocated for the resource properties */ Rm_resourceFreeResourceAllocator(allocatorType); Rm_resourceFreeResourceRange(rangeBasePtr); return(retVal); } int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo) { int32_t propertyLen; const char *propertyName; const void *propertyData; Rm_ResourcePropType propertyType; int32_t retVal = RM_DTB_UTIL_RESULT_OKAY; /* Get the property data and store it in the corresponding propertyInfo field */ propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen); if (propertyData) { propertyType = Rm_resourceGetPropertyType(propertyName); if (propertyType == Rm_resourcePropType_RESOURCE_ALLOCATOR) { if (propertyInfo->allocatorData || propertyInfo->allocatorLen) { /* The allocator fields have already been populated. Return an error. * The resource list has specified a property field more than once * for a resource node */ retVal = -17; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } else { propertyInfo->allocatorData = propertyData; propertyInfo->allocatorLen = propertyLen; } } else if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) { if (propertyInfo->rangeData || propertyInfo->rangeLen) { /* The range fields have already been populated. Return an error. * The resource list has specified a property field more than once * for a resource node */ retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } else { propertyInfo->rangeData = propertyData; propertyInfo->rangeLen = propertyLen; } } else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) { if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen) { /* The nsAssign fields have already been populated. Return an error. * The resource list has specified a property field more than once * for a resource node */ retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } else { propertyInfo->nsAssignData = propertyData; propertyInfo->nsAssignLen = propertyLen; } } else { retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } } else { retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */ } /* Don't get anymore properties if error occurred */ if (retVal == RM_DTB_UTIL_RESULT_OKAY) { offset = fdt_next_property_offset(globalResourceDtb, offset); if (offset >= 0) { retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo); } else if (offset != -FDT_ERR_NOTFOUND) { /* Error was returned by LIBFDT when parsing the properties */ retVal = offset; } } return (retVal); } int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth) { const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL); Rm_ResourceProperties resourceProperties; int32_t error = RM_DTB_UTIL_RESULT_OKAY; int32_t offset; /* Initialize the resource properties structure */ memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties)); /* Ignore properties of the base node */ if (strcmp(resourceName, rmDtbStartingNode)) { /* Get the properties for the resource node if any exist */ offset = fdt_first_property_offset(globalResourceDtb, nodeOffset); if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) { /* Since at least one property exists attempt to parse the property nodes and * use them to create and initialize a resource allocator */ error = Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties); if (error < -FDT_ERR_NOTFOUND) { return (error); } /* Initialize an allocator with the resource properties if no error was returned */ Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties); } else if (offset != -FDT_ERR_NOTFOUND) { /* Error was returned by LIBFDT when parsing the properties */ return (offset); } } /* Get the next resource node */ offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth); /* Check the offset and depth of the next node to make sure the current node * wasn't the last node in the Resource List. A depth less than the depth set * at the start of the recursion will signal the end of the resource list */ if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH)) { error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth); if (error < -FDT_ERR_NOTFOUND) { return (error); } } else if (offset != -FDT_ERR_NOTFOUND) { /* Error was returned by LIBFDT when parsing the nodes */ return (offset); } return (RM_DTB_UTIL_RESULT_OKAY); } /* Called when an allocate request is made but the base is unspecified. RM must preallocate * resources which then must be checked against the RM policy for the instance. If the * policy does not agree another resource(s) must be preallocated and tested against the * policy. Policy will provide initialize the preallocate with the base that it allows * for the rm instance for the specified resource. */ int32_t Rm_integerPreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry; Rm_IntegerEntry *resourceArray = root->resourceArrayBase; uint16_t index, i; bool resourcesValidated; int32_t retVal = RM_SERVICE_PROCESSING; /* Find the specified resource base within the allocator */ for (index = 0; index < root->numResourceElements; index++) { if (resourceArray[index].value == opInfo->resourceInfo->base) { /* Found the resource base in the allocator. Break from the loop */ break; } } /* Only execute the allocate operation if the resource base was found in the allocator * and the base+length does not exceed the number of entries in the allocator */ if ((index + opInfo->resourceInfo->length) <= root->numResourceElements) { /* Search for a contiguous block of unallocated resources of length "length" * and with the alignment specified */ while ((index + opInfo->resourceInfo->length) <= root->numResourceElements) { resourcesValidated = FALSE; /* Does the resource base value satisfy the alignment? */ if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0) { /* Check to see all the resource values in the requested range are free */ resourcesValidated = TRUE; for (i = index; i < opInfo->resourceInfo->length; i++) { if (strcmp(resourceArray[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0) { /* A resource within the range was already allocated. Update the * index to the resource after the allocated resource and continue * looking. */ index = i + 1; resourcesValidated = FALSE; /* Break out of the for loop */ break; } } if (resourcesValidated) { /* Found a set of resources that satisfies the request requirements. Return * the results to be tested against the policy. If the policy approves the * resources will be allocated via the Rm_integerAllocate API. */ opInfo->resourceInfo->base = resourceArray[index].value; /* Break out of the while loop */ break; } } else { /* Jump to the next resource value that satisfies the alignment */ for (; index < root->numResourceElements; index++) { if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0) { /* Found the next resource value that satisfies the alignment */ break; } } } } if (!resourcesValidated) { retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } } else { retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } return(retVal); } /* Assumes resource range for allocation has already been approved by the policy */ int32_t Rm_integerAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry; uint16_t resourceIndex, i, j; bool resourcesValidated = TRUE; int32_t retVal; /* Find the specified resource base within the allocator */ for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++) { if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base) { /* Found the resource base in the allocator. Break from the loop */ break; } } /* Only execute the allocate operation if the resource base was found in the allocator * and the base+length does not exceed the number of entries in the allocator */ if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements) { /* Verify all resource values from base to base+length exist in the allocator and * are not allocated to another instance. */ for (i = resourceIndex, j = opInfo->resourceInfo->base; i < (resourceIndex + opInfo->resourceInfo->length); i++, j++) { if (root->resourceArrayBase[i].value != j) { /* A value in the range did not match. */ retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; resourcesValidated = FALSE; break; } else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0) { /* A value in the range is already allocated. */ retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED; resourcesValidated = FALSE; break; } } if (resourcesValidated) { /* Allocate all resources from base to base+length */ for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++) { strcpy(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName); } retVal = RM_SERVICE_APPROVED_AND_COMPLETED; } } else { retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } return(retVal); } /* Assumes resource range for free has already been approved by the policy */ int32_t Rm_integerFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry; uint16_t resourceIndex, i, j; bool resourcesValidated = TRUE; int32_t retVal; /* Find the specified resource base within the allocator */ for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++) { if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base) { /* Found the resource base in the allocator. Break from the loop */ break; } } /* Only execute the free operation if the resource base was found in the allocator * and the base+length does not exceed the number of entries in the allocator */ if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements) { /* Verify all resource values from base to base+length exist in the allocator, * were not already free and were allocated to the instance that is the source * of the free request. */ for (i = resourceIndex, j = opInfo->resourceInfo->base; i < (resourceIndex + opInfo->resourceInfo->length); i++, j++) { if (root->resourceArrayBase[i].value != j) { /* A value in the range did not match. */ retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; resourcesValidated = FALSE; break; } else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) == 0) { /* A value in the range is already free. */ retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE; resourcesValidated = FALSE; break; } else if (strcmp(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName) != 0) { /* A value in the range was not allocated to the source of * the free request */ retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE; resourcesValidated = FALSE; break; } } if (resourcesValidated) { /* Free all resources from base to base+length */ for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++) { strcpy(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING); } retVal = RM_SERVICE_APPROVED_AND_COMPLETED; } } else { retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } return(retVal); } /* Called when an allocate request is made but the base is unspecified. RM must preallocate * resources which then must be checked against the RM policy for the instance. If the * policy does not agree another resource(s) must be preallocated and tested against the * policy */ int32_t Rm_treePreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { } /* Assume the policy has already approved of the allocation */ int32_t Rm_treeAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceTreeNode findNode; Rm_ResourceTreeNode *matchingNode = NULL; Rm_ResourceTreeNode *leftNode = NULL; Rm_ResourceTreeNode *rightNode = NULL; uint32_t findEnd, matchingEnd; int32_t retVal; /* Find the tree node that contains the specified resource range */ findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode); if (matchingNode != NULL) { findEnd = findNode.base + findNode.length - 1; matchingEnd = matchingNode->base + matchingNode->length - 1; /* Does the request range fit within the matching nodes entire range? */ if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) { /* Handle requested resource range that is isolated to a single node * * * base0 base0+length0-1 * |<---------------length0------------------->| => existing node * |<---------length1---------->| => requested resources * base1 base1+length1-1 */ if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0) { /* Resources are available - split up the node into potentially * three new nodes: * left node - free resources to left of newly allocated resources * middle node - newly allocated resources that satisfy the request * right node - free resources to the right of newly allocated resources * * There also may be combine possibilities to the left and right of the * matching node. Need to extract those as well to check */ leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); /* Remove the matching node from the tree and the nodes to the left and * right of the matching node. Removing from tree will not * wipe any of the base+length data in the node. Can reuse since they won't * be freed */ RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); if (leftNode) { RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } if (rightNode) { RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* Create the left node if needed. If the bases are equal the matchingNode can * be reused as the left bound of the range. */ if (findNode.base > matchingNode->base) { /* Can the left node be combined with the node to the left of the matching * node */ if (leftNode && (strcmp(leftNode->allocatedTo, opInfo->srcInstName) == 0)) { /* Combine the left node and what's leftover on the left side of the * matchingNode range after the allocation */ leftNode->length += (findNode.base - matchingNode->base); } else { /* Reinsert left node and create a new node to left of range to be allocated */ if (leftNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } /* New left node attributes: * base: base of the matching node * length: base of requested resources - base of matching node */ leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base, RM_NOT_ALLOCATED_STRING); } } /* Create the right node if needed. If the end ranges are equal the matchingNode * can be reused as the right bound of the range */ if (findEnd < matchingEnd) { /* Can the right node be combined with the node to the right of the matching * node */ if (rightNode && (strcmp(rightNode->allocatedTo, opInfo->srcInstName) == 0)) { /* Combine the right node and what's leftover on the right side of the * matchingNode range after the allocation */ rightNode->base = findNode.base + findNode.length; rightNode->length += (matchingEnd - findEnd); } else { /* Reinsert right node and create a new node to right of range to be allocated */ if (rightNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* New right node attributes: * base: base of the requested resources + length of requested resources * length: right bound of matching node - right bound of request resources */ rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length, matchingEnd - findEnd, RM_NOT_ALLOCATED_STRING); } } /* Reinsert the left node into the tree if it was modified or created. */ if (leftNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } /* Reinsert the right node into the tree if it was modified or created. */ if (rightNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* Base and length of matching node becomes the base and length of the requested resources */ matchingNode->base = findNode.base; matchingNode->length = findNode.length; /* Reserve the resources and insert them into the tree */ strcpy(matchingNode->allocatedTo, opInfo->srcInstName); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); retVal = RM_SERVICE_APPROVED_AND_COMPLETED; } else { /* A resource superset containing the requested range has * already been allocated. */ retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED; } } else { /* Request ranges that span multiple nodes signify resources are * not available because nodes are combined into larger contiguous ranges * on resource free operations. */ retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED; } } else { /* The requested resources could not be found in the allocator */ retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } return(retVal); } /* Assume policy has already approved of the free */ int32_t Rm_treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo) { Rm_ResourceTreeNode findNode; Rm_ResourceTreeNode *matchingNode = NULL; Rm_ResourceTreeNode *leftNode = NULL; Rm_ResourceTreeNode *rightNode = NULL; bool combineLeft = FALSE; bool combineRight = FALSE; uint32_t findEnd, matchingEnd; int32_t retVal; /* Find the tree node that contains the specified resource range */ findNode.base = opInfo->resourceInfo->base; findNode.length = opInfo->resourceInfo->length; matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode); if (matchingNode != NULL) { findEnd = findNode.base + findNode.length - 1; matchingEnd = matchingNode->base + matchingNode->length - 1; /* Does the free range fit within the matching nodes entire range? It should * either be the entire range or a subset set of the found range. (the latter * satisfies the case where an entity allocated a contiguous block of resources * then attempts to free a contiguous subset of the allocated block. */ if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) { if (strcmp(matchingNode->allocatedTo, opInfo->srcInstName) == 0) { /* Resources can be freed */ if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) { /* Case 1: free range equals allocated matched node exactly. Attempt to combine * the range to be freed with the resource nodes to the left and * right of the free range. * * |<--left node-->||<---matched node--->||<--right node-->| * |<---free request--->| */ leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); /* Remove the matching node from the tree and the nodes to the left and * right of the matching node. Removing from tree will not * wipe any of the base+length data in the node. Can reuse since they won't * be freed */ RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); if (leftNode) { RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } if (rightNode) { RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* See if the left or right or both nodes can be combined with the matching * node that will be freed. */ if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)) { /* Combine the left node and the matching node */ combineLeft = TRUE; } if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)) { /* Combine the right node and the matching node */ combineRight = TRUE; } /* Perform any combines, insert the leftover nodes, and free any memory associated * with any nodes that weren't reinserted into the tree */ if (combineLeft && combineRight) { /* Combine all three nodes into the matchingNode. Insert the freed cumulative * matching node and delete the memory for the old left and right nodes */ matchingNode->base = leftNode->base; matchingNode->length = leftNode->length + matchingNode->length + rightNode->length; Rm_freeResourceTreeNode(leftNode); Rm_freeResourceTreeNode(rightNode); } else if (combineLeft) { /* Combine the left and matching nodes. Reinsert the right. */ matchingNode->base = leftNode->base; matchingNode->length += leftNode->length; Rm_freeResourceTreeNode(leftNode); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } else if (combineRight) { /* Combine the right and matching nodes. Reinsert the left. */ matchingNode->length += rightNode->length; Rm_freeResourceTreeNode(rightNode); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } else { /* Combine cannot be performed. Reinsert the left and right nodes then * free the matching node and reinsert it */ RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* No matter the combine route taken the matching node will always be declared * free and reinserted */ strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); } else { /* Case 2: free range is less than range in matched node. Need to split * the matched node into three nodes. * * |<----------matched node---------->| * |<---free request--->| */ /* Create the left node if needed. If the bases are equal the matchingNode can * be reused as the left bound of the range. */ if (findNode.base > matchingNode->base) { /* New left node attributes: * base: base of the matching node * length: base of requested resources - base of matching node */ leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base, matchingNode->allocatedTo); } /* Create the right node if needed. If the end ranges are equal the matchingNode * can be reused as the right bound of the range */ if (findEnd < matchingEnd) { /* New right node attributes: * base: base of the requested resources + length of requested resources * length: right bound of matching node - right bound of request resources */ rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length, matchingEnd - findEnd, matchingNode->allocatedTo); } /* Insert the left node into the tree if it was created. */ if (leftNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode); } /* Insert the right node into the tree if it was created. */ if (rightNode) { RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); } /* Base and length of matching node becomes the base and length of the freed resources */ matchingNode->base = findNode.base; matchingNode->length = findNode.length; /* Free the resources and insert them into the tree */ strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING); RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); } retVal = RM_SERVICE_APPROVED_AND_COMPLETED; } else { /* The matching allocated range to be freed was allocated to a different instance. */ retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE; } } else { /* Free resource range crosses over node boundaries. This signifies a * free of both allocated and unallocated resources since nodes are combined * on allocate and free operations if possible. */ retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE; } } else { /* The free resources could not be found in the allocator */ retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST; } return(retVal); } int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo) { Rm_Allocator *allocator = NULL; int32_t retVal; void *key; /* Lock access to the RM instance's transaction queue */ key = Rm_osalMtCsEnter(); /* Get the specified resource's allocator */ allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name); if (allocator) { /* Call the allocator's type-based allocation function */ if(allocator->type == Rm_allocatorType_INTEGER) { if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) { retVal = Rm_integerPreAllocate(allocator, opInfo); } else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) { retVal = Rm_integerAllocate(allocator, opInfo); } else if (opInfo->operation == Rm_allocatorOp_FREE) { retVal = Rm_integerFree(allocator, opInfo); } } else if (allocator->type == Rm_allocatorType_TREE) { if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) { retVal = Rm_treePreAllocate(allocator, opInfo); } else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) { retVal = Rm_treeAllocate(allocator, opInfo); } else if (opInfo->operation == Rm_allocatorOp_FREE) { retVal = Rm_treeFree(allocator, opInfo); } } } else { /* Allocator could not be found for resource */ retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST; } Rm_osalMtCsExit(key); return(retVal); } void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction) { if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { #if 0 if (resourceBase is unspecified) { while (policy does not approve) { Rm_policy check get allowed base as starting point for prealloc preallocate resource based on the range and alignment Rm_policy...check } } else { /* Check local policy to see if the request can be satisfied with the * resources stored locally */ Rm_policy...API() if (policy check approves the resource) { /* call the allocator to allocate the resource */ if (allocator returns resource) { /* Populate the transaction with the allocated resources and the result */ transaction->state = approve reason; return ... } else { /* allocator ran out of resources, need to contact Server for more * resources */ Rm_resourcePoolModRequest(...); } } else if (policy check denies resource) { /* Policy check denied resource. */ transaction->state= deny reason; return ... } else if (policy check says forward to Server for validation) { /* Forward the transaction to the Server */ Rm_transactionForwarder(rmInst, transaction); } } #endif } else if (rmInst->instType == Rm_instType_SERVER) { #if 0 if (resourceBase is unspecified) { while (policy does not approve) { Rm_policy check get allowed base as starting point for prealloc preallocate resource based on the range and alignment Rm_policy...check } } else { /* Check global policy to see if resource can be allocated. return result * no matter what */ Rm_policy...API() if (policy approves) { /* call allocator to allocate resource */ } transaction->state = approve or deny reason; transaction->resourceInfo.base = ...; transaction->resourceInfo.length = ...; /* If source instance name does not match the current instance * name the allocation request came from a Client. The result * must be sent back to the Client */ if (strcmp(transaction->sourceInstName, rmInst->name)) { /* Names don't match. Send the transaction back to the Client */ Rm_transactionResponder(rmInst, transaction); } else { /* Resource allocation request originated locally on the active * instance. Send the response via the service responder. */ Rm_serviceResponder(rmInst, transaction); } } #endif } } void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction) { if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { #if 0 /* Check local policy to see if the request can be satisfied with the * resources stored locally */ Rm_policy...API() if (policy check approves the free) { /* call the allocator to free the resource */ /* Run a resource pool check to see if the free combined a resource block * that can be returned to the server */ if (resource block has been combined) { /* allocator ran out of resources, need to contact Server for more * resources */ Rm_resourcePoolModRequest(free pool block to server...); } else { /* Populate the receipt with the freed resources and the result */ transaction->state = approve reason; return ... } } else if (policy check denies resource free) { /* Policy check denied resource. */ transaction->state = deny reason; return ... } else if (policy check says forward to Server for validation) { /* Forward the transaction to the Server */ Rm_transactionForwarder(rmInst, transaction); } #endif } else if (rmInst->instType == Rm_instType_SERVER) { #if 0 /* Check global policy to see if resource can be freed. return result * no matter what */ Rm_policy...API() if (policy approves) { /* call allocator to free resources */ } transaction->state = approve or deny reason; transaction->resourceInfo.base = ...; transaction->resourceInfo.length = ...; /* If source instance name does not match the current instance * name the allocation request came from a client. The result * must be sent back to the Client */ if (strcmp(transaction->sourceInstName, rmInst->name)) { /* Names don't match. Send the transaction back to the Client Delegate or Client */ Rm_transactionResponder(rmInst, transaction); } else { /* Resource allocation request originated locally on the active * instance. Send the response via the service responder. */ Rm_serviceResponder(rmInst, transaction); } #endif } } /* Function used to forward RM transactions to higher level agents */ void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction) { Rm_TransportNode *dstTransportNode = NULL; Rm_Packet *rmPkt = NULL; /* Make sure the RM instance has a transport registered with a higher level agent */ if (rmInst->registeredWithDelegateOrServer == false) { transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER; return; } /* Find the transport for the higher level agent. Check for a connection to a Client Delegate * or a Server. Clients will be connected to either a Client Delegate or a Server. Client * Delegates will be connected to a Server. */ if (rmInst->instType == Rm_instType_CLIENT) { dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE); } else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) { dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER); } /* Create a RM packet using the service information */ switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE: case Rm_service_RESOURCE_BLOCK_ALLOCATE: case Rm_service_RESOURCE_ALLOCATE_BY_NAME: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_BLOCK_FREE: case Rm_service_RESOURCE_FREE_BY_NAME: rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, transaction); break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode, transaction); break; default: /* Invalid service type. Flag the error and return */ transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE; break; } if (transaction->state <= RM_SERVICE_ERROR_BASE) { /* Return immediately because an error occurred allocating the packet */ return; } /* Send the RM packet to the application transport */ if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL) { /* Negative value returned by transport send. An error occurred * in the transport while attempting to send the packet.*/ transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR; /* Clean up the packet */ if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt)) { /* Non-NULL value returned by transport packet free. Flag the * error */ transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR; } return; } /* Transaction is not deleted because it is awaiting a response from the higher level * RM instance */ } void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction) { /* Handle auto-forwarded transactions. These transactions include: * - All request transactions received on Clients are forwarded to the Client Delegate * - NameServer requests received on the Client Delegate are forwarded to the Server */ if ((rmInst->instType == Rm_instType_CLIENT) || ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) && (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) || (transaction->type == Rm_service_RESOURCE_UNMAP_NAME))) { /* Check if the transaction is a transaction that received a response to its * request. */ if (transaction->state != RM_SERVICE_PROCESSING) { /* A transaction has received a response. Send the response to either the * transaction or service responder based on the source instance */ if (strcmp(transaction->sourceInstName, rmInst->name)) { /* Transaction originated from another instance. Use the * transaction responder to send the result to the source instance. This * is not possible on RM Clients since they can't forward RM services */ Rm_transactionResponder(rmInst, transaction); } else { /* Transaction originated on this instance. Send to the * service responder */ Rm_serviceResponder(rmInst, transaction); } } else { /* This is a new transaction that must be forwarded to a higher level RM instance. */ Rm_transactionForwarder(rmInst, transaction); } } else { /* Client Delegate and Server transaction processors. */ switch (transaction->type) { case Rm_service_RESOURCE_ALLOCATE: case Rm_service_RESOURCE_BLOCK_ALLOCATE: case Rm_service_RESOURCE_ALLOCATE_BY_NAME: case Rm_service_RESOURCE_FREE: case Rm_service_RESOURCE_BLOCK_FREE: case Rm_service_RESOURCE_FREE_BY_NAME: /* Check if the transaction is fulfilled request */ if (transaction->state != RM_SERVICE_PROCESSING) { /* If source instance name does not match the current instance * name the allocation request came from a client. The result * must be sent back to the Client */ if (strcmp(transaction->sourceInstName, rmInst->name)) { Rm_transactionResponder(rmInst, transaction); } else { /* Resource allocation request originated locally. Send the response * via the service responder. */ Rm_serviceResponder(rmInst, transaction); } } else { /* This is a new transaction request originating from an RM instance with fewer * allocate/free privileges. Run the allocation or free handler to see if the resource * request can be handled locally or if it needs to be forwarded to a higher level * agent */ if ((transaction->type == Rm_service_RESOURCE_ALLOCATE) || (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) || (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME)) { Rm_allocationHandler(rmInst, transaction); } else { Rm_freeHandler(rmInst, transaction); } } break; case Rm_service_RESOURCE_MAP_TO_NAME: case Rm_service_RESOURCE_UNMAP_NAME: /* Server is the only RM instance capable of adding NameServer objects */ if (rmInst->instType == Rm_instType_SERVER) { if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) { /* Create a new NameServer object with the request transaction information. * Transaction will contain the state result of the NameServer addition. */ if (Rm_nsAddObject(rmInst, transaction->resourceInfo.nsName, transaction->resourceInfo.base) == RM_NS_ACTION_APPROVED) { transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED; } else { /* TEMP: UPDATE THIS STATE VALUE */ transaction->state = RM_SERVICE_DENIED_BEGIN; } } else { /* Delete an existing NameServer object with the request transaction information * Transaction will contain the state result of the NameServer addition. */ if (Rm_nsDeleteObject(rmInst, transaction->resourceInfo.nsName) == RM_NS_ACTION_APPROVED) { transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED; } else { /* TEMP: UPDATE THIS STATE VALUE */ transaction->state = RM_SERVICE_DENIED_BEGIN; } } /* If source instance name does not match the local instance * name the NameServer request came from a Client or Client Delegate. The * result must be sent back to the Client or Client Delegate. Just return if it does * match since the NameServer transaction result can be returned immediately by the * Rm_serviceHandler. */ if (strcmp(transaction->sourceInstName, rmInst->name)) { Rm_transactionResponder(rmInst, transaction); } } else { transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE; } break; } } } int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb) { int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET; int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH; int32_t result = RM_DTB_UTIL_RESULT_OKAY; /* Recursively parse the Global Resource List, creating an allocator for * each resource as specified in the node */ result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth); return(result); } int32_t Rm_reserveLinuxResources(Rm_Inst *rmInst, void *linuxResourceDtb) { return(0); } /********************************************************************** ********************** Application visible APIs ********************** **********************************************************************/ Rm_Handle Rm_init(Rm_InitCfg *initCfg) { Rm_Inst *rmInst; void *globalResourceDtb = NULL; void *linuxResourceDtb = NULL; /* Instance creation checks. Add one to strlen calculation for null character */ if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS) { /* Failure: Instance name is too big */ return (NULL); } /* Get memory for RM instance from local memory */ rmInst = Rm_osalMalloc (sizeof(Rm_Inst)); /* Populate instance based on input parameters */ strcpy (&rmInst->name[0], initCfg->instName); rmInst->instType = initCfg->instType; rmInst->registeredWithDelegateOrServer = false; rmInst->policyDtb = NULL; /* Initialize the transport routing map linked list pointer to NULL. The linked list * nodes will be created when the application registers transports */ rmInst->routeMap = NULL; /* Initialize the allocators linked list pointer to NULL. The linked list nodes will * be created on the Server instance when the application reads in the resource list. * Nodes will also be created on Client Delegates when blocks of resources are requested * for allocation to clients. */ rmInst->allocators = NULL; /* Initialize the transaction queue elements. */ rmInst->transactionSeqNum = Rm_transactionInitSequenceNum(); rmInst->transactionQueue= NULL; /* RM Server specific actions */ if (rmInst->instType == Rm_instType_SERVER) { /* Open the ResourceList file and provide it to the resource initializer. */ if (initCfg->globalResourceList) { globalResourceDtb = initCfg->globalResourceList; fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb)); Rm_initializeAllocators(rmInst, globalResourceDtb); } /* Parse the Linux DTB for the resources reserved by the Linux kernel. These resources * will be marked as used in the resource allocators. */ if (initCfg->linuxDtb) { linuxResourceDtb = initCfg->linuxDtb; fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb)); Rm_reserveLinuxResources(rmInst, linuxResourceDtb); } } /* Instance startup policies are only used for Servers and Client Delegates */ if (rmInst->instType != Rm_instType_CLIENT) { /* Open the instance's policy and store it */ if (initCfg->startupPolicy) { rmInst->policyDtb = initCfg->startupPolicy; fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb)); } /* Store policy via policy APIs ... */ } /* Return the RM Handle */ return ((Rm_Handle) rmInst); } uint32_t Rm_getVersion (void) { return RM_VERSION_ID; } const char* Rm_getVersionStr (void) { return rmVersionStr; } /** @} */