]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm.c
Finished tree allocator functions. Writing Linux DTB parsing routins
[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 int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
549 {\r
550     Rm_Allocator *allocator = NULL;\r
551     Rm_ResourceTree *treeRootEntry = NULL;\r
552     Rm_ResourceTreeNode *treeNode = NULL;\r
553     Rm_ResourceTreeNode *collidingNode = NULL;\r
554 \r
555     /* Create the new base integer allocator */\r
556     allocator = Rm_allocatorAdd(rmInst, resourceName, Rm_allocatorType_TREE);\r
557 \r
558     /* Create the tree root entry and initialize it */\r
559     treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));\r
560     RB_INIT(treeRootEntry);\r
561 \r
562     /* Create a node in the tree for resource range and insert them into the tree. */\r
563     while (range != NULL)\r
564     {\r
565         Rm_newResourceTreeNode(range->base, range->length, RM_NOT_ALLOCATED_STRING);\r
566 \r
567         /* Insert the node into the tree */\r
568         collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
569 \r
570         if (collidingNode)\r
571         {\r
572             Rm_ResourceTreeNode *nextNode = NULL;\r
573             \r
574             /* Node that was inserted colliding with an existing node.  Clean up the tree\r
575              * that's been allocated thus far and return an error since there should be no\r
576              * collisions */\r
577             for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode)\r
578             {\r
579                         nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
580                         RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode);\r
581                 Rm_freeResourceTreeNode(treeNode);\r
582                 }\r
583             /* Delete the tree root entry and the allocator */\r
584             Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));\r
585             Rm_allocatorDelete(rmInst, allocator->resourceName);\r
586             return (-24); /* TODO FIX RETURN */\r
587         }\r
588 \r
589         range = range->nextRange;\r
590     }\r
591 \r
592     /* Assign the tree's root to the allocator */\r
593     allocator->allocatorRootEntry = treeRootEntry;\r
594 \r
595     return(0);   /* TODO: FIX THIS RETURN */\r
596 }\r
597 \r
598 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
599                                   Rm_ResourceProperties *resourceProperties, void *linuxDtb)\r
600 {\r
601     char *allocatorType = NULL;\r
602     Rm_ResourceRange *range = NULL;\r
603     Rm_ResourceRange *rangeBasePtr = NULL;\r
604     Rm_NsAssignment *nsAssignments = NULL;\r
605     Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
606     Rm_LinuxAlias *linuxAlias = NULL;\r
607     Rm_LinuxAlias *linuxAliasBasePtr = NULL;\r
608     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
609 \r
610     /* TODO: NEED CHECKS FOR VALIDITY OF ALL THE resourceProperties FIELDS */\r
611 \r
612     /* Extract the resource properties from the DTB */\r
613     allocatorType = Rm_resourceExtractAllocator(resourceProperties->allocatorData, \r
614                                                 resourceProperties->allocatorLen);\r
615     range = rangeBasePtr = Rm_resourceExtractRange(resourceProperties->rangeData, \r
616                                                    resourceProperties->rangeLen);\r
617 \r
618     /* Create an allocator based on the allocator type specified */\r
619     if (strcmp(allocatorType, &rmIntegerAllocator[0]) == 0)\r
620     {\r
621         /* Create an integer allocator using the resource properties */\r
622         retVal = Rm_createIntegerAllocator(rmInst, resourceName, range);        \r
623     }\r
624     else if (strcmp(allocatorType, &rmTreeAllocator[0]) == 0)\r
625     {\r
626         /* Create a tree allocator using the resource properties */\r
627         retVal = Rm_createTreeAllocator(rmInst, resourceName, range); \r
628     }\r
629     else\r
630     {\r
631         /* Allocator type not recognized.  Free the resource properties and return */\r
632         retVal = -21; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
633     }\r
634 \r
635     /* Reserve the resources taken by the Linux kernel specified in the Linux DTB */\r
636     linuxAlias = linuxAliasBasePtr = Rm_resourceExtractLinuxAlias(resourceProperties->linuxAliasData,\r
637                                                                   resourceProperties->linuxAliasLen);\r
638     \r
639     if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
640     {\r
641         /* Create entries in the NameServer if any NameServer assignments were specified */\r
642         if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
643         {\r
644             nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
645                                                            resourceProperties->nsAssignLen);\r
646 \r
647             /* Cycle through the list of assignments and add them to the NameServer */\r
648             nsAssignmentBasePtr = nsAssignments;\r
649             while (nsAssignments)\r
650             {\r
651                 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
652                 Rm_nsAddObject(rmInst, nsAssignments->nsName, nsAssignments->resourceValue);\r
653                 nsAssignments = nsAssignments->nextNsAssignment;\r
654             }\r
655             /* Free the memory allocated for the NameServer assignments */\r
656             Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
657         }\r
658     }\r
659 \r
660     /* Free the memory allocated for the resource properties */\r
661     Rm_resourceFreeAllocator(allocatorType);\r
662     Rm_resourceFreeRange(rangeBasePtr);\r
663     Rm_resourceFreeLinuxAlias(linuxAliasBasePtr);\r
664 \r
665     return(retVal);\r
666 }\r
667 \r
668 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
669 {\r
670         int32_t propertyLen;\r
671         const char *propertyName;\r
672         const void *propertyData;\r
673     Rm_ResourcePropType propertyType;\r
674     int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
675 \r
676     /* Get the property data and store it in the corresponding propertyInfo field */\r
677         propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
678     if (propertyData)\r
679     {\r
680         propertyType = Rm_resourceGetPropertyType(propertyName);\r
681         if (propertyType == Rm_resourcePropType_RESOURCE_ALLOCATOR)\r
682         {\r
683             if (propertyInfo->allocatorData || propertyInfo->allocatorLen)\r
684             {\r
685                 /* The allocator fields have already been populated.  Return an error.\r
686                  * The resource list has specified a property field more than once\r
687                  * for a resource node */\r
688                 retVal = -17; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
689             }\r
690             else\r
691             {\r
692                 propertyInfo->allocatorData = propertyData;\r
693                 propertyInfo->allocatorLen = propertyLen;\r
694             }\r
695         }\r
696         else if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
697         {\r
698             if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
699             {\r
700                 /* The range fields have already been populated.  Return an error.\r
701                  * The resource list has specified a property field more than once\r
702                  * for a resource node */\r
703                 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
704             }\r
705             else\r
706             {\r
707                 propertyInfo->rangeData = propertyData;\r
708                 propertyInfo->rangeLen = propertyLen;\r
709             }\r
710         }\r
711         else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
712         {\r
713             if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
714             {\r
715                 /* The nsAssign fields have already been populated.  Return an error.\r
716                  * The resource list has specified a property field more than once\r
717                  * for a resource node */\r
718                 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
719             }\r
720             else\r
721             {\r
722                 propertyInfo->nsAssignData = propertyData;\r
723                 propertyInfo->nsAssignLen = propertyLen;\r
724             }\r
725         }\r
726         else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS)\r
727         {\r
728             if (propertyInfo->linuxAliasData || propertyInfo->linuxAliasLen)\r
729             {\r
730                 /* The linuxAlias fields have already been populated.  Return an error.\r
731                  * The resource list has specified a property field more than once\r
732                  * for a resource node */\r
733                 retVal = -28; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
734             }\r
735             else\r
736             {\r
737                 propertyInfo->linuxAliasData = propertyData;\r
738                 propertyInfo->linuxAliasLen = propertyLen;\r
739             }\r
740         }        \r
741         else\r
742         {\r
743             retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
744         }\r
745     }\r
746     else\r
747     {\r
748         retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
749     }\r
750 \r
751     /* Don't get anymore properties if error occurred */\r
752     if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
753     {\r
754         offset = fdt_next_property_offset(globalResourceDtb, offset);\r
755         if (offset >= 0)\r
756         {\r
757             retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
758         }\r
759         else if (offset != -FDT_ERR_NOTFOUND)\r
760         {\r
761             /* Error was returned by LIBFDT when parsing the properties */\r
762             retVal = offset;\r
763         }\r
764     }\r
765     \r
766     return (retVal);\r
767 }\r
768 \r
769 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,\r
770                              void *linuxDtb)\r
771 {\r
772         const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
773     Rm_ResourceProperties resourceProperties;\r
774         int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
775         int32_t offset;\r
776 \r
777     /* Initialize the resource properties structure */\r
778     memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
779 \r
780     /* Ignore properties of the base node */\r
781     if (strcmp(resourceName, rmDtbStartingNode))\r
782     {\r
783         /* Get the properties for the resource node if any exist */\r
784         offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
785         if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
786         {\r
787             /* Since at least one property exists attempt to parse the property nodes and \r
788              * use them to create and initialize a resource allocator */\r
789                 error =  Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
790             if (error < -FDT_ERR_NOTFOUND)\r
791             {\r
792                 return (error);\r
793             }\r
794             \r
795             /* Initialize an allocator with the resource properties if no error was returned */\r
796             Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb);\r
797         }\r
798         else if (offset != -FDT_ERR_NOTFOUND)\r
799         {\r
800                 /* Error was returned by LIBFDT when parsing the properties */\r
801             return (offset);\r
802         }\r
803     }\r
804     \r
805     /* Get the next resource node */\r
806         offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
807     /* Check the offset and depth of the next node to make sure the current node\r
808      * wasn't the last node in the Resource List.  A depth less than the depth set\r
809      * at the start of the recursion will signal the end of the resource list */\r
810     if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
811     {\r
812         error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);\r
813         if (error < -FDT_ERR_NOTFOUND)\r
814         {\r
815             return (error);\r
816         }\r
817     }\r
818     else if (offset != -FDT_ERR_NOTFOUND)\r
819     {\r
820         /* Error was returned by LIBFDT when parsing the nodes */\r
821         return (offset);\r
822     }\r
823 \r
824     return (RM_DTB_UTIL_RESULT_OKAY);\r
825 }\r
826 \r
827 /* Called when an allocate request is made but the base is unspecified.  RM must preallocate\r
828  * resources which then must be checked against the RM policy for the instance.  If the\r
829  * policy does not agree another resource(s) must be preallocated and tested against the \r
830  * policy.  Policy will provide initialize the preallocate with the base that it allows\r
831  * for the rm instance for the specified resource. */\r
832 int32_t Rm_integerPreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
833 {\r
834     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
835     Rm_IntegerEntry *resourceArray = root->resourceArrayBase;\r
836     uint16_t index, i;\r
837     bool resourcesValidated;\r
838     int32_t retVal = RM_SERVICE_PROCESSING;\r
839 \r
840     /* Find the specified resource base within the allocator */\r
841     for (index = 0; index < root->numResourceElements; index++)\r
842     {\r
843         if (resourceArray[index].value == opInfo->resourceInfo->base)\r
844         {\r
845             /* Found the resource base in the allocator.  Break from the loop */\r
846             break;\r
847         }\r
848     } \r
849 \r
850     /* Only execute the allocate operation if the resource base was found in the allocator\r
851      * and the base+length does not exceed the number of entries in the allocator */\r
852     if ((index + opInfo->resourceInfo->length) <= root->numResourceElements)\r
853     {\r
854         /* Search for a contiguous block of unallocated resources of length "length"\r
855          * and with the alignment specified */\r
856         while ((index + opInfo->resourceInfo->length) <= root->numResourceElements)\r
857         {\r
858             resourcesValidated = FALSE;            \r
859             \r
860             /* Does the resource base value satisfy the alignment? */\r
861             if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0)\r
862             {\r
863                 /* Check to see all the resource values in the requested range are free */\r
864                 resourcesValidated = TRUE;\r
865                 for (i = index; i < opInfo->resourceInfo->length; i++)\r
866                 {\r
867                     if (strcmp(resourceArray[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0)\r
868                     {\r
869                         /* A resource within the range was already allocated.  Update the\r
870                          * index to the resource after the allocated resource and continue \r
871                          * looking. */\r
872                         index = i + 1;\r
873                         resourcesValidated = FALSE;\r
874                         /* Break out of the for loop */\r
875                         break;\r
876                     }\r
877                 }\r
878 \r
879                 if (resourcesValidated)\r
880                 {\r
881                     /* Found a set of resources that satisfies the request requirements.  Return\r
882                      * the results to be tested against the policy.  If the policy approves the\r
883                      * resources will be allocated via the Rm_integerAllocate API. */\r
884                     opInfo->resourceInfo->base = resourceArray[index].value;\r
885                     /* Break out of the while loop */\r
886                     break;\r
887                 }\r
888             }\r
889             else\r
890             {\r
891                 /* Jump to the next resource value that satisfies the alignment */\r
892                 for (; index < root->numResourceElements; index++)\r
893                 {\r
894                     if ((resourceArray[index].value % opInfo->resourceInfo->alignment) == 0)\r
895                     {\r
896                         /* Found the next resource value that satisfies the alignment */\r
897                         break;\r
898                     }\r
899                 }\r
900             }\r
901         }\r
902 \r
903         if (!resourcesValidated)\r
904         {\r
905             retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
906         }\r
907     }\r
908     else\r
909     {\r
910         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
911     }\r
912 \r
913     return(retVal);     \r
914 }\r
915 \r
916 /* Assumes resource range for allocation has already been approved by the policy */\r
917 int32_t Rm_integerAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
918 {\r
919     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
920     uint16_t resourceIndex, i, j;\r
921     bool resourcesValidated = TRUE;\r
922     int32_t retVal;\r
923 \r
924     /* Find the specified resource base within the allocator */\r
925     for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++)\r
926     {\r
927         if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base)\r
928         {\r
929             /* Found the resource base in the allocator.  Break from the loop */\r
930             break;\r
931         }\r
932     }\r
933 \r
934     /* Only execute the allocate operation if the resource base was found in the allocator\r
935      * and the base+length does not exceed the number of entries in the allocator */\r
936     if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements)\r
937     {\r
938         /* Verify all resource values from base to base+length exist in the allocator and\r
939          * are not allocated to another instance. */\r
940         for (i = resourceIndex, j = opInfo->resourceInfo->base; \r
941              i < (resourceIndex + opInfo->resourceInfo->length);\r
942              i++, j++)\r
943         {\r
944             if (root->resourceArrayBase[i].value != j)\r
945             {\r
946                 /* A value in the range did not match. */\r
947                 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
948                 resourcesValidated = FALSE;\r
949                 break;\r
950             }\r
951             else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) != 0)\r
952             {\r
953                 /* A value in the range is already allocated. */\r
954                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
955                 resourcesValidated = FALSE;\r
956                 break;            \r
957             }\r
958         }\r
959 \r
960         if (resourcesValidated)\r
961         {\r
962             /* Allocate all resources from base to base+length */\r
963             for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++)\r
964             {\r
965                 strcpy(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName);\r
966             }\r
967             retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
968         }\r
969     }\r
970     else\r
971     {\r
972         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
973     }\r
974 \r
975     return(retVal); \r
976 }\r
977 \r
978 /* Assumes resource range for free has already been approved by the policy */\r
979 int32_t Rm_integerFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
980 {\r
981     Rm_IntegerAllocatorRootEntry *root = allocator->allocatorRootEntry;\r
982     uint16_t resourceIndex, i, j;\r
983     bool resourcesValidated = TRUE;\r
984     int32_t retVal;\r
985 \r
986     /* Find the specified resource base within the allocator */\r
987     for (resourceIndex = 0; resourceIndex < root->numResourceElements; resourceIndex++)\r
988     {\r
989         if (root->resourceArrayBase[resourceIndex].value == opInfo->resourceInfo->base)\r
990         {\r
991             /* Found the resource base in the allocator.  Break from the loop */\r
992             break;\r
993         }\r
994     }\r
995 \r
996     /* Only execute the free operation if the resource base was found in the allocator\r
997      * and the base+length does not exceed the number of entries in the allocator */\r
998     if ((resourceIndex + opInfo->resourceInfo->length) <= root->numResourceElements)\r
999     {\r
1000         /* Verify all resource values from base to base+length exist in the allocator,\r
1001          * were not already free and were allocated to the instance that is the source\r
1002          * of the free request. */\r
1003         for (i = resourceIndex, j = opInfo->resourceInfo->base; \r
1004              i < (resourceIndex + opInfo->resourceInfo->length);\r
1005              i++, j++)\r
1006         {\r
1007             if (root->resourceArrayBase[i].value != j)\r
1008             {\r
1009                 /* A value in the range did not match. */\r
1010                 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1011                 resourcesValidated = FALSE;\r
1012                 break;\r
1013             }\r
1014             else if (strcmp(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
1015             {\r
1016                 /* A value in the range is already free. */\r
1017                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
1018                 resourcesValidated = FALSE;\r
1019                 break;            \r
1020             }            \r
1021             else if (strcmp(root->resourceArrayBase[i].allocatedTo, opInfo->srcInstName) != 0)\r
1022             {\r
1023                 /* A value in the range was not allocated to the source of\r
1024                  * the free request */\r
1025                 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
1026                 resourcesValidated = FALSE;\r
1027                 break;\r
1028             }\r
1029         }\r
1030 \r
1031         if (resourcesValidated)\r
1032         {\r
1033             /* Free all resources from base to base+length */\r
1034             for (i = resourceIndex; i < (resourceIndex + opInfo->resourceInfo->length); i++)\r
1035             {\r
1036                 strcpy(root->resourceArrayBase[i].allocatedTo, RM_NOT_ALLOCATED_STRING);\r
1037             }\r
1038             retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1039         }\r
1040     }\r
1041     else\r
1042     {\r
1043         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1044     }\r
1045 \r
1046     return(retVal);\r
1047 }\r
1048 \r
1049 /* Called when an allocate request is made but the base is unspecified.  RM must preallocate\r
1050  * resources which then must be checked against the RM policy for the instance.  If the\r
1051  * policy does not agree another resource(s) must be preallocated and tested against the \r
1052  * policy.  Policy will provide initialize the preallocate with the base that it allows\r
1053  * for the rm instance for the specified resource. */\r
1054 int32_t Rm_treePreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
1055 {\r
1056     Rm_ResourceTreeNode findNode;\r
1057     Rm_ResourceTreeNode *matchingNode = NULL;\r
1058     uint32_t policyRangeEnd = opInfo->policyBase + opInfo->policyLength - 1;\r
1059     uint32_t index;\r
1060     bool resourceFound = FALSE;\r
1061     int32_t retVal = RM_SERVICE_PROCESSING;\r
1062 \r
1063     /* Find the tree node that contains the first value in the specified policy range. */\r
1064     findNode.base = opInfo->policyBase;\r
1065     findNode.length = 1;\r
1066     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
1067 \r
1068     if (matchingNode != NULL)\r
1069     {\r
1070         /* Begin searching for an available range of resources starting from the\r
1071          * matching node */\r
1072         for (index = matchingNode->base; index <= policyRangeEnd;)\r
1073         {\r
1074             /* Is the matchingNode free? */\r
1075             if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
1076             {\r
1077                 uint32_t matchEnd = matchingNode->base + matchingNode->length - 1;\r
1078 \r
1079                 /* Move index to the first resource satisfying the alignment property */\r
1080                 if ((index % opInfo->policyAlignment) != 0)\r
1081                 {\r
1082                     index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
1083                 }\r
1084                 \r
1085                 /* Move through the node's resource range looking for a contiguous set of resources\r
1086                  * that satisfy the request. */\r
1087                 while ((index <= matchEnd) && (index <= policyRangeEnd))\r
1088                 {\r
1089                     if (((index + opInfo->resourceInfo->length - 1) <= matchEnd) &&\r
1090                         ((index + opInfo->resourceInfo->length - 1) <= policyRangeEnd))\r
1091                     {\r
1092                         /* Found a resource range in the node that satisfies the requirements */\r
1093                         opInfo->resourceInfo->base = index;\r
1094                         resourceFound = TRUE;\r
1095                         break;\r
1096                     }\r
1097 \r
1098                     /* Move index to the next resource value that satisfies the alignment property */\r
1099                     index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
1100                 }\r
1101             }\r
1102             \r
1103             if (!resourceFound)\r
1104             {\r
1105                 /* Move to the next tree node */\r
1106                 matchingNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1107                 if (matchingNode == NULL)\r
1108                 {\r
1109                     /* Reached end of tree.  Resource range does not exist.  Leave the search\r
1110                      * loop */\r
1111                     break;\r
1112                 }\r
1113                 else\r
1114                 {\r
1115                     index = matchingNode->base;\r
1116                 }\r
1117             }\r
1118             else\r
1119             {\r
1120                 /* Found a resource range that satisfies the request properties.  Break out of the\r
1121                  * search loop */\r
1122                 break;\r
1123             }\r
1124         }\r
1125 \r
1126         if (!resourceFound)\r
1127         {\r
1128             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
1129         }\r
1130     }\r
1131     else\r
1132     {\r
1133         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1134     }\r
1135 \r
1136     return(retVal); \r
1137 }\r
1138 \r
1139 /* Assume the policy has already approved of the allocation */\r
1140 int32_t Rm_treeAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
1141 {\r
1142     Rm_ResourceTreeNode findNode;\r
1143     Rm_ResourceTreeNode *matchingNode = NULL;\r
1144     Rm_ResourceTreeNode *leftNode = NULL;\r
1145     Rm_ResourceTreeNode *rightNode = NULL;\r
1146     uint32_t findEnd, matchingEnd;\r
1147     int32_t retVal;\r
1148 \r
1149     /* Find the tree node that contains the specified resource range */\r
1150     findNode.base = opInfo->resourceInfo->base;\r
1151     findNode.length = opInfo->resourceInfo->length;\r
1152     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
1153 \r
1154     if (matchingNode != NULL)\r
1155     {\r
1156         findEnd = findNode.base + findNode.length - 1;\r
1157         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
1158         \r
1159         /* Does the request range fit within the matching nodes entire range? */\r
1160         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
1161         {\r
1162             /* Handle requested resource range that is isolated to a single node\r
1163              *\r
1164              *\r
1165              * base0                                  base0+length0-1\r
1166              *   |<---------------length0------------------->|  => existing node\r
1167              *         |<---------length1---------->|  => requested resources\r
1168              *       base1                   base1+length1-1\r
1169              */             \r
1170             if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
1171             {\r
1172                 /* Resources are available - split up the node into potentially\r
1173                  * three new nodes:\r
1174                  * left node - free resources to left of newly allocated resources\r
1175                  * middle node - newly allocated resources that satisfy the request\r
1176                  * right node - free resources to the right of newly allocated resources\r
1177                  *\r
1178                  * There also may be combine possibilities to the left and right of the\r
1179                  * matching node.  Need to extract those as well to check */\r
1180                 leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1181                 rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1182 \r
1183                 /* Remove the matching node from the tree and the nodes to the left and\r
1184                  * right of the matching node.  Removing from tree will not\r
1185                  * wipe any of the base+length data in the node.  Can reuse since they won't\r
1186                  * be freed */\r
1187                 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1188                 if (leftNode)\r
1189                 {\r
1190                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1191                 }\r
1192                 if (rightNode)\r
1193                 {\r
1194                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1195                 }\r
1196 \r
1197                 /* Create the left node if needed.  If the bases are equal the matchingNode can\r
1198                  * be reused as the left bound of the range. */\r
1199                 if (findNode.base > matchingNode->base)\r
1200                 {\r
1201                     /* Can the left node be combined with the node to the left of the matching\r
1202                      * node */\r
1203                     if (leftNode && (strcmp(leftNode->allocatedTo, opInfo->srcInstName) == 0))\r
1204                     {\r
1205                         /* Combine the left node and what's leftover on the left side of the \r
1206                          * matchingNode range after the allocation */\r
1207                         leftNode->length += (findNode.base - matchingNode->base);\r
1208                     }\r
1209                     else\r
1210                     {\r
1211                         /* Reinsert left node and create a new node to left of range to be allocated */\r
1212                         if (leftNode)\r
1213                         {\r
1214                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1215                         }\r
1216                         \r
1217                         /* New left node attributes:\r
1218                          * base: base of the matching node\r
1219                          * length: base of requested resources - base of matching node */\r
1220                         leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
1221                                                           RM_NOT_ALLOCATED_STRING);\r
1222                     }\r
1223 \r
1224                 }\r
1225 \r
1226                 /* Create the right node if needed.  If the end ranges are equal the matchingNode\r
1227                  * can be reused as the right bound of the range */\r
1228                 if (findEnd < matchingEnd)\r
1229                 {\r
1230                     /* Can the right node be combined with the node to the right of the matching\r
1231                      * node */\r
1232                     if (rightNode && (strcmp(rightNode->allocatedTo, opInfo->srcInstName) == 0))\r
1233                     {\r
1234                         /* Combine the right node and what's leftover on the right side of the \r
1235                          * matchingNode range after the allocation */\r
1236                         rightNode->base = findNode.base + findNode.length;\r
1237                         rightNode->length += (matchingEnd - findEnd);\r
1238                     }\r
1239                     else\r
1240                     {\r
1241                         /* Reinsert right node and create a new node to right of range to be allocated */\r
1242                         if (rightNode)\r
1243                         {\r
1244                             RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1245                         }\r
1246                                             \r
1247                         /* New right node attributes:\r
1248                          * base: base of the requested resources + length of requested resources\r
1249                          * length: right bound of matching node - right bound of request resources */\r
1250                         rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
1251                                                            matchingEnd - findEnd, RM_NOT_ALLOCATED_STRING);\r
1252                     }\r
1253                 }\r
1254 \r
1255                 /* Reinsert the left node into the tree if it was modified or created. */\r
1256                 if (leftNode)\r
1257                 {\r
1258                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1259                 }\r
1260                 /* Reinsert the right node into the tree if it was modified or created. */\r
1261                 if (rightNode)\r
1262                 {\r
1263                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1264                 }\r
1265 \r
1266                 /* Base and length of matching node becomes the base and length of the requested resources */\r
1267                 matchingNode->base = findNode.base;                                    \r
1268                 matchingNode->length = findNode.length;\r
1269                 /* Reserve the resources and insert them into the tree */\r
1270                 strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
1271                 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1272 \r
1273                 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1274             }\r
1275             else\r
1276             {\r
1277                 /* A resource superset containing the requested range has\r
1278                  * already been allocated. */\r
1279                 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
1280             }\r
1281         }\r
1282         else\r
1283         {\r
1284             /* Request ranges that span multiple nodes signify resources are\r
1285              * not available because nodes are combined into larger contiguous ranges\r
1286              * on resource free operations. */\r
1287             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
1288         }\r
1289     }\r
1290     else\r
1291     {\r
1292         /* The requested resources could not be found in the allocator */\r
1293         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1294     }\r
1295 \r
1296     return(retVal);        \r
1297 }\r
1298 \r
1299 /* Assume policy has already approved of the free */\r
1300 int32_t Rm_treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
1301 {\r
1302     Rm_ResourceTreeNode findNode;\r
1303     Rm_ResourceTreeNode *matchingNode = NULL;\r
1304     Rm_ResourceTreeNode *leftNode = NULL;\r
1305     Rm_ResourceTreeNode *rightNode = NULL;\r
1306     bool combineLeft = FALSE;\r
1307     bool combineRight = FALSE;\r
1308     uint32_t findEnd, matchingEnd;\r
1309     int32_t retVal;\r
1310 \r
1311     /* Find the tree node that contains the specified resource range */\r
1312     findNode.base = opInfo->resourceInfo->base;\r
1313     findNode.length = opInfo->resourceInfo->length;\r
1314     matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
1315 \r
1316     if (matchingNode != NULL)\r
1317     {\r
1318         findEnd = findNode.base + findNode.length - 1;\r
1319         matchingEnd = matchingNode->base + matchingNode->length - 1;\r
1320         \r
1321         /* Does the free range fit within the matching nodes entire range?  It should\r
1322          * either be the entire range or a subset set of the found range. (the latter\r
1323          * satisfies the case where an entity allocated a contiguous block of resources\r
1324          * then attempts to free a contiguous subset of the allocated block. */\r
1325         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
1326         {            \r
1327             if (strcmp(matchingNode->allocatedTo, opInfo->srcInstName) == 0)\r
1328             {\r
1329                 /* Resources can be freed */\r
1330 \r
1331                 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
1332                 {\r
1333                     /* Case 1: free range equals allocated matched node exactly. Attempt to combine \r
1334                      *         the range to be freed with the resource nodes to the left and\r
1335                      *         right of the free range.\r
1336                      *\r
1337                      * |<--left node-->||<---matched node--->||<--right node-->|\r
1338                      *                  |<---free request--->|\r
1339                      */ \r
1340 \r
1341                     leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1342                     rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1343 \r
1344                     /* Remove the matching node from the tree and the nodes to the left and\r
1345                      * right of the matching node.  Removing from tree will not\r
1346                      * wipe any of the base+length data in the node.  Can reuse since they won't\r
1347                      * be freed */\r
1348                     RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1349                     if (leftNode)\r
1350                     {\r
1351                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1352                     }\r
1353                     if (rightNode)\r
1354                     {\r
1355                         RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1356                     }\r
1357 \r
1358                     /* See if the left or right or both nodes can be combined with the matching\r
1359                      * node that will be freed. */\r
1360                     if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1361                     {\r
1362                         /* Combine the left node and the matching node */\r
1363                         combineLeft = TRUE;\r
1364                     }\r
1365                     if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
1366                     {\r
1367                         /* Combine the right node and the matching node */\r
1368                         combineRight = TRUE;\r
1369                     }\r
1370 \r
1371                     /* Perform any combines, insert the leftover nodes, and free any memory associated\r
1372                      * with any nodes that weren't reinserted into the tree */\r
1373                     if (combineLeft && combineRight)\r
1374                     {\r
1375                         /* Combine all three nodes into the matchingNode.  Insert the freed cumulative\r
1376                          * matching node and delete the memory for the old left and right nodes */\r
1377                         matchingNode->base = leftNode->base;\r
1378                         matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
1379 \r
1380                         Rm_freeResourceTreeNode(leftNode);\r
1381                         Rm_freeResourceTreeNode(rightNode);                        \r
1382                     }\r
1383                     else if (combineLeft)\r
1384                     {\r
1385                         /* Combine the left and matching nodes.  Reinsert the right. */\r
1386                         matchingNode->base = leftNode->base;\r
1387                         matchingNode->length += leftNode->length;\r
1388                         \r
1389                         Rm_freeResourceTreeNode(leftNode);\r
1390                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);                        \r
1391                     }\r
1392                     else if (combineRight)\r
1393                     {\r
1394                         /* Combine the right and matching nodes.  Reinsert the left. */\r
1395                         matchingNode->length += rightNode->length;\r
1396                         \r
1397                         Rm_freeResourceTreeNode(rightNode);\r
1398                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1399                     }\r
1400                     else\r
1401                     {\r
1402                         /* Combine cannot be performed.  Reinsert the left and right nodes then\r
1403                          * free the matching node and reinsert it */\r
1404                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1405                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1406                     }\r
1407 \r
1408                     /* No matter the combine route taken the matching node will always be declared\r
1409                      * free and reinserted */\r
1410                     strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
1411                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);                    \r
1412                 }\r
1413                 else\r
1414                 {\r
1415                     /* Case 2: free range is less than range in matched node. Need to split\r
1416                      *         the matched node into three nodes.\r
1417                      *\r
1418                      * |<----------matched node---------->|\r
1419                      *        |<---free request--->|\r
1420                      */ \r
1421 \r
1422                     /* Create the left node if needed.  If the bases are equal the matchingNode can\r
1423                      * be reused as the left bound of the range. */\r
1424                     if (findNode.base > matchingNode->base)\r
1425                     {\r
1426                         /* New left node attributes:\r
1427                          * base: base of the matching node\r
1428                          * length: base of requested resources - base of matching node */\r
1429                         leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
1430                                                           matchingNode->allocatedTo); \r
1431                     }\r
1432 \r
1433                     /* Create the right node if needed.  If the end ranges are equal the matchingNode\r
1434                      * can be reused as the right bound of the range */\r
1435                     if (findEnd < matchingEnd)\r
1436                     {                       \r
1437                         /* New right node attributes:\r
1438                          * base: base of the requested resources + length of requested resources\r
1439                          * length: right bound of matching node - right bound of request resources */\r
1440                         rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
1441                                                            matchingEnd - findEnd, matchingNode->allocatedTo);\r
1442                     }\r
1443 \r
1444                     /* Insert the left node into the tree if it was created. */\r
1445                     if (leftNode)\r
1446                     {\r
1447                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
1448                     }\r
1449                     /* Insert the right node into the tree if it was created. */\r
1450                     if (rightNode)\r
1451                     {\r
1452                         RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
1453                     }\r
1454 \r
1455                     /* Base and length of matching node becomes the base and length of the freed resources */\r
1456                     matchingNode->base = findNode.base;                                    \r
1457                     matchingNode->length = findNode.length;\r
1458                     /* Free the resources and insert them into the tree */\r
1459                     strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
1460                     RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
1461                 }\r
1462 \r
1463                 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1464             }\r
1465             else\r
1466             {\r
1467                 /* The matching allocated range to be freed was allocated to a different instance. */\r
1468                 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
1469             }\r
1470 \r
1471         }\r
1472         else\r
1473         {\r
1474             /* Free resource range crosses over node boundaries.  This signifies a\r
1475              * free of both allocated and unallocated resources since nodes are combined\r
1476              * on allocate and free operations if possible. */\r
1477             retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
1478         }\r
1479     }\r
1480     else\r
1481     {\r
1482         /* The free resources could not be found in the allocator */\r
1483         retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1484     }\r
1485 \r
1486     return(retVal);  \r
1487 }\r
1488 \r
1489 int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)\r
1490 {\r
1491     Rm_Allocator *allocator = NULL;\r
1492     int32_t retVal;\r
1493     void *key;\r
1494 \r
1495     /* Lock access to the RM instance's transaction queue */\r
1496     key = Rm_osalMtCsEnter();\r
1497 \r
1498     /* Get the specified resource's allocator */\r
1499     allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name);\r
1500 \r
1501     if (allocator)\r
1502     {\r
1503         /* Call the allocator's type-based allocation function */\r
1504         if(allocator->type == Rm_allocatorType_INTEGER)\r
1505         {\r
1506             if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
1507             {\r
1508                 retVal = Rm_integerPreAllocate(allocator, opInfo);\r
1509             }            \r
1510             else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
1511             {\r
1512                 retVal = Rm_integerAllocate(allocator, opInfo);\r
1513             }\r
1514             else if (opInfo->operation == Rm_allocatorOp_FREE)\r
1515             {\r
1516                 retVal = Rm_integerFree(allocator, opInfo);\r
1517             }\r
1518         }\r
1519         else if (allocator->type == Rm_allocatorType_TREE)\r
1520         {\r
1521             if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
1522             {\r
1523                 retVal = Rm_treePreAllocate(allocator, opInfo);\r
1524             }               \r
1525             else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
1526             {\r
1527                 retVal = Rm_treeAllocate(allocator, opInfo);\r
1528             }\r
1529             else if (opInfo->operation == Rm_allocatorOp_FREE)\r
1530             {\r
1531                 retVal = Rm_treeFree(allocator, opInfo);\r
1532             }  \r
1533         }        \r
1534     }\r
1535     else\r
1536     {\r
1537         /* Allocator could not be found for resource */\r
1538         retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST;\r
1539     }\r
1540 \r
1541     Rm_osalMtCsExit(key);\r
1542     return(retVal);\r
1543 }\r
1544 \r
1545 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1546 {\r
1547     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1548     {\r
1549 #if 0        \r
1550         if (resourceBase is unspecified)\r
1551         {\r
1552            while (policy does not approve)\r
1553            {\r
1554                Rm_policy check get allowed base as starting point for prealloc\r
1555                preallocate resource based on the range and alignment\r
1556                Rm_policy...check\r
1557            }\r
1558         }\r
1559         else\r
1560         {\r
1561             /* Check local policy to see if the request can be satisfied with the\r
1562              * resources stored locally */\r
1563             Rm_policy...API()\r
1564 \r
1565             if (policy check approves the resource)\r
1566             {\r
1567                 /* call the allocator to allocate the resource */\r
1568                 if (allocator returns resource)\r
1569                 {\r
1570                     /* Populate the transaction with the allocated resources and the result */\r
1571                     transaction->state = approve reason;\r
1572                     return ...\r
1573                 }\r
1574                 else\r
1575                 {\r
1576                     /* allocator ran out of resources, need to contact Server for more\r
1577                      * resources */\r
1578                     Rm_resourcePoolModRequest(...);\r
1579                 }\r
1580             }\r
1581             else if (policy check denies resource)\r
1582             {\r
1583                 /* Policy check denied resource. */\r
1584                 transaction->state= deny reason;\r
1585                 return ...\r
1586             }\r
1587             else if (policy check says forward to Server for validation)\r
1588             {\r
1589                 /* Forward the transaction to the Server */\r
1590                 Rm_transactionForwarder(rmInst, transaction);\r
1591             }\r
1592         }\r
1593 #endif         \r
1594     }\r
1595     else if (rmInst->instType == Rm_instType_SERVER)\r
1596     {\r
1597 #if 0       \r
1598         if (resourceBase is unspecified)\r
1599         {\r
1600            while (policy does not approve)\r
1601            {\r
1602                Rm_policy check get allowed base as starting point for prealloc\r
1603                preallocate resource based on the range and alignment\r
1604                Rm_policy...check\r
1605            }\r
1606         }\r
1607         else\r
1608         {\r
1609             /* Check global policy to see if resource can be allocated. return result\r
1610              * no matter what */\r
1611             Rm_policy...API()\r
1612 \r
1613             if (policy approves)\r
1614             {\r
1615                 /* call allocator to allocate resource */\r
1616             }\r
1617 \r
1618             transaction->state = approve or deny reason;\r
1619             transaction->resourceInfo.base = ...;\r
1620             transaction->resourceInfo.length = ...;\r
1621 \r
1622             /* If source instance name does not match the current instance\r
1623              * name the allocation request came from a Client.  The result\r
1624              * must be sent back to the Client */\r
1625             if (strcmp(transaction->sourceInstName, rmInst->name))\r
1626             {\r
1627                 /* Names don't match.  Send the transaction back to the Client */\r
1628                 Rm_transactionResponder(rmInst, transaction);\r
1629             }\r
1630             else\r
1631             {\r
1632                 /* Resource allocation request originated locally on the active\r
1633                  * instance. Send the response via the service responder. */          \r
1634                 Rm_serviceResponder(rmInst, transaction);                            \r
1635             }\r
1636         }\r
1637 #endif        \r
1638     }   \r
1639 }\r
1640 \r
1641 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1642 {\r
1643     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1644     {\r
1645 #if 0        \r
1646         /* Check local policy to see if the request can be satisfied with the\r
1647          * resources stored locally */\r
1648         Rm_policy...API()\r
1649 \r
1650         if (policy check approves the free)\r
1651         {\r
1652             /* call the allocator to free the resource */\r
1653             /* Run a resource pool check to see if the free combined a resource block\r
1654              * that can be returned to the server */\r
1655             if (resource block has been combined)\r
1656             {\r
1657                   /* allocator ran out of resources, need to contact Server for more\r
1658                  * resources */\r
1659                 Rm_resourcePoolModRequest(free pool block to server...);\r
1660             }\r
1661             else\r
1662             {\r
1663                 /* Populate the receipt with the freed resources and the result */\r
1664                 transaction->state = approve reason;\r
1665                 return ...\r
1666             }\r
1667         }\r
1668         else if (policy check denies resource free)\r
1669         {\r
1670             /* Policy check denied resource. */\r
1671             transaction->state = deny reason;\r
1672             return ...\r
1673         }\r
1674         else if (policy check says forward to Server for validation)\r
1675         {\r
1676             /* Forward the transaction to the Server */\r
1677             Rm_transactionForwarder(rmInst, transaction);\r
1678         }\r
1679 #endif         \r
1680     }\r
1681     else if (rmInst->instType == Rm_instType_SERVER)\r
1682     {\r
1683 #if 0        \r
1684         /* Check global policy to see if resource can be freed. return result\r
1685          * no matter what */\r
1686         Rm_policy...API()\r
1687         if (policy approves)\r
1688         {\r
1689             /* call allocator to free resources */\r
1690         }\r
1691             \r
1692         transaction->state = approve or deny reason;\r
1693         transaction->resourceInfo.base = ...;\r
1694         transaction->resourceInfo.length = ...;\r
1695 \r
1696         /* If source instance name does not match the current instance\r
1697          * name the allocation request came from a client.  The result\r
1698          * must be sent back to the Client */\r
1699         if (strcmp(transaction->sourceInstName, rmInst->name))\r
1700         {\r
1701             /* Names don't match.  Send the transaction back to the Client Delegate or Client */\r
1702             Rm_transactionResponder(rmInst, transaction);\r
1703         }\r
1704         else\r
1705         {\r
1706             /* Resource allocation request originated locally on the active\r
1707              * instance. Send the response via the service responder. */\r
1708             Rm_serviceResponder(rmInst, transaction);                            \r
1709         }\r
1710 #endif        \r
1711     }   \r
1712 }\r
1713 \r
1714 /* Function used to forward RM transactions to higher level agents */\r
1715 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1716 {\r
1717     Rm_TransportNode *dstTransportNode = NULL;\r
1718     Rm_Packet *rmPkt = NULL;\r
1719 \r
1720     /* Make sure the RM instance has a transport registered with a higher level agent */\r
1721     if (rmInst->registeredWithDelegateOrServer == false)\r
1722     {\r
1723         transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
1724         return;\r
1725     }\r
1726 \r
1727     /* Find the transport for the higher level agent.  Check for a connection to a Client Delegate\r
1728      * or a Server.  Clients will be connected to either a Client Delegate or a Server.  Client\r
1729      * Delegates will be connected to a Server. */\r
1730     if (rmInst->instType == Rm_instType_CLIENT)\r
1731     {\r
1732         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
1733     } \r
1734     else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1735     {\r
1736         dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1737     }\r
1738 \r
1739     /* Create a RM packet using the service information */\r
1740     switch (transaction->type)\r
1741     {\r
1742         case Rm_service_RESOURCE_ALLOCATE:\r
1743         case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
1744         case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
1745         case Rm_service_RESOURCE_FREE:\r
1746         case Rm_service_RESOURCE_BLOCK_FREE:\r
1747         case Rm_service_RESOURCE_FREE_BY_NAME:\r
1748             rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
1749                                                      transaction);\r
1750             break;\r
1751         case Rm_service_RESOURCE_MAP_TO_NAME:\r
1752         case Rm_service_RESOURCE_UNMAP_NAME:\r
1753             rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
1754                                                    transaction);\r
1755             break;\r
1756         default:\r
1757             /* Invalid service type.  Flag the error and return */\r
1758             transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1759             break;\r
1760     }\r
1761 \r
1762     if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
1763     {\r
1764         /* Return immediately because an error occurred allocating the packet */\r
1765         return;\r
1766     }\r
1767 \r
1768     /* Send the RM packet to the application transport */\r
1769     if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
1770     {\r
1771         /* Negative value returned by transport send.  An error occurred\r
1772          * in the transport while attempting to send the packet.*/\r
1773         transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1774         /* Clean up the packet */\r
1775         if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
1776         {\r
1777             /* Non-NULL value returned by transport packet free. Flag the\r
1778              * error */\r
1779             transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1780         }\r
1781         return;\r
1782     }\r
1783 \r
1784     /* Transaction is not deleted because it is awaiting a response from the higher level\r
1785      * RM instance */\r
1786 }\r
1787 \r
1788 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1789 {\r
1790     /* Handle auto-forwarded transactions.  These transactions include:\r
1791      * - All request transactions received on Clients are forwarded to the Client Delegate\r
1792      * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
1793     if ((rmInst->instType == Rm_instType_CLIENT) ||\r
1794         ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
1795          (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
1796          (transaction->type == Rm_service_RESOURCE_UNMAP_NAME)))\r
1797     {\r
1798         /* Check if the transaction is a transaction that received a response to its\r
1799          * request. */\r
1800         if (transaction->state != RM_SERVICE_PROCESSING)\r
1801         {\r
1802 \r
1803             /* A transaction has received a response. Send the response to either the \r
1804              * transaction or service responder based on the source instance */\r
1805             if (strcmp(transaction->sourceInstName, rmInst->name))\r
1806             {\r
1807                 /* Transaction originated from another instance.  Use the \r
1808                  * transaction responder to send the result to the source instance.  This\r
1809                  * is not possible on RM Clients since they can't forward RM services */\r
1810                 Rm_transactionResponder(rmInst, transaction);\r
1811             }\r
1812             else\r
1813             {\r
1814                 /* Transaction originated on this instance.  Send to the\r
1815                  * service responder */\r
1816                 Rm_serviceResponder(rmInst, transaction);\r
1817             }\r
1818         }\r
1819         else\r
1820         {\r
1821             /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
1822             Rm_transactionForwarder(rmInst, transaction);\r
1823         }\r
1824     }\r
1825     else\r
1826     {\r
1827         /* Client Delegate and Server transaction processors. */\r
1828         switch (transaction->type)\r
1829         {\r
1830             case Rm_service_RESOURCE_ALLOCATE:\r
1831             case Rm_service_RESOURCE_BLOCK_ALLOCATE:\r
1832             case Rm_service_RESOURCE_ALLOCATE_BY_NAME:\r
1833             case Rm_service_RESOURCE_FREE:\r
1834             case Rm_service_RESOURCE_BLOCK_FREE:\r
1835             case Rm_service_RESOURCE_FREE_BY_NAME:                \r
1836                 /* Check if the transaction is fulfilled request */\r
1837                 if (transaction->state != RM_SERVICE_PROCESSING)\r
1838                 {\r
1839                     /* If source instance name does not match the current instance\r
1840                      * name the allocation request came from a client.  The result\r
1841                      * must be sent back to the Client */\r
1842                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
1843                     {\r
1844                         Rm_transactionResponder(rmInst, transaction);\r
1845                     }\r
1846                     else\r
1847                     {\r
1848                         /* Resource allocation request originated locally.  Send the response\r
1849                          * via the service responder. */\r
1850                         Rm_serviceResponder(rmInst, transaction);      \r
1851                     }\r
1852                 }\r
1853                 else\r
1854                 {\r
1855                     /* This is a new transaction request originating from an RM instance with fewer\r
1856                      * allocate/free privileges.  Run the allocation or free handler to see if the resource\r
1857                      * request can be handled locally or if it needs to be forwarded to a higher level\r
1858                      * agent */\r
1859                     if ((transaction->type == Rm_service_RESOURCE_ALLOCATE) ||\r
1860                         (transaction->type == Rm_service_RESOURCE_BLOCK_ALLOCATE) ||\r
1861                         (transaction->type == Rm_service_RESOURCE_ALLOCATE_BY_NAME))\r
1862                     {\r
1863                         Rm_allocationHandler(rmInst, transaction);\r
1864                     }\r
1865                     else\r
1866                     {\r
1867                         Rm_freeHandler(rmInst, transaction);\r
1868                     }\r
1869                 }\r
1870                 break;\r
1871             case Rm_service_RESOURCE_MAP_TO_NAME:\r
1872             case Rm_service_RESOURCE_UNMAP_NAME:                \r
1873                 /* Server is the only RM instance capable of adding NameServer objects */\r
1874                 if (rmInst->instType == Rm_instType_SERVER)\r
1875                 {\r
1876                     if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
1877                     {\r
1878                         /* Create a new NameServer object with the request transaction information.\r
1879                          * Transaction will contain the state result of the NameServer addition. */\r
1880                         if (Rm_nsAddObject(rmInst, transaction->resourceInfo.nsName,\r
1881                                            transaction->resourceInfo.base) == RM_NS_ACTION_APPROVED)\r
1882                         {\r
1883                             transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1884                         }\r
1885                         else\r
1886                         {\r
1887                             /* TEMP: UPDATE THIS STATE VALUE */\r
1888                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1889                         }\r
1890                     }\r
1891                     else\r
1892                     {\r
1893                         /* Delete an existing NameServer object with the request transaction information\r
1894                          * Transaction will contain the state result of the NameServer addition. */\r
1895                         if (Rm_nsDeleteObject(rmInst, transaction->resourceInfo.nsName) == \r
1896                             RM_NS_ACTION_APPROVED)\r
1897                         {\r
1898                             transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1899                         }\r
1900                         else\r
1901                         {\r
1902                             /* TEMP: UPDATE THIS STATE VALUE */\r
1903                             transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1904                         }\r
1905                     }\r
1906 \r
1907                     /* If source instance name does not match the local instance\r
1908                      * name the NameServer request came from a Client or Client Delegate.  The \r
1909                      * result must be sent back to the Client or Client Delegate.  Just return if it does\r
1910                      * match since the NameServer transaction result can be returned immediately by the\r
1911                      * Rm_serviceHandler. */\r
1912                     if (strcmp(transaction->sourceInstName, rmInst->name))\r
1913                     {\r
1914                         Rm_transactionResponder(rmInst, transaction);\r
1915                     }\r
1916                 }\r
1917                 else\r
1918                 {\r
1919                     transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1920                 }\r
1921                 break;\r
1922         }\r
1923     }\r
1924 }\r
1925 \r
1926 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)\r
1927 {\r
1928     int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1929     int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
1930     int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
1931 \r
1932     /* Recursively parse the Global Resource List, creating an allocator for\r
1933      * each resource as specified in the node */\r
1934     result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);\r
1935 \r
1936     return(result);\r
1937 }\r
1938          \r
1939 /**********************************************************************\r
1940  ********************** Application visible APIs **********************\r
1941  **********************************************************************/\r
1942 \r
1943 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
1944 {\r
1945     Rm_Inst *rmInst;\r
1946     void *globalResourceDtb = NULL;\r
1947     void *linuxResourceDtb = NULL;\r
1948 \r
1949     /* Instance creation checks.  Add one to strlen calculation for null character */\r
1950     if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
1951     {\r
1952         /* Failure: Instance name is too big */\r
1953         return (NULL);\r
1954     }\r
1955     \r
1956     /* Get memory for RM instance from local memory */\r
1957     rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
1958     /* Populate instance based on input parameters */\r
1959     strcpy (&rmInst->name[0], initCfg->instName);\r
1960     rmInst->instType = initCfg->instType;\r
1961     rmInst->registeredWithDelegateOrServer = false;\r
1962     rmInst->policyDtb = NULL;\r
1963 \r
1964     /* Initialize the transport routing map linked list pointer to NULL.  The linked list\r
1965      * nodes will be created when the application registers transports */\r
1966     rmInst->routeMap = NULL;\r
1967 \r
1968     /* Initialize the allocators linked list pointer to NULL.  The linked list nodes will\r
1969      * be created on the Server instance when the application reads in the resource list.\r
1970      * Nodes will also be created on Client Delegates when blocks of resources are requested\r
1971      * for allocation to clients. */\r
1972     rmInst->allocators = NULL;\r
1973 \r
1974     /* Initialize the transaction queue elements. */\r
1975     rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
1976     rmInst->transactionQueue= NULL;\r
1977 \r
1978     /* RM Server specific actions */\r
1979     if (rmInst->instType == Rm_instType_SERVER)\r
1980     {\r
1981         /* Open the ResourceList file and provide it to the resource initializer.  The Linux\r
1982          * DTB will be parsed simultaneously for resource's consumed by the kernel.  The resources\r
1983          * used by the kernel will be marked as used in the resource allocators. */\r
1984         if (initCfg->globalResourceList)\r
1985         {\r
1986             globalResourceDtb = initCfg->globalResourceList;\r
1987             fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));\r
1988 \r
1989             if (initCfg->linuxDtb)\r
1990             {\r
1991                 linuxResourceDtb = initCfg->linuxDtb;\r
1992                 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb));   \r
1993             }\r
1994             \r
1995             Rm_initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb);\r
1996         }\r
1997     }\r
1998 \r
1999     /* Instance startup policies are only used for Servers and Client Delegates */\r
2000     if (rmInst->instType != Rm_instType_CLIENT)\r
2001     {\r
2002         /* Open the instance's policy and store it */\r
2003         if (initCfg->startupPolicy)\r
2004         {\r
2005             rmInst->policyDtb = initCfg->startupPolicy;\r
2006             fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb));  \r
2007         }\r
2008 \r
2009         /* Store policy via policy APIs ... */\r
2010     }\r
2011 \r
2012     /* Return the RM Handle */\r
2013     return ((Rm_Handle) rmInst);\r
2014 }\r
2015 \r
2016 uint32_t Rm_getVersion (void)\r
2017 {\r
2018     return RM_VERSION_ID;\r
2019 }\r
2020 \r
2021 \r
2022 const char* Rm_getVersionStr (void)\r
2023 {\r
2024     return rmVersionStr;\r
2025 }\r
2026 \r
2027 /**\r
2028 @}\r
2029 */\r