64a9dafa2025076d5dcf36341d9835d33e25be30
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**\r
2  *   @file  rm.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.\r
10  * \r
11  *  Redistribution and use in source and binary forms, with or without \r
12  *  modification, are permitted provided that the following conditions \r
13  *  are met:\r
14  *\r
15  *    Redistributions of source code must retain the above copyright \r
16  *    notice, this list of conditions and the following disclaimer.\r
17  *\r
18  *    Redistributions in binary form must reproduce the above copyright\r
19  *    notice, this list of conditions and the following disclaimer in the \r
20  *    documentation and/or other materials provided with the   \r
21  *    distribution.\r
22  *\r
23  *    Neither the name of Texas Instruments Incorporated nor the names of\r
24  *    its contributors may be used to endorse or promote products derived\r
25  *    from this software without specific prior written permission.\r
26  *\r
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38  *\r
39  *  \par\r
40 */\r
41 \r
42 /* RM Types */\r
43 #include <ti/drv/rm/rm_types.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_services.h>\r
48 #include <ti/drv/rm/rm_transport.h>\r
49 #include <ti/drv/rm/rm_policy.h>\r
50 \r
51 /* RM internal includes */\r
52 #include <ti/drv/rm/include/rm_loc.h>\r
53 #include <ti/drv/rm/include/rm_transportloc.h>\r
54 #include <ti/drv/rm/include/rm_servicesloc.h>\r
55 #include <ti/drv/rm/include/rm_nameserverloc.h>\r
56 #include <ti/drv/rm/include/rm_dtb_utilloc.h>\r
57 \r
58 /* RM LIBFDT includes */\r
59 #include <ti/drv/rm/src/libfdt/libfdt.h>\r
60 \r
61 /* RM OSAL layer */\r
62 #include <rm_osal.h>\r
63 \r
64 /**********************************************************************\r
65  ************************** Globals ***********************************\r
66  **********************************************************************/\r
67 #if 0\r
68 /* Place QMSS PDSP permissions array */\r
69 #pragma DATA_SECTION (rmQmssPdspFirmwarePerms, ".rm");\r
70 #pragma DATA_ALIGN (rmQmssPdspFirmwarePerms, 128)\r
71 Rm_Perms rmQmssPdspFirmwarePerms[RM_ALIGN_PERMISSIONS_ARRAY(RM_QMSS_FIRMWARE_PDSPS, Rm_Perms)];\r
72 #endif\r
73 \r
74 char rmIntegerAllocator[] = "integer";\r
75 char rmTreeAllocator[] = "tree";\r
76 \r
77 extern char rmDtbStartingNode[];\r
78 \r
79 /** @brief Global Variable which describes the RM Version Information */\r
80 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
81 \r
82 /**********************************************************************\r
83  ********************** Internal Functions ****************************\r
84  **********************************************************************/\r
85 \r
86 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst)\r
87 {\r
88     Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
89     Rm_Transaction *newTransaction = NULL;\r
90     void *key;\r
91 \r
92     /* Lock access to the RM instance's transaction queue */\r
93     key = Rm_osalMtCsEnter();\r
94 \r
95     /* Get memory for a new transaction from local memory */\r
96     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));\r
97 \r
98     /* Return if the memory allocated for the transaction entry is NULL */\r
99     if (newTransaction == NULL)\r
100     {\r
101         /* Clear the transaction */\r
102         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
103 \r
104         /* Create an ID for the new transaction.  The ID will be used for two purposes:\r
105          * 1) Matching responses from higher level RM agents to requests\r
106          * 2) Provided to the component that requested the service so that it can match its\r
107          *    request with the response it receives via its callback function it provided */\r
108         newTransaction->localId = Rm_transactionGetSequenceNum(rmInst);\r
109         /* New transaction's nextTransaction pointer will always be NULL */\r
110         newTransaction->nextTransaction = NULL;  \r
111 \r
112         /* Check if there are any transactions in the transaction queue */\r
113         if (transactionQueue)\r
114         {\r
115             /* At least one transaction in the transaction queue.  Add the new entry to the \r
116              * end of the transaction queue */\r
117             while (transactionQueue->nextTransaction != NULL)\r
118             {\r
119                 /* Traverse the list until arriving at the last transaction */\r
120                 transactionQueue = transactionQueue->nextTransaction;\r
121             }\r
122 \r
123             /* Add the new transaction to the end of the queue */\r
124             transactionQueue->nextTransaction = newTransaction;\r
125         }\r
126         else\r
127         {\r
128             /* The transaction queue does not currently exist.  The new transaction is the \r
129              * first transaction */\r
130             rmInst->transactionQueue = newTransaction;\r
131         }\r
132     }\r
133 \r
134     Rm_osalMtCsExit(key);\r
135     return (newTransaction);\r
136 }\r
137 \r
138 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
139 {\r
140     Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
141 \r
142     /* Make sure there is at least one transaction in the transaction queue */\r
143     if (transaction != NULL)\r
144     {\r
145         /* Find the transaction ID within the specified RM instance's transaction queue.\r
146          * If the end of the transaction queue is reached without finding the transaction the \r
147          * transaction pointer will be NULL */\r
148         while (transaction != NULL)\r
149         {\r
150             if (transaction->localId == transactionId)\r
151             {\r
152                 /* Match: break out of loop and return the transaction */\r
153                 break;             \r
154             }\r
155             transaction = transaction->nextTransaction;\r
156         }\r
157     }\r
158 \r
159     return (transaction);\r
160 }\r
161 \r
162 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
163 {\r
164     Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
165     Rm_Transaction *prevTransaction = NULL;\r
166     int32_t retVal = RM_SERVICE_STATE_OKAY;\r
167     void *key;\r
168 \r
169     /* Lock access to the RM instance's transaction queue */\r
170     key = Rm_osalMtCsEnter();\r
171 \r
172     /* Find the transaction ID within the specified RM instance's transaction queue. */\r
173     while (transaction != NULL)\r
174     {\r
175         if (transaction->localId == transactionId)\r
176         {\r
177             /* Match: break out of loop and delete the transaction */\r
178             break;             \r
179         }\r
180 \r
181         prevTransaction = transaction;\r
182         transaction = transaction->nextTransaction;\r
183     }\r
184 \r
185     /* Traversed entire queue but did not find transaction */\r
186     if (transaction == NULL)\r
187     {\r
188         retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST;\r
189     }\r
190     else\r
191     {\r
192         /* Delete the transaction */\r
193         if ((prevTransaction == NULL) && transaction->nextTransaction)\r
194         {\r
195             /* Transaction to be deleted exists at start of transaction queue.  Map second\r
196              * transaction to be start of transaction queue as long as there are more than\r
197              * one transactions. */\r
198             rmInst->transactionQueue = transaction->nextTransaction;\r
199         }\r
200         else\r
201         {\r
202             /* Transaction to be deleted is in the middle or at end of the queue.  Adjust \r
203              * adjacent transaction pointers.  This covers the case where the transaction to be \r
204              * removed is at the end of the queue. */\r
205             prevTransaction->nextTransaction = transaction->nextTransaction;\r
206         }\r
207 \r
208         /* Free the memory associated with the transaction. */\r
209         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));\r
210     }\r
211 \r
212     Rm_osalMtCsExit(key);\r
213     return (retVal);\r
214 }\r
215 \r
216 uint32_t Rm_transactionInitSequenceNum(void)\r
217 {\r
218     /* Sequence number can never have a value of zero so that there are no conflicts\r
219      * with transactions that have a remoteOriginatingId of zero */\r
220     return (1);\r
221 }\r
222 \r
223 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
224 {\r
225     uint32_t sequenceNum = 0;\r
226 \r
227     /* Get the next sequence number and then increment.  If there's an overflow\r
228      * assign the initial value instead of incrementing. */\r
229     if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum)\r
230     {\r
231         /* Overflow */\r
232         sequenceNum = rmInst->transactionSeqNum;\r
233         rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
234     }\r
235     else\r
236     {\r
237         sequenceNum = rmInst->transactionSeqNum++;\r
238     }    \r
239 \r
240     return (sequenceNum);\r
241 }\r
242 \r
243 /* Function used to send RM response transactions to lower level agents */\r
244 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
245 {\r
246     Rm_TransportNode *dstTransportNode = NULL;\r
247     Rm_Packet *rmPkt = NULL;\r
248 \r
249     /* Find the transport for the RM instance that sent the request. */\r
250     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
251 \r
252     /* Create a RM packet using the service information */\r
253     switch (transaction->type)\r
254     {\r
255         case Rm_service_RESOURCE_ALLOCATE:\r
256         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
257         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
258         case Rm_service_RESOURCE_FREE:\r
259         case Rm_service_RESOURCE_BLOCK_FREE:\r
260         case Rm_service_RESOURCE_FREE_BY_NAME:\r
261             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
262                                                           transaction);\r
263             break;\r
264         case Rm_service_RESOURCE_MAP_TO_NAME:\r
265         case Rm_service_RESOURCE_UNMAP_NAME:\r
266             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
267                                                     transaction);\r
268             break;\r
269         default:\r
270             /* Invalid service type.  Flag the error and return */\r
271             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
272             break;\r
273     }\r
274 \r
275     if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
276     {\r
277         /* Delete the transaction and return immediately because an error occurred \r
278          * allocating the packet */\r
279         Rm_transactionQueueDelete(rmInst, transaction->localId);\r
280         return;\r
281     }\r
282 \r
283     /* Send the RM packet to the application transport */\r
284     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
285     {\r
286         /* Negative value returned by transport send.  An error occurred\r
287          * in the transport while attempting to send the packet.*/\r
288         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
289         /* Clean up the packet */\r
290         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
291         {\r
292             /* Non-NULL value returned by transport packet free. Flag the\r
293              * error */\r
294             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
295         }\r
296         return;\r
297     }\r
298 \r
299     /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD.  CREATE\r
300      * NEW TRANSACTION WITH DATA FROM ORIGINAL?  THEN TRY TO SEND FAILED REQUEST BACK\r
301      * TO REQUESTER???  KEEP RETRYING SEND OF RESPONSE??? */\r
302 \r
303     /* Delete the transaction */\r
304     Rm_transactionQueueDelete(rmInst, transaction->localId);\r
305 }\r
306 \r
307 Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName, Rm_AllocatorType type)\r
308 {\r
309     Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators;\r
310     Rm_Allocator *newAllocator = NULL;\r
311     void *key;\r
312 \r
313     /* Lock access to the RM instance's allocator list */\r
314     key = Rm_osalMtCsEnter();\r
315 \r
316     /* Get memory for a new allocator from local memory */\r
317     newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
318 \r
319     /* Return if the memory allocated for the allocator is NULL */\r
320     if (newAllocator != NULL)\r
321     {\r
322         /* Clear the allocator */\r
323         memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
324 \r
325         /* Populate the allocator */\r
326         newAllocator->type = type;\r
327         strcpy(newAllocator->resourceName, resourceName);\r
328         /* allocator's root entry will be created by the invoking function */\r
329         newAllocator->allocatorRootEntry = NULL;\r
330         /* New allocator's nextAllocator pointer will always be NULL */\r
331         newAllocator->nextAllocator = NULL;  \r
332 \r
333         /* Check if there are any allocators in the allocator list */\r
334         if (allocators)\r
335         {\r
336             /* At least one allocator in the allocator list.  Add the new allocator to the \r
337              * end of the allocator list */\r
338             while (allocators->nextAllocator != NULL)\r
339             {\r
340                 /* Traverse the list until arriving at the last allocator */\r
341                 allocators = allocators->nextAllocator;\r
342             }\r
343 \r
344             /* Add the new allocator to the end of the list */\r
345             allocators->nextAllocator = newAllocator;\r
346         }\r
347         else\r
348         {\r
349             /* The allocator list does not currently exist.  The new allocator is the \r
350              * first allocator */\r
351             rmInst->allocators = newAllocator;\r
352         }\r
353     }\r
354 \r
355     Rm_osalMtCsExit(key);\r
356     return (newAllocator);\r
357 }\r
358 \r
359 int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
360 {\r
361     Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
362     Rm_Allocator *prevAllocator = NULL;\r
363     int32_t retVal = RM_SERVICE_STATE_OKAY;\r
364     void *key;\r
365 \r
366     /* Lock access to the RM instance's allocator list */\r
367     key = Rm_osalMtCsEnter();\r
368 \r
369     /* Find the resource within the specified RM instance's allocator list. */\r
370     while (allocator != NULL)\r
371     {\r
372         if (strcmp(allocator->resourceName, resourceName) == 0)\r
373         {\r
374             /* Match: break out of loop and delete the transaction */\r
375             break;             \r
376         }\r
377 \r
378         prevAllocator = allocator;\r
379         allocator = allocator->nextAllocator;\r
380     }\r
381 \r
382     /* Traversed entire list but did not find allocator. */\r
383     if (allocator == NULL)\r
384     {\r
385         retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
386     }\r
387     else\r
388     {\r
389         /* Delete the allocator */\r
390         if ((prevAllocator == NULL) && allocator->nextAllocator)\r
391         {\r
392             /* Allocator to be deleted exists at start of allocator list.  Map second\r
393              * allocator to be start of allocator list as long as there are more than\r
394              * one allocators. */\r
395             rmInst->allocators = allocator->nextAllocator;\r
396         }\r
397         else\r
398         {\r
399             /* Allocator to be deleted is in the middle or at end of the list.  Adjust \r
400              * adjacent allocator pointers.  This covers the case where the allocator to be \r
401              * removed is at the end of the list. */\r
402             prevAllocator->nextAllocator = allocator->nextAllocator;\r
403         }\r
404 \r
405         /* Free the memory associated with the allocator. */\r
406         Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
407     }\r
408 \r
409     Rm_osalMtCsExit(key);\r
410     return (retVal);\r
411 }\r
412 \r
413 int32_t Rm_createIntegerAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
414 {\r
415     Rm_Allocator *allocator = NULL;\r
416     Rm_ResourceRange *rangeBasePtr = range;\r
417     Rm_IntegerAllocatorRootEntry *intRootEntry = NULL;\r
418     uint16_t i, entryIndex;\r
419 \r
420     /* Create the new base integer allocator */\r
421     allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_INTEGER);\r
422 \r
423     /* Construct the integer allocator root entry */\r
424     intRootEntry = Rm_osalMalloc(sizeof(Rm_IntegerAllocatorRootEntry));\r
425     intRootEntry->numResourceElements = 0;\r
426 \r
427     /* Get the number of entries to allocate based on the lengths in the ranges */\r
428     while (range != NULL)\r
429     {\r
430         intRootEntry->numResourceElements += range->length;\r
431         range = range->nextRange;\r
432     }\r
433 \r
434     /* Initialize the entries using the range information */\r
435     if (intRootEntry->numResourceElements)\r
436     {\r
437         intRootEntry->resourceArrayBase = Rm_osalMalloc(sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
438         memset((void *)intRootEntry->resourceArrayBase, 0, sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
439 \r
440         /* Reset the range pointer */\r
441         range = rangeBasePtr;\r
442         entryIndex = 0;\r
443 \r
444         while (range != NULL)\r
445         {\r
446             /* Initialize each entry */\r
447             for (i = range->base; i < (range->base + range->length); i++, entryIndex++)\r
448             {\r
449                 intRootEntry->resourceArrayBase[entryIndex].value = i;\r
450             }\r
451             \r
452             range = range->nextRange;\r
453         }\r
454         \r
455         allocator->allocatorRootEntry = intRootEntry;\r
456     }\r
457     else\r
458     {\r
459         /* No resource entries were created.  Free the memory associated with the\r
460          * allocator and the root entry */\r
461         Rm_osalFree((void *)intRootEntry, sizeof(Rm_IntegerAllocatorRootEntry));\r
462         Rm_allocatorDelete(rmInst, allocator->resourceName);\r
463     }\r
464 \r
465     return(0);  /* TODO: FIX THIS RETURN */\r
466 }\r
467 \r
468 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
469                                   Rm_ResourceProperties *resourceProperties)\r
470 {\r
471     char *allocatorType = NULL;\r
472     Rm_ResourceRange *range = NULL;\r
473     Rm_ResourceRange *rangeBasePtr = NULL;\r
474     Rm_NsAssignment *nsAssignments = NULL;\r
475     Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
476     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
477 \r
478     /* TODO: NEED CHECKS FOR VALIDITY OF ALL THE resourceProperties FIELDS */\r
479 \r
480     /* Extract the resource properties from the DTB */\r
481     allocatorType = Rm_resourceExtractResourceAllocator(resourceProperties->allocatorData, \r
482                                                         resourceProperties->allocatorLen);\r
483     range = rangeBasePtr = Rm_resourceExtractResourceRange(resourceProperties->rangeData, \r
484                                                            resourceProperties->rangeLen);\r
485 \r
486     /* Create an allocator based on the allocator type specified */\r
487     if (strcmp(allocatorType, &rmIntegerAllocator[0]) == 0)\r
488     {\r
489         /* Create an integer allocator using the resource properties */\r
490         retVal = Rm_createIntegerAllocator(rmInst, resourceName, range);        \r
491     }\r
492     else if (strcmp(allocatorType, &rmTreeAllocator[0]) == 0)\r
493     {\r
494         /* Create a tree allocator using the resource properties */\r
495     }\r
496     else\r
497     {\r
498         /* Allocator type not recognized.  Free the resource properties and return */\r
499         retVal = -21; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
500     }\r
501     \r
502     if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
503     {\r
504         /* Create entries in the NameServer if any NameServer assignments were specified */\r
505         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
506         {\r
507             nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
508                                                            resourceProperties->nsAssignLen);\r
509 \r
510             /* Cycle through the list of assignments and add them to the NameServer */\r
511             nsAssignmentBasePtr = nsAssignments;\r
512             while (nsAssignments)\r
513             {\r
514                 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
515                 Rm_nsAddObject(rmInst, nsAssignments->nsName, nsAssignments->resourceValue);\r
516                 nsAssignments = nsAssignments->nextNsAssignment;\r
517             }\r
518             /* Free the memory allocated for the NameServer assignments */\r
519             Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
520         }\r
521     }\r
522 \r
523     /* Free the memory allocated for the resource properties */\r
524     Rm_resourceFreeResourceAllocator(allocatorType);\r
525     Rm_resourceFreeResourceRange(rangeBasePtr);\r
526 \r
527     return(retVal);\r
528 }\r
529 \r
530 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
531 {\r
532         int32_t propertyLen;\r
533         const char *propertyName;\r
534         const void *propertyData;\r
535     Rm_ResourcePropType propertyType;\r
536     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
537 \r
538     /* Get the property data and store it in the corresponding propertyInfo field */\r
539         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
540     if (propertyData)\r
541     {\r
542         propertyType = Rm_resourceGetPropertyType(propertyName);\r
543         if (propertyType == Rm_resourcePropType_RESOURCE_ALLOCATOR)\r
544         {\r
545             if (propertyInfo->allocatorData || propertyInfo->allocatorLen)\r
546             {\r
547                 /* The allocator fields have already been populated.  Return an error.\r
548                  * The resource list has specified a property field more than once\r
549                  * for a resource node */\r
550                 retVal = -17; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
551             }\r
552             else\r
553             {\r
554                 propertyInfo->allocatorData = propertyData;\r
555                 propertyInfo->allocatorLen = propertyLen;\r
556             }\r
557         }\r
558         else if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
559         {\r
560             if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
561             {\r
562                 /* The range fields have already been populated.  Return an error.\r
563                  * The resource list has specified a property field more than once\r
564                  * for a resource node */\r
565                 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
566             }\r
567             else\r
568             {\r
569                 propertyInfo->rangeData = propertyData;\r
570                 propertyInfo->rangeLen = propertyLen;\r
571             }\r
572         }\r
573         else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
574         {\r
575             if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
576             {\r
577                 /* The nsAssign fields have already been populated.  Return an error.\r
578                  * The resource list has specified a property field more than once\r
579                  * for a resource node */\r
580                 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
581             }\r
582             else\r
583             {\r
584                 propertyInfo->nsAssignData = propertyData;\r
585                 propertyInfo->nsAssignLen = propertyLen;\r
586             }\r
587         }\r
588         else\r
589         {\r
590             retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
591         }\r
592     }\r
593     else\r
594     {\r
595         retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
596     }\r
597 \r
598     /* Don't get anymore properties if error occurred */\r
599     if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
600     {\r
601         offset = fdt_next_property_offset(globalResourceDtb, offset);\r
602         if (offset >= 0)\r
603         {\r
604             retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
605         }\r
606         else if (offset != -FDT_ERR_NOTFOUND)\r
607         {\r
608             /* Error was returned by LIBFDT when parsing the properties */\r
609             retVal = offset;\r
610         }\r
611     }\r
612     \r
613     return (retVal);\r
614 }\r
615 \r
616 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth)\r
617 {\r
618         const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
619     Rm_ResourceProperties resourceProperties;\r
620         int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
621         int32_t offset;\r
622 \r
623     /* Initialize the resource properties structure */\r
624     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
625 \r
626     /* Ignore properties of the base node */\r
627     if (strcmp(resourceName, rmDtbStartingNode))\r
628     {\r
629         /* Get the properties for the resource node if any exist */\r
630         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
631         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
632         {\r
633             /* Since at least one property exists attempt to parse the property nodes and \r
634              * use them to create and initialize a resource allocator */\r
635                 error =  Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
636             if (error < -FDT_ERR_NOTFOUND)\r
637             {\r
638                 return (error);\r
639             }\r
640             \r
641             /* Initialize an allocator with the resource properties if no error was returned */\r
642             Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties);\r
643         }\r
644         else if (offset != -FDT_ERR_NOTFOUND)\r
645         {\r
646                 /* Error was returned by LIBFDT when parsing the properties */\r
647             return (offset);\r
648         }\r
649     }\r
650     \r
651     /* Get the next resource node */\r
652         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
653     /* Check the offset and depth of the next node to make sure the current node\r
654      * wasn't the last node in the Resource List.  A depth less than the depth set\r
655      * at the start of the recursion will signal the end of the resource list */\r
656     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
657     {\r
658         error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth);\r
659         if (error < -FDT_ERR_NOTFOUND)\r
660         {\r
661             return (error);\r
662         }\r
663     }\r
664     else if (offset != -FDT_ERR_NOTFOUND)\r
665     {\r
666         /* Error was returned by LIBFDT when parsing the nodes */\r
667         return (offset);\r
668     }\r
669 \r
670     return (RM_DTB_UTIL_RESULT_OKAY);\r
671 }\r
672 \r
673 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb)\r
674 {\r
675     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
676     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
677     int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
678 \r
679     /* Recursively parse the Global Resource List, creating an allocator for\r
680      * each resource as specified in the node */\r
681     result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth);\r
682 \r
683     return(result);\r
684 }\r
685          \r
686 int32_t Rm_reserveLinuxResources(void *linuxResourceDtb)\r
687 {\r
688     return(0);\r
689 \r
690 }\r
691 \r
692 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
693 {\r
694     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
695     {\r
696 #if 0        \r
697         /* Check local policy to see if the request can be satisfied with the\r
698          * resources stored locally */\r
699         Rm_policy...API()\r
700 \r
701         if (policy check approves the resource)\r
702         {\r
703             /* call the allocator to allocate the resource */\r
704             if (allocator returns resource)\r
705             {\r
706                 /* Populate the transaction with the allocated resources and the result */\r
707                 transaction->state = approve reason;\r
708                 return ...\r
709             }\r
710             else\r
711             {\r
712                 /* allocator ran out of resources, need to contact Server for more\r
713                  * resources */\r
714                 Rm_resourcePoolModRequest(...);\r
715             }\r
716         }\r
717         else if (policy check denies resource)\r
718         {\r
719             /* Policy check denied resource. */\r
720             transaction->state= deny reason;\r
721             return ...\r
722         }\r
723         else if (policy check says forward to Server for validation)\r
724         {\r
725             /* Forward the transaction to the Server */\r
726             Rm_transactionForwarder(rmInst, transaction);\r
727         }\r
728 #endif         \r
729     }\r
730     else if (rmInst->instType == Rm_instType_SERVER)\r
731     {\r
732 #if 0        \r
733         /* Check global policy to see if resource can be allocated. return result\r
734          * no matter what */\r
735         Rm_policy...API()\r
736 \r
737         if (policy approves)\r
738         {\r
739             /* call allocator to allocate resource */\r
740         }\r
741 \r
742         transaction->state = approve or deny reason;\r
743         transaction->resourceInfo.base = ...;\r
744         transaction->resourceInfo.range = ...;\r
745 \r
746         /* If source instance name does not match the current instance\r
747          * name the allocation request came from a Client.  The result\r
748          * must be sent back to the Client */\r
749         if (strcmp(transaction->sourceInstName, rmInst->name))\r
750         {\r
751             /* Names don't match.  Send the transaction back to the Client */\r
752             Rm_transactionResponder(rmInst, transaction);\r
753         }\r
754         else\r
755         {\r
756             /* Resource allocation request originated locally on the active\r
757              * instance. Send the response via the service responder. */          \r
758             Rm_serviceResponder(rmInst, transaction);                            \r
759         }\r
760 #endif        \r
761     }   \r
762 }\r
763 \r
764 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
765 {\r
766     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
767     {\r
768 #if 0        \r
769         /* Check local policy to see if the request can be satisfied with the\r
770          * resources stored locally */\r
771         Rm_policy...API()\r
772 \r
773         if (policy check approves the free)\r
774         {\r
775             /* call the allocator to free the resource */\r
776             /* Run a resource pool check to see if the free combined a resource block\r
777              * that can be returned to the server */\r
778             if (resource block has been combined)\r
779             {\r
780                   /* allocator ran out of resources, need to contact Server for more\r
781                  * resources */\r
782                 Rm_resourcePoolModRequest(free pool block to server...);\r
783             }\r
784             else\r
785             {\r
786                 /* Populate the receipt with the freed resources and the result */\r
787                 transaction->state = approve reason;\r
788                 return ...\r
789             }\r
790         }\r
791         else if (policy check denies resource free)\r
792         {\r
793             /* Policy check denied resource. */\r
794             transaction->state = deny reason;\r
795             return ...\r
796         }\r
797         else if (policy check says forward to Server for validation)\r
798         {\r
799             /* Forward the transaction to the Server */\r
800             Rm_transactionForwarder(rmInst, transaction);\r
801         }\r
802 #endif         \r
803     }\r
804     else if (rmInst->instType == Rm_instType_SERVER)\r
805     {\r
806 #if 0        \r
807         /* Check global policy to see if resource can be freed. return result\r
808          * no matter what */\r
809         Rm_policy...API()\r
810         if (policy approves)\r
811         {\r
812             /* call allocator to free resources */\r
813         }\r
814             \r
815         transaction->state = approve or deny reason;\r
816         transaction->resourceInfo.base = ...;\r
817         transaction->resourceInfo.range = ...;\r
818 \r
819         /* If source instance name does not match the current instance\r
820          * name the allocation request came from a client.  The result\r
821          * must be sent back to the Client */\r
822         if (strcmp(transaction->sourceInstName, rmInst->name))\r
823         {\r
824             /* Names don't match.  Send the transaction back to the Client Delegate or Client */\r
825             Rm_transactionResponder(rmInst, transaction);\r
826         }\r
827         else\r
828         {\r
829             /* Resource allocation request originated locally on the active\r
830              * instance. Send the response via the service responder. */\r
831             Rm_serviceResponder(rmInst, transaction);                            \r
832         }\r
833 #endif        \r
834     }   \r
835 }\r
836 \r
837 /* Function used to forward RM transactions to higher level agents */\r
838 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
839 {\r
840     Rm_TransportNode *dstTransportNode = NULL;\r
841     Rm_Packet *rmPkt = NULL;\r
842 \r
843     /* Make sure the RM instance has a transport registered with a higher level agent */\r
844     if (rmInst->registeredWithDelegateOrServer == false)\r
845     {\r
846         transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
847         return;\r
848     }\r
849 \r
850     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
851      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
852      * Delegates will be connected to a Server. */\r
853     if (rmInst->instType == Rm_instType_CLIENT)\r
854     {\r
855         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
856     } \r
857     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
858     {\r
859         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
860     }\r
861 \r
862     /* Create a RM packet using the service information */\r
863     switch (transaction->type)\r
864     {\r
865         case Rm_service_RESOURCE_ALLOCATE:\r
866         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
867         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
868         case Rm_service_RESOURCE_FREE:\r
869         case Rm_service_RESOURCE_BLOCK_FREE:\r
870         case Rm_service_RESOURCE_FREE_BY_NAME:\r
871             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
872                                                      transaction);\r
873             break;\r
874         case Rm_service_RESOURCE_MAP_TO_NAME:\r
875         case Rm_service_RESOURCE_UNMAP_NAME:\r
876             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
877                                                    transaction);\r
878             break;\r
879         default:\r
880             /* Invalid service type.  Flag the error and return */\r
881             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
882             break;\r
883     }\r
884 \r
885     if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
886     {\r
887         /* Return immediately because an error occurred allocating the packet */\r
888         return;\r
889     }\r
890 \r
891     /* Send the RM packet to the application transport */\r
892     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
893     {\r
894         /* Negative value returned by transport send.  An error occurred\r
895          * in the transport while attempting to send the packet.*/\r
896         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
897         /* Clean up the packet */\r
898         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
899         {\r
900             /* Non-NULL value returned by transport packet free. Flag the\r
901              * error */\r
902             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
903         }\r
904         return;\r
905     }\r
906 \r
907     /* Transaction is not deleted because it is awaiting a response from the higher level\r
908      * RM instance */\r
909 }\r
910 \r
911 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
912 {\r
913     /* Handle auto-forwarded transactions.  These transactions include:\r
914      * - All request transactions received on Clients are forwarded to the Client Delegate\r
915      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
916     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
917         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
918          (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
919          (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
920     {\r
921         /* Check if the transaction is a transaction that received a response to its\r
922          * request. */\r
923         if (transaction->state != RM_SERVICE_PROCESSING)\r
924         {\r
925 \r
926             /* A transaction has received a response. Send the response to either the \r
927              * transaction or service responder based on the source instance */\r
928             if (strcmp(transaction->sourceInstName, rmInst->name))\r
929             {\r
930                 /* Transaction originated from another instance.  Use the \r
931                  * transaction responder to send the result to the source instance.  This\r
932                  * is not possible on RM Clients since they can't forward RM services */\r
933                 Rm_transactionResponder(rmInst, transaction);\r
934             }\r
935             else\r
936             {\r
937                 /* Transaction originated on this instance.  Send to the\r
938                  * service responder */\r
939                 Rm_serviceResponder(rmInst, transaction);\r
940             }\r
941         }\r
942         else\r
943         {\r
944             /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
945             Rm_transactionForwarder(rmInst, transaction);\r
946         }\r
947     }\r
948     else\r
949     {\r
950         /* Client Delegate and Server transaction processors. */\r
951         switch (transaction->type)\r
952         {\r
953             case Rm_service_RESOURCE_ALLOCATE:\r
954             case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
955             case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
956             case Rm_service_RESOURCE_FREE:\r
957             case Rm_service_RESOURCE_BLOCK_FREE:\r
958             case Rm_service_RESOURCE_FREE_BY_NAME:                \r
959                 /* Check if the transaction is fulfilled request */\r
960                 if (transaction->state != RM_SERVICE_PROCESSING)\r
961                 {\r
962                     /* If source instance name does not match the current instance\r
963                      * name the allocation request came from a client.  The result\r
964                      * must be sent back to the Client */\r
965                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
966                     {\r
967                         Rm_transactionResponder(rmInst, transaction);\r
968                     }\r
969                     else\r
970                     {\r
971                         /* Resource allocation request originated locally.  Send the response\r
972                          * via the service responder. */\r
973                         Rm_serviceResponder(rmInst, transaction);      \r
974                     }\r
975                 }\r
976                 else\r
977                 {\r
978                     /* This is a new transaction request originating from an RM instance with fewer\r
979                      * allocate/free privileges.  Run the allocation or free handler to see if the resource\r
980                      * request can be handled locally or if it needs to be forwarded to a higher level\r
981                      * agent */\r
982                     if ((transaction->type == Rm_service_RESOURCE_ALLOCATE) ||\r
983                         (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) ||\r
984                         (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))\r
985                     {\r
986                         Rm_allocationHandler(rmInst, transaction);\r
987                     }\r
988                     else\r
989                     {\r
990                         Rm_freeHandler(rmInst, transaction);\r
991                     }\r
992                 }\r
993                 break;\r
994             case Rm_service_RESOURCE_MAP_TO_NAME:\r
995             case Rm_service_RESOURCE_UNMAP_NAME:                \r
996                 /* Server is the only RM instance capable of adding NameServer objects */\r
997                 if (rmInst->instType == Rm_instType_SERVER)\r
998                 {\r
999                     if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
1000                     {\r
1001                         /* Create a new NameServer object with the request transaction information.\r
1002                          * Transaction will contain the state result of the NameServer addition. */\r
1003                         if (Rm_nsAddObject(rmInst, transaction->resourceInfo.nsName,\r
1004                                            transaction->resourceInfo.base) == RM_NS_ACTION_APPROVED)\r
1005                         {\r
1006                             transaction->state = RM_SERVICE_APPROVED;\r
1007                         }\r
1008                         else\r
1009                         {\r
1010                             /* TEMP: UPDATE THIS STATE VALUE */\r
1011                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1012                         }\r
1013                     }\r
1014                     else\r
1015                     {\r
1016                         /* Delete an existing NameServer object with the request transaction information\r
1017                          * Transaction will contain the state result of the NameServer addition. */\r
1018                         if (Rm_nsDeleteObject(rmInst, transaction->resourceInfo.nsName) == \r
1019                             RM_NS_ACTION_APPROVED)\r
1020                         {\r
1021                             transaction->state = RM_SERVICE_APPROVED;\r
1022                         }\r
1023                         else\r
1024                         {\r
1025                             /* TEMP: UPDATE THIS STATE VALUE */\r
1026                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1027                         }\r
1028                     }\r
1029 \r
1030                     /* If source instance name does not match the local instance\r
1031                      * name the NameServer request came from a Client or Client Delegate.  The \r
1032                      * result must be sent back to the Client or Client Delegate.  Just return if it does\r
1033                      * match since the NameServer transaction result can be returned immediately by the\r
1034                      * Rm_serviceHandler. */\r
1035                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
1036                     {\r
1037                         Rm_transactionResponder(rmInst, transaction);\r
1038                     }\r
1039                 }\r
1040                 else\r
1041                 {\r
1042                     transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1043                 }\r
1044                 break;\r
1045         }\r
1046     }\r
1047 }\r
1048 \r
1049 /**********************************************************************\r
1050  ********************** Application visible APIs **********************\r
1051  **********************************************************************/\r
1052 \r
1053 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
1054 {\r
1055     Rm_Inst *rmInst;\r
1056     void *globalResourceDtb = NULL;\r
1057     void *linuxResourceDtb = NULL;\r
1058 \r
1059     /* Instance creation checks.  Add one to strlen calculation for null character */\r
1060     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
1061     {\r
1062         /* Failure: Instance name is too big */\r
1063         return (NULL);\r
1064     }\r
1065     \r
1066     /* Get memory for RM instance from local memory */\r
1067     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
1068     /* Populate instance based on input parameters */\r
1069     strcpy (&rmInst->name[0], initCfg->instName);\r
1070     rmInst->instType = initCfg->instType;\r
1071     rmInst->registeredWithDelegateOrServer = false;\r
1072     rmInst->policyDtb = NULL;\r
1073 \r
1074     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
1075      * nodes will be created when the application registers transports */\r
1076     rmInst->routeMap = NULL;\r
1077 \r
1078     /* Initialize the allocators linked list pointer to NULL.  The linked list nodes will\r
1079      * be created on the Server instance when the application reads in the resource list.\r
1080      * Nodes will also be created on Client Delegates when blocks of resources are requested\r
1081      * for allocation to clients. */\r
1082     rmInst->allocators = NULL;\r
1083 \r
1084     /* Initialize the transaction queue elements. */\r
1085     rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
1086     rmInst->transactionQueue= NULL;\r
1087 \r
1088     /* RM Server specific actions */\r
1089     if (rmInst->instType == Rm_instType_SERVER)\r
1090     {\r
1091         /* Open the ResourceList file and provide it to the resource initializer. */\r
1092         if (initCfg->globalResourceList)\r
1093         {\r
1094             globalResourceDtb = initCfg->globalResourceList;\r
1095             fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));            \r
1096             Rm_initializeAllocators(rmInst, globalResourceDtb);\r
1097         }\r
1098 \r
1099         /* Parse the Linux DTB for the resources reserved by the Linux kernel.  These resources\r
1100          * will be marked as used in the resource allocators. */\r
1101         if (initCfg->linuxDtb)\r
1102         {\r
1103             linuxResourceDtb = initCfg->linuxDtb;\r
1104             fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));            \r
1105             Rm_reserveLinuxResources(linuxResourceDtb);\r
1106         }\r
1107     }\r
1108 \r
1109     /* Instance startup policies are only used for Servers and Client Delegates */\r
1110     if (rmInst->instType != Rm_instType_CLIENT)\r
1111     {\r
1112         /* Open the instance's policy and store it */\r
1113         if (initCfg->startupPolicy)\r
1114         {\r
1115             rmInst->policyDtb = initCfg->startupPolicy;\r
1116             fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb));  \r
1117         }\r
1118 \r
1119         /* Store policy via policy APIs ... */\r
1120     }\r
1121 \r
1122     /* Return the RM Handle */\r
1123     return ((Rm_Handle) rmInst);\r
1124 }\r
1125 \r
1126 uint32_t Rm_getVersion (void)\r
1127 {\r
1128     return RM_VERSION_ID;\r
1129 }\r
1130 \r
1131 \r
1132 const char* Rm_getVersionStr (void)\r
1133 {\r
1134     return rmVersionStr;\r
1135 }\r
1136 \r
1137 /**\r
1138 @}\r
1139 */\r