Completed and tested routines that automatically reserve linux resources
[keystone-rtos/rm-lld.git] / src / rm.c
1 /**\r
2  *   @file  rm.c\r
3  *\r
4  *   @brief   \r
5  *      This is the Resource Manager source.\r
6  *\r
7  *  \par\r
8  *  ============================================================================\r
9  *  @n   (C) Copyright 2012, Texas Instruments, Inc.\r
10  * \r
11  *  Redistribution and use in source and binary forms, with or without \r
12  *  modification, are permitted provided that the following conditions \r
13  *  are met:\r
14  *\r
15  *    Redistributions of source code must retain the above copyright \r
16  *    notice, this list of conditions and the following disclaimer.\r
17  *\r
18  *    Redistributions in binary form must reproduce the above copyright\r
19  *    notice, this list of conditions and the following disclaimer in the \r
20  *    documentation and/or other materials provided with the   \r
21  *    distribution.\r
22  *\r
23  *    Neither the name of Texas Instruments Incorporated nor the names of\r
24  *    its contributors may be used to endorse or promote products derived\r
25  *    from this software without specific prior written permission.\r
26  *\r
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \r
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT \r
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \r
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \r
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT \r
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE \r
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
38  *\r
39  *  \par\r
40 */\r
41 \r
42 /* RM Types */\r
43 #include <ti/drv/rm/rm_types.h>\r
44 \r
45 /* RM external includes */\r
46 #include <ti/drv/rm/rm.h>\r
47 #include <ti/drv/rm/rm_services.h>\r
48 #include <ti/drv/rm/rm_transport.h>\r
49 #include <ti/drv/rm/rm_policy.h>\r
50 \r
51 /* RM internal includes */\r
52 #include <ti/drv/rm/include/rm_loc.h>\r
53 #include <ti/drv/rm/include/rm_transportloc.h>\r
54 #include <ti/drv/rm/include/rm_servicesloc.h>\r
55 #include <ti/drv/rm/include/rm_nameserverloc.h>\r
56 #include <ti/drv/rm/include/rm_dtb_utilloc.h>\r
57 \r
58 /* RM LIBFDT includes */\r
59 #include <ti/drv/rm/src/libfdt/libfdt.h>\r
60 \r
61 /* AVL BBST includes */\r
62 #include <ti/drv/rm/include/tree.h>\r
63 \r
64 /* RM OSAL layer */\r
65 #include <rm_osal.h>\r
66 \r
67 /**********************************************************************\r
68  ************************** Globals ***********************************\r
69  **********************************************************************/\r
70 char rmIntegerAllocator[] = "integer";\r
71 char rmTreeAllocator[] = "tree";\r
72 \r
73 extern char rmDtbStartingNode[];\r
74 \r
75 /** @brief Global Variable which describes the RM Version Information */\r
76 const char   rmVersionStr[] = RM_VERSION_STR ":" __DATE__  ":" __TIME__;\r
77 \r
78 /**********************************************************************\r
79  ************** Red-Black BBST Tree Allocator Functions ***************\r
80  **********************************************************************/\r
81 \r
82 /* Prototype for function that allocates new tree nodes */\r
83 Rm_ResourceTreeNode *Rm_newResourceTreeNode(uint32_t resourceBase, uint32_t resourceLength, \r
84                                             char *allocatedTo)\r
85 {\r
86     Rm_ResourceTreeNode *newNode = NULL;\r
87 \r
88     newNode = Rm_osalMalloc(sizeof(Rm_ResourceTreeNode));\r
89 \r
90     /* Populate the RM relevant fields */\r
91     newNode->base = resourceBase;\r
92     newNode->length = resourceLength;\r
93     strcpy(newNode->allocatedTo, allocatedTo);\r
94 \r
95     return(newNode);\r
96 }\r
97 \r
98 /* Prototype for function that frees new tree nodes */\r
99 void Rm_freeResourceTreeNode(Rm_ResourceTreeNode *treeNode)\r
100 {\r
101     /* Free the memory associated with the tree node. */\r
102     Rm_osalFree((void *)treeNode, sizeof(Rm_ResourceTreeNode));\r
103 }\r
104 \r
105 /* Prototype for tree node comparison function\r
106  * element1 < element2 --> return < 0\r
107  * element1 = element2 --> return 0\r
108  * element1 > element2 --> return > 0 */\r
109 int Rm_ResourceTreeNodeCompare(Rm_ResourceTreeNode *element1, Rm_ResourceTreeNode *element2)\r
110 {\r
111     uint32_t element1End = element1->base + element1->length - 1;\r
112     uint32_t element2End = element2->base + element2->length - 1;\r
113 \r
114     if (element1End < element2->base)\r
115     {\r
116         /* End of element1 range is less than the start of element2's range.  Return a negative\r
117          * value */\r
118         return (-1);\r
119     }\r
120     else if (element1->base > element2End)\r
121     {\r
122         /* Start of element1 range is after end of element2's range.  Return a positive value */\r
123         return (1);\r
124     }\r
125     else\r
126     {\r
127         /* If neither of the latter conditions were satisfied there is some overlap between\r
128          * element1 and element2.  Return 0 since the application must handle this overlap. */\r
129         return (0);\r
130     }\r
131 }\r
132 \r
133 /* Generate the red-black tree manipulation functions */\r
134 RB_GENERATE(_Rm_ResourceTree, _Rm_ResourceTreeNode, linkage, Rm_ResourceTreeNodeCompare);\r
135 \r
136 /**********************************************************************\r
137  ********************** Internal Functions ****************************\r
138  **********************************************************************/\r
139 \r
140 Rm_Transaction *Rm_transactionQueueAdd(Rm_Inst *rmInst)\r
141 {\r
142     Rm_Transaction *transactionQueue = (Rm_Transaction *)rmInst->transactionQueue;\r
143     Rm_Transaction *newTransaction = NULL;\r
144     void *key;\r
145 \r
146     /* Lock access to the RM instance's transaction queue */\r
147     key = Rm_osalMtCsEnter();\r
148 \r
149     /* Get memory for a new transaction from local memory */\r
150     newTransaction = Rm_osalMalloc(sizeof(Rm_Transaction));\r
151 \r
152     /* Return if the memory allocated for the transaction entry is NULL */\r
153     if (newTransaction == NULL)\r
154     {\r
155         /* Clear the transaction */\r
156         memset((void *)newTransaction, 0, sizeof(Rm_Transaction));\r
157 \r
158         /* Create an ID for the new transaction.  The ID will be used for two purposes:\r
159          * 1) Matching responses from higher level RM agents to requests\r
160          * 2) Provided to the component that requested the service so that it can match its\r
161          *    request with the response it receives via its callback function it provided */\r
162         newTransaction->localId = Rm_transactionGetSequenceNum(rmInst);\r
163         /* New transaction's nextTransaction pointer will always be NULL */\r
164         newTransaction->nextTransaction = NULL;  \r
165 \r
166         /* Check if there are any transactions in the transaction queue */\r
167         if (transactionQueue)\r
168         {\r
169             /* At least one transaction in the transaction queue.  Add the new entry to the \r
170              * end of the transaction queue */\r
171             while (transactionQueue->nextTransaction != NULL)\r
172             {\r
173                 /* Traverse the list until arriving at the last transaction */\r
174                 transactionQueue = transactionQueue->nextTransaction;\r
175             }\r
176 \r
177             /* Add the new transaction to the end of the queue */\r
178             transactionQueue->nextTransaction = newTransaction;\r
179         }\r
180         else\r
181         {\r
182             /* The transaction queue does not currently exist.  The new transaction is the \r
183              * first transaction */\r
184             rmInst->transactionQueue = newTransaction;\r
185         }\r
186     }\r
187 \r
188     Rm_osalMtCsExit(key);\r
189     return (newTransaction);\r
190 }\r
191 \r
192 Rm_Transaction *Rm_transactionQueueFind(Rm_Inst *rmInst, uint32_t transactionId)\r
193 {\r
194     Rm_Transaction *transaction = (Rm_Transaction *)rmInst->transactionQueue;\r
195 \r
196     /* Make sure there is at least one transaction in the transaction queue */\r
197     if (transaction != NULL)\r
198     {\r
199         /* Find the transaction ID within the specified RM instance's transaction queue.\r
200          * If the end of the transaction queue is reached without finding the transaction the \r
201          * transaction pointer will be NULL */\r
202         while (transaction != NULL)\r
203         {\r
204             if (transaction->localId == transactionId)\r
205             {\r
206                 /* Match: break out of loop and return the transaction */\r
207                 break;             \r
208             }\r
209             transaction = transaction->nextTransaction;\r
210         }\r
211     }\r
212 \r
213     return (transaction);\r
214 }\r
215 \r
216 int32_t Rm_transactionQueueDelete(Rm_Inst *rmInst, uint32_t transactionId)\r
217 {\r
218     Rm_Transaction *transaction = (Rm_Transaction *) rmInst->transactionQueue;\r
219     Rm_Transaction *prevTransaction = NULL;\r
220     int32_t retVal = RM_SERVICE_STATE_OKAY;\r
221     void *key;\r
222 \r
223     /* Lock access to the RM instance's transaction queue */\r
224     key = Rm_osalMtCsEnter();\r
225 \r
226     /* Find the transaction ID within the specified RM instance's transaction queue. */\r
227     while (transaction != NULL)\r
228     {\r
229         if (transaction->localId == transactionId)\r
230         {\r
231             /* Match: break out of loop and delete the transaction */\r
232             break;             \r
233         }\r
234 \r
235         prevTransaction = transaction;\r
236         transaction = transaction->nextTransaction;\r
237     }\r
238 \r
239     /* Traversed entire queue but did not find transaction */\r
240     if (transaction == NULL)\r
241     {\r
242         retVal = RM_SERVICE_ERROR_SERVICE_TRANSACTION_DOES_NOT_EXIST;\r
243     }\r
244     else\r
245     {\r
246         /* Delete the transaction */\r
247         if ((prevTransaction == NULL) && transaction->nextTransaction)\r
248         {\r
249             /* Transaction to be deleted exists at start of transaction queue.  Map second\r
250              * transaction to be start of transaction queue as long as there are more than\r
251              * one transactions. */\r
252             rmInst->transactionQueue = transaction->nextTransaction;\r
253         }\r
254         else\r
255         {\r
256             /* Transaction to be deleted is in the middle or at end of the queue.  Adjust \r
257              * adjacent transaction pointers.  This covers the case where the transaction to be \r
258              * removed is at the end of the queue. */\r
259             prevTransaction->nextTransaction = transaction->nextTransaction;\r
260         }\r
261 \r
262         /* Free the memory associated with the transaction. */\r
263         Rm_osalFree((void *)transaction, sizeof(Rm_Transaction));\r
264     }\r
265 \r
266     Rm_osalMtCsExit(key);\r
267     return (retVal);\r
268 }\r
269 \r
270 uint32_t Rm_transactionInitSequenceNum(void)\r
271 {\r
272     /* Sequence number can never have a value of zero so that there are no conflicts\r
273      * with transactions that have a remoteOriginatingId of zero */\r
274     return (1);\r
275 }\r
276 \r
277 uint32_t Rm_transactionGetSequenceNum(Rm_Inst *rmInst)\r
278 {\r
279     uint32_t sequenceNum = 0;\r
280 \r
281     /* Get the next sequence number and then increment.  If there's an overflow\r
282      * assign the initial value instead of incrementing. */\r
283     if (rmInst->transactionSeqNum + 1 < rmInst->transactionSeqNum)\r
284     {\r
285         /* Overflow */\r
286         sequenceNum = rmInst->transactionSeqNum;\r
287         rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
288     }\r
289     else\r
290     {\r
291         sequenceNum = rmInst->transactionSeqNum++;\r
292     }    \r
293 \r
294     return (sequenceNum);\r
295 }\r
296 \r
297 /* Function used to send RM response transactions to lower level agents */\r
298 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
299 {\r
300     Rm_TransportNode *dstTransportNode = NULL;\r
301     Rm_Packet *rmPkt = NULL;\r
302 \r
303     /* Find the transport for the RM instance that sent the request. */\r
304     dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
305 \r
306     /* Create a RM packet using the service information */\r
307     switch (transaction->type)\r
308     {\r
309         case Rm_service_RESOURCE_ALLOCATE:\r
310         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
311         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
312         case Rm_service_RESOURCE_FREE:\r
313         case Rm_service_RESOURCE_BLOCK_FREE:\r
314         case Rm_service_RESOURCE_FREE_BY_NAME:\r
315             rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
316                                                           transaction);\r
317             break;\r
318         case Rm_service_RESOURCE_MAP_TO_NAME:\r
319         case Rm_service_RESOURCE_UNMAP_NAME:\r
320             rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
321                                                     transaction);\r
322             break;\r
323         default:\r
324             /* Invalid service type.  Flag the error and return */\r
325             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
326             break;\r
327     }\r
328 \r
329     if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
330     {\r
331         /* Delete the transaction and return immediately because an error occurred \r
332          * allocating the packet */\r
333         Rm_transactionQueueDelete(rmInst, transaction->localId);\r
334         return;\r
335     }\r
336 \r
337     /* Send the RM packet to the application transport */\r
338     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
339     {\r
340         /* Negative value returned by transport send.  An error occurred\r
341          * in the transport while attempting to send the packet.*/\r
342         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
343         /* Clean up the packet */\r
344         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
345         {\r
346             /* Non-NULL value returned by transport packet free. Flag the\r
347              * error */\r
348             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
349         }\r
350         return;\r
351     }\r
352 \r
353     /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD.  CREATE\r
354      * NEW TRANSACTION WITH DATA FROM ORIGINAL?  THEN TRY TO SEND FAILED REQUEST BACK\r
355      * TO REQUESTER???  KEEP RETRYING SEND OF RESPONSE??? */\r
356 \r
357     /* Delete the transaction */\r
358     Rm_transactionQueueDelete(rmInst, transaction->localId);\r
359 }\r
360 \r
361 Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName, Rm_AllocatorType type)\r
362 {\r
363     Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators;\r
364     Rm_Allocator *newAllocator = NULL;\r
365     void *key;\r
366 \r
367     /* Lock access to the RM instance's allocator list */\r
368     key = Rm_osalMtCsEnter();\r
369 \r
370     /* Get memory for a new allocator from local memory */\r
371     newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
372 \r
373     /* Return if the memory allocated for the allocator is NULL */\r
374     if (newAllocator != NULL)\r
375     {\r
376         /* Clear the allocator */\r
377         memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
378 \r
379         /* Populate the allocator */\r
380         newAllocator->type = type;\r
381         strcpy(newAllocator->resourceName, resourceName);\r
382         /* allocator's root entry will be created by the invoking function */\r
383         newAllocator->allocatorRootEntry = NULL;\r
384         /* New allocator's nextAllocator pointer will always be NULL */\r
385         newAllocator->nextAllocator = NULL;  \r
386 \r
387         /* Check if there are any allocators in the allocator list */\r
388         if (allocators)\r
389         {\r
390             /* At least one allocator in the allocator list.  Add the new allocator to the \r
391              * end of the allocator list */\r
392             while (allocators->nextAllocator != NULL)\r
393             {\r
394                 /* Traverse the list until arriving at the last allocator */\r
395                 allocators = allocators->nextAllocator;\r
396             }\r
397 \r
398             /* Add the new allocator to the end of the list */\r
399             allocators->nextAllocator = newAllocator;\r
400         }\r
401         else\r
402         {\r
403             /* The allocator list does not currently exist.  The new allocator is the \r
404              * first allocator */\r
405             rmInst->allocators = newAllocator;\r
406         }\r
407     }\r
408 \r
409     Rm_osalMtCsExit(key);\r
410     return (newAllocator);\r
411 }\r
412 \r
413 Rm_Allocator *Rm_allocatorFind(Rm_Inst *rmInst, char *resourceName)\r
414 {\r
415     Rm_Allocator *allocator = (Rm_Allocator *)rmInst->allocators;\r
416 \r
417     /* Make sure there is at least one allocator in the allocator list */\r
418     if (allocator != NULL)\r
419     {\r
420         /* Find the resource name within the allocator list.  If the end of the\r
421          * allocator list is reached without finding the resource name the \r
422          * allocator pointer will be NULL */\r
423         while (allocator != NULL)\r
424         {\r
425             if (strcmp(allocator->resourceName, resourceName) == 0)\r
426             {\r
427                 /* Match: break out of loop and return the allocator */\r
428                 break;             \r
429             }\r
430             allocator = allocator->nextAllocator;\r
431         }\r
432     }\r
433 \r
434     return (allocator);\r
435 }\r
436 \r
437 int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
438 {\r
439     Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
440     Rm_Allocator *prevAllocator = NULL;\r
441     int32_t retVal = RM_SERVICE_STATE_OKAY;\r
442     void *key;\r
443 \r
444     /* Lock access to the RM instance's allocator list */\r
445     key = Rm_osalMtCsEnter();\r
446 \r
447     /* Find the resource within the specified RM instance's allocator list. */\r
448     while (allocator != NULL)\r
449     {\r
450         if (strcmp(allocator->resourceName, resourceName) == 0)\r
451         {\r
452             /* Match: break out of loop and delete the transaction */\r
453             break;             \r
454         }\r
455 \r
456         prevAllocator = allocator;\r
457         allocator = allocator->nextAllocator;\r
458     }\r
459 \r
460     /* Traversed entire list but did not find allocator. */\r
461     if (allocator == NULL)\r
462     {\r
463         retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
464     }\r
465     else\r
466     {\r
467         /* Delete the allocator */\r
468         if ((prevAllocator == NULL) && allocator->nextAllocator)\r
469         {\r
470             /* Allocator to be deleted exists at start of allocator list.  Map second\r
471              * allocator to be start of allocator list as long as there are more than\r
472              * one allocators. */\r
473             rmInst->allocators = allocator->nextAllocator;\r
474         }\r
475         else\r
476         {\r
477             /* Allocator to be deleted is in the middle or at end of the list.  Adjust \r
478              * adjacent allocator pointers.  This covers the case where the allocator to be \r
479              * removed is at the end of the list. */\r
480             prevAllocator->nextAllocator = allocator->nextAllocator;\r
481         }\r
482 \r
483         /* Free the memory associated with the allocator. */\r
484         Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
485     }\r
486 \r
487     Rm_osalMtCsExit(key);\r
488     return (retVal);\r
489 }\r
490 \r
491 int32_t Rm_createIntegerAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
492 {\r
493     Rm_Allocator *allocator = NULL;\r
494     Rm_ResourceRange *rangeBasePtr = range;\r
495     Rm_IntegerAllocatorRootEntry *intRootEntry = NULL;\r
496     uint16_t i, entryIndex;\r
497 \r
498     /* Create the new base integer allocator */\r
499     allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_INTEGER);\r
500 \r
501     /* Construct the integer allocator root entry */\r
502     intRootEntry = Rm_osalMalloc(sizeof(Rm_IntegerAllocatorRootEntry));\r
503     intRootEntry->numResourceElements = 0;\r
504 \r
505     /* Get the number of entries to allocate based on the lengths in the ranges */\r
506     while (range != NULL)\r
507     {\r
508         intRootEntry->numResourceElements += range->length;\r
509         range = range->nextRange;\r
510     }\r
511 \r
512     /* Initialize the entries using the range information */\r
513     if (intRootEntry->numResourceElements)\r
514     {\r
515         intRootEntry->resourceArrayBase = Rm_osalMalloc(sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
516         memset((void *)intRootEntry->resourceArrayBase, 0, sizeof(Rm_IntegerEntry) * intRootEntry->numResourceElements);\r
517 \r
518         /* Reset the range pointer */\r
519         range = rangeBasePtr;\r
520         entryIndex = 0;\r
521 \r
522         while (range != NULL)\r
523         {\r
524             /* Initialize each entry */\r
525             for (i = range->base; i < (range->base + range->length); i++, entryIndex++)\r
526             {\r
527                 intRootEntry->resourceArrayBase[entryIndex].value = i;\r
528                 /* Initialize the allocatedTo field to the NOT_ALLOCATED string */\r
529                 strcpy(intRootEntry->resourceArrayBase[entryIndex].allocatedTo, RM_NOT_ALLOCATED_STRING);\r
530             }\r
531             \r
532             range = range->nextRange;\r
533         }\r
534         \r
535         allocator->allocatorRootEntry = intRootEntry;\r
536     }\r
537     else\r
538     {\r
539         /* No resource entries were created.  Free the memory associated with the\r
540          * allocator and the root entry */\r
541         Rm_osalFree((void *)intRootEntry, sizeof(Rm_IntegerAllocatorRootEntry));\r
542         Rm_allocatorDelete(rmInst, allocator->resourceName);\r
543     }\r
544 \r
545     return(0);  /* TODO: FIX THIS RETURN */\r
546 }\r
547 \r
548 /* Called when an allocate request is made but the base is unspecified.  RM must preallocate\r
549  * resources which then must be checked against the RM policy for the instance.  If the\r
550  * policy does not agree another resource(s) must be preallocated and tested against the \r
551  * policy.  Policy will provide initialize the preallocate with the base that it allows\r
552  * for the rm instance for the specified resource. */\r
553 int32_t Rm_integerPreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
554 {\r
555     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
556     Rm_IntegerEntry *resourceArray = root->resourceArrayBase;\r
557     uint16_t index, i;\r
558     bool resourcesValidated;\r
559     int32_t retVal = RM_SERVICE_PROCESSING;\r
560 \r
561     /* Find the specified resource base within the allocator */\r
562     for (index = 0; index < root->numResourceElements; index++)\r
563     {\r
564         if (resourceArray[index].value == opInfo->resourceInfo->base)\r
565         {\r
566             /* Found the resource base in the allocator.  Break from the loop */\r
567             break;\r
568         }\r
569     } \r
570 \r
571     /* Only execute the allocate operation if the resource base was found in the allocator\r
572      * and the base+length does not exceed the number of entries in the allocator */\r
573     if ((index + opInfo->resourceInfo->length) <= root->numResourceElements)\r
574     {\r
575         /* Search for a contiguous block of unallocated resources of length "length"\r
576          * and with the alignment specified */\r
577         while ((index + opInfo->resourceInfo->length) <= root->numResourceElements)\r
578         {\r
579             resourcesValidated = FALSE;            \r
580             \r
581             /* Does the resource base value satisfy the alignment? */\r
582             if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0)\r
583             {\r
584                 /* Check to see all the resource values in the requested range are free */\r
585                 resourcesValidated = TRUE;\r
586                 for (i = index; i < opInfo->resourceInfo->length; i++)\r
587                 {\r
588                     if (strcmp(resourceArray[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0)\r
589                     {\r
590                         /* A resource within the range was already allocated.  Update the\r
591                          * index to the resource after the allocated resource and continue \r
592                          * looking. */\r
593                         index = i + 1;\r
594                         resourcesValidated = FALSE;\r
595                         /* Break out of the for loop */\r
596                         break;\r
597                     }\r
598                 }\r
599 \r
600                 if (resourcesValidated)\r
601                 {\r
602                     /* Found a set of resources that satisfies the request requirements.  Return\r
603                      * the results to be tested against the policy.  If the policy approves the\r
604                      * resources will be allocated via the Rm_integerAllocate API. */\r
605                     opInfo->resourceInfo->base = resourceArray[index].value;\r
606                     /* Break out of the while loop */\r
607                     break;\r
608                 }\r
609             }\r
610             else\r
611             {\r
612                 /* Jump to the next resource value that satisfies the alignment */\r
613                 for (; index < root->numResourceElements; index++)\r
614                 {\r
615                     if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0)\r
616                     {\r
617                         /* Found the next resource value that satisfies the alignment */\r
618                         break;\r
619                     }\r
620                 }\r
621             }\r
622         }\r
623 \r
624         if (!resourcesValidated)\r
625         {\r
626             retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
627         }\r
628     }\r
629     else\r
630     {\r
631         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
632     }\r
633 \r
634     return(retVal);     \r
635 }\r
636 \r
637 /* Assumes resource range for allocation has already been approved by the policy */\r
638 int32_t Rm_integerAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
639 {\r
640     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
641     uint16_t resourceIndex, i, j;\r
642     bool resourcesValidated = TRUE;\r
643     int32_t retVal;\r
644 \r
645     /* Find the specified resource base within the allocator */\r
646     for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++)\r
647     {\r
648         if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base)\r
649         {\r
650             /* Found the resource base in the allocator.  Break from the loop */\r
651             break;\r
652         }\r
653     }\r
654 \r
655     /* Only execute the allocate operation if the resource base was found in the allocator\r
656      * and the base+length does not exceed the number of entries in the allocator */\r
657     if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements)\r
658     {\r
659         /* Verify all resource values from base to base+length exist in the allocator and\r
660          * are not allocated to another instance. */\r
661         for (i = resourceIndex, j = opInfo->resourceInfo->base; \r
662              i < (resourceIndex + opInfo->resourceInfo->length);\r
663              i++, j++)\r
664         {\r
665             if (root->resourceArrayBase[i].value != j)\r
666             {\r
667                 /* A value in the range did not match. */\r
668                 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
669                 resourcesValidated = FALSE;\r
670                 break;\r
671             }\r
672             else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0)\r
673             {\r
674                 /* A value in the range is already allocated. */\r
675                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
676                 resourcesValidated = FALSE;\r
677                 break;            \r
678             }\r
679         }\r
680 \r
681         if (resourcesValidated)\r
682         {\r
683             /* Allocate all resources from base to base+length */\r
684             for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++)\r
685             {\r
686                 strcpy(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName);\r
687             }\r
688             retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
689         }\r
690     }\r
691     else\r
692     {\r
693         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
694     }\r
695 \r
696     return(retVal); \r
697 }\r
698 \r
699 /* Assumes resource range for free has already been approved by the policy */\r
700 int32_t Rm_integerFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
701 {\r
702     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
703     uint16_t resourceIndex, i, j;\r
704     bool resourcesValidated = TRUE;\r
705     int32_t retVal;\r
706 \r
707     /* Find the specified resource base within the allocator */\r
708     for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++)\r
709     {\r
710         if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base)\r
711         {\r
712             /* Found the resource base in the allocator.  Break from the loop */\r
713             break;\r
714         }\r
715     }\r
716 \r
717     /* Only execute the free operation if the resource base was found in the allocator\r
718      * and the base+length does not exceed the number of entries in the allocator */\r
719     if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements)\r
720     {\r
721         /* Verify all resource values from base to base+length exist in the allocator,\r
722          * were not already free and were allocated to the instance that is the source\r
723          * of the free request. */\r
724         for (i = resourceIndex, j = opInfo->resourceInfo->base; \r
725              i < (resourceIndex + opInfo->resourceInfo->length);\r
726              i++, j++)\r
727         {\r
728             if (root->resourceArrayBase[i].value != j)\r
729             {\r
730                 /* A value in the range did not match. */\r
731                 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
732                 resourcesValidated = FALSE;\r
733                 break;\r
734             }\r
735             else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
736             {\r
737                 /* A value in the range is already free. */\r
738                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
739                 resourcesValidated = FALSE;\r
740                 break;            \r
741             }            \r
742             else if (strcmp(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName) != 0)\r
743             {\r
744                 /* A value in the range was not allocated to the source of\r
745                  * the free request */\r
746                 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
747                 resourcesValidated = FALSE;\r
748                 break;\r
749             }\r
750         }\r
751 \r
752         if (resourcesValidated)\r
753         {\r
754             /* Free all resources from base to base+length */\r
755             for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++)\r
756             {\r
757                 strcpy(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING);\r
758             }\r
759             retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
760         }\r
761     }\r
762     else\r
763     {\r
764         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
765     }\r
766 \r
767     return(retVal);\r
768 }\r
769 \r
770 int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
771 {\r
772     Rm_Allocator *allocator = NULL;\r
773     Rm_ResourceTree *treeRootEntry = NULL;\r
774     Rm_ResourceTreeNode *treeNode = NULL;\r
775     Rm_ResourceTreeNode *collidingNode = NULL;\r
776 \r
777     /* Create the new base integer allocator */\r
778     allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_TREE);\r
779 \r
780     /* Create the tree root entry and initialize it */\r
781     treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));\r
782     RB_INIT(treeRootEntry);\r
783 \r
784     /* Create a node in the tree for resource range and insert them into the tree. */\r
785     while (range != NULL)\r
786     {\r
787         treeNode = Rm_newResourceTreeNode(range->base, range->length, RM_NOT_ALLOCATED_STRING);\r
788 \r
789         /* Insert the node into the tree */\r
790         collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
791 \r
792         if (collidingNode)\r
793         {\r
794             Rm_ResourceTreeNode *nextNode = NULL;\r
795             \r
796             /* Node that was inserted colliding with an existing node.  Clean up the tree\r
797              * that's been allocated thus far and return an error since there should be no\r
798              * collisions */\r
799             for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode)\r
800             {\r
801                         nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
802                         RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode);\r
803                 Rm_freeResourceTreeNode(treeNode);\r
804                 }\r
805             /* Delete the tree root entry and the allocator */\r
806             Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));\r
807             Rm_allocatorDelete(rmInst, allocator->resourceName);\r
808             return (-24); /* TODO FIX RETURN */\r
809         }\r
810 \r
811         range = range->nextRange;\r
812     }\r
813 \r
814     /* Assign the tree's root to the allocator */\r
815     allocator->allocatorRootEntry = treeRootEntry;\r
816 \r
817     return(0);   /* TODO: FIX THIS RETURN */\r
818 }\r
819 \r
820 /* Called when an allocate request is made but the base is unspecified.  RM must preallocate\r
821  * resources which then must be checked against the RM policy for the instance.  If the\r
822  * policy does not agree another resource(s) must be preallocated and tested against the \r
823  * policy.  Policy will provide initialize the preallocate with the base that it allows\r
824  * for the rm instance for the specified resource. */\r
825 int32_t Rm_treePreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
826 {\r
827     Rm_ResourceTreeNode findNode;\r
828     Rm_ResourceTreeNode *matchingNode = NULL;\r
829     uint32_t policyRangeEnd = opInfo->policyBase + opInfo->policyLength - 1;\r
830     uint32_t index;\r
831     bool resourceFound = FALSE;\r
832     int32_t retVal = RM_SERVICE_PROCESSING;\r
833 \r
834     /* Find the tree node that contains the first value in the specified policy range. */\r
835     findNode.base = opInfo->policyBase;\r
836     findNode.length = 1;\r
837     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
838 \r
839     if (matchingNode != NULL)\r
840     {\r
841         /* Begin searching for an available range of resources starting from the\r
842          * matching node */\r
843         for (index = matchingNode->base; index <= policyRangeEnd;)\r
844         {\r
845             /* Is the matchingNode free? */\r
846             if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
847             {\r
848                 uint32_t matchEnd = matchingNode->base + matchingNode->length - 1;\r
849 \r
850                 /* Move index to the first resource satisfying the alignment property */\r
851                 if ((index % opInfo->policyAlignment) != 0)\r
852                 {\r
853                     index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
854                 }\r
855                 \r
856                 /* Move through the node's resource range looking for a contiguous set of resources\r
857                  * that satisfy the request. */\r
858                 while ((index <= matchEnd) && (index <= policyRangeEnd))\r
859                 {\r
860                     if (((index + opInfo->resourceInfo->length - 1) <= matchEnd) &&\r
861                         ((index + opInfo->resourceInfo->length - 1) <= policyRangeEnd))\r
862                     {\r
863                         /* Found a resource range in the node that satisfies the requirements */\r
864                         opInfo->resourceInfo->base = index;\r
865                         resourceFound = TRUE;\r
866                         break;\r
867                     }\r
868 \r
869                     /* Move index to the next resource value that satisfies the alignment property */\r
870                     index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
871                 }\r
872             }\r
873             \r
874             if (!resourceFound)\r
875             {\r
876                 /* Move to the next tree node */\r
877                 matchingNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
878                 if (matchingNode == NULL)\r
879                 {\r
880                     /* Reached end of tree.  Resource range does not exist.  Leave the search\r
881                      * loop */\r
882                     break;\r
883                 }\r
884                 else\r
885                 {\r
886                     index = matchingNode->base;\r
887                 }\r
888             }\r
889             else\r
890             {\r
891                 /* Found a resource range that satisfies the request properties.  Break out of the\r
892                  * search loop */\r
893                 break;\r
894             }\r
895         }\r
896 \r
897         if (!resourceFound)\r
898         {\r
899             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
900         }\r
901     }\r
902     else\r
903     {\r
904         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
905     }\r
906 \r
907     return(retVal); \r
908 }\r
909 \r
910 /* Assume the policy has already approved of the allocation */\r
911 int32_t Rm_treeAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
912 {\r
913     Rm_ResourceTreeNode findNode;\r
914     Rm_ResourceTreeNode *matchingNode = NULL;\r
915     Rm_ResourceTreeNode *leftNode = NULL;\r
916     Rm_ResourceTreeNode *rightNode = NULL;  \r
917     uint32_t findEnd, matchingEnd;\r
918     int32_t retVal;\r
919 \r
920     /* Find the tree node that contains the specified resource range */\r
921     findNode.base = opInfo->resourceInfo->base;\r
922     findNode.length = opInfo->resourceInfo->length;\r
923     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
924 \r
925     if (matchingNode != NULL)\r
926     {\r
927         findEnd = findNode.base + findNode.length - 1;\r
928         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
929         \r
930         /* Does the request range fit within the matching nodes entire range? */\r
931         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
932         {\r
933             /* Handle node create, combine, deletion based on the request range if\r
934              * resources are available. */\r
935             if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
936             {\r
937                 /* Handle case where the findNode range matches the matchingNode\r
938                  * range exactly.\r
939                  *\r
940                  * base0                                  base0+length0-1\r
941                  *   |<---------------length0------------------->|  => existing node\r
942                  *   |<---------------length1------------------->|  => requested resources\r
943                  * base1                                  base1+length1-1\r
944                  */    \r
945                 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
946                 {\r
947                     /* Can reserve matchingNode's resources in-place */\r
948                     strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
949                 }\r
950                 /* Handle case where the findNode range is a subset of the matchingNode\r
951                  * range and neither of the boundaries of the two ranges are equivalent.\r
952                  *\r
953                  * base0                                  base0+length0-1\r
954                  *   |<---------------length0------------------->|  => existing node\r
955                  *         |<---------length1---------->|  => requested resources\r
956                  *       base1                   base1+length1-1\r
957                  */    \r
958                 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
959                 {\r
960                     /* Split the matching node into three nodes:\r
961                      * left node - free resources to left of newly allocated resources\r
962                      * middle node - newly allocated resources that satisfy the request\r
963                      * right node - free resources to the right of newly allocated resources */\r
964 \r
965                     /* Remove the matching node from the tree for modification. */\r
966                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
967 \r
968                     /* New left node attributes:\r
969                      * base: base of the matching node\r
970                      * length: base of requested resources - base of matching node */\r
971                     leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
972                                                       RM_NOT_ALLOCATED_STRING);\r
973                     /* New right node attributes:\r
974                      * base: base of the requested resources + length of requested resources\r
975                      * length: right bound of matching node - right bound of request resources */\r
976                     rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
977                                                        matchingEnd - findEnd, RM_NOT_ALLOCATED_STRING);\r
978 \r
979                     /* Base and length of matching node become the base and length of the\r
980                      * requested resources */\r
981                     matchingNode->base = findNode.base;                                    \r
982                     matchingNode->length = findNode.length;\r
983                     /* Reserve the resources */\r
984                     strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
985 \r
986                     /* Insert all the nodes */\r
987                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
988                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
989                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
990                 }\r
991                 /* Handle cases where one of findNode range boundaries is equivalent to\r
992                  * one of the matchingNode range boundaries.\r
993                  *\r
994                  * base0                                  base0+length0-1\r
995                  *   |<---------------length0------------------->|  => existing node\r
996                  *   |<---------length1---------->|  => requested resources\r
997                  * base1                   base1+length1-1\r
998                  *\r
999                  * OR\r
1000                  *\r
1001                  * base0                                  base0+length0-1\r
1002                  *   |<---------------length0------------------->|  => existing node\r
1003                  *                  |<---------length1---------->|  => requested resources\r
1004                  *                base1                   base1+length1-1                 \r
1005                  */    \r
1006                 else\r
1007                 {     \r
1008                     /* Remove the matchingNode from the tree since it will be edited */\r
1009                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1010                     \r
1011                     if (findNode.base == matchingNode->base)\r
1012                     {\r
1013                         /* There may be a combine possibility to the left. Extract leftNode to check */\r
1014                         leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1015                         \r
1016                         /* Can the node to the left of the matchingNode be combined with the \r
1017                          * findNode's range? */\r
1018                         if (leftNode && (strcmp(leftNode->allocatedTo, opInfo->srcInstName) == 0))\r
1019                         {\r
1020                             /* Remove the leftNode from the tree for editing */\r
1021                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1022 \r
1023                             /* Combine the leftNode and the findNode */\r
1024                             leftNode->length += findNode.length;\r
1025                         }\r
1026                         else\r
1027                         {\r
1028                             /* Allocate a new leftNode that will take the place of the findNode\r
1029                              * range in tree. */\r
1030                             leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
1031                                                               opInfo->srcInstName);\r
1032                         }\r
1033 \r
1034                         /* Account for the leftNode in the matchingNode */\r
1035                         matchingNode->base = findNode.base + findNode.length;\r
1036                         matchingNode->length = matchingEnd - findEnd;  \r
1037 \r
1038                         /* Insert the left node */\r
1039                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1040                     }\r
1041                     else if (findEnd == matchingEnd)\r
1042                     {\r
1043                         /* There may be a combine possibility to the right. Extract rightNode to check */\r
1044                         rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1045                         \r
1046                         /* Can the node to the right of the matchingNode be combined with the \r
1047                          * findNode's range? */\r
1048                         if (rightNode && (strcmp(rightNode->allocatedTo, opInfo->srcInstName) == 0))\r
1049                         {\r
1050                             /* Remove the rightNode from the tree for editing */\r
1051                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1052 \r
1053                             /* Combine the rightNode and the findNode */\r
1054                             rightNode->base = findNode.base;\r
1055                             rightNode->length += findNode.length;\r
1056                         }\r
1057                         else\r
1058                         {\r
1059                             /* Allocate a new rightNode that will take the place of the findNode\r
1060                              * range in tree. */\r
1061                             rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
1062                                                                opInfo->srcInstName);\r
1063                         }\r
1064 \r
1065                         /* Account for the rightNode in the matchingNode */\r
1066                         matchingNode->length -= findNode.length;  \r
1067 \r
1068                         /* Insert the right node */\r
1069                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1070                     }\r
1071 \r
1072                     /* Reinsert the edited matching node */\r
1073                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1074                 }\r
1075                 \r
1076                 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1077             }\r
1078             else\r
1079             {\r
1080                 /* A resource superset containing the requested range has\r
1081                  * already been allocated. */\r
1082                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
1083             }\r
1084         }\r
1085         else\r
1086         {\r
1087             /* Request ranges that span multiple nodes signify resources are\r
1088              * not available because nodes are combined into larger contiguous ranges\r
1089              * on resource free operations. */\r
1090             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
1091         }\r
1092     }\r
1093     else\r
1094     {\r
1095         /* The requested resources could not be found in the allocator */\r
1096         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1097     }\r
1098 \r
1099     return(retVal);        \r
1100 }\r
1101 \r
1102 /* Assume policy has already approved of the free */\r
1103 int32_t Rm_treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
1104 {\r
1105     Rm_ResourceTreeNode findNode;\r
1106     Rm_ResourceTreeNode *matchingNode = NULL;\r
1107     Rm_ResourceTreeNode *leftNode = NULL;\r
1108     Rm_ResourceTreeNode *rightNode = NULL;\r
1109     bool combineLeft = FALSE;\r
1110     bool combineRight = FALSE;\r
1111     uint32_t findEnd, matchingEnd;\r
1112     int32_t retVal;\r
1113 \r
1114     /* Find the tree node that contains the specified resource range */\r
1115     findNode.base = opInfo->resourceInfo->base;\r
1116     findNode.length = opInfo->resourceInfo->length;\r
1117     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
1118 \r
1119     if (matchingNode != NULL)\r
1120     {\r
1121         findEnd = findNode.base + findNode.length - 1;\r
1122         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
1123         \r
1124         /* Does the free range fit within the matching nodes entire range?  It should\r
1125          * either be the entire range or a subset set of the found range. (the latter\r
1126          * satisfies the case where an entity allocated a contiguous block of resources\r
1127          * then attempts to free a contiguous subset of the allocated block. */\r
1128         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
1129         {            \r
1130             if (strcmp(matchingNode->allocatedTo, opInfo->srcInstName) == 0)\r
1131             {\r
1132                 /* Resources can be freed */\r
1133 \r
1134                 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
1135                 {\r
1136                     /* Case 1: free range equals allocated matched node exactly. Attempt to combine \r
1137                      *         the range to be freed with the resource nodes to the left and\r
1138                      *         right of the free range.\r
1139                      *\r
1140                      * |<--left node-->||<---matched node--->||<--right node-->|\r
1141                      *                  |<---free request--->|\r
1142                      */ \r
1143 \r
1144                     leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1145                     rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1146 \r
1147                     /* Remove the matching node from the tree and the nodes to the left and\r
1148                      * right of the matching node.  Removing from tree will not\r
1149                      * wipe any of the base+length data in the node.  Can reuse since they won't\r
1150                      * be freed */\r
1151                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1152 \r
1153                     /* See if the left or right or both nodes can be combined with the matching\r
1154                      * node that will be freed. */\r
1155                     if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1156                     {\r
1157                         /* Combine the left node and the matching node */\r
1158                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1159                         combineLeft = TRUE;\r
1160                     }\r
1161                     if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1162                     {\r
1163                         /* Combine the right node and the matching node */\r
1164                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1165                         combineRight = TRUE;\r
1166                     }\r
1167 \r
1168                     /* Perform any combines, insert the leftover nodes, and free any memory associated\r
1169                      * with any nodes that weren't reinserted into the tree */\r
1170                     if (combineLeft && combineRight)\r
1171                     {\r
1172                         /* Combine all three nodes into the matchingNode.  Insert the freed cumulative\r
1173                          * matching node and delete the memory for the old left and right nodes */\r
1174                         matchingNode->base = leftNode->base;\r
1175                         matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
1176 \r
1177                         Rm_freeResourceTreeNode(leftNode);\r
1178                         Rm_freeResourceTreeNode(rightNode);                        \r
1179                     }\r
1180                     else if (combineLeft)\r
1181                     {\r
1182                         /* Combine the left and matching nodes.  Reinsert the right. */\r
1183                         matchingNode->base = leftNode->base;\r
1184                         matchingNode->length += leftNode->length;\r
1185                         \r
1186                         Rm_freeResourceTreeNode(leftNode);\r
1187                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);                        \r
1188                     }\r
1189                     else if (combineRight)\r
1190                     {\r
1191                         /* Combine the right and matching nodes.  Reinsert the left. */\r
1192                         matchingNode->length += rightNode->length;\r
1193                         \r
1194                         Rm_freeResourceTreeNode(rightNode);\r
1195                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1196                     }\r
1197                     else\r
1198                     {\r
1199                         /* Combine cannot be performed.  Reinsert the left and right nodes then\r
1200                          * free the matching node and reinsert it */\r
1201                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1202                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1203                     }\r
1204 \r
1205                     /* No matter the combine route taken the matching node will always be declared\r
1206                      * free and reinserted */\r
1207                     strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
1208                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);                    \r
1209                 }\r
1210                 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
1211                 {\r
1212                     /* Case 2: free range is less than range in matched node. Need to split\r
1213                      *         the matched node into three nodes.\r
1214                      *\r
1215                      * |<----------matched node---------->|\r
1216                      *        |<---free request--->|\r
1217                      */ \r
1218 \r
1219                     /* Remove matching node for editing. */\r
1220                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1221 \r
1222                     /* New left node attributes:\r
1223                      * base: base of the matching node\r
1224                      * length: base of requested resources - base of matching node */\r
1225                     leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
1226                                                       matchingNode->allocatedTo); \r
1227                     /* New right node attributes:\r
1228                      * base: base of the requested resources + length of requested resources\r
1229                      * length: right bound of matching node - right bound of request resources */\r
1230                     rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
1231                                                        matchingEnd - findEnd, matchingNode->allocatedTo);\r
1232 \r
1233                     /* Insert the left and right nodes into the tree. */\r
1234                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1235                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1236 \r
1237                     /* Base and length of matching node become the base and length of the freed resources */\r
1238                     matchingNode->base = findNode.base;                                    \r
1239                     matchingNode->length = findNode.length;\r
1240                     /* Free the resources and insert them into the tree */\r
1241                     strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
1242                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1243                 }\r
1244                 else\r
1245                 {\r
1246                     /* Remove the matchingNode from the tree since it will be edited */\r
1247                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1248                     \r
1249                     if (findNode.base == matchingNode->base)\r
1250                     {\r
1251                         /* Case 3: Free range is on left boundary of matched node. Try to \r
1252                          *         combine the free range with the left node if free.\r
1253                          *\r
1254                          * |<---left node (free)--->||<----------matched node---------->|\r
1255                          *                           |<---findNode (free req)--->|\r
1256                          */ \r
1257                    \r
1258                         /* There may be a combine possibility to the left. Extract leftNode to check */\r
1259                         leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1260                         \r
1261                         /* Can the node to the left of the matchingNode be combined with the \r
1262                          * findNode's range? */\r
1263                         if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1264                         {\r
1265                             /* Remove the leftNode from the tree for editing */\r
1266                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1267 \r
1268                             /* Combine the leftNode and the findNode */\r
1269                             leftNode->length += findNode.length;\r
1270                         }\r
1271                         else\r
1272                         {\r
1273                             /* Allocate a new leftNode that will take the place of the findNode\r
1274                              * range in tree. */\r
1275                             leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
1276                                                               RM_NOT_ALLOCATED_STRING);\r
1277                         }\r
1278 \r
1279                         /* Account for the leftNode in the matchingNode */\r
1280                         matchingNode->base = findNode.base + findNode.length;\r
1281                         matchingNode->length = matchingEnd - findEnd;  \r
1282 \r
1283                         /* Insert the left node */\r
1284                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1285                     }\r
1286                     else if (findEnd == matchingEnd)\r
1287                     {\r
1288                         /* Case 4: Free range is on right boundary of matched node. Try to \r
1289                          *         combine the free range with the right node if free.\r
1290                          *\r
1291                          * |<----------matched node---------->||<---right node (free)--->|\r
1292                          *        |<---findNode (free req)--->|\r
1293                          */ \r
1294                         \r
1295                         /* There may be a combine possibility to the right. Extract rightNode to check */\r
1296                         rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1297                         \r
1298                         /* Can the node to the right of the matchingNode be combined with the \r
1299                          * findNode's range? */\r
1300                         if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1301                         {\r
1302                             /* Remove the rightNode from the tree for editing */\r
1303                             RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1304 \r
1305                             /* Combine the rightNode and the findNode */\r
1306                             rightNode->base = findNode.base;\r
1307                             rightNode->length += findNode.length;\r
1308                         }\r
1309                         else\r
1310                         {\r
1311                             /* Allocate a new rightNode that will take the place of the findNode\r
1312                              * range in tree. */\r
1313                             rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
1314                                                                RM_NOT_ALLOCATED_STRING);\r
1315                         }\r
1316 \r
1317                         /* Account for the rightNode in the matchingNode */\r
1318                         matchingNode->length -= findNode.length;  \r
1319 \r
1320                         /* Insert the right node */\r
1321                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1322                     }\r
1323 \r
1324                     /* Reinsert the edited matching node */\r
1325                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1326                 }\r
1327 \r
1328                 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1329             }\r
1330             else\r
1331             {\r
1332                 /* The matching allocated range to be freed was allocated to a different instance. */\r
1333                 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
1334             }\r
1335         }\r
1336         else\r
1337         {\r
1338             /* Free resource range crosses over node boundaries.  This signifies a\r
1339              * free of both allocated and unallocated resources since nodes are combined\r
1340              * on allocate and free operations if possible. */\r
1341             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
1342         }\r
1343     }\r
1344     else\r
1345     {\r
1346         /* The free resources could not be found in the allocator */\r
1347         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1348     }\r
1349 \r
1350     return(retVal);  \r
1351 }\r
1352 \r
1353 int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)\r
1354 {\r
1355     Rm_Allocator *allocator = NULL;\r
1356     int32_t retVal;\r
1357     void *key;\r
1358 \r
1359     /* Lock access to the RM instance's transaction queue */\r
1360     key = Rm_osalMtCsEnter();\r
1361 \r
1362     /* Get the specified resource's allocator */\r
1363     allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name);\r
1364 \r
1365     if (allocator)\r
1366     {\r
1367         /* Call the allocator's type-based allocation function */\r
1368         if(allocator->type == Rm_allocatorType_INTEGER)\r
1369         {\r
1370             if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
1371             {\r
1372                 retVal = Rm_integerPreAllocate(allocator, opInfo);\r
1373             }            \r
1374             else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
1375             {\r
1376                 retVal = Rm_integerAllocate(allocator, opInfo);\r
1377             }\r
1378             else if (opInfo->operation == Rm_allocatorOp_FREE)\r
1379             {\r
1380                 retVal = Rm_integerFree(allocator, opInfo);\r
1381             }\r
1382         }\r
1383         else if (allocator->type == Rm_allocatorType_TREE)\r
1384         {\r
1385             if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
1386             {\r
1387                 retVal = Rm_treePreAllocate(allocator, opInfo);\r
1388             }               \r
1389             else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
1390             {\r
1391                 retVal = Rm_treeAllocate(allocator, opInfo);\r
1392             }\r
1393             else if (opInfo->operation == Rm_allocatorOp_FREE)\r
1394             {\r
1395                 retVal = Rm_treeFree(allocator, opInfo);\r
1396             }  \r
1397         }        \r
1398     }\r
1399     else\r
1400     {\r
1401         /* Allocator could not be found for resource */\r
1402         retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST;\r
1403     }\r
1404 \r
1405     Rm_osalMtCsExit(key);\r
1406     return(retVal);\r
1407 }\r
1408 \r
1409 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1410 {\r
1411     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1412     {\r
1413 #if 0        \r
1414         if (resourceBase is unspecified)\r
1415         {\r
1416            while (policy does not approve)\r
1417            {\r
1418                Rm_policy check get allowed base as starting point for prealloc\r
1419                preallocate resource based on the range and alignment\r
1420                Rm_policy...check\r
1421            }\r
1422         }\r
1423         else\r
1424         {\r
1425             /* Check local policy to see if the request can be satisfied with the\r
1426              * resources stored locally */\r
1427             Rm_policy...API()\r
1428 \r
1429             if (policy check approves the resource)\r
1430             {\r
1431                 /* call the allocator to allocate the resource */\r
1432                 if (allocator returns resource)\r
1433                 {\r
1434                     /* Populate the transaction with the allocated resources and the result */\r
1435                     transaction->state = approve reason;\r
1436                     return ...\r
1437                 }\r
1438                 else\r
1439                 {\r
1440                     /* allocator ran out of resources, need to contact Server for more\r
1441                      * resources */\r
1442                     Rm_resourcePoolModRequest(...);\r
1443                 }\r
1444             }\r
1445             else if (policy check denies resource)\r
1446             {\r
1447                 /* Policy check denied resource. */\r
1448                 transaction->state= deny reason;\r
1449                 return ...\r
1450             }\r
1451             else if (policy check says forward to Server for validation)\r
1452             {\r
1453                 /* Forward the transaction to the Server */\r
1454                 Rm_transactionForwarder(rmInst, transaction);\r
1455             }\r
1456         }\r
1457 #endif         \r
1458     }\r
1459     else if (rmInst->instType == Rm_instType_SERVER)\r
1460     {\r
1461 #if 0       \r
1462         if (resourceBase is unspecified)\r
1463         {\r
1464            while (policy does not approve)\r
1465            {\r
1466                Rm_policy check get allowed base as starting point for prealloc\r
1467                preallocate resource based on the range and alignment\r
1468                Rm_policy...check\r
1469            }\r
1470         }\r
1471         else\r
1472         {\r
1473             /* Check global policy to see if resource can be allocated. return result\r
1474              * no matter what */\r
1475             Rm_policy...API()\r
1476 \r
1477             if (policy approves)\r
1478             {\r
1479                 /* call allocator to allocate resource */\r
1480             }\r
1481 \r
1482             transaction->state = approve or deny reason;\r
1483             transaction->resourceInfo.base = ...;\r
1484             transaction->resourceInfo.length = ...;\r
1485 \r
1486             /* If source instance name does not match the current instance\r
1487              * name the allocation request came from a Client.  The result\r
1488              * must be sent back to the Client */\r
1489             if (strcmp(transaction->sourceInstName, rmInst->name))\r
1490             {\r
1491                 /* Names don't match.  Send the transaction back to the Client */\r
1492                 Rm_transactionResponder(rmInst, transaction);\r
1493             }\r
1494             else\r
1495             {\r
1496                 /* Resource allocation request originated locally on the active\r
1497                  * instance. Send the response via the service responder. */          \r
1498                 Rm_serviceResponder(rmInst, transaction);                            \r
1499             }\r
1500         }\r
1501 #endif        \r
1502     }   \r
1503 }\r
1504 \r
1505 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1506 {\r
1507     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1508     {\r
1509 #if 0        \r
1510         /* Check local policy to see if the request can be satisfied with the\r
1511          * resources stored locally */\r
1512         Rm_policy...API()\r
1513 \r
1514         if (policy check approves the free)\r
1515         {\r
1516             /* call the allocator to free the resource */\r
1517             /* Run a resource pool check to see if the free combined a resource block\r
1518              * that can be returned to the server */\r
1519             if (resource block has been combined)\r
1520             {\r
1521                   /* allocator ran out of resources, need to contact Server for more\r
1522                  * resources */\r
1523                 Rm_resourcePoolModRequest(free pool block to server...);\r
1524             }\r
1525             else\r
1526             {\r
1527                 /* Populate the receipt with the freed resources and the result */\r
1528                 transaction->state = approve reason;\r
1529                 return ...\r
1530             }\r
1531         }\r
1532         else if (policy check denies resource free)\r
1533         {\r
1534             /* Policy check denied resource. */\r
1535             transaction->state = deny reason;\r
1536             return ...\r
1537         }\r
1538         else if (policy check says forward to Server for validation)\r
1539         {\r
1540             /* Forward the transaction to the Server */\r
1541             Rm_transactionForwarder(rmInst, transaction);\r
1542         }\r
1543 #endif         \r
1544     }\r
1545     else if (rmInst->instType == Rm_instType_SERVER)\r
1546     {\r
1547 #if 0        \r
1548         /* Check global policy to see if resource can be freed. return result\r
1549          * no matter what */\r
1550         Rm_policy...API()\r
1551         if (policy approves)\r
1552         {\r
1553             /* call allocator to free resources */\r
1554         }\r
1555             \r
1556         transaction->state = approve or deny reason;\r
1557         transaction->resourceInfo.base = ...;\r
1558         transaction->resourceInfo.length = ...;\r
1559 \r
1560         /* If source instance name does not match the current instance\r
1561          * name the allocation request came from a client.  The result\r
1562          * must be sent back to the Client */\r
1563         if (strcmp(transaction->sourceInstName, rmInst->name))\r
1564         {\r
1565             /* Names don't match.  Send the transaction back to the Client Delegate or Client */\r
1566             Rm_transactionResponder(rmInst, transaction);\r
1567         }\r
1568         else\r
1569         {\r
1570             /* Resource allocation request originated locally on the active\r
1571              * instance. Send the response via the service responder. */\r
1572             Rm_serviceResponder(rmInst, transaction);                            \r
1573         }\r
1574 #endif        \r
1575     }   \r
1576 }\r
1577 \r
1578 /* Function used to forward RM transactions to higher level agents */\r
1579 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1580 {\r
1581     Rm_TransportNode *dstTransportNode = NULL;\r
1582     Rm_Packet *rmPkt = NULL;\r
1583 \r
1584     /* Make sure the RM instance has a transport registered with a higher level agent */\r
1585     if (rmInst->registeredWithDelegateOrServer == false)\r
1586     {\r
1587         transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
1588         return;\r
1589     }\r
1590 \r
1591     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
1592      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
1593      * Delegates will be connected to a Server. */\r
1594     if (rmInst->instType == Rm_instType_CLIENT)\r
1595     {\r
1596         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
1597     } \r
1598     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1599     {\r
1600         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1601     }\r
1602 \r
1603     /* Create a RM packet using the service information */\r
1604     switch (transaction->type)\r
1605     {\r
1606         case Rm_service_RESOURCE_ALLOCATE:\r
1607         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
1608         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
1609         case Rm_service_RESOURCE_FREE:\r
1610         case Rm_service_RESOURCE_BLOCK_FREE:\r
1611         case Rm_service_RESOURCE_FREE_BY_NAME:\r
1612             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
1613                                                      transaction);\r
1614             break;\r
1615         case Rm_service_RESOURCE_MAP_TO_NAME:\r
1616         case Rm_service_RESOURCE_UNMAP_NAME:\r
1617             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
1618                                                    transaction);\r
1619             break;\r
1620         default:\r
1621             /* Invalid service type.  Flag the error and return */\r
1622             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1623             break;\r
1624     }\r
1625 \r
1626     if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
1627     {\r
1628         /* Return immediately because an error occurred allocating the packet */\r
1629         return;\r
1630     }\r
1631 \r
1632     /* Send the RM packet to the application transport */\r
1633     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
1634     {\r
1635         /* Negative value returned by transport send.  An error occurred\r
1636          * in the transport while attempting to send the packet.*/\r
1637         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1638         /* Clean up the packet */\r
1639         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
1640         {\r
1641             /* Non-NULL value returned by transport packet free. Flag the\r
1642              * error */\r
1643             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1644         }\r
1645         return;\r
1646     }\r
1647 \r
1648     /* Transaction is not deleted because it is awaiting a response from the higher level\r
1649      * RM instance */\r
1650 }\r
1651 \r
1652 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1653 {\r
1654     /* Handle auto-forwarded transactions.  These transactions include:\r
1655      * - All request transactions received on Clients are forwarded to the Client Delegate\r
1656      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
1657     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
1658         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
1659          (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
1660          (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
1661     {\r
1662         /* Check if the transaction is a transaction that received a response to its\r
1663          * request. */\r
1664         if (transaction->state != RM_SERVICE_PROCESSING)\r
1665         {\r
1666 \r
1667             /* A transaction has received a response. Send the response to either the \r
1668              * transaction or service responder based on the source instance */\r
1669             if (strcmp(transaction->sourceInstName, rmInst->name))\r
1670             {\r
1671                 /* Transaction originated from another instance.  Use the \r
1672                  * transaction responder to send the result to the source instance.  This\r
1673                  * is not possible on RM Clients since they can't forward RM services */\r
1674                 Rm_transactionResponder(rmInst, transaction);\r
1675             }\r
1676             else\r
1677             {\r
1678                 /* Transaction originated on this instance.  Send to the\r
1679                  * service responder */\r
1680                 Rm_serviceResponder(rmInst, transaction);\r
1681             }\r
1682         }\r
1683         else\r
1684         {\r
1685             /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
1686             Rm_transactionForwarder(rmInst, transaction);\r
1687         }\r
1688     }\r
1689     else\r
1690     {\r
1691         /* Client Delegate and Server transaction processors. */\r
1692         switch (transaction->type)\r
1693         {\r
1694             case Rm_service_RESOURCE_ALLOCATE:\r
1695             case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
1696             case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
1697             case Rm_service_RESOURCE_FREE:\r
1698             case Rm_service_RESOURCE_BLOCK_FREE:\r
1699             case Rm_service_RESOURCE_FREE_BY_NAME:                \r
1700                 /* Check if the transaction is fulfilled request */\r
1701                 if (transaction->state != RM_SERVICE_PROCESSING)\r
1702                 {\r
1703                     /* If source instance name does not match the current instance\r
1704                      * name the allocation request came from a client.  The result\r
1705                      * must be sent back to the Client */\r
1706                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
1707                     {\r
1708                         Rm_transactionResponder(rmInst, transaction);\r
1709                     }\r
1710                     else\r
1711                     {\r
1712                         /* Resource allocation request originated locally.  Send the response\r
1713                          * via the service responder. */\r
1714                         Rm_serviceResponder(rmInst, transaction);      \r
1715                     }\r
1716                 }\r
1717                 else\r
1718                 {\r
1719                     /* This is a new transaction request originating from an RM instance with fewer\r
1720                      * allocate/free privileges.  Run the allocation or free handler to see if the resource\r
1721                      * request can be handled locally or if it needs to be forwarded to a higher level\r
1722                      * agent */\r
1723                     if ((transaction->type == Rm_service_RESOURCE_ALLOCATE) ||\r
1724                         (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) ||\r
1725                         (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))\r
1726                     {\r
1727                         Rm_allocationHandler(rmInst, transaction);\r
1728                     }\r
1729                     else\r
1730                     {\r
1731                         Rm_freeHandler(rmInst, transaction);\r
1732                     }\r
1733                 }\r
1734                 break;\r
1735             case Rm_service_RESOURCE_MAP_TO_NAME:\r
1736             case Rm_service_RESOURCE_UNMAP_NAME:                \r
1737                 /* Server is the only RM instance capable of adding NameServer objects */\r
1738                 if (rmInst->instType == Rm_instType_SERVER)\r
1739                 {\r
1740                     if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
1741                     {\r
1742                         /* Create a new NameServer object with the request transaction information.\r
1743                          * Transaction will contain the state result of the NameServer addition. */\r
1744                         if (Rm_nsAddObject(rmInst, transaction->resourceInfo.nsName,\r
1745                                            transaction->resourceInfo.base) == RM_NS_ACTION_APPROVED)\r
1746                         {\r
1747                             transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1748                         }\r
1749                         else\r
1750                         {\r
1751                             /* TEMP: UPDATE THIS STATE VALUE */\r
1752                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1753                         }\r
1754                     }\r
1755                     else\r
1756                     {\r
1757                         /* Delete an existing NameServer object with the request transaction information\r
1758                          * Transaction will contain the state result of the NameServer addition. */\r
1759                         if (Rm_nsDeleteObject(rmInst, transaction->resourceInfo.nsName) == \r
1760                             RM_NS_ACTION_APPROVED)\r
1761                         {\r
1762                             transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1763                         }\r
1764                         else\r
1765                         {\r
1766                             /* TEMP: UPDATE THIS STATE VALUE */\r
1767                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1768                         }\r
1769                     }\r
1770 \r
1771                     /* If source instance name does not match the local instance\r
1772                      * name the NameServer request came from a Client or Client Delegate.  The \r
1773                      * result must be sent back to the Client or Client Delegate.  Just return if it does\r
1774                      * match since the NameServer transaction result can be returned immediately by the\r
1775                      * Rm_serviceHandler. */\r
1776                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
1777                     {\r
1778                         Rm_transactionResponder(rmInst, transaction);\r
1779                     }\r
1780                 }\r
1781                 else\r
1782                 {\r
1783                     transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1784                 }\r
1785                 break;\r
1786         }\r
1787     }\r
1788 }\r
1789 \r
1790 int32_t Rm_reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, \r
1791                                 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)\r
1792 {\r
1793     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1794     bool baseFound = FALSE;\r
1795     bool lengthFound = FALSE;\r
1796     uint32_t valueIndex = 0;\r
1797 \r
1798     while ((linuxValues != NULL) && (!baseFound || !lengthFound))\r
1799     {\r
1800         if (linuxAlias->baseOffset == valueIndex)\r
1801         {\r
1802             /* Found the resource base.  Store it in the operation info structure */\r
1803             opInfo->resourceInfo->base = linuxValues->value;\r
1804             baseFound = TRUE;\r
1805 \r
1806             /* length will always be 1 if there is no length specified in the Linux DTB */\r
1807             if (linuxAlias->lengthOffset == RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET)\r
1808             {\r
1809                 opInfo->resourceInfo->length = 1;\r
1810                 lengthFound = TRUE;\r
1811             }\r
1812         }\r
1813         else if (linuxAlias->lengthOffset == valueIndex)\r
1814         {\r
1815             /* Found the resource length.  Store it in the operation info structure */\r
1816             opInfo->resourceInfo->length = linuxValues->value;\r
1817             lengthFound = TRUE;\r
1818         }\r
1819 \r
1820         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;\r
1821         valueIndex++;\r
1822     }\r
1823 \r
1824     if (!baseFound || !lengthFound)\r
1825     {\r
1826         retVal = -33; /* TODO: ERROR BASE OR LENGTH OFFSET IN LINUX DTB WAS INCORRECT */\r
1827     }\r
1828     else\r
1829     {\r
1830         /* Allocate the resource to Linux */\r
1831         retVal = Rm_allocatorOperation(rmInst, opInfo);\r
1832     }\r
1833 \r
1834     return (retVal);\r
1835 }\r
1836 \r
1837 int32_t Rm_findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, \r
1838                                        Rm_LinuxAlias *linuxAlias)\r
1839 {\r
1840     Rm_AllocatorOpInfo opInfo;\r
1841     Rm_ResourceInfo resourceInfo;\r
1842     uint32_t pathOffset;\r
1843     int32_t propOffset;\r
1844     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1845     int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
1846     int32_t depth;\r
1847     int32_t propertyLen;\r
1848     const char *propertyName;\r
1849     const void *propertyData; \r
1850     Rm_LinuxValueRange *linuxValueRange;\r
1851     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY; \r
1852 \r
1853     /* Initialize the allocator opInfo and resourceInfo structures that will be used to \r
1854      * reserve the resources taken by the Linux kernel */\r
1855     memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1856     memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
1857 \r
1858     strcpy(resourceInfo.name, resourceName);\r
1859 \r
1860     /* Set the source instance name for allocation to be the Linux Kernel */\r
1861     opInfo.srcInstName = RM_ALLOCATED_TO_LINUX;\r
1862     opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
1863     opInfo.resourceInfo = &resourceInfo;    \r
1864 \r
1865     /* Find each resource specified in the Linux resource alias list and reserve that \r
1866      * resource as used */\r
1867     while(linuxAlias != NULL)\r
1868     {\r
1869         /* Reset the parsing variables */\r
1870         pathOffset = 0;\r
1871         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1872         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;   \r
1873         resourceInfo.base = 0;\r
1874         resourceInfo.length = 0;\r
1875         \r
1876         while(pathOffset < linuxAlias->pathListLenBytes)\r
1877         {\r
1878             /* Move through the DTB nodes until the next alias path node is found */\r
1879             if (strcmp(linuxAlias->pathList + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL)))\r
1880             {\r
1881                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);\r
1882 \r
1883                 if (depth < prevDepth)\r
1884                 {\r
1885                     /* Returning from subnode that matched part of alias path without finding\r
1886                      * the resource values */\r
1887                     retVal = (-31); /* TODO: COULD NOT FIND RESOURCE AT ALIAS PATH */\r
1888                     break;\r
1889                 }\r
1890             }\r
1891             else\r
1892             {\r
1893                 /* Found the next alias path node */\r
1894                 pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
1895                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);\r
1896 \r
1897                 /* Check the properties of the node to see if they match the next alias\r
1898                  * path string */\r
1899                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);\r
1900            \r
1901                 /* Search the properties for the next alias path string */\r
1902                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&\r
1903                        (pathOffset < linuxAlias->pathListLenBytes))\r
1904                 {\r
1905                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, \r
1906                                                          &propertyName, &propertyLen);\r
1907 \r
1908                     if (strcmp(linuxAlias->pathList + pathOffset, propertyName) == 0)\r
1909                     {\r
1910                         pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
1911                         /* Found the alias property.  Extract the values that will\r
1912                          * contain the resource information that must be reserved. */\r
1913                         linuxValueRange = Rm_linuxExtractValues(propertyData, propertyLen);\r
1914                         /* Use the values to reserve resources for the Linux kernel */\r
1915                         retVal = Rm_reserveLinuxResource(rmInst, linuxAlias, \r
1916                                                          linuxValueRange, &opInfo);\r
1917                         \r
1918                         /* Free the memory used to store the values */\r
1919                         Rm_linuxFreeValues(linuxValueRange);\r
1920                     }\r
1921                     \r
1922                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);\r
1923                 } \r
1924 \r
1925                 if (propOffset < -FDT_ERR_NOTFOUND)\r
1926                 {\r
1927                         /* Error was returned by LIBFDT when parsing the properties */\r
1928                     retVal = propOffset;\r
1929                     break;\r
1930                 }\r
1931             }\r
1932         }\r
1933 \r
1934         if (retVal < RM_DTB_UTIL_RESULT_OKAY)\r
1935         {\r
1936             /* Error occurred during parsing of Linux DTB.  Return the error */\r
1937             break;\r
1938         }\r
1939         linuxAlias = (Rm_LinuxAlias *) linuxAlias->nextLinuxAlias;\r
1940     }\r
1941 \r
1942     return (retVal);\r
1943 }\r
1944 \r
1945 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
1946                                   Rm_ResourceProperties *resourceProperties, void *linuxDtb)\r
1947 {\r
1948     char *allocatorType = NULL;\r
1949     Rm_ResourceRange *range = NULL;\r
1950     Rm_ResourceRange *rangeBasePtr = NULL;\r
1951     Rm_NsAssignment *nsAssignments = NULL;\r
1952     Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
1953     Rm_LinuxAlias *linuxAlias = NULL;\r
1954     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1955 \r
1956     /* TODO: NEED CHECKS FOR VALIDITY OF ALL THE resourceProperties FIELDS */\r
1957 \r
1958     /* Extract the resource properties from the DTB */\r
1959     allocatorType = Rm_resourceExtractAllocator(resourceProperties->allocatorData, \r
1960                                                 resourceProperties->allocatorLen);\r
1961     range = rangeBasePtr = Rm_resourceExtractRange(resourceProperties->rangeData, \r
1962                                                    resourceProperties->rangeLen);\r
1963 \r
1964     /* Create an allocator based on the allocator type specified */\r
1965     if (strcmp(allocatorType, &rmIntegerAllocator[0]) == 0)\r
1966     {\r
1967         /* Create an integer allocator using the resource properties */\r
1968         retVal = Rm_createIntegerAllocator(rmInst, resourceName, range);        \r
1969     }\r
1970     else if (strcmp(allocatorType, &rmTreeAllocator[0]) == 0)\r
1971     {\r
1972         /* Create a tree allocator using the resource properties */\r
1973         retVal = Rm_createTreeAllocator(rmInst, resourceName, range); \r
1974     }\r
1975     else\r
1976     {\r
1977         /* Allocator type not recognized.  Free the resource properties and return */\r
1978         retVal = -21; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1979     }\r
1980 \r
1981     if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1982     {\r
1983         if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen)\r
1984         {\r
1985             /* Reserve the resources taken by the Linux kernel specified in the Linux DTB */\r
1986             linuxAlias = Rm_resourceExtractLinuxAlias(resourceProperties->linuxAliasData,\r
1987                                                       resourceProperties->linuxAliasLen);\r
1988 \r
1989             retVal = Rm_findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias);            \r
1990         }\r
1991     }\r
1992     \r
1993     if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1994     {\r
1995         /* Create entries in the NameServer if any NameServer assignments were specified */\r
1996         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
1997         {\r
1998             nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
1999                                                            resourceProperties->nsAssignLen);\r
2000 \r
2001             /* Cycle through the list of assignments and add them to the NameServer */\r
2002             nsAssignmentBasePtr = nsAssignments;\r
2003             while (nsAssignments)\r
2004             {\r
2005                 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
2006                 Rm_nsAddObject(rmInst, nsAssignments->nsName, nsAssignments->resourceValue);\r
2007                 nsAssignments = nsAssignments->nextNsAssignment;\r
2008             }\r
2009             /* Free the memory allocated for the NameServer assignments */\r
2010             Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
2011         }\r
2012     }\r
2013 \r
2014     /* Free the memory allocated for the resource properties */\r
2015     Rm_resourceFreeAllocator(allocatorType);\r
2016     Rm_resourceFreeRange(rangeBasePtr);\r
2017     Rm_resourceFreeLinuxAlias(linuxAlias);\r
2018 \r
2019     return(retVal);\r
2020 }\r
2021 \r
2022 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
2023 {\r
2024         int32_t propertyLen;\r
2025         const char *propertyName;\r
2026         const void *propertyData;\r
2027     Rm_ResourcePropType propertyType;\r
2028     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
2029 \r
2030     /* Get the property data and store it in the corresponding propertyInfo field */\r
2031         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
2032     if (propertyData)\r
2033     {\r
2034         propertyType = Rm_resourceGetPropertyType(propertyName);\r
2035         if (propertyType == Rm_resourcePropType_RESOURCE_ALLOCATOR)\r
2036         {\r
2037             if (propertyInfo->allocatorData || propertyInfo->allocatorLen)\r
2038             {\r
2039                 /* The allocator fields have already been populated.  Return an error.\r
2040                  * The resource list has specified a property field more than once\r
2041                  * for a resource node */\r
2042                 retVal = -17; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2043             }\r
2044             else\r
2045             {\r
2046                 propertyInfo->allocatorData = propertyData;\r
2047                 propertyInfo->allocatorLen = propertyLen;\r
2048             }\r
2049         }\r
2050         else if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
2051         {\r
2052             if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
2053             {\r
2054                 /* The range fields have already been populated.  Return an error.\r
2055                  * The resource list has specified a property field more than once\r
2056                  * for a resource node */\r
2057                 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2058             }\r
2059             else\r
2060             {\r
2061                 propertyInfo->rangeData = propertyData;\r
2062                 propertyInfo->rangeLen = propertyLen;\r
2063             }\r
2064         }\r
2065         else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
2066         {\r
2067             if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
2068             {\r
2069                 /* The nsAssign fields have already been populated.  Return an error.\r
2070                  * The resource list has specified a property field more than once\r
2071                  * for a resource node */\r
2072                 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2073             }\r
2074             else\r
2075             {\r
2076                 propertyInfo->nsAssignData = propertyData;\r
2077                 propertyInfo->nsAssignLen = propertyLen;\r
2078             }\r
2079         }\r
2080         else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS)\r
2081         {\r
2082             if (propertyInfo->linuxAliasData || propertyInfo->linuxAliasLen)\r
2083             {\r
2084                 /* The linuxAlias fields have already been populated.  Return an error.\r
2085                  * The resource list has specified a property field more than once\r
2086                  * for a resource node */\r
2087                 retVal = -28; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2088             }\r
2089             else\r
2090             {\r
2091                 propertyInfo->linuxAliasData = propertyData;\r
2092                 propertyInfo->linuxAliasLen = propertyLen;\r
2093             }\r
2094         }        \r
2095         else\r
2096         {\r
2097             retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2098         }\r
2099     }\r
2100     else\r
2101     {\r
2102         retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
2103     }\r
2104 \r
2105     /* Don't get anymore properties if error occurred */\r
2106     if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
2107     {\r
2108         offset = fdt_next_property_offset(globalResourceDtb, offset);\r
2109         if (offset >= 0)\r
2110         {\r
2111             retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
2112         }\r
2113         else if (offset != -FDT_ERR_NOTFOUND)\r
2114         {\r
2115             /* Error was returned by LIBFDT when parsing the properties */\r
2116             retVal = offset;\r
2117         }\r
2118     }\r
2119     \r
2120     return (retVal);\r
2121 }\r
2122 \r
2123 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,\r
2124                              void *linuxDtb)\r
2125 {\r
2126         const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
2127     Rm_ResourceProperties resourceProperties;\r
2128         int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
2129         int32_t offset;\r
2130 \r
2131     /* Initialize the resource properties structure */\r
2132     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
2133 \r
2134     /* Ignore properties of the base node */\r
2135     if (strcmp(resourceName, rmDtbStartingNode))\r
2136     {\r
2137         /* Get the properties for the resource node if any exist */\r
2138         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
2139         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
2140         {\r
2141             /* Since at least one property exists attempt to parse the property nodes and \r
2142              * use them to create and initialize a resource allocator */\r
2143                 error =  Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
2144             if (error < -FDT_ERR_NOTFOUND)\r
2145             {\r
2146                 return (error);\r
2147             }\r
2148             \r
2149             /* Initialize an allocator with the resource properties if no error was returned */\r
2150             Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb);\r
2151         }\r
2152         else if (offset != -FDT_ERR_NOTFOUND)\r
2153         {\r
2154                 /* Error was returned by LIBFDT when parsing the properties */\r
2155             return (offset);\r
2156         }\r
2157     }\r
2158     \r
2159     /* Get the next resource node */\r
2160         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
2161     /* Check the offset and depth of the next node to make sure the current node\r
2162      * wasn't the last node in the Resource List.  A depth less than the depth set\r
2163      * at the start of the recursion will signal the end of the resource list */\r
2164     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
2165     {\r
2166         error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);\r
2167         if (error < -FDT_ERR_NOTFOUND)\r
2168         {\r
2169             return (error);\r
2170         }\r
2171     }\r
2172     else if (offset != -FDT_ERR_NOTFOUND)\r
2173     {\r
2174         /* Error was returned by LIBFDT when parsing the nodes */\r
2175         return (offset);\r
2176     }\r
2177 \r
2178     return (RM_DTB_UTIL_RESULT_OKAY);\r
2179 }\r
2180 \r
2181 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)\r
2182 {\r
2183     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
2184     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
2185     int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
2186 \r
2187     /* Recursively parse the Global Resource List, creating an allocator for\r
2188      * each resource as specified in the node */\r
2189     result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);\r
2190 \r
2191     return(result);\r
2192 }\r
2193 \r
2194 void Rm_printResourceStatus(Rm_Inst *rmInst)\r
2195 {\r
2196     Rm_Allocator *allocator = rmInst->allocators;\r
2197     Rm_IntegerAllocatorRootEntry *integerRoot;\r
2198     Rm_IntegerEntry *integerEntry;\r
2199     Rm_ResourceTree *treeRoot;\r
2200     Rm_ResourceTreeNode *treeNode;\r
2201     uint32_t numLinuxResources;\r
2202     uint32_t i;\r
2203 \r
2204     while (allocator != NULL)\r
2205     {\r
2206         numLinuxResources = 0;\r
2207 \r
2208         Rm_osalLog("Resource: %s\n", allocator->resourceName);\r
2209 \r
2210         if (allocator->type == Rm_allocatorType_INTEGER)\r
2211         {\r
2212             integerRoot = allocator->allocatorRootEntry;\r
2213             integerEntry = integerRoot->resourceArrayBase;\r
2214 \r
2215             for (i = 0; i < integerRoot->numResourceElements; i++)\r
2216             {\r
2217                 if (strcmp(integerEntry[i].allocatedTo, RM_ALLOCATED_TO_LINUX) == 0)\r
2218                 {\r
2219                     Rm_osalLog("Value: %5d reserved for %s\n", integerEntry[i].value, \r
2220                                                                integerEntry[i].allocatedTo);\r
2221                     numLinuxResources++;\r
2222                 }\r
2223             }\r
2224         }\r
2225         else if (allocator->type == Rm_allocatorType_TREE)\r
2226         {\r
2227             treeRoot = allocator->allocatorRootEntry;\r
2228 \r
2229             RB_FOREACH(treeNode, _Rm_ResourceTree, treeRoot)\r
2230             {               \r
2231                 Rm_osalLog("          %5d - %5d ", treeNode->base, \r
2232                                                    treeNode->base + treeNode->length -1);\r
2233                 \r
2234                 if (strcmp(treeNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
2235                 {\r
2236                     Rm_osalLog("NOT ALLOCATED\n");\r
2237                 }\r
2238                 else\r
2239                 {\r
2240                     Rm_osalLog("allocated to %s\n", treeNode->allocatedTo);\r
2241                 }\r
2242 \r
2243                 if (strcmp(treeNode->allocatedTo, RM_ALLOCATED_TO_LINUX) == 0)\r
2244                 {\r
2245                     numLinuxResources += treeNode->length;\r
2246                 }\r
2247             }\r
2248         }\r
2249         else\r
2250         {\r
2251             Rm_osalLog("Error: Unknown allocator type\n");\r
2252         }\r
2253         \r
2254         Rm_osalLog("Total allocated to Linux: %d\n", numLinuxResources);\r
2255         \r
2256         allocator = allocator->nextAllocator;\r
2257     }\r
2258 }\r
2259      \r
2260 /**********************************************************************\r
2261  ********************** Application visible APIs **********************\r
2262  **********************************************************************/\r
2263 \r
2264 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
2265 {\r
2266     Rm_Inst *rmInst;\r
2267     void *globalResourceDtb = NULL;\r
2268     void *linuxResourceDtb = NULL;\r
2269 \r
2270     /* Instance creation checks.  Add one to strlen calculation for null character */\r
2271     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
2272     {\r
2273         /* Failure: Instance name is too big */\r
2274         return (NULL);\r
2275     }\r
2276     \r
2277     /* Get memory for RM instance from local memory */\r
2278     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
2279     /* Populate instance based on input parameters */\r
2280     strcpy (&rmInst->name[0], initCfg->instName);\r
2281     rmInst->instType = initCfg->instType;\r
2282     rmInst->registeredWithDelegateOrServer = false;\r
2283     rmInst->policyDtb = NULL;\r
2284 \r
2285     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
2286      * nodes will be created when the application registers transports */\r
2287     rmInst->routeMap = NULL;\r
2288 \r
2289     /* Initialize the allocators linked list pointer to NULL.  The linked list nodes will\r
2290      * be created on the Server instance when the application reads in the resource list.\r
2291      * Nodes will also be created on Client Delegates when blocks of resources are requested\r
2292      * for allocation to clients. */\r
2293     rmInst->allocators = NULL;\r
2294 \r
2295     /* Initialize the transaction queue elements. */\r
2296     rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
2297     rmInst->transactionQueue= NULL;\r
2298 \r
2299     /* RM Server specific actions */\r
2300     if (rmInst->instType == Rm_instType_SERVER)\r
2301     {\r
2302         /* Open the ResourceList file and provide it to the resource initializer.  The Linux\r
2303          * DTB will be parsed simultaneously for resource's consumed by the kernel.  The resources\r
2304          * used by the kernel will be marked as used in the resource allocators. */\r
2305         if (initCfg->globalResourceList)\r
2306         {\r
2307             globalResourceDtb = initCfg->globalResourceList;\r
2308             fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));\r
2309 \r
2310             if (initCfg->linuxDtb)\r
2311             {\r
2312                 linuxResourceDtb = initCfg->linuxDtb;\r
2313                 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));   \r
2314             }\r
2315             \r
2316             Rm_initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb);\r
2317 \r
2318             Rm_printResourceStatus(rmInst);\r
2319         }\r
2320     }\r
2321 \r
2322     /* Instance startup policies are only used for Servers and Client Delegates */\r
2323     if (rmInst->instType != Rm_instType_CLIENT)\r
2324     {\r
2325         /* Open the instance's policy and store it */\r
2326         if (initCfg->startupPolicy)\r
2327         {\r
2328             rmInst->policyDtb = initCfg->startupPolicy;\r
2329             fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb));  \r
2330         }\r
2331 \r
2332         /* Store policy via policy APIs ... */\r
2333     }\r
2334 \r
2335     /* Return the RM Handle */\r
2336     return ((Rm_Handle) rmInst);\r
2337 }\r
2338 \r
2339 uint32_t Rm_getVersion (void)\r
2340 {\r
2341     return RM_VERSION_ID;\r
2342 }\r
2343 \r
2344 \r
2345 const char* Rm_getVersionStr (void)\r
2346 {\r
2347     return rmVersionStr;\r
2348 }\r
2349 \r
2350 /**\r
2351 @}\r
2352 */\r