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