c108bf6c58d4a978b52367f0802715634bd2fe63
[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 #include <ti/drv/rm/include/rm_policyloc.h>\r
58 \r
59 /* RM LIBFDT includes */\r
60 #include <ti/drv/rm/src/libfdt/libfdt.h>\r
61 \r
62 /* AVL BBST includes */\r
63 #include <ti/drv/rm/include/tree.h>\r
64 \r
65 /* RM OSAL layer */\r
66 #include <rm_osal.h>\r
67 \r
68 /**********************************************************************\r
69  ************************** Globals ***********************************\r
70  **********************************************************************/\r
71 extern char rmDtbStartingNode[];\r
72 \r
73 /** @brief Global Variable which describes the RM Version Information */\r
74 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
75 \r
76 /**********************************************************************\r
77  ************** Red-Black BBST Tree Allocator Functions ***************\r
78  **********************************************************************/\r
79 \r
80 \r
81 Rm_ResourceNode *Rm_newResourceNode(uint32_t resourceBase, uint32_t resourceLength)\r
82 {\r
83     Rm_ResourceNode *newNode = NULL;\r
84 \r
85     newNode = Rm_osalMalloc(sizeof(Rm_ResourceNode));\r
86     memset((void *)newNode, 0, sizeof(Rm_ResourceNode));\r
87 \r
88     newNode->base = resourceBase;\r
89     newNode->length = resourceLength;\r
90     newNode->allocationCount = 0;\r
91     newNode->allocatedTo = NULL;\r
92 \r
93     return(newNode);\r
94 }\r
95 \r
96 void Rm_freeResourceNode(Rm_ResourceNode *node)\r
97 {\r
98     if (node->allocationCount == 0) {\r
99         Rm_osalFree((void *)node, sizeof(Rm_ResourceNode));\r
100     }\r
101 }\r
102 \r
103 /* Prototype for tree node comparison function\r
104  * element1 < element2 --> return < 0\r
105  * element1 = element2 --> return 0\r
106  * element1 > element2 --> return > 0 */\r
107 int Rm_ResourceNodeCompare(Rm_ResourceNode *element1, Rm_ResourceNode *element2)\r
108 {\r
109     uint32_t element1End = element1->base + element1->length - 1;\r
110     uint32_t element2End = element2->base + element2->length - 1;\r
111 \r
112     if (element1End < element2->base) {\r
113         /* End of element1 range is less than the start of element2's range.  Return a negative\r
114          * value */\r
115         return (-1);\r
116     }\r
117     else if (element1->base > element2End) {\r
118         /* Start of element1 range is after end of element2's range.  Return a positive value */\r
119         return (1);\r
120     }\r
121     else {\r
122         /* If neither of the latter conditions were satisfied there is some overlap between\r
123          * element1 and element2.  Return 0 since the application must handle this overlap. */\r
124         return (0);\r
125     }\r
126 }\r
127 \r
128 /* Generate the red-black tree manipulation functions */\r
129 RB_GENERATE(_Rm_ResourceTree, _Rm_ResourceNode, linkage, Rm_ResourceNodeCompare);\r
130 \r
131 /**********************************************************************\r
132  ********************** Internal Functions ****************************\r
133  **********************************************************************/\r
134 \r
135 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst)\r
136 {\r
137     Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
138     Rm_Transaction *newTransaction   = NULL;\r
139     void           *key;\r
140 \r
141     /* Lock access to the RM instance's transaction queue */\r
142     key = Rm_osalMtCsEnter();\r
143 \r
144     /* Get memory for a new transaction from local memory */\r
145     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));\r
146 \r
147     /* Return if the memory allocated for the transaction entry is NULL */\r
148     if (newTransaction != NULL) {\r
149         /* Clear the transaction */\r
150         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
151 \r
152         /* Create an ID for the new transaction.  The ID will be used for two purposes:\r
153          * 1) Matching responses from higher level RM agents to requests\r
154          * 2) Provided to the component that requested the service so that it can match its\r
155          *    request with the response it receives via its callback function it provided */\r
156         newTransaction->localId = Rm_transactionGetSequenceNum(rmInst);\r
157         /* New transaction's nextTransaction pointer will always be NULL */\r
158         newTransaction->nextTransaction = NULL;  \r
159 \r
160         /* Check if there are any transactions in the transaction queue */\r
161         if (transactionQueue) {\r
162             /* At least one transaction in the transaction queue.  Add the new entry to the \r
163              * end of the transaction queue */\r
164             while (transactionQueue->nextTransaction != NULL) {\r
165                 /* Traverse the list until arriving at the last transaction */\r
166                 transactionQueue = transactionQueue->nextTransaction;\r
167             }\r
168 \r
169             /* Add the new transaction to the end of the queue */\r
170             transactionQueue->nextTransaction = newTransaction;\r
171         }\r
172         else {\r
173             /* The transaction queue does not currently exist.  The new transaction is the \r
174              * first transaction */\r
175             rmInst->transactionQueue = newTransaction;\r
176         }\r
177     }\r
178 \r
179     Rm_osalMtCsExit(key);\r
180     return (newTransaction);\r
181 }\r
182 \r
183 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
184 {\r
185     Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
186 \r
187     if (transaction != NULL) {\r
188         while (transaction != NULL) {\r
189             if (transaction->localId == transactionId) {\r
190                 break;             \r
191             }\r
192             transaction = transaction->nextTransaction;\r
193         }\r
194     }\r
195     return (transaction);\r
196 }\r
197 \r
198 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
199 {\r
200     Rm_Transaction *transaction     = (Rm_Transaction *) rmInst->transactionQueue;\r
201     Rm_Transaction *prevTransaction = NULL;\r
202     int32_t         retVal          = RM_SERVICE_STATE_OKAY;\r
203     void           *key;\r
204 \r
205     /* Lock access to the instance */\r
206     key = Rm_osalMtCsEnter();\r
207 \r
208     /* Find transaction ID within transaction queue. */\r
209     while (transaction) {\r
210         if (transaction->localId == transactionId) {\r
211             break;             \r
212         }\r
213 \r
214         prevTransaction = transaction;\r
215         transaction = transaction->nextTransaction;\r
216     }\r
217 \r
218     if (transaction) {\r
219         if (prevTransaction == NULL) {\r
220             /* Transaction at start of queue. Map second transaction to start of queue \r
221              * as long as more than one transactions. */\r
222             rmInst->transactionQueue = transaction->nextTransaction;\r
223         }\r
224         else {\r
225             /* Transaction in middle or end of queue. */\r
226             prevTransaction->nextTransaction = transaction->nextTransaction;\r
227         }\r
228         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));\r
229     }\r
230     else {\r
231         retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST;\r
232     }    \r
233 \r
234     Rm_osalMtCsExit(key);\r
235     return (retVal);\r
236 }\r
237 \r
238 uint32_t Rm_transactionInitSequenceNum(void)\r
239 {\r
240     /* Sequence number can never have value of 0.  Avoids conflicts\r
241      * with non-response transactions that have remoteOriginatingId of 0 */\r
242     return (1);\r
243 }\r
244 \r
245 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
246 {\r
247     uint32_t sequenceNum = 0;\r
248 \r
249     if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum) {\r
250         /* Overflow */\r
251         sequenceNum = rmInst->transactionSeqNum;\r
252         rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
253     }\r
254     else {\r
255         sequenceNum = rmInst->transactionSeqNum++;\r
256     }    \r
257     return (sequenceNum);\r
258 }\r
259 \r
260 Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName)\r
261 {\r
262     Rm_Allocator *allocators   = (Rm_Allocator *)rmInst->allocators;\r
263     Rm_Allocator *newAllocator = NULL;\r
264     void         *key;\r
265 \r
266     /* Lock access to the instance */\r
267     key = Rm_osalMtCsEnter();\r
268 \r
269     newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
270 \r
271     if (newAllocator) {\r
272         memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
273         strcpy(newAllocator->resourceName, resourceName);\r
274         newAllocator->allocatorRootEntry = NULL;\r
275         newAllocator->nextAllocator = NULL;  \r
276 \r
277         /* Add allocator to end of list */\r
278         if (allocators) {\r
279             while (allocators->nextAllocator != NULL) {\r
280                 allocators = allocators->nextAllocator;\r
281             }\r
282             allocators->nextAllocator = newAllocator;\r
283         }\r
284         else {\r
285             rmInst->allocators = newAllocator;\r
286         }\r
287     }\r
288 \r
289     Rm_osalMtCsExit(key);\r
290     return (newAllocator);\r
291 }\r
292 \r
293 Rm_Allocator *Rm_allocatorFind(Rm_Inst *rmInst, char *resourceName)\r
294 {\r
295     Rm_Allocator *allocator = (Rm_Allocator *)rmInst->allocators;\r
296 \r
297     while (allocator) {\r
298         if (strcmp(allocator->resourceName, resourceName) == 0) {\r
299             break;             \r
300         }\r
301         allocator = allocator->nextAllocator;\r
302     }\r
303 \r
304     return (allocator);\r
305 }\r
306 \r
307 int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
308 {\r
309     Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
310     Rm_Allocator *prevAllocator = NULL;\r
311     int32_t       retVal = RM_SERVICE_STATE_OKAY;\r
312     void         *key;\r
313 \r
314     /* Lock access to instance */\r
315     key = Rm_osalMtCsEnter();\r
316 \r
317     while (allocator) {\r
318         if (strcmp(allocator->resourceName, resourceName) == 0) {\r
319             break;             \r
320         }\r
321         prevAllocator = allocator;\r
322         allocator = allocator->nextAllocator;\r
323     }\r
324 \r
325     if (allocator) {\r
326         if (prevAllocator == NULL) {\r
327             /* Allocator at start of list. Map second allocator to start of list \r
328              * as long as more than one allocators. */\r
329             rmInst->allocators = allocator->nextAllocator;\r
330         }\r
331         else {\r
332             /* Allocator in middle or end of list. */\r
333             prevAllocator->nextAllocator = allocator->nextAllocator;\r
334         }\r
335         Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
336     }\r
337     else {\r
338         retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
339     }\r
340 \r
341     Rm_osalMtCsExit(key);\r
342     return (retVal);\r
343 }\r
344 \r
345 void Rm_addAllocatedTo(Rm_ResourceNode *node, void *serviceInstNode)\r
346 {\r
347     Rm_AllocatedTo *allocatedToList = node->allocatedTo;\r
348     Rm_AllocatedTo *newAllocatedTo = NULL;\r
349 \r
350     newAllocatedTo = Rm_osalMalloc(sizeof(Rm_AllocatedTo));\r
351 \r
352     if (newAllocatedTo) {\r
353         newAllocatedTo->instNameNode = serviceInstNode;\r
354         newAllocatedTo->nextAllocatedTo = NULL;  \r
355 \r
356         /* Add allocatedTo entry to end of list */\r
357         if (allocatedToList) {\r
358             while (allocatedToList->nextAllocatedTo) {\r
359                 allocatedToList = allocatedToList->nextAllocatedTo;\r
360             }\r
361             allocatedToList->nextAllocatedTo = newAllocatedTo;\r
362         }\r
363         else {\r
364             node->allocatedTo = newAllocatedTo;\r
365         }\r
366 \r
367         node->allocationCount++;\r
368         Rm_policyIncrementValidInstAllocationCount(newAllocatedTo->instNameNode);\r
369     }\r
370 }\r
371 \r
372 bool Rm_isAllocatedTo(Rm_ResourceNode *node, void *serviceInstNode)\r
373 {\r
374     Rm_AllocatedTo *allocatedTo = node->allocatedTo;\r
375 \r
376     while (allocatedTo) {\r
377         if (allocatedTo->instNameNode == serviceInstNode) {\r
378             return(TRUE);           \r
379         }\r
380         allocatedTo = allocatedTo->nextAllocatedTo;\r
381     }\r
382     return(FALSE);\r
383 }\r
384 \r
385 bool Rm_compareResourceNodeAllocations(Rm_ResourceNode *nodeOne, Rm_ResourceNode *nodeTwo)\r
386 {\r
387     Rm_AllocatedTo *nodeOneAllocs = nodeOne->allocatedTo;\r
388     Rm_AllocatedTo *nodeTwoAllocs = nodeTwo->allocatedTo;\r
389     bool            matchedInst;\r
390 \r
391     if (nodeOne->allocationCount == nodeTwo->allocationCount) {\r
392         while (nodeOneAllocs) {\r
393             matchedInst = FALSE;\r
394             while (nodeTwoAllocs) {\r
395                 if (nodeOneAllocs->instNameNode == nodeTwoAllocs->instNameNode) {\r
396                     matchedInst = TRUE;\r
397                     break;\r
398                 }\r
399                 nodeTwoAllocs = nodeTwoAllocs->nextAllocatedTo;\r
400             }\r
401 \r
402             if (matchedInst) {\r
403                 nodeTwoAllocs = nodeTwo->allocatedTo;\r
404                 nodeOneAllocs = nodeOneAllocs->nextAllocatedTo;\r
405             }\r
406             else {\r
407                 return(FALSE);\r
408             }                \r
409         }\r
410     }\r
411     else {\r
412         return(FALSE);\r
413     }  \r
414     \r
415     return(TRUE);\r
416 }\r
417 \r
418 void Rm_deleteAllocatedTo(Rm_ResourceNode *node, void *serviceInstNode)\r
419 {\r
420     Rm_AllocatedTo *allocatedTo = node->allocatedTo;\r
421     Rm_AllocatedTo *prevAllocatedTo = NULL;\r
422 \r
423     while (allocatedTo) {\r
424         if (allocatedTo->instNameNode == serviceInstNode) {\r
425             break;             \r
426         }\r
427         prevAllocatedTo = allocatedTo;\r
428         allocatedTo = allocatedTo->nextAllocatedTo;\r
429     }\r
430 \r
431     if (prevAllocatedTo == NULL) {\r
432         /* AllocatedTo entry at start of list. Map second allocatedTo entry to start of list \r
433          * as long as more than one allocatedTo entries. */\r
434         node->allocatedTo = allocatedTo->nextAllocatedTo;\r
435     }\r
436     else {\r
437         /* AllocatedTo entry in middle or end of list. */\r
438         prevAllocatedTo->nextAllocatedTo = allocatedTo->nextAllocatedTo;\r
439     }\r
440     \r
441     node->allocationCount--;\r
442     Rm_policyDecrementValidInstAllocationCount(allocatedTo->instNameNode);\r
443     Rm_osalFree((void *)allocatedTo, sizeof(Rm_AllocatedTo));\r
444 }\r
445 \r
446 void Rm_copyAllocatedTo(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)\r
447 {\r
448     Rm_AllocatedTo *srcAllocs = srcNode->allocatedTo;\r
449     Rm_AllocatedTo *newDstAlloc;\r
450     Rm_AllocatedTo *prevDstAlloc;\r
451 \r
452     dstNode->allocationCount = srcNode->allocationCount;\r
453 \r
454     while (srcAllocs) {\r
455         newDstAlloc = Rm_osalMalloc(sizeof(Rm_AllocatedTo));\r
456         newDstAlloc->instNameNode = srcAllocs->instNameNode;\r
457         newDstAlloc->nextAllocatedTo = NULL;\r
458 \r
459         if (dstNode->allocatedTo == NULL) {\r
460             dstNode->allocatedTo = newDstAlloc;\r
461         }\r
462         else {\r
463             prevDstAlloc->nextAllocatedTo = newDstAlloc;\r
464         }\r
465         prevDstAlloc = newDstAlloc;\r
466         srcAllocs = srcAllocs->nextAllocatedTo;\r
467     }\r
468 }\r
469 \r
470 void Rm_clearAllocatedTo(Rm_ResourceNode *node)\r
471 {\r
472     Rm_AllocatedTo *allocatedTo = node->allocatedTo;\r
473     Rm_AllocatedTo *nextAllocatedTo;\r
474 \r
475     while (allocatedTo) {\r
476         nextAllocatedTo = allocatedTo->nextAllocatedTo;\r
477         node->allocationCount--;\r
478         Rm_osalFree((void *)allocatedTo, sizeof(Rm_AllocatedTo));\r
479         allocatedTo = nextAllocatedTo;\r
480     }\r
481 }\r
482 \r
483 int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
484 {\r
485     Rm_Allocator    *allocator = NULL;\r
486     Rm_ResourceTree *treeRootEntry = NULL;\r
487     Rm_ResourceNode *treeNode = NULL;\r
488     Rm_ResourceNode *collidingNode = NULL;\r
489 \r
490     allocator = Rm_allocatorAdd(rmInst, resourceName);\r
491     treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));\r
492     RB_INIT(treeRootEntry);\r
493 \r
494     while (range != NULL) {\r
495         treeNode = Rm_newResourceNode(range->base, range->length);\r
496         collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
497 \r
498         if (collidingNode) {\r
499             Rm_ResourceNode *nextNode = NULL;\r
500             \r
501             /* Node that was inserted collides with existing node.  Destroy tree and return error */\r
502             for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) {\r
503                         nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
504                         RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode);\r
505                 Rm_freeResourceNode(treeNode);\r
506                 }\r
507             Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));\r
508             Rm_allocatorDelete(rmInst, allocator->resourceName);\r
509             return (-24); /* TODO FIX RETURN */\r
510         }\r
511         range = range->nextRange;\r
512     }\r
513     \r
514     allocator->allocatorRootEntry = treeRootEntry;\r
515     return(0);   /* TODO: FIX THIS RETURN */\r
516 }\r
517 \r
518 /* Called when an allocate request is made but the base is unspecified.  RM must preallocate\r
519  * resources which then must be checked against the RM policy for the instance.  If the\r
520  * policy does not agree another resource(s) must be preallocated and tested against the \r
521  * policy.  Policy will provide initialize the preallocate with the base that it allows\r
522  * for the rm instance for the specified resource. */\r
523 int32_t Rm_treePreAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,\r
524                            Rm_AllocatorOpInfo *opInfo)\r
525 {\r
526     Rm_ResourceNode    findNode;\r
527     Rm_ResourceNode   *matchingNode = NULL;\r
528     uint32_t           matchingEnd;\r
529     uint32_t           rangeIndex;\r
530     bool               resourceFound = FALSE;\r
531     Rm_PolicyCheckType policyCheckType;\r
532     Rm_PolicyCheckCfg  policyCheckCfg;\r
533     bool               nodePassesPolicy;\r
534     int32_t            retVal = RM_SERVICE_PROCESSING;    \r
535 \r
536     opInfo->resourceInfo->base = Rm_policyGetResourceBase(rmInst->policy, opInfo->serviceSrcInstNode, \r
537                                                           resourcePolicy, opInfo->allocType, \r
538                                                           &retVal);\r
539     if (retVal != RM_SERVICE_PROCESSING) {\r
540         return (retVal);\r
541     }\r
542 \r
543     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {  \r
544         /* Get alignment from policy */\r
545         opInfo->resourceInfo->alignment = Rm_policyGetResourceAlignment(rmInst->policy, resourcePolicy);\r
546     }\r
547     \r
548     if (opInfo->resourceInfo->alignment == 0) {\r
549         opInfo->resourceInfo->alignment = 1;\r
550     }    \r
551 \r
552     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));\r
553     findNode.base = opInfo->resourceInfo->base;\r
554     findNode.length = opInfo->resourceInfo->length;\r
555 \r
556     /* Configure policy checking structure */\r
557     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));\r
558     if (RM_POLICY_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {\r
559         policyCheckType = Rm_policyCheck_INIT;\r
560     }\r
561     else if (RM_POLICY_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {\r
562         policyCheckType = Rm_policyCheck_USE;\r
563     }\r
564     policyCheckCfg.policyDtb = rmInst->policy;\r
565     policyCheckCfg.resourcePolicy = resourcePolicy;\r
566     \r
567     do {\r
568         matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
569         \r
570         if (matchingNode) {\r
571             nodePassesPolicy = FALSE;\r
572             policyCheckCfg.type = policyCheckType;\r
573             policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;\r
574             policyCheckCfg.resourceBase = findNode.base;\r
575             policyCheckCfg.resourceLength = findNode.length;\r
576             nodePassesPolicy = Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);    \r
577             \r
578             if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {\r
579                 /* Check exclusive privileges of instance requesting resource.  Requesting\r
580                  * instance with exclusive privileges can't reserve resource if already owned*/\r
581                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;\r
582                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;\r
583                 nodePassesPolicy = !Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);\r
584             }\r
585             \r
586             if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {\r
587                 /* Check exclusive privileges of instance that currently owns resource */\r
588                 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;\r
589                 policyCheckCfg.validInstNode = matchingNode->allocatedTo->instNameNode;\r
590                 nodePassesPolicy = !Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);\r
591             }\r
592 \r
593             if (retVal != RM_SERVICE_PROCESSING) {\r
594                 break;\r
595             }\r
596 \r
597             if (nodePassesPolicy) {\r
598                 matchingEnd = matchingNode->base + matchingNode->length - 1;\r
599                 /* Initialize indexer to be first resource value that alignment */\r
600                 rangeIndex = findNode.base;\r
601                 if (rangeIndex % opInfo->resourceInfo->alignment) {\r
602                     rangeIndex += (opInfo->resourceInfo->alignment -\r
603                                   (rangeIndex % opInfo->resourceInfo->alignment));\r
604                 }\r
605                 \r
606                 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {\r
607                     /* Block of unallocated resources within matchingNode that satisfies\r
608                      * allocate requirements */\r
609                     opInfo->resourceInfo->base = rangeIndex;\r
610                     resourceFound = TRUE;\r
611                 }     \r
612             }\r
613             \r
614             if (!resourceFound) {\r
615                 /* Check next resource node for available resources */\r
616                 findNode.base = matchingNode->base + matchingNode->length;\r
617             }\r
618         }\r
619         else {\r
620             retVal = RM_SERVICE_DENIED_RESOURCE_ALLOCATION_REQUIREMENTS_COULD_NOT_BE_SATISFIED;\r
621         }\r
622     } while ((!resourceFound) && \r
623              (retVal != RM_SERVICE_DENIED_RESOURCE_ALLOCATION_REQUIREMENTS_COULD_NOT_BE_SATISFIED));\r
624 \r
625     return(retVal); \r
626 }\r
627 \r
628 int32_t Rm_treeAllocate(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy,\r
629                         Rm_AllocatorOpInfo *opInfo)\r
630 {\r
631     Rm_ResourceNode     findNode;\r
632     Rm_ResourceNode    *matchingNode = NULL;\r
633     Rm_ResourceNode    *leftNode = NULL;\r
634     Rm_ResourceNode    *rightNode = NULL;\r
635     Rm_PolicyCheckType  policyCheckType;    \r
636     Rm_PolicyCheckCfg   policyCheckCfg;\r
637     bool                allocPassesPolicy;\r
638     bool                combineLeft = FALSE;\r
639     bool                combineRight = FALSE;    \r
640     uint32_t            findEnd;\r
641     uint32_t            matchingEnd;  \r
642     int32_t             retVal = RM_SERVICE_PROCESSING;\r
643 \r
644     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));\r
645     findNode.base = opInfo->resourceInfo->base;\r
646     findNode.length = opInfo->resourceInfo->length;\r
647     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
648 \r
649     /* Prepare privilege checks */\r
650     memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));\r
651     if (RM_POLICY_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {\r
652         policyCheckType = Rm_policyCheck_INIT;\r
653     }\r
654     else if (RM_POLICY_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {\r
655         policyCheckType = Rm_policyCheck_USE;\r
656     }\r
657 \r
658     if (matchingNode) {\r
659         findEnd = findNode.base + findNode.length - 1;\r
660         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
661         \r
662         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {\r
663             if (opInfo->serviceSrcInstNode == Rm_policyGetLinuxInstNode(rmInst->validInstances)) {\r
664                 /* Bypass policy checks since Linux Kernel has full privileges */\r
665                 allocPassesPolicy = TRUE;\r
666             }\r
667             else {\r
668                 allocPassesPolicy = FALSE;\r
669                 policyCheckCfg.policyDtb = rmInst->policy;\r
670                 policyCheckCfg.resourcePolicy = resourcePolicy;    \r
671                 policyCheckCfg.type = policyCheckType;\r
672                 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;\r
673                 policyCheckCfg.resourceBase = findNode.base;\r
674                 policyCheckCfg.resourceLength = findNode.length;\r
675                 allocPassesPolicy = Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);\r
676                 if (!allocPassesPolicy) {\r
677                     retVal = RM_SERVICE_DENIED_INIT_USE_PERMISSION_DENIED;\r
678                 }\r
679                 \r
680                 if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {\r
681                     /* Check exclusive privileges of instance requesting resource.  Requesting\r
682                      * instance with exclusive privileges can't reserve resource if already owned*/\r
683                     policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;\r
684                     policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;\r
685                     allocPassesPolicy = !Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);\r
686                     if (!allocPassesPolicy) {\r
687                         retVal = RM_SERVICE_DENIED_REQUESTER_HAS_EXCLUSIVE_PRIV_BUT_RESOURCE_ALLOCATED;\r
688                     }\r
689                 }\r
690                 if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {\r
691                     /* Check exclusive privileges of instance that currently owns resource */\r
692                     policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;\r
693                     policyCheckCfg.validInstNode = matchingNode->allocatedTo->instNameNode;\r
694                     allocPassesPolicy = !Rm_policyCheckPrivilege(&policyCheckCfg, &retVal);\r
695                     if (!allocPassesPolicy) {\r
696                         retVal = RM_SERVICE_DENIED_RESOURCE_ALLOCATED_TO_INSTANCE_WITH_EXCLUSIVE_PRIV;\r
697                     }                \r
698                 }  \r
699             }\r
700             \r
701             if (allocPassesPolicy) {   \r
702                 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {\r
703                     /* findNode range matches matchingNode range\r
704                      *\r
705                      *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node\r
706                      *                    |<--alloc request-->|  => requested resources\r
707                      */                     \r
708                     leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
709                     rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
710                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
711                     Rm_addAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
712 \r
713                     if (leftNode && Rm_compareResourceNodeAllocations(leftNode, matchingNode)) {\r
714                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
715                         combineLeft = TRUE;\r
716                     }\r
717                     if (rightNode && Rm_compareResourceNodeAllocations(rightNode, matchingNode)) {\r
718                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
719                         combineRight = TRUE;\r
720                     }\r
721 \r
722                     if (combineLeft && combineRight) {\r
723                         /* Combine all three nodes into matchingNode */\r
724                         matchingNode->base = leftNode->base;\r
725                         matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
726 \r
727                         Rm_clearAllocatedTo(leftNode);\r
728                         Rm_freeResourceNode(leftNode);\r
729                         Rm_clearAllocatedTo(rightNode);\r
730                         Rm_freeResourceNode(rightNode);                        \r
731                     }\r
732                     else if (combineLeft) {\r
733                         /* Combine left and matching nodes.  Reinsert right. */\r
734                         matchingNode->base = leftNode->base;\r
735                         matchingNode->length += leftNode->length;\r
736 \r
737                         Rm_clearAllocatedTo(leftNode);\r
738                         Rm_freeResourceNode(leftNode);\r
739                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);                        \r
740                     }\r
741                     else if (combineRight) {\r
742                         /* Combine right and matching nodes.  Reinsert left. */\r
743                         matchingNode->length += rightNode->length;\r
744 \r
745                         Rm_clearAllocatedTo(rightNode);\r
746                         Rm_freeResourceNode(rightNode);\r
747                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
748                     }\r
749                     else {\r
750                         /* No combine. */\r
751                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
752                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
753                     }\r
754 \r
755                     /* Always reinsert matchingNode */                \r
756                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);   \r
757                 }   \r
758                 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {\r
759                     /* findNode range is subset of matchingNode range and neither boundary is\r
760                      * equivalent.\r
761                      *\r
762                      * |<----------matched node---------->|\r
763                      *        |<---alloc request--->|\r
764                      */ \r
765                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
766                     leftNode = Rm_newResourceNode(matchingNode->base, findNode.base - matchingNode->base);\r
767                     Rm_copyAllocatedTo(leftNode, matchingNode);\r
768                     rightNode = Rm_newResourceNode(findNode.base + findNode.length, matchingEnd - findEnd);\r
769                     Rm_copyAllocatedTo(rightNode, matchingNode);\r
770 \r
771                     matchingNode->base = findNode.base;                                    \r
772                     matchingNode->length = findNode.length;\r
773                     Rm_addAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
774 \r
775                     /* Insert all the nodes */\r
776                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
777                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
778                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
779                 }  \r
780                 else {    \r
781                     if (findNode.base == matchingNode->base) {\r
782                         /* findNode base and matchingNode base are equivalent.  May be combine\r
783                          * possibilities to the left\r
784                          *\r
785                          * |<---left node (alloc'd)--->||<----------matched node---------->|\r
786                          *                              |<---findNode (alloc req)--->|\r
787                          */                         \r
788                         leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
789                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
790                         /* Add allocating instance to allocatedTo list for compare with leftNode */\r
791                         Rm_addAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
792                         \r
793                         if (leftNode && Rm_compareResourceNodeAllocations(leftNode, matchingNode)) {\r
794                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
795                             /* Combine leftNode and findNode */\r
796                             leftNode->length += findNode.length;\r
797                         }\r
798                         else {\r
799                             leftNode = Rm_newResourceNode(findNode.base, findNode.length);\r
800                             Rm_copyAllocatedTo(leftNode, matchingNode);\r
801                         }\r
802 \r
803                         /* Account for leftNode in matchingNode */\r
804                         matchingNode->base = findNode.base + findNode.length;\r
805                         matchingNode->length = matchingEnd - findEnd;  \r
806 \r
807                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
808                     }\r
809                     else if (findEnd == matchingEnd) {\r
810                         /* findNode end and matchingNode end are equivalent.  May be combine\r
811                          * possibilities to the right\r
812                          *\r
813                          * |<----------matched node---------->||<---right node (alloc'd)--->|\r
814                          *       |<---findNode (alloc req)--->| \r
815                          */                        \r
816                         rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
817                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
818                         /* Add allocating instance to allocatedTo list for compare with rightNode */\r
819                         Rm_addAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
820                         \r
821                         if (rightNode && Rm_compareResourceNodeAllocations(rightNode, matchingNode)) {\r
822                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
823                             /* Combine rightNode and findNode */\r
824                             rightNode->base = findNode.base;\r
825                             rightNode->length += findNode.length;\r
826                         }\r
827                         else {\r
828                             rightNode = Rm_newResourceNode(findNode.base, findNode.length);\r
829                             Rm_copyAllocatedTo(rightNode, matchingNode);\r
830                         }\r
831 \r
832                         /* Account for rightNode in matchingNode */\r
833                         matchingNode->length -= findNode.length;  \r
834 \r
835                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
836                     }\r
837                     /* Remove allocating instance from leftover matchingNode */\r
838                     Rm_deleteAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
839                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
840                 }\r
841                 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
842             }\r
843         }\r
844         else {\r
845             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
846         }\r
847     }\r
848     else {\r
849         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
850     }\r
851 \r
852     return(retVal);        \r
853 }\r
854 \r
855 int32_t Rm_treeFree(Rm_Inst *rmInst, Rm_Allocator *allocator, int32_t resourcePolicy, Rm_AllocatorOpInfo *opInfo)\r
856 {\r
857     Rm_ResourceNode  findNode;\r
858     Rm_ResourceNode *matchingNode = NULL;\r
859     Rm_ResourceNode *leftNode = NULL;\r
860     Rm_ResourceNode *rightNode = NULL;\r
861     bool             combineLeft = FALSE;\r
862     bool             combineRight = FALSE;\r
863     uint32_t         findEnd;\r
864     uint32_t         matchingEnd;\r
865     int32_t          retVal;\r
866 \r
867     memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));\r
868     findNode.base = opInfo->resourceInfo->base;\r
869     findNode.length = opInfo->resourceInfo->length;\r
870     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
871 \r
872     if (matchingNode) {\r
873         findEnd = findNode.base + findNode.length - 1;\r
874         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
875         \r
876         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {  \r
877             if (matchingNode->allocationCount) {\r
878                 if (Rm_isAllocatedTo(matchingNode, opInfo->serviceSrcInstNode)) {\r
879                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
880                     {\r
881                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine \r
882                          *         freed node with nodes to left and right.\r
883                          *\r
884                          * |<--left node-->||<---matched node--->||<--right node-->|\r
885                          *                  |<---free request--->|\r
886                          */ \r
887                         leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
888                         rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
889                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
890                         Rm_deleteAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
891 \r
892                         if (leftNode && Rm_compareResourceNodeAllocations(leftNode, matchingNode)) {\r
893                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
894                             combineLeft = TRUE;\r
895                         }\r
896                         if (rightNode && Rm_compareResourceNodeAllocations(rightNode, matchingNode)) {\r
897                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
898                             combineRight = TRUE;\r
899                         }\r
900 \r
901                         if (combineLeft && combineRight) {\r
902                             /* Combine all three nodes into matchingNode */\r
903                             matchingNode->base = leftNode->base;\r
904                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
905 \r
906                             Rm_clearAllocatedTo(leftNode);\r
907                             Rm_freeResourceNode(leftNode);\r
908                             Rm_clearAllocatedTo(rightNode);\r
909                             Rm_freeResourceNode(rightNode);                        \r
910                         }\r
911                         else if (combineLeft) {\r
912                             /* Combine left and matching nodes.  Reinsert right. */\r
913                             matchingNode->base = leftNode->base;\r
914                             matchingNode->length += leftNode->length;\r
915 \r
916                             Rm_clearAllocatedTo(leftNode);\r
917                             Rm_freeResourceNode(leftNode);\r
918                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);                        \r
919                         }\r
920                         else if (combineRight) {\r
921                             /* Combine right and matching nodes.  Reinsert left. */\r
922                             matchingNode->length += rightNode->length;\r
923 \r
924                             Rm_clearAllocatedTo(rightNode);\r
925                             Rm_freeResourceNode(rightNode);\r
926                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
927                         }\r
928                         else {\r
929                             /* No combine. */\r
930                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
931                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
932                         }\r
933 \r
934                         /* Always reinsert matchingNode */\r
935                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);                    \r
936                     }\r
937                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {\r
938                         /* Case 2: Free range is less than range in matched node. Split\r
939                          *         matched node into three nodes.\r
940                          *\r
941                          * |<----------matched node---------->|\r
942                          *        |<---free request--->|\r
943                          *\r
944                          * Remove instance from AllocatedTo list then add it back in for side nodes for\r
945                          * proper accounting of allocations in validInstance list\r
946                          */ \r
947                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
948                         Rm_deleteAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
949                         \r
950                         leftNode = Rm_newResourceNode(matchingNode->base, findNode.base - matchingNode->base);\r
951                         Rm_copyAllocatedTo(leftNode, matchingNode);\r
952                         Rm_addAllocatedTo(leftNode, opInfo->serviceSrcInstNode);\r
953                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
954                         \r
955                         rightNode = Rm_newResourceNode(findNode.base + findNode.length, matchingEnd - findEnd);\r
956                         Rm_copyAllocatedTo(rightNode, matchingNode);\r
957                         Rm_addAllocatedTo(rightNode, opInfo->serviceSrcInstNode);\r
958                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
959 \r
960                         matchingNode->base = findNode.base;                                    \r
961                         matchingNode->length = findNode.length;\r
962                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
963                     }\r
964                     else {                        \r
965                         if (findNode.base == matchingNode->base) {\r
966                             /* Case 3: Free range is on left boundary of matched node. Try to \r
967                              *         combine free range with left node.\r
968                              *\r
969                              * |<---left node (free)--->||<----------matched node---------->|\r
970                              *                           |<---findNode (free req)--->|\r
971                              */ \r
972 \r
973                             leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
974                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
975                             /* Remove freeing instance from allocatedTo list for compare with leftNode */\r
976                             Rm_deleteAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
977                             \r
978                             if (leftNode && Rm_compareResourceNodeAllocations(leftNode, matchingNode)) {\r
979                                 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
980                                 /* Combine leftNode and findNode */\r
981                                 leftNode->length += findNode.length;\r
982                             }\r
983                             else {\r
984                                 leftNode = Rm_newResourceNode(findNode.base, findNode.length);\r
985                                 Rm_copyAllocatedTo(leftNode, matchingNode);\r
986                             }\r
987 \r
988                             /* Remove leftNode range from matchingNode */\r
989                             matchingNode->base = findNode.base + findNode.length;\r
990                             matchingNode->length = matchingEnd - findEnd;  \r
991                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
992                         }\r
993                         else if (findEnd == matchingEnd) {\r
994                             /* Case 4: Free range is on right boundary of matched node. Try to \r
995                              *         combine free range with right node.\r
996                              *\r
997                              * |<----------matched node---------->||<---right node (free)--->|\r
998                              *        |<---findNode (free req)--->|\r
999                              */ \r
1000                             \r
1001                             rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1002                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); \r
1003                             /* Remove freeing instance from allocatedTo list for compare with rightNode */\r
1004                             Rm_deleteAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
1005                             \r
1006                             if (rightNode && Rm_compareResourceNodeAllocations(rightNode, matchingNode)) {\r
1007                                 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1008                                 /* Combine rightNode and findNode */\r
1009                                 rightNode->base = findNode.base;\r
1010                                 rightNode->length += findNode.length;\r
1011                             }\r
1012                             else {\r
1013                                 rightNode = Rm_newResourceNode(findNode.base, findNode.length);\r
1014                                 Rm_copyAllocatedTo(rightNode, matchingNode);\r
1015                             }\r
1016 \r
1017                             /* Remove rightNode range from matchingNode */\r
1018                             matchingNode->length -= findNode.length;  \r
1019                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1020                         }\r
1021 \r
1022                         /* Add freeing instance back into matchingNode allocations */\r
1023                         Rm_addAllocatedTo(matchingNode, opInfo->serviceSrcInstNode);\r
1024                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1025                     }\r
1026 \r
1027                     retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1028                 }\r
1029                 else {\r
1030                     retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
1031                 }\r
1032             }\r
1033             else {\r
1034                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
1035             }\r
1036         }\r
1037         else {\r
1038             retVal = RM_SERVICE_DENIED_INVALID_RESOURCE_RANGE;\r
1039         }\r
1040     }\r
1041     else {\r
1042         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1043     }\r
1044     return(retVal);  \r
1045 }\r
1046 \r
1047 int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)\r
1048 {\r
1049     Rm_Allocator *allocator = NULL;\r
1050     int32_t       resourcePolicy = NULL;\r
1051     int32_t       retVal;\r
1052     void         *key;\r
1053 \r
1054     /* Lock access to the RM instance's transaction queue */\r
1055     key = Rm_osalMtCsEnter();\r
1056     \r
1057     resourcePolicy = Rm_policyGetResourcePolicy(rmInst->policy, opInfo->resourceInfo->name);\r
1058     allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name);\r
1059     \r
1060     if ((resourcePolicy > 0) && allocator) {\r
1061         if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {\r
1062             retVal = Rm_treePreAllocate(rmInst, allocator, resourcePolicy, opInfo);\r
1063         }               \r
1064         else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {\r
1065             retVal = Rm_treeAllocate(rmInst, allocator, resourcePolicy, opInfo);\r
1066         }\r
1067         else if (opInfo->operation == Rm_allocatorOp_FREE) {\r
1068             retVal = Rm_treeFree(rmInst, allocator, resourcePolicy, opInfo);\r
1069         }         \r
1070     }\r
1071     else {\r
1072         /* Resource could not be found in policy and/or allocator */\r
1073         retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST;\r
1074     }\r
1075 \r
1076     Rm_osalMtCsExit(key);\r
1077     return(retVal);\r
1078 }\r
1079 \r
1080 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode,\r
1081                            uint32_t allocType)\r
1082 {\r
1083     Rm_AllocatorOpInfo opInfo;\r
1084     int32_t            retVal = transaction->state;\r
1085 \r
1086     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1087     \r
1088     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {\r
1089         /* TEMP: For now forward all allocations to the RM Server */\r
1090         Rm_transactionForwarder(rmInst, transaction);\r
1091              \r
1092     }\r
1093     else if (rmInst->instType == Rm_instType_SERVER) {\r
1094         opInfo.resourceInfo = &transaction->resourceInfo;\r
1095         opInfo.serviceSrcInstNode = validInstNode;\r
1096         opInfo.allocType = allocType;\r
1097 \r
1098         if (strlen(transaction->resourceInfo.nsName) > 0) {\r
1099             if (transaction->resourceInfo.base != 0) {\r
1100                 /* Both NameServer name and static value cannot be specified for the request */\r
1101                 retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
1102             }\r
1103             else {\r
1104                 retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
1105             }\r
1106         }\r
1107 \r
1108         if (retVal == RM_SERVICE_PROCESSING) {      \r
1109             if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED) {\r
1110                 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;\r
1111                 retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1112             }\r
1113         \r
1114             if (retVal == RM_SERVICE_PROCESSING) {\r
1115                 opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
1116                 retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1117             }      \r
1118         }\r
1119         \r
1120         transaction->state = retVal;\r
1121 \r
1122         if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1123             /* Source of allocation was not the server instance, provide the transaction\r
1124              * to the transaction responder */\r
1125             Rm_transactionResponder(rmInst, transaction);\r
1126         }\r
1127         /* Otherwise let the return stack return the transaction to the serviceHandler */                   \r
1128     }   \r
1129 }\r
1130 \r
1131 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction, void *validInstNode)\r
1132 {\r
1133     Rm_AllocatorOpInfo opInfo; \r
1134     int32_t            retVal = transaction->state;\r
1135 \r
1136     memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1137     \r
1138     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {\r
1139         /* TEMP: Forward all free requests to the Server */\r
1140         Rm_transactionForwarder(rmInst, transaction);        \r
1141     }\r
1142     else if (rmInst->instType == Rm_instType_SERVER) {\r
1143         opInfo.resourceInfo = &transaction->resourceInfo;\r
1144         opInfo.serviceSrcInstNode = validInstNode;\r
1145 \r
1146         if (strlen(transaction->resourceInfo.nsName) > 0) {\r
1147             if (transaction->resourceInfo.base != 0) {\r
1148                 /* Both a name and a value cannot be specified for the request */\r
1149                 retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
1150             }\r
1151             else {\r
1152                 retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
1153             }\r
1154         }\r
1155         \r
1156         if(retVal == RM_SERVICE_PROCESSING) {        \r
1157             opInfo.operation = Rm_allocatorOp_FREE;\r
1158             retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1159         }       \r
1160 \r
1161         transaction->state = retVal;\r
1162 \r
1163         if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1164             /* Source of allocation was not the server instance, provide the transaction\r
1165              * to the transaction responder */\r
1166             Rm_transactionResponder(rmInst, transaction);\r
1167         }\r
1168         /* Otherwise let the return stack return the transaction to the serviceHandler */        \r
1169     }   \r
1170 }\r
1171 \r
1172 /* Function used to send RM response transactions to lower level agents */\r
1173 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1174 {\r
1175     Rm_TransportNode *dstTransportNode = NULL;\r
1176     Rm_Packet *rmPkt = NULL;\r
1177 \r
1178     /* Find the transport for the RM instance that sent the request. */\r
1179     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->pktSrcInstName);\r
1180 \r
1181     /* Create a RM packet using the service information */\r
1182     switch (transaction->type) {\r
1183         case Rm_service_RESOURCE_ALLOCATE_INIT:\r
1184         case Rm_service_RESOURCE_ALLOCATE_USE:\r
1185         case Rm_service_RESOURCE_FREE:\r
1186         case Rm_service_RESOURCE_GET_BY_NAME:\r
1187             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
1188                                                           transaction);\r
1189             break;\r
1190         case Rm_service_RESOURCE_MAP_TO_NAME:\r
1191         case Rm_service_RESOURCE_UNMAP_NAME:\r
1192             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
1193                                                     transaction);\r
1194             break;\r
1195         default:\r
1196             /* Invalid service type.  Flag the error and return */\r
1197             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1198             break;\r
1199     }\r
1200 \r
1201     if (transaction->state <= RM_SERVICE_ERROR_BASE) {\r
1202         /* Delete the transaction and return immediately because an error occurred \r
1203          * allocating the packet */\r
1204         Rm_transactionQueueDelete(rmInst, transaction->localId);\r
1205         return;\r
1206     }\r
1207 \r
1208     /* Send the RM packet to the application transport */\r
1209     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL) {\r
1210         /* Negative value returned by transport send.  An error occurred\r
1211          * in the transport while attempting to send the packet.*/\r
1212         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1213         /* Clean up the packet */\r
1214         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt)) {\r
1215             /* Non-NULL value returned by transport packet free. Flag the\r
1216              * error */\r
1217             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1218         }\r
1219         return;\r
1220     }\r
1221 \r
1222     /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD.  CREATE\r
1223      * NEW TRANSACTION WITH DATA FROM ORIGINAL?  THEN TRY TO SEND FAILED REQUEST BACK\r
1224      * TO REQUESTER???  KEEP RETRYING SEND OF RESPONSE??? */\r
1225 \r
1226     /* Delete the transaction */\r
1227     Rm_transactionQueueDelete(rmInst, transaction->localId);\r
1228 }\r
1229 \r
1230 /* Function used to forward RM transactions to higher level agents */\r
1231 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1232 {\r
1233     Rm_TransportNode *dstTransportNode = NULL;\r
1234     Rm_Packet *rmPkt = NULL;\r
1235 \r
1236     /* Make sure the RM instance has a transport registered with a higher level agent */\r
1237     if (rmInst->registeredWithDelegateOrServer == false) {\r
1238         transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
1239         return;\r
1240     }\r
1241 \r
1242     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
1243      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
1244      * Delegates will be connected to a Server. */\r
1245     if (rmInst->instType == Rm_instType_CLIENT) {\r
1246         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
1247 \r
1248         if (!dstTransportNode) {\r
1249             /* No Client Delegate connection found.  Check for a Server connection */\r
1250             dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1251         }\r
1252     } \r
1253     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {\r
1254         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1255     }\r
1256 \r
1257     /* Create a RM packet using the service information */\r
1258     switch (transaction->type) {\r
1259         case Rm_service_RESOURCE_ALLOCATE_INIT:\r
1260         case Rm_service_RESOURCE_ALLOCATE_USE:\r
1261         case Rm_service_RESOURCE_FREE:\r
1262         case Rm_service_RESOURCE_GET_BY_NAME:\r
1263             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
1264                                                      transaction);\r
1265             break;\r
1266         case Rm_service_RESOURCE_MAP_TO_NAME:\r
1267         case Rm_service_RESOURCE_UNMAP_NAME:\r
1268             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
1269                                                    transaction);\r
1270             break;\r
1271         default:\r
1272             /* Invalid service type.  Flag the error and return */\r
1273             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1274             break;\r
1275     }\r
1276 \r
1277     if (transaction->state <= RM_SERVICE_ERROR_BASE) {\r
1278         /* Return immediately because an error occurred allocating the packet */\r
1279         return;\r
1280     }\r
1281 \r
1282     /* Send the RM packet to the application transport */\r
1283     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL) {\r
1284         /* Negative value returned by transport send.  An error occurred\r
1285          * in the transport while attempting to send the packet.*/\r
1286         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1287         /* Clean up the packet */\r
1288         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt)) {\r
1289             /* Non-NULL value returned by transport packet free. Flag the\r
1290              * error */\r
1291             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1292         }\r
1293         return;\r
1294     }\r
1295 \r
1296     /* Transaction is not deleted because it is awaiting a response from the higher level\r
1297      * RM instance */\r
1298 }\r
1299 \r
1300 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1301 {\r
1302     void     *validInstNode;\r
1303     uint32_t  allocType = 0;\r
1304     \r
1305     /* Handle auto-forwarded transactions.  These transactions include:\r
1306      * - All request transactions received on Clients are forwarded to the Client Delegate\r
1307      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
1308     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
1309         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
1310          ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
1311           (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||\r
1312           (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))) {\r
1313           \r
1314         if (transaction->state != RM_SERVICE_PROCESSING) {\r
1315             if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1316                 /* Transaction did not originate on this instance */\r
1317                 Rm_transactionResponder(rmInst, transaction);\r
1318             }\r
1319             else {\r
1320                 /* Transaction originated on this instance */\r
1321                 Rm_serviceResponder(rmInst, transaction);\r
1322             }\r
1323         }\r
1324         else {\r
1325             /* Forward new transaction */\r
1326             Rm_transactionForwarder(rmInst, transaction);\r
1327         }\r
1328     }\r
1329     else {\r
1330         /* Validate service's originating instance name */\r
1331         if (rmInst->instType == Rm_instType_SERVER) {\r
1332             validInstNode = Rm_policyGetValidInstNode(rmInst->validInstances, transaction->serviceSrcInstName);\r
1333             if (validInstNode == NULL) {\r
1334                 transaction->state = RM_SERVICE_DENIED_ORIGINATING_INSTANCE_NAME_NOT_VALID;\r
1335 \r
1336                 /* Send result via responder if transaction did not originate from this instance */\r
1337                 if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1338                     Rm_transactionResponder(rmInst, transaction);\r
1339                 }\r
1340             }\r
1341         }\r
1342 \r
1343         switch (transaction->type) {\r
1344             case Rm_service_RESOURCE_ALLOCATE_INIT:\r
1345             case Rm_service_RESOURCE_ALLOCATE_USE:\r
1346             case Rm_service_RESOURCE_FREE:               \r
1347                 if (transaction->state != RM_SERVICE_PROCESSING) {\r
1348                     /* Transaction complete */\r
1349                     if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1350                         /* Transaction result not destined for this instance */\r
1351                         Rm_transactionResponder(rmInst, transaction);\r
1352                     }\r
1353                     else {\r
1354                         /* Transaction result destined for this instance */\r
1355                         Rm_serviceResponder(rmInst, transaction);      \r
1356                     }\r
1357                 }\r
1358                 else {\r
1359                     /* Complete allocation/free request */\r
1360                     if (transaction->type == Rm_service_RESOURCE_FREE) {\r
1361                         Rm_freeHandler(rmInst, transaction, validInstNode);\r
1362                     }\r
1363                     else {\r
1364                         switch (transaction->type) {\r
1365                             case Rm_service_RESOURCE_ALLOCATE_INIT:\r
1366                                 RM_POLICY_SET_PERM(allocType, RM_POLICY_PERM_INIT_SHIFT, 1);\r
1367                                 break;\r
1368                             case Rm_service_RESOURCE_ALLOCATE_USE:\r
1369                                 RM_POLICY_SET_PERM(allocType, RM_POLICY_PERM_USE_SHIFT, 1);    \r
1370                                 break;\r
1371                         }\r
1372                         Rm_allocationHandler(rmInst, transaction, validInstNode, allocType);\r
1373                     }\r
1374                 }\r
1375                 break;\r
1376             case Rm_service_RESOURCE_MAP_TO_NAME:\r
1377             case Rm_service_RESOURCE_GET_BY_NAME:\r
1378             case Rm_service_RESOURCE_UNMAP_NAME:                \r
1379                 /* NameServer resides on server */\r
1380                 if (rmInst->instType == Rm_instType_SERVER) {\r
1381                     if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) {\r
1382                         transaction->state = Rm_nsAddObject(rmInst, &transaction->resourceInfo);\r
1383                     }\r
1384                     else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) {\r
1385                         if (Rm_nsFindObject(rmInst, &transaction->resourceInfo) == RM_SERVICE_PROCESSING) {\r
1386                             transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1387                         }\r
1388                     }\r
1389                     else if (transaction->type == Rm_service_RESOURCE_UNMAP_NAME) {\r
1390                         transaction->state = Rm_nsDeleteObject(rmInst, &transaction->resourceInfo);\r
1391                     }\r
1392 \r
1393                     /* Send result via responder if transaction did not originate from this instance */\r
1394                     if (strcmp(transaction->serviceSrcInstName, rmInst->name)) {\r
1395                         Rm_transactionResponder(rmInst, transaction);\r
1396                     }\r
1397                 }\r
1398                 else {\r
1399                     transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1400                 }\r
1401                 break;\r
1402         }\r
1403     }\r
1404 }\r
1405 \r
1406 int32_t Rm_reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, \r
1407                                 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)\r
1408 {\r
1409     int32_t  retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1410     bool     baseFound = FALSE;\r
1411     bool     lengthFound = FALSE;\r
1412     uint32_t valueIndex = 0;\r
1413 \r
1414     while ((linuxValues != NULL) && (!baseFound || !lengthFound)) {\r
1415         if (linuxAlias->baseOffset == valueIndex) {\r
1416             opInfo->resourceInfo->base = linuxValues->value;\r
1417             baseFound = TRUE;\r
1418 \r
1419             if (linuxAlias->lengthOffset == RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET) {\r
1420                 opInfo->resourceInfo->length = 1;\r
1421                 lengthFound = TRUE;\r
1422             }\r
1423         }\r
1424         else if (linuxAlias->lengthOffset == valueIndex) {\r
1425             opInfo->resourceInfo->length = linuxValues->value;\r
1426             lengthFound = TRUE;\r
1427         }\r
1428 \r
1429         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;\r
1430         valueIndex++;\r
1431     }\r
1432 \r
1433     if (!baseFound || !lengthFound) {\r
1434         retVal = -33; /* TODO: ERROR BASE OR LENGTH OFFSET IN LINUX DTB WAS INCORRECT */\r
1435     }\r
1436     else {\r
1437         /* Allocate resource to Linux */\r
1438         retVal = Rm_allocatorOperation(rmInst, opInfo);\r
1439     }\r
1440     return (retVal);\r
1441 }\r
1442 \r
1443 int32_t Rm_findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, \r
1444                                        Rm_LinuxAlias *linuxAlias)\r
1445 {\r
1446     Rm_AllocatorOpInfo  opInfo;\r
1447     Rm_ResourceInfo     resourceInfo;\r
1448     uint32_t            pathOffset;\r
1449     uint32_t            pathSize;\r
1450     char               *spacePtr;\r
1451     int32_t             propOffset;\r
1452     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1453     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
1454     int32_t             depth;\r
1455     int32_t             propertyLen;\r
1456     const char         *propertyName;\r
1457     const void         *propertyData; \r
1458     Rm_LinuxValueRange *linuxValueRange;\r
1459     int32_t             retVal = RM_DTB_UTIL_RESULT_OKAY; \r
1460 \r
1461     memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1462     memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
1463 \r
1464     strcpy(resourceInfo.name, resourceName);\r
1465     opInfo.serviceSrcInstNode = Rm_policyGetLinuxInstNode(rmInst->validInstances);\r
1466     opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
1467     opInfo.resourceInfo = &resourceInfo;    \r
1468 \r
1469     while(linuxAlias != NULL) {\r
1470         /* Reset parsing variables */\r
1471         pathOffset = 0;\r
1472         pathSize = strlen(linuxAlias->path) + 1;\r
1473         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1474         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   \r
1475         resourceInfo.base = 0;\r
1476         resourceInfo.length = 0;\r
1477 \r
1478         spacePtr = strpbrk(linuxAlias->path, " ");\r
1479         if (spacePtr) {\r
1480             *spacePtr = '\0';\r
1481         }       \r
1482         \r
1483         while(pathOffset < pathSize) {\r
1484             /* Move through DTB nodes until next alias path node found */\r
1485             if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {\r
1486                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);\r
1487 \r
1488                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {\r
1489                     /* Returning from subnode that matched part of alias path without finding\r
1490                      * resource values */\r
1491                     retVal = (-31); /* TODO: COULD NOT FIND RESOURCE AT ALIAS PATH */\r
1492                     break;\r
1493                 }\r
1494             }\r
1495             else {\r
1496                 /* Found next alias path node.  Move to next node name in path string. */\r
1497                 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);\r
1498                 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");\r
1499                 if (spacePtr) {\r
1500                     *spacePtr = '\0';\r
1501                 }       \r
1502                 \r
1503                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);\r
1504                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);\r
1505                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&\r
1506                        (pathOffset < pathSize)) {\r
1507                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, \r
1508                                                          &propertyName, &propertyLen);\r
1509 \r
1510                     if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {\r
1511                         /* Found resource at end of alias path */\r
1512                         pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);\r
1513                         linuxValueRange = Rm_linuxExtractValues(propertyData, propertyLen);\r
1514                         retVal = Rm_reserveLinuxResource(rmInst, linuxAlias, \r
1515                                                          linuxValueRange, &opInfo);\r
1516                         Rm_linuxFreeValues(linuxValueRange);\r
1517                     }\r
1518                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);\r
1519                 } \r
1520 \r
1521                 if (propOffset < -FDT_ERR_NOTFOUND) {\r
1522                     retVal = propOffset;\r
1523                     break;\r
1524                 }\r
1525             }\r
1526         }\r
1527 \r
1528         if (retVal < RM_DTB_UTIL_RESULT_OKAY) {\r
1529             break;\r
1530         }\r
1531         linuxAlias = (Rm_LinuxAlias *) linuxAlias->nextLinuxAlias;\r
1532     }\r
1533     return (retVal);\r
1534 }\r
1535 \r
1536 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
1537                                   Rm_ResourceProperties *resourceProperties, void *linuxDtb)\r
1538 {\r
1539     Rm_ResourceRange *range = NULL;\r
1540     Rm_ResourceRange *rangeBasePtr = NULL;\r
1541     Rm_NsAssignment *nsAssignments = NULL;\r
1542     Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
1543     Rm_LinuxAlias *linuxAlias = NULL;\r
1544     Rm_ResourceInfo resourceInfo;\r
1545     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1546 \r
1547     if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0))\r
1548     {\r
1549         /* Extract the resource properties from the DTB */\r
1550         range = rangeBasePtr = Rm_resourceExtractRange(resourceProperties->rangeData, \r
1551                                                        resourceProperties->rangeLen);\r
1552 \r
1553         /* Create a tree allocator using the resource properties */\r
1554         retVal = Rm_createTreeAllocator(rmInst, resourceName, range); \r
1555 \r
1556         if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1557         {\r
1558             if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen)\r
1559             {\r
1560                 /* Reserve the resources taken by the Linux kernel specified in the Linux DTB */\r
1561                 linuxAlias = Rm_resourceExtractLinuxAlias(resourceProperties->linuxAliasData,\r
1562                                                           resourceProperties->linuxAliasLen);\r
1563 \r
1564                 retVal = Rm_findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias);            \r
1565             }\r
1566         }\r
1567     }\r
1568     \r
1569     if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1570     {\r
1571         /* Create entries in the NameServer if any NameServer assignments were specified */\r
1572         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
1573         {\r
1574             nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
1575                                                            resourceProperties->nsAssignLen);\r
1576 \r
1577             /* Cycle through the list of assignments and add them to the NameServer */\r
1578             nsAssignmentBasePtr = nsAssignments;\r
1579             while (nsAssignments)\r
1580             {\r
1581                 memset((void *)&resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
1582 \r
1583                 strcpy(resourceInfo.name, resourceName);\r
1584                 resourceInfo.base = nsAssignments->resourceBase;\r
1585                 resourceInfo.length = nsAssignments->resourceLength;\r
1586                 strcpy(resourceInfo.nsName, nsAssignments->nsName);\r
1587                 \r
1588                 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
1589                 Rm_nsAddObject(rmInst, &resourceInfo);\r
1590                 nsAssignments = nsAssignments->nextNsAssignment;\r
1591             }\r
1592             /* Free the memory allocated for the NameServer assignments */\r
1593             Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
1594         }\r
1595     }\r
1596 \r
1597     /* Free the memory allocated for the resource properties */\r
1598     Rm_resourceFreeRange(rangeBasePtr);\r
1599     Rm_resourceFreeLinuxAlias(linuxAlias);\r
1600 \r
1601     return(retVal);\r
1602 }\r
1603 \r
1604 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
1605 {\r
1606         int32_t propertyLen;\r
1607         const char *propertyName;\r
1608         const void *propertyData;\r
1609     Rm_ResourcePropType propertyType;\r
1610     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1611 \r
1612     /* Get the property data and store it in the corresponding propertyInfo field */\r
1613         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
1614     if (propertyData)\r
1615     {\r
1616         propertyType = Rm_resourceGetPropertyType(propertyName);\r
1617         if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
1618         {\r
1619             if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
1620             {\r
1621                 /* The range fields have already been populated.  Return an error.\r
1622                  * The resource list has specified a property field more than once\r
1623                  * for a resource node */\r
1624                 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1625             }\r
1626             else\r
1627             {\r
1628                 propertyInfo->rangeData = propertyData;\r
1629                 propertyInfo->rangeLen = propertyLen;\r
1630             }\r
1631         }\r
1632         else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
1633         {\r
1634             if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
1635             {\r
1636                 /* The nsAssign fields have already been populated.  Return an error.\r
1637                  * The resource list has specified a property field more than once\r
1638                  * for a resource node */\r
1639                 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1640             }\r
1641             else\r
1642             {\r
1643                 propertyInfo->nsAssignData = propertyData;\r
1644                 propertyInfo->nsAssignLen = propertyLen;\r
1645             }\r
1646         }\r
1647         else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS)\r
1648         {\r
1649             if (propertyInfo->linuxAliasData || propertyInfo->linuxAliasLen)\r
1650             {\r
1651                 /* The linuxAlias fields have already been populated.  Return an error.\r
1652                  * The resource list has specified a property field more than once\r
1653                  * for a resource node */\r
1654                 retVal = -28; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1655             }\r
1656             else\r
1657             {\r
1658                 propertyInfo->linuxAliasData = propertyData;\r
1659                 propertyInfo->linuxAliasLen = propertyLen;\r
1660             }\r
1661         }        \r
1662         else\r
1663         {\r
1664             retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1665         }\r
1666     }\r
1667     else\r
1668     {\r
1669         retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1670     }\r
1671 \r
1672     /* Don't get anymore properties if error occurred */\r
1673     if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
1674     {\r
1675         offset = fdt_next_property_offset(globalResourceDtb, offset);\r
1676         if (offset >= 0)\r
1677         {\r
1678             retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
1679         }\r
1680         else if (offset != -FDT_ERR_NOTFOUND)\r
1681         {\r
1682             /* Error was returned by LIBFDT when parsing the properties */\r
1683             retVal = offset;\r
1684         }\r
1685     }\r
1686     \r
1687     return (retVal);\r
1688 }\r
1689 \r
1690 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,\r
1691                              void *linuxDtb)\r
1692 {\r
1693         const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
1694     Rm_ResourceProperties resourceProperties;\r
1695         int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
1696         int32_t offset;\r
1697 \r
1698     /* Initialize the resource properties structure */\r
1699     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
1700 \r
1701     /* Ignore properties of the base node */\r
1702     if (strcmp(resourceName, rmDtbStartingNode))\r
1703     {\r
1704         /* Get the properties for the resource node if any exist */\r
1705         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
1706         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
1707         {\r
1708             /* Since at least one property exists attempt to parse the property nodes and \r
1709              * use them to create and initialize a resource allocator */\r
1710                 error =  Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
1711             if (error < -FDT_ERR_NOTFOUND)\r
1712             {\r
1713                 return (error);\r
1714             }\r
1715             \r
1716             /* Initialize an allocator with the resource properties if no error was returned */\r
1717             Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb);\r
1718         }\r
1719         else if (offset != -FDT_ERR_NOTFOUND)\r
1720         {\r
1721                 /* Error was returned by LIBFDT when parsing the properties */\r
1722             return (offset);\r
1723         }\r
1724     }\r
1725     \r
1726     /* Get the next resource node */\r
1727         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
1728     /* Check the offset and depth of the next node to make sure the current node\r
1729      * wasn't the last node in the Resource List.  A depth less than the depth set\r
1730      * at the start of the recursion will signal the end of the resource list */\r
1731     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
1732     {\r
1733         error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);\r
1734         if (error < -FDT_ERR_NOTFOUND)\r
1735         {\r
1736             return (error);\r
1737         }\r
1738     }\r
1739     else if (offset != -FDT_ERR_NOTFOUND)\r
1740     {\r
1741         /* Error was returned by LIBFDT when parsing the nodes */\r
1742         return (offset);\r
1743     }\r
1744 \r
1745     return (RM_DTB_UTIL_RESULT_OKAY);\r
1746 }\r
1747 \r
1748 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)\r
1749 {\r
1750     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1751     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
1752     int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
1753 \r
1754     /* Recursively parse the Global Resource List, creating an allocator for\r
1755      * each resource as specified in the node */\r
1756     result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);\r
1757 \r
1758     return(result);\r
1759 }\r
1760      \r
1761 /**********************************************************************\r
1762  ********************** Application visible APIs **********************\r
1763  **********************************************************************/\r
1764 \r
1765 /* Server Only */\r
1766 void Rm_printResourceStatus(Rm_Handle *rmHandle)\r
1767 {\r
1768     Rm_Inst         *rmInst = (Rm_Inst *) rmHandle;\r
1769     Rm_Allocator    *allocator = rmInst->allocators;\r
1770     Rm_AllocatedTo  *allocatedTo;\r
1771     Rm_ResourceTree *treeRoot;\r
1772     Rm_ResourceNode *treeNode;\r
1773 \r
1774     while (allocator != NULL) {\r
1775         Rm_osalLog("Resource: %s\n", allocator->resourceName);\r
1776 \r
1777         treeRoot = allocator->allocatorRootEntry;\r
1778 \r
1779         RB_FOREACH(treeNode, _Rm_ResourceTree, treeRoot) {               \r
1780             Rm_osalLog("          %10d - %10d ", treeNode->base, \r
1781                                                  treeNode->base + treeNode->length -1);\r
1782             \r
1783             if (treeNode->allocationCount == 0) {\r
1784                 Rm_osalLog("NOT ALLOCATED\n");\r
1785             }\r
1786             else {\r
1787                 allocatedTo = treeNode->allocatedTo;\r
1788                 Rm_osalLog("allocated to ");\r
1789                 while (allocatedTo) {\r
1790                     Rm_osalLog(" %s", Rm_policyGetValidInstNodeName(allocatedTo->instNameNode));\r
1791                     allocatedTo = allocatedTo->nextAllocatedTo;\r
1792                 }\r
1793                 Rm_osalLog("\n");\r
1794             }\r
1795         }        \r
1796         allocator = allocator->nextAllocator;\r
1797     }\r
1798 \r
1799     Rm_nsPrintObjects(rmInst);\r
1800 }\r
1801 \r
1802 Rm_Handle Rm_init(Rm_InitCfg *initCfg, int32_t *result)\r
1803 {\r
1804     Rm_Inst *rmInst;\r
1805     void    *globalResourceDtb = NULL;\r
1806     void    *linuxResourceDtb = NULL;\r
1807     void    *policyDtb = NULL;\r
1808 \r
1809     *result = RM_INIT_OK;\r
1810     \r
1811     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS) {\r
1812         *result = RM_INIT_ERROR_INSTANCE_NAME_TOO_BIG;\r
1813         return (NULL);\r
1814     }\r
1815 \r
1816     /* Create and initialize instance */\r
1817     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
1818     memset ((void *) rmInst, 0, sizeof(Rm_Inst));\r
1819     strcpy (&rmInst->name[0], initCfg->instName);\r
1820     rmInst->instType = initCfg->instType;\r
1821     rmInst->registeredWithDelegateOrServer = false;\r
1822     rmInst->routeMap = NULL;\r
1823     rmInst->allocators = NULL;\r
1824     rmInst->nameServer = NULL;\r
1825     rmInst->policy = NULL;\r
1826     rmInst->validInstances = NULL;\r
1827     rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
1828     rmInst->transactionQueue= NULL;\r
1829 \r
1830     if ((rmInst->instType != Rm_instType_CLIENT) && initCfg->policy) {\r
1831         policyDtb = initCfg->policy;\r
1832         fdt_open_into(policyDtb, policyDtb, fdt_totalsize(policyDtb)); \r
1833 \r
1834         /* Create valid instance list from policy.  Must be done prior to parsing\r
1835          * GRL so that Linux resources can be reserved correctly */\r
1836         rmInst->validInstances = Rm_policyCreateValidInstTree(policyDtb, result);\r
1837         /* Validate policy assignment strings */\r
1838         *result = Rm_policyValidatePolicy(rmInst, policyDtb);\r
1839         rmInst->policy = policyDtb;\r
1840     }\r
1841 \r
1842     /* RM Server specific actions */\r
1843     if (rmInst->instType == Rm_instType_SERVER) {\r
1844         Rm_nsInit(rmInst);\r
1845 \r
1846         if (initCfg->globalResourceList) {\r
1847             globalResourceDtb = initCfg->globalResourceList;\r
1848             fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));\r
1849 \r
1850             if (initCfg->linuxDtb) {\r
1851                 linuxResourceDtb = initCfg->linuxDtb;\r
1852                 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));   \r
1853             }\r
1854             Rm_initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb);\r
1855         }\r
1856     }\r
1857 \r
1858     if ((rmInst->instType != Rm_instType_CLIENT) && initCfg->policy) {\r
1859         *result = Rm_policyValidatePolicyResourceNames(rmInst, policyDtb);\r
1860     }    \r
1861 \r
1862     return ((Rm_Handle) rmInst);\r
1863 }\r
1864 \r
1865 uint32_t Rm_getVersion (void)\r
1866 {\r
1867     return RM_VERSION_ID;\r
1868 }\r
1869 \r
1870 \r
1871 const char* Rm_getVersionStr (void)\r
1872 {\r
1873     return rmVersionStr;\r
1874 }\r
1875 \r
1876 /**\r
1877 @}\r
1878 */\r