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