/** * @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 includes */ #include #include #include #include #include /* RM OSAL layer */ #include /********************************************************************** ************************** Globals *********************************** **********************************************************************/ /* Place QMSS PDSP permissions array */ #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm"); #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128) Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)]; /** @brief Global Variable which describes the RM Version Information */ const char rmVersionStr[] = RM_VERSION_STR ":" __DATE__ ":" __TIME__; /********************************************************************** ********************** Internal Functions ********************************* **********************************************************************/ Rm_TransactionResult rmTransactionForwarder (void *rmHandle, Rm_Transaction *transInfo, Rm_TransactionReceipt *transReceipt) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_TransRouteMapNode *routeMap = (Rm_TransRouteMapNode *) rmInst->routeMap; Rm_ProtocolPkt *rmPkt = NULL; /* Error if no transports have been registered and a service has been requested that * must be forwarded to another RM agent */ if (routeMap == NULL) { return (-1); /* temp error */ } /* Make sure the RM instance has a transport registered with a higher level agent */ if (!rmInst->registeredWithDelegateOrServer) { return (-1); /* temp error - can't handle request because client delegate or server not registered */ } /* Parse the RM instance's routing map to find the higher level agent for forwarding */ while ((routeMap->remoteInstType != Rm_instType_CLIENT_DELEGATE) || (routeMap->remoteInstType != Rm_instType_SERVER)) { /* Traverse the list until arriving at the upper level agent node */ routeMap = routeMap->nextNode; } /* Create a RM packet using the service information */ if (rmInst->transport.rmAllocPkt) { rmPkt = rmInst->transport.rmAllocPkt (routeMap->transHandle, sizeof(Rm_ProtocolPkt)); } /* Return error if the packet allocation API is not plugged or if a NULL packet pointer * was returned */ if (!rmPkt) { return (-1); /* temp error */ } /* Populate the RM packet using the service information */ /* Inform component that requested the service that the resource is being requested * from the higher level RM agent. The component must assume the resource service * result will be returned using the specified callback function */ return (RM_REQUESTING_RESOURCE); } Rm_TransactionResult rmTransactionProcessor (rmHandle, Rm_Transaction *newTransaction, Rm_TransactionReceipt *newTransactionReceipt) { } Rm_ServiceResult rmServiceHandler (void *rmHandle, Rm_ServiceReqInfo *requestInfo, Rm_ServiceRespInfo *responseInfo) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_Transaction newTransaction; Rm_TransactionReceipt newTransactionReceipt; Rm_ServiceResult retVal = RM_service_OKAY; void *key; /* Prevent another component using the same instance from wiping out the current * service request */ key = Rm_osalLocalCsEnter(); /* Transfer request information into the internal transaction format */ newTransaction.transType = (Rm_Command) requestInfo->serviceType; /* Policy modifications will never originate from components */ strcpy ((void *) &(newTransaction.u.transInfo.resName)[0], (void *)requestInfo->resName); newTransaction.u.transInfo.resBase = requestInfo->resourceAlign; newTransaction.u.transInfo.resNum = requestInfo->resourceNum; newTransaction.u.transInfo.resAlign = requestInfo->resourceAlign; strcpy ((void *) &(newTransaction.u.transInfo.resNsName)[0], (void *)requestInfo->resNsName); /* All service requests on Clients are forwarded to the higher level RM agent * either a Client Delegate or Server, based on the RM system architecture */ if (rmInst->instType == Rm_instType_CLIENT) { retVal = (Rm_ServiceResult) rmTransactionForwarder (rmHandle, &newTransaction, &newTransactionReceipt); /* Copy internal transaction receipt information into the response info fields for the * component */ responseInfo->requestId = newTransactionReceipt.transactionId; responseInfo->resBase = newTransactionReceipt.resBase; responseInfo->resNum = newTransactionReceipt.resNum; } else { /* Directly handle the request if on a Client Delegate or Server. On Client Delegates, if * the request cannot be serviced it will be forwarded to the higher level RM instance. */ retVal = (Rm_ServiceResult) rmTransactionProcessor (rmHandle, &newTransaction, &newTransactionReceipt); /* Copy internal transaction receipt information into the response info fields for the * component */ responseInfo->requestId = newTransactionReceipt.transactionId; responseInfo->resBase = newTransactionReceipt.resBase; responseInfo->resNum = newTransactionReceipt.resNum; } Rm_osalLocalCsExit(key); return (retVal); } /********************************************************************** *********************** Application visible APIs *************************** **********************************************************************/ Rm_Handle Rm_init(Rm_InitCfg *initCfg) { Rm_Inst *rmInst; /* 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), false); /* Populate instance based on input parameters */ strcpy (&rmInst->name[0], initCfg->instName); rmInst->instType = initCfg->instType; rmInst->instState = RM_state_IDLE; rmInst->registeredWithDelegateOrServer = false; rmInst->serviceCallback = NULL; /* Populate the instance transport callouts */ rmInst->transport.rmAllocPkt = initCfg->rmAllocPktFuncPtr; rmInst->transport.rmFreePkt = initCfg->rmFreePktFuncPtr; rmInst->transport.rmSend = initCfg->rmSendFuncPtr; rmInst->transport.rmReceive = initCfg->rmReceiveFuncPtr; rmInst->transport.rmNumPktsReceived = initCfg->rmNumPktsReceivedFuncPtr; /* 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; /* RM Server specific actions */ if (rmInst->instType == Rm_instType_SERVER) { } /* Instance startup policies are only used for Servers and Client Delegates */ if (rmInst->instType != Rm_instType_CLIENT) { rmInst->instPolicy = initCfg->startupPolicy; /* Store policy via policy APIs ... */ } /* Return the RM Handle */ return ((Rm_Handle) rmInst); } Rm_Result Rm_preMainAllocResource(Rm_PreMainAllocInfo *preMainAllocInfo) { } Rm_ServiceHandle Rm_getServiceHandle(Rm_Handle rmHandle) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_ServicesPort *newServicePort; /* Create a new service handle for the specified RM instance */ /* Get memory for a new service port from local memory */ newServicePort = Rm_osalMalloc (sizeof(Rm_ServicesPort), false); newServicePort->rmHandle = rmHandle; newServicePort->rmService = rmServiceHandler; return ((Rm_ServiceHandle) newServicePort); } Rm_TransportHandle Rm_registerTransport (Rm_Handle rmHandle, Rm_TransCfg *transCfg) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_TransRouteMapNode *existingRouteMap = (Rm_TransRouteMapNode *) rmInst->routeMap; Rm_TransRouteMapNode *newRouteMapNode; /* RM Servers cannot connect to other Servers */ if ((rmInst->instType == Rm_instType_SERVER) && (transCfg->rmRemoteInstType == Rm_instType_SERVER)) { return (NULL); /* Error -return null */ } /* Verify Clients and Client Delegates are not registering with more than one Client Delegate or Server. * Assuming a Client Delegate can register with another Client Delegate that can "act" as a server */ if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) && ((transCfg->rmRemoteInstType == Rm_instType_CLIENT_DELEGATE) || (transCfg->rmRemoteInstType == Rm_instType_SERVER)) && rmInst->registeredWithDelegateOrServer) { return (NULL); /* Error -return null */ } /* Error checks passed - Create a new transport handle for the specified RM instance */ /* Get memory for a new routing map node from local memory */ newRouteMapNode = Rm_osalMalloc (sizeof(Rm_TransRouteMapNode), false); /* Populate the new node. The address of the node itself is stored since this address is returned * to the application as the Rm_TransportHandle */ newRouteMapNode->transHandle = newRouteMapNode; newRouteMapNode->remoteInstType = transCfg->rmRemoteInstType; newRouteMapNode->nextNode = NULL; /* New node will always be NULL */ /* Check if there are any entries in the routing map */ if (existingRouteMap) { /* At least one entry in the routing map. Add the new routing map node to the end of the * routing map node list */ while (existingRouteMap->nextNode != NULL) { /* Traverse the list until arriving at the last node */ existingRouteMap = existingRouteMap->nextNode; } /* Add the new node to the end of the list */ existingRouteMap->nextNode = newRouteMapNode; } else { /* A routing map does not currently exist. The new node is the first entry */ rmInst->routeMap = newRouteMapNode; } /* Specify RM instance has registered with a higher level agent */ if ((newRouteMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) || (newRouteMapNode->remoteInstType == Rm_instType_SERVER)) { rmInst->registeredWithDelegateOrServer = true; } return ((Rm_TransportHandle) newRouteMapNode); } Rm_Result Rm_unregisterTransport (Rm_Handle rmHandle, Rm_TransportHandle transHandle) { Rm_Inst *rmInst = (Rm_Inst *) rmHandle; Rm_TransRouteMapNode *routeMapNode = (Rm_TransRouteMapNode *) rmInst->routeMap; Rm_TransRouteMapNode *prevNode = NULL; /* Make sure a routing map exists for the RM instance */ if (!routeMapNode) { return (-1); /* TEMP ERROR RETURN */ } /* Find the transport handle within the specified RM instance's routing map. */ while (1) { if (routeMapNode->transHandle == transHandle) { /* Match: break out of loop and delete the node */ break; } else if (routeMapNode->nextNode == NULL) { return (-1); /* TEMP ERROR: transhandle does not exist for RM instance */ } prevNode = routeMapNode; routeMapNode = routeMapNode->nextNode; } /* Delete the routing map node */ if ((prevNode == NULL) && routeMapNode->nextNode) { /* Node to be deleted exists at start of route map. Map second node to be start of * node list as long as there are more than one routing map nodes */ rmInst->routeMap = routeMapNode->nextNode; } else { /* Node to be deleted is in the middle or at end of the list. Adjust adjacent * nodes pointers. This covers the case where the node to be removed is at the * end of the list. */ prevNode->nextNode = routeMapNode->nextNode; } /* Remove specification in RM instance that it has been connected to an upper level agent * if the node to be deleted has a remote instance type of Client Delegate or Server */ if ((routeMapNode->remoteInstType == Rm_instType_CLIENT_DELEGATE) || (routeMapNode->remoteInstType == Rm_instType_SERVER)) { rmInst->registeredWithDelegateOrServer = false; } /* Delete the node, free the memory associated with the node. */ Rm_osalFree((void *) routeMapNode, sizeof(Rm_TransRouteMapNode), false); return (RM_OK); } Rm_TransVerifyResult Rm_verifyTransport (Rm_Handle, uint32_t timeout, Rm_TransFailData *failData) { } uint32_t Rm_getVersion (void) { return RM_VERSION_ID; } const char* Rm_getVersionStr (void) { return rmVersionStr; } /** @} */