]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm.c
Created allocator module
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**
2  *   @file  rm.c
3  *
4  *   @brief   
5  *      This is the Resource Manager source.
6  *
7  *  \par
8  *  ============================================================================
9  *  @n   (C) Copyright 2012-2013, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
42 /* Standard includes */
43 #include <stdint.h>
44 #include <string.h>
45 #include <stdbool.h>
47 /* RM external includes */
48 #include <ti/drv/rm/rm.h>
49 #include <ti/drv/rm/rmver.h>
50 #include <ti/drv/rm/rm_services.h>
51 #include <ti/drv/rm/rm_transport.h>
53 /* RM internal includes */
54 #include <ti/drv/rm/include/rm_loc.h>
55 #include <ti/drv/rm/include/rm_allocatorloc.h>
56 #include <ti/drv/rm/include/rm_transportloc.h>
57 #include <ti/drv/rm/include/rm_nameserverloc.h>
59 /* RM LIBFDT includes */
60 #include <ti/drv/rm/util/libfdt/libfdt.h>
62 /* RM OSAL layer */
63 #include <rm_osal.h>
65 /**********************************************************************
66  ************************** Globals ***********************************
67  **********************************************************************/
69 /** @brief Global Variable which describes the RM Version Information */
70 const char  rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;
72 /**********************************************************************
73  ************************ Local Functions *****************************
74  **********************************************************************/
76 /* FUNCTION PURPOSE: Initializes a RM inst's transaction sequence number
77  ***********************************************************************
78  * DESCRIPTION: The RM instance transaction sequence number can never
79  *              have a value of 0 to avoid conflicts with transactions
80  *              that have a remoteOriginatingId of 0 (transaction ID
81  *              will be used as the remoteOriginatingId for
82  *              transactions that are responses to requests).
83  */
84 static uint32_t transactionInitSequenceNum(void)
85 {
86     return (1);
87 }
89 /* FUNCTION PURPOSE: Provides a sequence number for new transactions
90  ***********************************************************************
91  * DESCRIPTION: Returns a sequence number for a new transaction
92  *              specific to a RM instance.  Handles rollover of
93  *              sequence number.
94  */
95 static uint32_t transactionGetSequenceNum(Rm_Inst *rmInst)
96 {
97     rmInst->transactionSeqNum++;
98     if (!rmInst->transactionSeqNum) {
99         rmInst->transactionSeqNum++;
100     }    
101     return (rmInst->transactionSeqNum);
104 /* FUNCTION PURPOSE: Creates a resource request packet
105  ***********************************************************************
106  * DESCRIPTION: Returns a RM packet handle that points to a RM
107  *              resource request packet that has been prepared
108  *              for sending to another RM instance.  The packet
109  *              is allocated via the rmAllocPkt API using the
110  *              appTransport handle provided by the application
111  */
112 void createResourceReqPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction)
114     Rm_ResourceRequestPkt *resourceReqPkt = NULL;
115        
116     rmPkt->pktType = Rm_pktType_RESOURCE_REQUEST;
117     resourceReqPkt = (Rm_ResourceRequestPkt *) rmPkt->data;
118     resourceReqPkt->requestId = transaction->localId;
119     if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
120         resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_INIT;
121     }
122     else if (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) {
123         resourceReqPkt->resourceReqType = Rm_resReqPktType_ALLOCATE_USE;
124     }    
125     else if (transaction->type == Rm_service_RESOURCE_FREE) {
126         resourceReqPkt->resourceReqType = Rm_resReqPktType_FREE;
127     }
128     else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
129         resourceReqPkt->resourceReqType = Rm_resReqPktType_GET_NAMED;
130     }
131     strncpy(resourceReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS);
132     strncpy(resourceReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS);
133     memcpy ((void *)&(resourceReqPkt->resourceInfo), (void *)&(transaction->resourceInfo),
134             sizeof(Rm_ResourceInfo));
137 /* FUNCTION PURPOSE: Creates a resource response packet
138  ***********************************************************************
139  * DESCRIPTION: Returns a RM packet handle that points to a RM
140  *              resource response packet that has been prepared
141  *              for sending to another RM instance.  The packet
142  *              is allocated via the rmAllocPkt API using the
143  *              appTransport handle provided by the application
144  */
145 void createResourceResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction)
147     Rm_ResourceResponsePkt *resourceRespPkt = NULL;
148      
149     rmPkt->pktType = Rm_pktType_RESOURCE_RESPONSE;                 
150     resourceRespPkt = (Rm_ResourceResponsePkt *)rmPkt->data;
151     resourceRespPkt->responseId = transaction->remoteOriginatingId;
152     resourceRespPkt->requestState = transaction->state;
153     memcpy ((void *)&(resourceRespPkt->resourceInfo), (void *)&(transaction->resourceInfo),
154             sizeof(Rm_ResourceInfo));
157 /* FUNCTION PURPOSE: Creates a NameServer request packet
158  ***********************************************************************
159  * DESCRIPTION: Returns a RM packet handle that points to a RM
160  *              NameServer request packet that has been prepared
161  *              for sending to another RM instance.  The packet
162  *              is allocated via the rmAllocPkt API using the
163  *              appTransport handle provided by the application
164  */
165 void createNsRequestPkt(Rm_Packet *rmPkt, char *localInstName, Rm_Transaction *transaction)
166
167     Rm_NsRequestPkt *nsReqPkt = NULL;
169     rmPkt->pktType = Rm_pktType_NAMESERVER_REQUEST;                   
170     nsReqPkt = (Rm_NsRequestPkt *)rmPkt->data;
171     nsReqPkt->requestId = transaction->localId;
172     if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
173         nsReqPkt->nsRequestType = Rm_nsReqPktType_MAP_RESOURCE;
174     }
175     else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
176         nsReqPkt->nsRequestType = Rm_nsReqPktType_UNMAP_RESOURCE;
177     }
178     strncpy(nsReqPkt->pktSrcInstName, localInstName, RM_NAME_MAX_CHARS);
179     strncpy(nsReqPkt->serviceSrcInstName, transaction->serviceSrcInstName, RM_NAME_MAX_CHARS);
180     memcpy ((void *)&(nsReqPkt->resourceInfo), (void *)&(transaction->resourceInfo),
181             sizeof(Rm_ResourceInfo));
184 /* FUNCTION PURPOSE: Creates a NameServer response packet
185  ***********************************************************************
186  * DESCRIPTION: Returns a RM packet handle that points to a RM
187  *              NameServer response packet that has been prepared
188  *              for sending to another RM instance.  The packet
189  *              is allocated via the rmAllocPkt API using the
190  *              appTransport handle provided by the application
191  */
192 void createNsResponsePkt(Rm_Packet *rmPkt, Rm_Transaction *transaction)
194     Rm_NsResponsePkt *nsRespPkt = NULL;
196     rmPkt->pktType = Rm_pktType_NAMESERVER_RESPONSE;                
197     nsRespPkt = (Rm_NsResponsePkt *)rmPkt->data;
198     nsRespPkt->responseId = transaction->remoteOriginatingId;
199     nsRespPkt->requestState = transaction->state;
202 /* FUNCTION PURPOSE: Issues a service response to application
203  ***********************************************************************
204  * DESCRIPTION: Provides a service response back to the application
205  *              using the service callback function provided to
206  *              the RM instance at the time of the service request.
207  */
208 static void serviceResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
210     Rm_ServiceRespInfo serviceResponse;
212     /* The responseTransaction will contain the resultant state details of
213      * the requestTransaction's service request */
214     serviceResponse.serviceState = transaction->state;
215     /* Pass back the ID that was provided to the component when it requested
216      * the service */
217     serviceResponse.serviceId = transaction->localId;
219     /* Service was approved and service was an allocate request.  The resource
220      * data is passed back to the component */
221     if ((serviceResponse.serviceState == RM_SERVICE_APPROVED) &&
222         ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
223          (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE) ||
224          (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)))
225     {
226         strncpy(serviceResponse.resourceName, transaction->resourceInfo.name, RM_NAME_MAX_CHARS);
227         serviceResponse.resourceBase = transaction->resourceInfo.base;
228         serviceResponse.resourceLength = transaction->resourceInfo.length;
229     }
231     /* Issue the callback to the requesting component with the response information */
232     transaction->callback.serviceCallback(&serviceResponse);
234     /* Delete the transaction from the transaction queue */
235     rmTransactionQueueDelete(rmInst, transaction->localId);
236     return;
239 /* FUNCTION PURPOSE: Sends RM response packets
240  ***********************************************************************
241  * DESCRIPTION: Sends RM response packets to RM instance's that sent
242  *              RM request packets to the RM instance.  The response
243  *              is sent via the RM transport API which is plugged
244  *              with an application created transport path.
245  */
246 static void transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)
248     Rm_Transport    *dstTransport = NULL;
249     Rm_Packet       *rmPkt = NULL;
250     Rm_PacketHandle  pktHandle = NULL;
252     if (dstTransport = rmTransportFindRemoteName(rmInst->transports, transaction->pktSrcInstName)) {
253         rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, 
254                                                   sizeof(Rm_Packet), &pktHandle);
255         if (!rmPkt || !pktHandle) {
256             transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR;
257             goto errorExit;
258         }
260         switch (transaction->type) {
261             case Rm_service_RESOURCE_ALLOCATE_INIT:
262             case Rm_service_RESOURCE_ALLOCATE_USE:
263             case Rm_service_RESOURCE_FREE:
264             case Rm_service_RESOURCE_GET_BY_NAME:
265                 createResourceResponsePkt(rmPkt, transaction);
266                 break;
267             case Rm_service_RESOURCE_MAP_TO_NAME:
268             case Rm_service_RESOURCE_UNMAP_NAME:
269                 createNsResponsePkt(rmPkt, transaction);
270                 break;
271         }
272         if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
273             transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
274             goto errorExit;
275         }
276         
277         /* Response packet sent: Delete transaction from queue */
278         rmTransactionQueueDelete(rmInst, transaction->localId);
279     }
280     else {
281         transaction->state = RM_ERROR_TRANSPORT_REMOTE_HNDL_NOT_REGD;
282     }
283 errorExit:
284     /* Do not delete transaction on error.  Error transactions should be visible from
285      * from Rm_printInstanceStatus() */
286     return;
289 /* FUNCTION PURPOSE: Sends RM request packets
290  ***********************************************************************
291  * DESCRIPTION: Sends RM request packets to RM instance's that are
292  *              capable of forwarding or validating service requests.
293  *              The request is sent via the RM transport API which is
294  *              plugged with an application created transport path.
295  */
296 static void transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)
298     Rm_Transport    *dstTransport = NULL;
299     Rm_Packet       *rmPkt = NULL;    
300     Rm_PacketHandle  pktHandle = NULL;
302     if (rmInst->instType == Rm_instType_CLIENT) {
303         dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_CLIENT_DELEGATE);
305         if (!dstTransport) {
306             dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER);
307         }
308     } 
309     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
310         dstTransport = rmTransportFindRemoteInstType(rmInst->transports, Rm_instType_SERVER);
311     }
313     /* Just queue transaction if transport hasn't been registered.  Do not return error */
314     if (dstTransport) {            
315         rmPkt = dstTransport->callouts.rmAllocPkt(dstTransport->appTransportHandle, 
316                                                   sizeof(Rm_Packet), &pktHandle);
317         if (!rmPkt || !pktHandle) {
318             transaction->state = RM_ERROR_TRANSPORT_ALLOC_PKT_ERROR;
319             goto errorExit;
320         }
322         switch (transaction->type) {
323             case Rm_service_RESOURCE_ALLOCATE_INIT:
324             case Rm_service_RESOURCE_ALLOCATE_USE:
325             case Rm_service_RESOURCE_FREE:
326             case Rm_service_RESOURCE_GET_BY_NAME:
327                 createResourceReqPkt(rmPkt, rmInst->instName, transaction);
328                 break;
329             case Rm_service_RESOURCE_MAP_TO_NAME:
330             case Rm_service_RESOURCE_UNMAP_NAME:
331                 createNsRequestPkt(rmPkt, rmInst->instName, transaction);
332                 break;
333         }
334   
335         if (dstTransport->callouts.rmSendPkt(dstTransport->appTransportHandle, pktHandle) < RM_OK) {
336             transaction->state = RM_ERROR_TRANSPORT_SEND_ERROR;
337             goto errorExit;
338         }              
339         transaction->hasBeenForwarded = true;
340         /* Transaction not deleted.  Waiting for response from RM CD or Server */
341     }
342 errorExit: 
343     return;
346 /* FUNCTION PURPOSE: Arbitrates allocation service requests
347  ***********************************************************************
348  * DESCRIPTION: Issues a set of allocator operations in order to
349  *              handle a received allocation request.  Allocation
350  *              requests are always forwarded to the Server on Client
351  *              CD instances.  If a request is made with a NameServer
352  *              name the resource base and length parameters are
353  *              retrieved from the NameServer prior to the allocation
354  *              attempt.
355  */
356 static void allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode,
357                                uint32_t allocType)
359     Rm_AllocatorOpInfo  opInfo;
360     Rm_NameServerObjCfg nameServerObjCfg;
361     int32_t             retVal = transaction->state;
363     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
364     
365     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
366         /* Forward all allocation requests to Server if transport is up.  Otherwise, just queue. */
367         if (rmInst->registeredWithDelegateOrServer) {
368             transactionForwarder(rmInst, transaction);   
369         }  
370     }
371     else if (rmInst->instType == Rm_instType_SERVER) {
372         opInfo.policy = rmInst->policy;
373         opInfo.resourceInfo = &transaction->resourceInfo;
374         opInfo.serviceSrcInstNode = validInstNode;
375         if (validInstNode == rmPolicyGetLinuxInstNode(rmInst->validInstances)) {
376             opInfo.LinuxKernelBypass = true;
377         }
378         else {
379             opInfo.LinuxKernelBypass = false;
380         }
381         opInfo.allocType = allocType;
383         /* Populated NameServer name has precedence over base */
384         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
385             if ((transaction->resourceInfo.base == 0) &&
386                 (transaction->resourceInfo.length == 0) &&
387                 (transaction->resourceInfo.alignment == 0)) {
388                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
389                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
390                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
391                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
392                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
393                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
394                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
395                 }                
396             }
397             else {
398                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
399             }
400         }
402         if (retVal == RM_SERVICE_PROCESSING) {      
403             if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {
404                 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;
405                 retVal = rmAllocatorOperation(rmInst->allocators, &opInfo);
406             }
407         
408             if (retVal == RM_SERVICE_PROCESSING) {
409                 opInfo.operation = Rm_allocatorOp_ALLOCATE;
410                 retVal = rmAllocatorOperation(rmInst->allocators, &opInfo);
411             }      
412         }
413         
414         transaction->state = retVal;
416         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
417             /* Source of allocation was not the server instance, provide the transaction
418              * to the transaction responder */
419             transactionResponder(rmInst, transaction);
420         }
421         /* Otherwise let the return stack return the transaction to the serviceHandler */                   
422     }   
425 /* FUNCTION PURPOSE: Arbitrates free service requests
426  ***********************************************************************
427  * DESCRIPTION: Issues a set of allocator operations in order to
428  *              handle a received free request.  Free
429  *              requests are always forwarded to the Server on Client
430  *              CD instances.  If a request is made with a NameServer
431  *              name the resource base and length parameters are
432  *              retrieved from the NameServer prior to the free
433  *              attempt.
434  */
435 static void freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode)
437     Rm_AllocatorOpInfo  opInfo; 
438     Rm_NameServerObjCfg nameServerObjCfg;    
439     int32_t             retVal = transaction->state;
441     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));
442     
443     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
444         /* Forward all free requests to Server if transport is up.  Otherwise, just queue. */
445         if (rmInst->registeredWithDelegateOrServer) {
446             transactionForwarder(rmInst, transaction);   
447         }
448     }
449     else if (rmInst->instType == Rm_instType_SERVER) {
450         opInfo.policy = rmInst->policy;
451         opInfo.resourceInfo = &transaction->resourceInfo;
452         opInfo.serviceSrcInstNode = validInstNode;
454         /* Populated NameServer name has precedence over base */
455         if (strlen(transaction->resourceInfo.nameServerName) > 0) {
456             if ((transaction->resourceInfo.base == 0) &&
457                 (transaction->resourceInfo.length == 0) &&
458                 (transaction->resourceInfo.alignment == 0)) {
459                 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
460                 nameServerObjCfg.nameServerTree = rmInst->nameServer;
461                 nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
462                 if ((retVal = rmNameServerFindObject(&nameServerObjCfg)) == RM_SERVICE_PROCESSING) {
463                     strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
464                     transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
465                     transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
466                 } 
467             }
468             else {
469                 retVal = RM_ERROR_NS_NAME_AND_RES_VAL_CONFLICT;
470             }                
471         }
472         
473         if(retVal == RM_SERVICE_PROCESSING) {        
474             opInfo.operation = Rm_allocatorOp_FREE;
475             retVal = rmAllocatorOperation(rmInst->allocators, &opInfo);
476         }       
478         transaction->state = retVal;
480         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
481             /* Source of allocation was not the server instance, provide the transaction
482              * to the transaction responder */
483             transactionResponder(rmInst, transaction);
484         }
485         /* Otherwise let the return stack return the transaction to the serviceHandler */        
486     }   
489 /**********************************************************************
490  ********************** Internal Functions ****************************
491  **********************************************************************/
493 /* FUNCTION PURPOSE: Adds a transaction
494  ***********************************************************************
495  * DESCRIPTION: Returns a pointer to a newly created transaction.
496  *              The transaction is created based on a new service
497  *              request received via the service API or the
498  *              transport API (service forwarded from another instance)
499  */
500 Rm_Transaction *rmTransactionQueueAdd(Rm_Inst *rmInst)
502     Rm_Transaction *transactionQueue = rmInst->transactionQueue;
503     Rm_Transaction *newTransaction   = NULL;
505     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));
506     if (newTransaction) {
507         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));
509         newTransaction->localId = transactionGetSequenceNum(rmInst);
510         newTransaction->nextTransaction = NULL;  
511         if (transactionQueue) {
512             while (transactionQueue->nextTransaction) {
513                 transactionQueue = transactionQueue->nextTransaction;
514             }
515             transactionQueue->nextTransaction = newTransaction;
516         }
517         else {
518             rmInst->transactionQueue = newTransaction;
519         }
520     }
521     return (newTransaction);
524 /* FUNCTION PURPOSE: Finds a transaction
525  ***********************************************************************
526  * DESCRIPTION: Returns a pointer to a transaction resident
527  *              in the transaction queue that matches the provided
528  *              transaction ID.
529  */
530 Rm_Transaction *rmTransactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)
532     Rm_Transaction *transaction = rmInst->transactionQueue;
534     while (transaction) {
535         if (transaction->localId == transactionId) {
536             break;             
537         }
538         transaction = transaction->nextTransaction;
539     }
541     return (transaction);
544 /* FUNCTION PURPOSE: Deletes a transaction
545  ***********************************************************************
546  * DESCRIPTION: Deletes the transaction with the provided transaction
547  *              ID from the instance's transaction queue.
548  */
549 int32_t rmTransactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)
551     Rm_Transaction *transaction     = rmInst->transactionQueue;
552     Rm_Transaction *prevTransaction = NULL;
553     int32_t         retVal          = RM_OK;
555     while (transaction) {
556         if (transaction->localId == transactionId) {
557             break;             
558         }
560         prevTransaction = transaction;
561         transaction = transaction->nextTransaction;
562     }
564     if (transaction) {
565         if (prevTransaction == NULL) {
566             /* Transaction at start of queue. Map second transaction to start of queue 
567              * as long as more than one transactions. */
568             rmInst->transactionQueue = transaction->nextTransaction;
569         }
570         else {
571             /* Transaction in middle or end of queue. */
572             prevTransaction->nextTransaction = transaction->nextTransaction;
573         }
574         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));
575     }
576     else {
577         retVal = RM_ERROR_SERVICE_TRANS_DOES_NOT_EXIST;
578     }    
579     return (retVal);
582 /* FUNCTION PURPOSE: Processes a transaction
583  ***********************************************************************
584  * DESCRIPTION: Processes transactions created from services
585  *              received via the service handle or the transport.
586  *              Transactions will be routed within the RM system
587  *              based on the RM instance type and the type of
588  *              the transaction.
589  */
590 void rmTransactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)
592     void                *validInstNode;
593     Rm_PolicyCheckCfg    privCheckCfg;
594     Rm_NameServerObjCfg  nameServerObjCfg;      
595     uint32_t             allocType = 0;    
597     /* Handle static transactions originating on this instance.  Any other static transactions will be
598      * stored in transaction queue until all transports are up. */
599     if (((rmInst->instType == Rm_instType_CLIENT) || (rmInst->instType == Rm_instType_CLIENT_DELEGATE)) &&
600         (!rmInst->registeredWithDelegateOrServer) && 
601         (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS) == 0)) {
602         if (rmInst->staticInfo.staticPolicy) {
603             if ((transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) ||
604                 (transaction->type == Rm_service_RESOURCE_ALLOCATE_USE)) {
605                 /* Check request against startup policy */
606                 memset((void *)&privCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
608                 if (transaction->type == Rm_service_RESOURCE_ALLOCATE_INIT) {
609                     privCheckCfg.type = Rm_policyCheck_INIT;
610                 }
611                 else {
612                     privCheckCfg.type = Rm_policyCheck_USE;
613                 }
614                 privCheckCfg.policyDtb = rmInst->staticInfo.staticPolicy;
615                 privCheckCfg.validInstNode = rmPolicyGetValidInstNode(rmInst->staticInfo.staticValidInstTree, 
616                                                                       rmInst->instName);
617                 privCheckCfg.resourceOffset = rmPolicyGetResourceOffset(rmInst->staticInfo.staticPolicy,
618                                                                         transaction->resourceInfo.name);
619                 privCheckCfg.resourceBase = transaction->resourceInfo.base;
620                 privCheckCfg.resourceLength = transaction->resourceInfo.length;
622                 if (rmPolicyCheckPrivilege(&privCheckCfg, &transaction->state)) {
623                     transaction->state = RM_SERVICE_APPROVED_STATIC;
624                 }
625                 else if (transaction->state == RM_SERVICE_PROCESSING) {
626                     /* Privilege check returned false without error */
627                     transaction->state = RM_SERVICE_DENIED_BY_STATIC_POLICY;
628                 }
629             }
630             else {
631                 transaction->state = RM_SERVICE_DENIED_INVALID_STATIC_REQUEST;
632             }
633         }
634         else {
635             transaction->state = RM_ERROR_REQ_FAILED_NO_STATIC_POLICY;
636         }        
637     }
638     else {
639         /* Handle auto-forwarded transactions.  These transactions include:
640          * - All request transactions received on Clients are forwarded to the Client Delegate
641          * - NameServer requests received on the Client Delegate are forwarded to the Server */
642         if ((rmInst->instType == Rm_instType_CLIENT) ||
643             ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
644              ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||
645               (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||
646               (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) {
647               
648             if ((transaction->state != RM_SERVICE_PROCESSING) &&
649                 (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
650                 if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
651                     /* Transaction did not originate on this instance */
652                     transactionResponder(rmInst, transaction);
653                 }
654                 else {
655                     /* Transaction originated on this instance */
656                     serviceResponder(rmInst, transaction);
657                 }
658             }
659             else {
660                 /* Forward request if transport is up.  Otherwise, just queue. */
661                 if (rmInst->registeredWithDelegateOrServer) {
662                     transactionForwarder(rmInst, transaction);   
663                 } 
664             }
665         }
666         else {
667             /* Validate service's originating instance name */
668             if (rmInst->instType == Rm_instType_SERVER) {
669                 validInstNode = rmPolicyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName);
670                 if (validInstNode == NULL) {
671                     transaction->state = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
673                     /* Send result via responder if transaction did not originate from this instance */
674                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
675                         transactionResponder(rmInst, transaction);
676                     }
677                 }
678             }
680             switch (transaction->type) {
681                 case Rm_service_RESOURCE_ALLOCATE_INIT:
682                 case Rm_service_RESOURCE_ALLOCATE_USE:
683                 case Rm_service_RESOURCE_FREE:               
684                     if ((transaction->state != RM_SERVICE_PROCESSING) &&
685                         (transaction->state != RM_SERVICE_APPROVED_STATIC)) {
686                         /* Transaction complete */
687                         if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
688                             /* Transaction result not destined for this instance */
689                             transactionResponder(rmInst, transaction);
690                         }
691                         else {
692                             /* Transaction result destined for this instance */
693                             serviceResponder(rmInst, transaction);      
694                         }
695                     }
696                     else {
697                         /* Complete allocation/free request */
698                         if (transaction->type == Rm_service_RESOURCE_FREE) {
699                             freeHandler(rmInst, transaction, validInstNode);
700                         }
701                         else {
702                             switch (transaction->type) {
703                                 case Rm_service_RESOURCE_ALLOCATE_INIT:
704                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1);
705                                     break;
706                                 case Rm_service_RESOURCE_ALLOCATE_USE:
707                                     RM_policy_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1);    
708                                     break;
709                             }
710                             allocationHandler(rmInst, transaction, validInstNode, allocType);
711                         }
712                     }
713                     break;
714                 case Rm_service_RESOURCE_MAP_TO_NAME:
715                 case Rm_service_RESOURCE_GET_BY_NAME:
716                 case Rm_service_RESOURCE_UNMAP_NAME:                
717                     /* NameServer resides on server */
718                     memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
719                     if (rmInst->nameServer) {
720                         nameServerObjCfg.nameServerTree = rmInst->nameServer;
721                         nameServerObjCfg.nodeCfg.objName = transaction->resourceInfo.nameServerName;
722                         if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {
723                             nameServerObjCfg.nodeCfg.resourceName = transaction->resourceInfo.name;
724                             nameServerObjCfg.nodeCfg.resourceBase= transaction->resourceInfo.base;
725                             nameServerObjCfg.nodeCfg.resourceLength = transaction->resourceInfo.length;
726                             transaction->state = rmNameServerAddObject(&nameServerObjCfg);
727                         }
728                         else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {
729                             if ((transaction->state = rmNameServerFindObject(&nameServerObjCfg)) ==
730                                 RM_SERVICE_PROCESSING) {
731                                 strncpy(transaction->resourceInfo.name, nameServerObjCfg.nodeCfg.resourceName, RM_NAME_MAX_CHARS);
732                                 transaction->resourceInfo.base = nameServerObjCfg.nodeCfg.resourceBase;
733                                 transaction->resourceInfo.length = nameServerObjCfg.nodeCfg.resourceLength;
734                                 transaction->state = RM_SERVICE_APPROVED;
735                             } 
736                         }
737                         else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {
738                             transaction->state = rmNameServerDeleteObject(&nameServerObjCfg);
739                         }
740                     }
741                     else {
742                         transaction->state = RM_ERROR_NAMESERVER_DOES_NOT_EXIST;
743                     }
745                     /* Send result via responder if transaction did not originate from this instance */
746                     if (strncmp(transaction->serviceSrcInstName, rmInst->instName, RM_NAME_MAX_CHARS)) {
747                         transactionResponder(rmInst, transaction);
748                     }
749                     break;
750             }
751         }
752     }
754     /* Forward any queued requests that weren't forwarded yet */
755     if (rmInst->registeredWithDelegateOrServer) {
756         transaction = rmInst->transactionQueue;
757         while(transaction) {
758             if (((transaction->state == RM_SERVICE_PROCESSING) ||
759                  (transaction->state == RM_SERVICE_APPROVED_STATIC)) &&
760                 !transaction->hasBeenForwarded) {
761                 transactionForwarder(rmInst, transaction);
762             }
763             transaction = transaction->nextTransaction;
764         }
765     }
767      
768 /**********************************************************************
769  ********************** Application visible APIs **********************
770  **********************************************************************/
772 /* FUNCTION PURPOSE: Display status of managed resources
773  ***********************************************************************
774  * DESCRIPTION: Prints the status (allocate/free status, as well as
775  *              owners) for all resources managed by the RM 
776  *              instance network.  Also, prints the NameServer name
777  *              entries.  This function is only available on server
778  *              instances.
779  */
780 void Rm_printResourceStatus(Rm_Handle rmServerHandle)
782     Rm_Inst         *rmInst = (Rm_Inst *)rmServerHandle;
783     Rm_Allocator    *allocator = rmInst->allocators;
784     Rm_Owner        *owners;
785     Rm_ResourceTree *treeRoot;
786     Rm_ResourceNode *treeNode;
788     if (rmInst->instType == Rm_instType_SERVER) {
789         while (allocator != NULL) {
790             Rm_osalLog("Resource: %s\n", allocator->resourceName);
792             treeRoot = allocator->allocatorRootEntry;
794             RB_FOREACH(treeNode, _Rm_AllocatorResourceTree, treeRoot) {               
795                 Rm_osalLog("          %10d - %10d ", treeNode->base, 
796                                                      treeNode->base + treeNode->length -1);
797                 
798                 if (treeNode->allocationCount == 0) {
799                     Rm_osalLog("NOT ALLOCATED\n");
800                 }
801                 else {
802                     owners = treeNode->ownerList;
803                     Rm_osalLog("allocated to");
804                     while (owners) {
805                         Rm_osalLog(" %s", owners->instNameNode->name);
806                         owners = owners->nextOwner;
807                     }
808                     Rm_osalLog("\n");
809                 }
810             }        
811             allocator = allocator->nextAllocator;
812         }
813         rmNameServerPrintObjects(rmInst->nameServer);
814     }
817 /* FUNCTION PURPOSE: Display status of a RM instance
818  ***********************************************************************
819  * DESCRIPTION: Prints the current status of various RM instance
820  *              properties such as the state of all transactions
821  *              in the transaction queue and registered transports
822  */
823 void Rm_printInstanceStatus(Rm_Handle rmHandle)
825     Rm_Inst        *rmInst = (Rm_Inst *)rmHandle;
826     Rm_Transport   *transportList = rmInst->transports;
827     Rm_Transaction *transactionQ = rmInst->transactionQueue;
829     Rm_osalLog("Instance name: %s\n", rmInst->instName);
830     if (rmInst->instType == Rm_instType_SERVER) {
831         Rm_osalLog("Type: Server\n");
832     }
833     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
834         Rm_osalLog("Type: Client Delegate\n");
835     }
836     else {
837         Rm_osalLog("Type: Client\n");
838     }
840     if (transportList) {
841         Rm_osalLog("\nRegistered Transports:\n");
842         while (transportList) {
843             Rm_osalLog("    Remote instName:    %s\n", transportList->remoteInstName);
844             if (transportList->remoteInstType == Rm_instType_SERVER) {
845                 Rm_osalLog("    Remote instType:    Server\n");
846             }
847             else if (transportList->remoteInstType == Rm_instType_CLIENT_DELEGATE) {
848                 Rm_osalLog("    Remote instType:    Client Delegate\n");
849             }
850             else {
851                 Rm_osalLog("    Remote instType:    Client\n");
852             }
853             Rm_osalLog("    appTransportHandle: 0x%08x\n", transportList->appTransportHandle);
854             Rm_osalLog("\n");
855             transportList = transportList->nextTransport;
856         }
857     }
859     if (transactionQ) {
860         Rm_osalLog("\nQueued Service Transactions:\n");
861         while (transactionQ) {
862             Rm_osalLog("    Service type:       %d\n", transactionQ->type);
863             Rm_osalLog("    Service ID:         %d\n", transactionQ->localId);
864             Rm_osalLog("    Service srcInstName %s\n", transactionQ->serviceSrcInstName);
865             Rm_osalLog("    Service state:      %d\n", transactionQ->state);
866             Rm_osalLog("    Resource name:      %s\n", transactionQ->resourceInfo.name);
867             Rm_osalLog("    Resource base:      %d\n", transactionQ->resourceInfo.base);
868             Rm_osalLog("    Resource length:    %d\n", transactionQ->resourceInfo.length);
869             Rm_osalLog("    Resource alignment: %d\n", transactionQ->resourceInfo.alignment);
870             Rm_osalLog("    Resource NS name:   %s\n", transactionQ->resourceInfo.nameServerName);
871             Rm_osalLog("\n");
872             transactionQ = transactionQ->nextTransaction;
873         }    
874     }
877 /* FUNCTION PURPOSE: RM instance creation and initialization
878  ***********************************************************************
879  * DESCRIPTION: Returns a new RM instance created and initialized
880  *              using the parameters provided via the initCfg
881  *              structure.
882  */
883 Rm_Handle Rm_init(const Rm_InitCfg *initCfg, int32_t *result)
885     Rm_Inst *rmInst;
886     void    *globalResourceDtb = NULL;
887     void    *linuxResourceDtb = NULL;
888     bool     addLinux = false;
890     *result = RM_OK;
891     
892     if ((initCfg->instName == NULL) ||
893         ((strlen(initCfg->instName) + 1) > RM_NAME_MAX_CHARS)) {
894         *result = RM_ERROR_INVALID_INST_NAME;
895         return (NULL);
896     }
898     if (initCfg->instType >= Rm_instType_LAST) {
899         *result = RM_ERROR_INVALID_INST_TYPE;
900     }
902     /* Create and initialize instance */
903     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));
904     memset ((void *) rmInst, 0, sizeof(Rm_Inst));
905     rmInst->isLocked = false;
906     rmInst->registeredWithDelegateOrServer = false;
907     rmInst->transactionSeqNum = transactionInitSequenceNum();
909     rmInst->instType = initCfg->instType;    
910     strncpy (rmInst->instName, initCfg->instName, RM_NAME_MAX_CHARS);
912     if (rmInst->instType == Rm_instType_SERVER) {
913         if (!initCfg->instCfg.serverCfg.globalResourceList ||
914             !initCfg->instCfg.serverCfg.globalPolicy) {
915             *result = RM_ERROR_INVALID_SERVER_CONFIGURATION;
916             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
917             return(NULL);
918         }
920         rmInst->policy = initCfg->instCfg.serverCfg.globalPolicy;
921         fdt_open_into(rmInst->policy, rmInst->policy, fdt_totalsize(rmInst->policy)); 
923         if (initCfg->instCfg.serverCfg.linuxDtb) {
924             linuxResourceDtb = initCfg->instCfg.serverCfg.linuxDtb;
925             fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));
926             addLinux = true;
927         }
929         /* Create valid instance list from policy.  Must be done prior to parsing
930          * GRL so that Linux resources can be reserved correctly */
931         rmInst->validInstances = rmPolicyCreateValidInstTree(rmInst->policy, addLinux, result);
932         /* Validate policy assignment strings */
933         *result = rmPolicyValidatePolicy(rmInst->policy, rmInst->validInstances);  
935         rmInst->nameServer = rmNameServerInit();
937         globalResourceDtb = initCfg->instCfg.serverCfg.globalResourceList;
938         fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));
940         if ((*result = rmAllocatorInitializeResources((Rm_Handle) rmInst, globalResourceDtb, linuxResourceDtb)) == RM_OK) {  
941             *result = rmPolicyValidatePolicyResourceNames(rmInst->policy, (void *)rmInst->allocators);
942         }
943         if (*result < RM_OK) {
944             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
945             return(NULL);
946         }
947     }
949     if ((rmInst->instType == Rm_instType_CLIENT) && 
950         (initCfg->instCfg.clientCfg.staticPolicy)) {
951         rmInst->staticInfo.staticPolicy = initCfg->instCfg.clientCfg.staticPolicy; 
952     }
953     else if ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&
954              (initCfg->instCfg.cdCfg.staticPolicy)) { 
955         rmInst->staticInfo.staticPolicy = initCfg->instCfg.cdCfg.staticPolicy; 
956     }
957     if (rmInst->staticInfo.staticPolicy) {
958         fdt_open_into(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticPolicy, 
959                       fdt_totalsize(rmInst->staticInfo.staticPolicy));       
960         rmInst->staticInfo.staticValidInstTree = rmPolicyCreateValidInstTree(rmInst->staticInfo.staticPolicy, 
961                                                                              addLinux, result);        
962         if (*result == RM_OK) {
963             /* Validate policy assignment strings */
964             *result = rmPolicyValidatePolicy(rmInst->staticInfo.staticPolicy, rmInst->staticInfo.staticValidInstTree);
965         }
966         if (*result != RM_OK) {
967             if (rmInst->staticInfo.staticValidInstTree) {
968                 rmPolicyFreeValidInstTree(rmInst->staticInfo.staticValidInstTree);
969             }
970             Rm_osalFree((void *)rmInst, sizeof(Rm_Inst));
971             rmInst = NULL;
972         }
973     }
974     return ((Rm_Handle) rmInst);
977 /* FUNCTION PURPOSE: Returns RM version information
978  ***********************************************************************
979  */
980 uint32_t Rm_getVersion (void)
982     return RM_VERSION_ID;
985 /* FUNCTION PURPOSE: Returns RM version string
986  ***********************************************************************
987  */
988 const char* Rm_getVersionStr (void)
990     return rmVersionStr;