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)\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 Rm_Allocator *Rm_allocatorAdd(Rm_Inst *rmInst, const char *resourceName)\r
298 {\r
299 Rm_Allocator *allocators = (Rm_Allocator *)rmInst->allocators;\r
300 Rm_Allocator *newAllocator = NULL;\r
301 void *key;\r
302 \r
303 /* Lock access to the RM instance's allocator list */\r
304 key = Rm_osalMtCsEnter();\r
305 \r
306 /* Get memory for a new allocator from local memory */\r
307 newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));\r
308 \r
309 /* Return if the memory allocated for the allocator is NULL */\r
310 if (newAllocator != NULL)\r
311 {\r
312 /* Clear the allocator */\r
313 memset((void *)newAllocator, 0, sizeof(Rm_Allocator));\r
314 \r
315 /* Populate the allocator */\r
316 strcpy(newAllocator->resourceName, resourceName);\r
317 /* allocator's root entry will be created by the invoking function */\r
318 newAllocator->allocatorRootEntry = NULL;\r
319 /* New allocator's nextAllocator pointer will always be NULL */\r
320 newAllocator->nextAllocator = NULL; \r
321 \r
322 /* Check if there are any allocators in the allocator list */\r
323 if (allocators)\r
324 {\r
325 /* At least one allocator in the allocator list. Add the new allocator to the \r
326 * end of the allocator list */\r
327 while (allocators->nextAllocator != NULL)\r
328 {\r
329 /* Traverse the list until arriving at the last allocator */\r
330 allocators = allocators->nextAllocator;\r
331 }\r
332 \r
333 /* Add the new allocator to the end of the list */\r
334 allocators->nextAllocator = newAllocator;\r
335 }\r
336 else\r
337 {\r
338 /* The allocator list does not currently exist. The new allocator is the \r
339 * first allocator */\r
340 rmInst->allocators = newAllocator;\r
341 }\r
342 }\r
343 \r
344 Rm_osalMtCsExit(key);\r
345 return (newAllocator);\r
346 }\r
347 \r
348 Rm_Allocator *Rm_allocatorFind(Rm_Inst *rmInst, char *resourceName)\r
349 {\r
350 Rm_Allocator *allocator = (Rm_Allocator *)rmInst->allocators;\r
351 \r
352 /* Make sure there is at least one allocator in the allocator list */\r
353 if (allocator != NULL)\r
354 {\r
355 /* Find the resource name within the allocator list. If the end of the\r
356 * allocator list is reached without finding the resource name the \r
357 * allocator pointer will be NULL */\r
358 while (allocator != NULL)\r
359 {\r
360 if (strcmp(allocator->resourceName, resourceName) == 0)\r
361 {\r
362 /* Match: break out of loop and return the allocator */\r
363 break; \r
364 }\r
365 allocator = allocator->nextAllocator;\r
366 }\r
367 }\r
368 \r
369 return (allocator);\r
370 }\r
371 \r
372 int32_t Rm_allocatorDelete(Rm_Inst *rmInst, char *resourceName)\r
373 {\r
374 Rm_Allocator *allocator = (Rm_Allocator *) rmInst->allocators;\r
375 Rm_Allocator *prevAllocator = NULL;\r
376 int32_t retVal = RM_SERVICE_STATE_OKAY;\r
377 void *key;\r
378 \r
379 /* Lock access to the RM instance's allocator list */\r
380 key = Rm_osalMtCsEnter();\r
381 \r
382 /* Find the resource within the specified RM instance's allocator list. */\r
383 while (allocator != NULL)\r
384 {\r
385 if (strcmp(allocator->resourceName, resourceName) == 0)\r
386 {\r
387 /* Match: break out of loop and delete the transaction */\r
388 break; \r
389 }\r
390 \r
391 prevAllocator = allocator;\r
392 allocator = allocator->nextAllocator;\r
393 }\r
394 \r
395 /* Traversed entire list but did not find allocator. */\r
396 if (allocator == NULL)\r
397 {\r
398 retVal = -22; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
399 }\r
400 else\r
401 {\r
402 /* Delete the allocator */\r
403 if (prevAllocator == NULL)\r
404 {\r
405 /* Allocator to be deleted exists at start of allocator list. Map second\r
406 * allocator to be start of allocator list as long as there are more than\r
407 * one allocators. */\r
408 rmInst->allocators = allocator->nextAllocator;\r
409 }\r
410 else\r
411 {\r
412 /* Allocator to be deleted is in the middle or at end of the list. Adjust \r
413 * adjacent allocator pointers. This covers the case where the allocator to be \r
414 * removed is at the end of the list. */\r
415 prevAllocator->nextAllocator = allocator->nextAllocator;\r
416 }\r
417 \r
418 /* Free the memory associated with the allocator. */\r
419 Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));\r
420 }\r
421 \r
422 Rm_osalMtCsExit(key);\r
423 return (retVal);\r
424 }\r
425 \r
426 int32_t Rm_createTreeAllocator(Rm_Inst *rmInst, const char *resourceName, Rm_ResourceRange *range)\r
427 {\r
428 Rm_Allocator *allocator = NULL;\r
429 Rm_ResourceTree *treeRootEntry = NULL;\r
430 Rm_ResourceTreeNode *treeNode = NULL;\r
431 Rm_ResourceTreeNode *collidingNode = NULL;\r
432 \r
433 /* Create the new base integer allocator */\r
434 allocator = Rm_allocatorAdd(rmInst, resourceName);\r
435 \r
436 /* Create the tree root entry and initialize it */\r
437 treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));\r
438 RB_INIT(treeRootEntry);\r
439 \r
440 /* Create a node in the tree for resource range and insert them into the tree. */\r
441 while (range != NULL)\r
442 {\r
443 treeNode = Rm_newResourceTreeNode(range->base, range->length, RM_NOT_ALLOCATED_STRING);\r
444 \r
445 /* Insert the node into the tree */\r
446 collidingNode = RB_INSERT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
447 \r
448 if (collidingNode)\r
449 {\r
450 Rm_ResourceTreeNode *nextNode = NULL;\r
451 \r
452 /* Node that was inserted colliding with an existing node. Clean up the tree\r
453 * that's been allocated thus far and return an error since there should be no\r
454 * collisions */\r
455 for (treeNode = RB_MIN(_Rm_ResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode)\r
456 {\r
457 nextNode = RB_NEXT(_Rm_ResourceTree, treeRootEntry, treeNode);\r
458 RB_REMOVE(_Rm_ResourceTree, treeRootEntry, nextNode);\r
459 Rm_freeResourceTreeNode(treeNode);\r
460 }\r
461 /* Delete the tree root entry and the allocator */\r
462 Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));\r
463 Rm_allocatorDelete(rmInst, allocator->resourceName);\r
464 return (-24); /* TODO FIX RETURN */\r
465 }\r
466 \r
467 range = range->nextRange;\r
468 }\r
469 \r
470 /* Assign the tree's root to the allocator */\r
471 allocator->allocatorRootEntry = treeRootEntry;\r
472 \r
473 return(0); /* TODO: FIX THIS RETURN */\r
474 }\r
475 \r
476 /* Called when an allocate request is made but the base is unspecified. RM must preallocate\r
477 * resources which then must be checked against the RM policy for the instance. If the\r
478 * policy does not agree another resource(s) must be preallocated and tested against the \r
479 * policy. Policy will provide initialize the preallocate with the base that it allows\r
480 * for the rm instance for the specified resource. */\r
481 int32_t Rm_treePreAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
482 {\r
483 Rm_ResourceTreeNode findNode;\r
484 Rm_ResourceTreeNode *matchingNode = NULL;\r
485 uint32_t policyRangeEnd = opInfo->policyBase + opInfo->policyLength - 1;\r
486 uint32_t index;\r
487 bool resourceFound = FALSE;\r
488 int32_t retVal = RM_SERVICE_PROCESSING;\r
489 \r
490 /* Find the tree node that contains the first value in the specified policy range. */\r
491 if (opInfo->policyBase)\r
492 {\r
493 findNode.base = opInfo->policyBase;\r
494 }\r
495 else\r
496 {\r
497 matchingNode = RB_MIN(_Rm_ResourceTree, allocator->allocatorRootEntry);\r
498 findNode.base = matchingNode->base;\r
499 }\r
500 \r
501 findNode.length = 1;\r
502 matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
503 \r
504 if (matchingNode != NULL)\r
505 {\r
506 /* Begin searching for an available range of resources starting from the\r
507 * matching node */\r
508 for (index = matchingNode->base; index <= policyRangeEnd;)\r
509 {\r
510 /* Is the matchingNode free? */\r
511 if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
512 {\r
513 uint32_t matchEnd = matchingNode->base + matchingNode->length - 1;\r
514 \r
515 /* Move index to the first resource satisfying the alignment property */\r
516 if ((index % opInfo->policyAlignment) != 0)\r
517 {\r
518 index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
519 }\r
520 \r
521 /* Move through the node's resource range looking for a contiguous set of resources\r
522 * that satisfy the request. */\r
523 while ((index <= matchEnd) && (index <= policyRangeEnd))\r
524 {\r
525 if (((index + opInfo->resourceInfo->length - 1) <= matchEnd) &&\r
526 ((index + opInfo->resourceInfo->length - 1) <= policyRangeEnd))\r
527 {\r
528 /* Found a resource range in the node that satisfies the requirements */\r
529 opInfo->resourceInfo->base = index;\r
530 resourceFound = TRUE;\r
531 break;\r
532 }\r
533 \r
534 /* Move index to the next resource value that satisfies the alignment property */\r
535 index += (opInfo->policyAlignment - (index % opInfo->policyAlignment));\r
536 }\r
537 }\r
538 \r
539 if (!resourceFound)\r
540 {\r
541 /* Move to the next tree node */\r
542 matchingNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
543 if (matchingNode == NULL)\r
544 {\r
545 /* Reached end of tree. Resource range does not exist. Leave the search\r
546 * loop */\r
547 break;\r
548 }\r
549 else\r
550 {\r
551 index = matchingNode->base;\r
552 }\r
553 }\r
554 else\r
555 {\r
556 /* Found a resource range that satisfies the request properties. Break out of the\r
557 * search loop */\r
558 break;\r
559 }\r
560 }\r
561 \r
562 if (!resourceFound)\r
563 {\r
564 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
565 }\r
566 }\r
567 else\r
568 {\r
569 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
570 }\r
571 \r
572 return(retVal); \r
573 }\r
574 \r
575 /* Assume the policy has already approved of the allocation */\r
576 int32_t Rm_treeAllocate(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
577 {\r
578 Rm_ResourceTreeNode findNode;\r
579 Rm_ResourceTreeNode *matchingNode = NULL;\r
580 Rm_ResourceTreeNode *leftNode = NULL;\r
581 Rm_ResourceTreeNode *rightNode = NULL; \r
582 uint32_t findEnd, matchingEnd;\r
583 int32_t retVal;\r
584 \r
585 /* Find the tree node that contains the specified resource range */\r
586 findNode.base = opInfo->resourceInfo->base;\r
587 findNode.length = opInfo->resourceInfo->length;\r
588 matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
589 \r
590 if (matchingNode != NULL)\r
591 {\r
592 findEnd = findNode.base + findNode.length - 1;\r
593 matchingEnd = matchingNode->base + matchingNode->length - 1;\r
594 \r
595 /* Does the request range fit within the matching nodes entire range? */\r
596 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
597 {\r
598 /* Handle node create, combine, deletion based on the request range if\r
599 * resources are available. */\r
600 if (strcmp(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
601 {\r
602 /* Handle case where the findNode range matches the matchingNode\r
603 * range exactly.\r
604 *\r
605 * base0 base0+length0-1\r
606 * |<---------------length0------------------->| => existing node\r
607 * |<---------------length1------------------->| => requested resources\r
608 * base1 base1+length1-1\r
609 */ \r
610 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
611 {\r
612 /* Can reserve matchingNode's resources in-place */\r
613 strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
614 }\r
615 /* Handle case where the findNode range is a subset of the matchingNode\r
616 * range and neither of the boundaries of the two ranges are equivalent.\r
617 *\r
618 * base0 base0+length0-1\r
619 * |<---------------length0------------------->| => existing node\r
620 * |<---------length1---------->| => requested resources\r
621 * base1 base1+length1-1\r
622 */ \r
623 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
624 {\r
625 /* Split the matching node into three nodes:\r
626 * left node - free resources to left of newly allocated resources\r
627 * middle node - newly allocated resources that satisfy the request\r
628 * right node - free resources to the right of newly allocated resources */\r
629 \r
630 /* Remove the matching node from the tree for modification. */\r
631 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
632 \r
633 /* New left node attributes:\r
634 * base: base of the matching node\r
635 * length: base of requested resources - base of matching node */\r
636 leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
637 RM_NOT_ALLOCATED_STRING);\r
638 /* New right node attributes:\r
639 * base: base of the requested resources + length of requested resources\r
640 * length: right bound of matching node - right bound of request resources */\r
641 rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
642 matchingEnd - findEnd, RM_NOT_ALLOCATED_STRING);\r
643 \r
644 /* Base and length of matching node become the base and length of the\r
645 * requested resources */\r
646 matchingNode->base = findNode.base; \r
647 matchingNode->length = findNode.length;\r
648 /* Reserve the resources */\r
649 strcpy(matchingNode->allocatedTo, opInfo->srcInstName);\r
650 \r
651 /* Insert all the nodes */\r
652 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
653 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
654 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
655 }\r
656 /* Handle cases where one of findNode range boundaries is equivalent to\r
657 * one of the matchingNode range boundaries.\r
658 *\r
659 * base0 base0+length0-1\r
660 * |<---------------length0------------------->| => existing node\r
661 * |<---------length1---------->| => requested resources\r
662 * base1 base1+length1-1\r
663 *\r
664 * OR\r
665 *\r
666 * base0 base0+length0-1\r
667 * |<---------------length0------------------->| => existing node\r
668 * |<---------length1---------->| => requested resources\r
669 * base1 base1+length1-1 \r
670 */ \r
671 else\r
672 { \r
673 /* Remove the matchingNode from the tree since it will be edited */\r
674 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
675 \r
676 if (findNode.base == matchingNode->base)\r
677 {\r
678 /* There may be a combine possibility to the left. Extract leftNode to check */\r
679 leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
680 \r
681 /* Can the node to the left of the matchingNode be combined with the \r
682 * findNode's range? */\r
683 if (leftNode && (strcmp(leftNode->allocatedTo, opInfo->srcInstName) == 0))\r
684 {\r
685 /* Remove the leftNode from the tree for editing */\r
686 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
687 \r
688 /* Combine the leftNode and the findNode */\r
689 leftNode->length += findNode.length;\r
690 }\r
691 else\r
692 {\r
693 /* Allocate a new leftNode that will take the place of the findNode\r
694 * range in tree. */\r
695 leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
696 opInfo->srcInstName);\r
697 }\r
698 \r
699 /* Account for the leftNode in the matchingNode */\r
700 matchingNode->base = findNode.base + findNode.length;\r
701 matchingNode->length = matchingEnd - findEnd; \r
702 \r
703 /* Insert the left node */\r
704 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
705 }\r
706 else if (findEnd == matchingEnd)\r
707 {\r
708 /* There may be a combine possibility to the right. Extract rightNode to check */\r
709 rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
710 \r
711 /* Can the node to the right of the matchingNode be combined with the \r
712 * findNode's range? */\r
713 if (rightNode && (strcmp(rightNode->allocatedTo, opInfo->srcInstName) == 0))\r
714 {\r
715 /* Remove the rightNode from the tree for editing */\r
716 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
717 \r
718 /* Combine the rightNode and the findNode */\r
719 rightNode->base = findNode.base;\r
720 rightNode->length += findNode.length;\r
721 }\r
722 else\r
723 {\r
724 /* Allocate a new rightNode that will take the place of the findNode\r
725 * range in tree. */\r
726 rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
727 opInfo->srcInstName);\r
728 }\r
729 \r
730 /* Account for the rightNode in the matchingNode */\r
731 matchingNode->length -= findNode.length; \r
732 \r
733 /* Insert the right node */\r
734 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
735 }\r
736 \r
737 /* Reinsert the edited matching node */\r
738 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
739 }\r
740 \r
741 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
742 }\r
743 else\r
744 {\r
745 /* A resource superset containing the requested range has\r
746 * already been allocated. */\r
747 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
748 }\r
749 }\r
750 else\r
751 {\r
752 /* Request ranges that span multiple nodes signify resources are\r
753 * not available because nodes are combined into larger contiguous ranges\r
754 * on resource free operations. */\r
755 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_ALLOCATED;\r
756 }\r
757 }\r
758 else\r
759 {\r
760 /* The requested resources could not be found in the allocator */\r
761 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
762 }\r
763 \r
764 return(retVal); \r
765 }\r
766 \r
767 /* Assume policy has already approved of the free */\r
768 int32_t Rm_treeFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)\r
769 {\r
770 Rm_ResourceTreeNode findNode;\r
771 Rm_ResourceTreeNode *matchingNode = NULL;\r
772 Rm_ResourceTreeNode *leftNode = NULL;\r
773 Rm_ResourceTreeNode *rightNode = NULL;\r
774 bool combineLeft = FALSE;\r
775 bool combineRight = FALSE;\r
776 uint32_t findEnd, matchingEnd;\r
777 int32_t retVal;\r
778 \r
779 /* Find the tree node that contains the specified resource range */\r
780 findNode.base = opInfo->resourceInfo->base;\r
781 findNode.length = opInfo->resourceInfo->length;\r
782 matchingNode = RB_FIND(_Rm_ResourceTree, allocator->allocatorRootEntry, &findNode);\r
783 \r
784 if (matchingNode != NULL)\r
785 {\r
786 findEnd = findNode.base + findNode.length - 1;\r
787 matchingEnd = matchingNode->base + matchingNode->length - 1;\r
788 \r
789 /* Does the free range fit within the matching nodes entire range? It should\r
790 * either be the entire range or a subset set of the found range. (the latter\r
791 * satisfies the case where an entity allocated a contiguous block of resources\r
792 * then attempts to free a contiguous subset of the allocated block. */\r
793 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd))\r
794 { \r
795 if (strcmp(matchingNode->allocatedTo, opInfo->srcInstName) == 0)\r
796 {\r
797 /* Resources can be freed */\r
798 \r
799 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))\r
800 {\r
801 /* Case 1: free range equals allocated matched node exactly. Attempt to combine \r
802 * the range to be freed with the resource nodes to the left and\r
803 * right of the free range.\r
804 *\r
805 * |<--left node-->||<---matched node--->||<--right node-->|\r
806 * |<---free request--->|\r
807 */ \r
808 \r
809 leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
810 rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
811 \r
812 /* Remove the matching node from the tree and the nodes to the left and\r
813 * right of the matching node. Removing from tree will not\r
814 * wipe any of the base+length data in the node. Can reuse since they won't\r
815 * be freed */\r
816 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
817 \r
818 /* See if the left or right or both nodes can be combined with the matching\r
819 * node that will be freed. */\r
820 if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
821 {\r
822 /* Combine the left node and the matching node */\r
823 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
824 combineLeft = TRUE;\r
825 }\r
826 if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
827 {\r
828 /* Combine the right node and the matching node */\r
829 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
830 combineRight = TRUE;\r
831 }\r
832 \r
833 /* Perform any combines, insert the leftover nodes, and free any memory associated\r
834 * with any nodes that weren't reinserted into the tree */\r
835 if (combineLeft && combineRight)\r
836 {\r
837 /* Combine all three nodes into the matchingNode. Insert the freed cumulative\r
838 * matching node and delete the memory for the old left and right nodes */\r
839 matchingNode->base = leftNode->base;\r
840 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;\r
841 \r
842 Rm_freeResourceTreeNode(leftNode);\r
843 Rm_freeResourceTreeNode(rightNode); \r
844 }\r
845 else if (combineLeft)\r
846 {\r
847 /* Combine the left and matching nodes. Reinsert the right. */\r
848 matchingNode->base = leftNode->base;\r
849 matchingNode->length += leftNode->length;\r
850 \r
851 Rm_freeResourceTreeNode(leftNode);\r
852 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode); \r
853 }\r
854 else if (combineRight)\r
855 {\r
856 /* Combine the right and matching nodes. Reinsert the left. */\r
857 matchingNode->length += rightNode->length;\r
858 \r
859 Rm_freeResourceTreeNode(rightNode);\r
860 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
861 }\r
862 else\r
863 {\r
864 /* Combine cannot be performed. Reinsert the left and right nodes then\r
865 * free the matching node and reinsert it */\r
866 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
867 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
868 }\r
869 \r
870 /* No matter the combine route taken the matching node will always be declared\r
871 * free and reinserted */\r
872 strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
873 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode); \r
874 }\r
875 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd))\r
876 {\r
877 /* Case 2: free range is less than range in matched node. Need to split\r
878 * the matched node into three nodes.\r
879 *\r
880 * |<----------matched node---------->|\r
881 * |<---free request--->|\r
882 */ \r
883 \r
884 /* Remove matching node for editing. */\r
885 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
886 \r
887 /* New left node attributes:\r
888 * base: base of the matching node\r
889 * length: base of requested resources - base of matching node */\r
890 leftNode = Rm_newResourceTreeNode(matchingNode->base, findNode.base - matchingNode->base,\r
891 matchingNode->allocatedTo); \r
892 /* New right node attributes:\r
893 * base: base of the requested resources + length of requested resources\r
894 * length: right bound of matching node - right bound of request resources */\r
895 rightNode = Rm_newResourceTreeNode(findNode.base + findNode.length,\r
896 matchingEnd - findEnd, matchingNode->allocatedTo);\r
897 \r
898 /* Insert the left and right nodes into the tree. */\r
899 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
900 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
901 \r
902 /* Base and length of matching node become the base and length of the freed resources */\r
903 matchingNode->base = findNode.base; \r
904 matchingNode->length = findNode.length;\r
905 /* Free the resources and insert them into the tree */\r
906 strcpy(matchingNode->allocatedTo, RM_NOT_ALLOCATED_STRING);\r
907 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
908 }\r
909 else\r
910 {\r
911 /* Remove the matchingNode from the tree since it will be edited */\r
912 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
913 \r
914 if (findNode.base == matchingNode->base)\r
915 {\r
916 /* Case 3: Free range is on left boundary of matched node. Try to \r
917 * combine the free range with the left node if free.\r
918 *\r
919 * |<---left node (free)--->||<----------matched node---------->|\r
920 * |<---findNode (free req)--->|\r
921 */ \r
922 \r
923 /* There may be a combine possibility to the left. Extract leftNode to check */\r
924 leftNode = RB_PREV(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
925 \r
926 /* Can the node to the left of the matchingNode be combined with the \r
927 * findNode's range? */\r
928 if (leftNode && (strcmp(leftNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
929 {\r
930 /* Remove the leftNode from the tree for editing */\r
931 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
932 \r
933 /* Combine the leftNode and the findNode */\r
934 leftNode->length += findNode.length;\r
935 }\r
936 else\r
937 {\r
938 /* Allocate a new leftNode that will take the place of the findNode\r
939 * range in tree. */\r
940 leftNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
941 RM_NOT_ALLOCATED_STRING);\r
942 }\r
943 \r
944 /* Account for the leftNode in the matchingNode */\r
945 matchingNode->base = findNode.base + findNode.length;\r
946 matchingNode->length = matchingEnd - findEnd; \r
947 \r
948 /* Insert the left node */\r
949 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, leftNode);\r
950 }\r
951 else if (findEnd == matchingEnd)\r
952 {\r
953 /* Case 4: Free range is on right boundary of matched node. Try to \r
954 * combine the free range with the right node if free.\r
955 *\r
956 * |<----------matched node---------->||<---right node (free)--->|\r
957 * |<---findNode (free req)--->|\r
958 */ \r
959 \r
960 /* There may be a combine possibility to the right. Extract rightNode to check */\r
961 rightNode = RB_NEXT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
962 \r
963 /* Can the node to the right of the matchingNode be combined with the \r
964 * findNode's range? */\r
965 if (rightNode && (strcmp(rightNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0))\r
966 {\r
967 /* Remove the rightNode from the tree for editing */\r
968 RB_REMOVE(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
969 \r
970 /* Combine the rightNode and the findNode */\r
971 rightNode->base = findNode.base;\r
972 rightNode->length += findNode.length;\r
973 }\r
974 else\r
975 {\r
976 /* Allocate a new rightNode that will take the place of the findNode\r
977 * range in tree. */\r
978 rightNode = Rm_newResourceTreeNode(findNode.base, findNode.length,\r
979 RM_NOT_ALLOCATED_STRING);\r
980 }\r
981 \r
982 /* Account for the rightNode in the matchingNode */\r
983 matchingNode->length -= findNode.length; \r
984 \r
985 /* Insert the right node */\r
986 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, rightNode);\r
987 }\r
988 \r
989 /* Reinsert the edited matching node */\r
990 RB_INSERT(_Rm_ResourceTree, allocator->allocatorRootEntry, matchingNode);\r
991 }\r
992 \r
993 retVal = RM_SERVICE_APPROVED_AND_COMPLETED;\r
994 }\r
995 else\r
996 {\r
997 /* The matching allocated range to be freed was allocated to a different instance. */\r
998 retVal = RM_SERVICE_DENIED_RESOURCE_NOT_ALLOCATED_TO_INSTANCE_REQUESTING_THE_SERVICE;\r
999 }\r
1000 }\r
1001 else\r
1002 {\r
1003 /* Free resource range crosses over node boundaries. This signifies a\r
1004 * free of both allocated and unallocated resources since nodes are combined\r
1005 * on allocate and free operations if possible. */\r
1006 retVal = RM_SERVICE_DENIED_RESOURCE_ALREADY_FREE;\r
1007 }\r
1008 }\r
1009 else\r
1010 {\r
1011 /* The free resources could not be found in the allocator */\r
1012 retVal = RM_SERVICE_DENIED_RESOURCE_VALUE_RANGE_DOES_NOT_EXIST;\r
1013 }\r
1014 \r
1015 return(retVal); \r
1016 }\r
1017 \r
1018 int32_t Rm_allocatorOperation(Rm_Inst *rmInst, Rm_AllocatorOpInfo *opInfo)\r
1019 {\r
1020 Rm_Allocator *allocator = NULL;\r
1021 int32_t retVal;\r
1022 void *key;\r
1023 \r
1024 /* Lock access to the RM instance's transaction queue */\r
1025 key = Rm_osalMtCsEnter();\r
1026 \r
1027 /* Get the specified resource's allocator */\r
1028 allocator = Rm_allocatorFind(rmInst, opInfo->resourceInfo->name);\r
1029 \r
1030 if (allocator)\r
1031 {\r
1032 /* Call the allocator's function */\r
1033 if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE)\r
1034 {\r
1035 retVal = Rm_treePreAllocate(allocator, opInfo);\r
1036 } \r
1037 else if (opInfo->operation == Rm_allocatorOp_ALLOCATE)\r
1038 {\r
1039 retVal = Rm_treeAllocate(allocator, opInfo);\r
1040 }\r
1041 else if (opInfo->operation == Rm_allocatorOp_FREE)\r
1042 {\r
1043 retVal = Rm_treeFree(allocator, opInfo);\r
1044 } \r
1045 }\r
1046 else\r
1047 {\r
1048 /* Allocator could not be found for resource */\r
1049 retVal = RM_SERVICE_DENIED_RESOURCE_DOES_NOT_EXIST;\r
1050 }\r
1051 \r
1052 Rm_osalMtCsExit(key);\r
1053 return(retVal);\r
1054 }\r
1055 \r
1056 void Rm_allocationHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1057 {\r
1058 Rm_AllocatorOpInfo opInfo;\r
1059 int32_t retVal = transaction->state;\r
1060 \r
1061 /* Initialize the opInfo structure */\r
1062 memset((void *)&opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1063 \r
1064 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1065 {\r
1066 /* TEMP: For now forward all allocations to the RM Server */\r
1067 Rm_transactionForwarder(rmInst, transaction);\r
1068 \r
1069 #if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
1070 if (resourceBase is unspecified)\r
1071 {\r
1072 while (policy does not approve)\r
1073 {\r
1074 Rm_policy check get allowed base as starting point for prealloc\r
1075 preallocate resource based on the range and alignment\r
1076 Rm_policy...check\r
1077 }\r
1078 }\r
1079 else\r
1080 {\r
1081 /* Check local policy to see if the request can be satisfied with the\r
1082 * resources stored locally */\r
1083 Rm_policy...API()\r
1084 \r
1085 if (policy check approves the resource)\r
1086 {\r
1087 /* call the allocator to allocate the resource */\r
1088 if (allocator returns resource)\r
1089 {\r
1090 /* Populate the transaction with the allocated resources and the result */\r
1091 transaction->state = approve reason;\r
1092 return ...\r
1093 }\r
1094 else\r
1095 {\r
1096 /* allocator ran out of resources, need to contact Server for more\r
1097 * resources */\r
1098 Rm_resourcePoolModRequest(...);\r
1099 }\r
1100 }\r
1101 else if (policy check denies resource)\r
1102 {\r
1103 /* Policy check denied resource. */\r
1104 transaction->state= deny reason;\r
1105 return ...\r
1106 }\r
1107 else if (policy check says forward to Server for validation)\r
1108 {\r
1109 /* Forward the transaction to the Server */\r
1110 Rm_transactionForwarder(rmInst, transaction);\r
1111 }\r
1112 }\r
1113 #endif \r
1114 }\r
1115 else if (rmInst->instType == Rm_instType_SERVER)\r
1116 {\r
1117 /* TEMP: If resource properties are unspecified allocate the next available.\r
1118 * If resource properties are specified allocate if they are available. */\r
1119 \r
1120 /* Fill out the allocator operation general information */\r
1121 opInfo.resourceInfo = &transaction->resourceInfo;\r
1122 opInfo.srcInstName = transaction->sourceInstName;\r
1123 \r
1124 if (strlen(transaction->resourceInfo.nsName) > 0)\r
1125 {\r
1126 /* See if a NameServer name is being used to allocate a resource */\r
1127 if (transaction->resourceInfo.base != 0)\r
1128 {\r
1129 /* A name and a value cannot be specified for the request. It's one\r
1130 * or the other. */\r
1131 retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
1132 }\r
1133 else\r
1134 {\r
1135 /* Get the resource information from the NameServer */\r
1136 retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
1137 }\r
1138 }\r
1139 else if (transaction->resourceInfo.base == RM_RESOURCE_BASE_UNSPECIFIED)\r
1140 {\r
1141 /* Execute the allocator pre-allocate operation to get the next available resources.\r
1142 * NORMALLY CHECKED AGAINST THE POLICY */\r
1143 opInfo.operation = Rm_allocatorOp_PRE_ALLOCATE;\r
1144 \r
1145 if (transaction->resourceInfo.alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED)\r
1146 { \r
1147 /* TEMP: Default resource alignment of 1 if the resource alignment is not\r
1148 * specified */\r
1149 opInfo.policyAlignment = 1;\r
1150 }\r
1151 else\r
1152 {\r
1153 opInfo.policyAlignment = transaction->resourceInfo.alignment;\r
1154 }\r
1155 \r
1156 /* opInfo.policyBase = comes from policy once implemented */\r
1157 opInfo.policyLength = transaction->resourceInfo.length;\r
1158 \r
1159 /* If the pre-allocate operation succeeds the resourceInfo field pointed to\r
1160 * by opInfo will contain the next available resources taht satisfy the\r
1161 * resource properties */\r
1162 retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1163 }\r
1164 \r
1165 /* Call allocator as long as an error or denial hasn't occurred */\r
1166 if (retVal == RM_SERVICE_PROCESSING)\r
1167 {\r
1168 opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
1169 \r
1170 retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1171 }\r
1172 \r
1173 transaction->state = retVal;\r
1174 \r
1175 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1176 {\r
1177 /* Source of allocation was not the server instance, provide the transaction\r
1178 * to the transaction responder */\r
1179 Rm_transactionResponder(rmInst, transaction);\r
1180 }\r
1181 /* Otherwise let the return stack return the transaction to the serviceHandler */ \r
1182 \r
1183 #if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
1184 if (resourceBase is unspecified)\r
1185 {\r
1186 while (policy does not approve)\r
1187 {\r
1188 Rm_policy check get allowed base as starting point for prealloc\r
1189 preallocate resource based on the range and alignment\r
1190 Rm_policy...check\r
1191 }\r
1192 }\r
1193 else\r
1194 {\r
1195 /* Check global policy to see if resource can be allocated. return result\r
1196 * no matter what */\r
1197 Rm_policy...API()\r
1198 \r
1199 if (policy approves)\r
1200 {\r
1201 /* call allocator to allocate resource */\r
1202 }\r
1203 \r
1204 transaction->state = approve or deny reason;\r
1205 transaction->resourceInfo.base = ...;\r
1206 transaction->resourceInfo.length = ...;\r
1207 \r
1208 /* If source instance name does not match the current instance\r
1209 * name the allocation request came from a Client. The result\r
1210 * must be sent back to the Client */\r
1211 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1212 {\r
1213 /* Names don't match. Send the transaction back to the Client */\r
1214 Rm_transactionResponder(rmInst, transaction);\r
1215 }\r
1216 else\r
1217 {\r
1218 /* Resource allocation request originated locally on the active\r
1219 * instance. Send the response via the service responder. */ \r
1220 Rm_serviceResponder(rmInst, transaction); \r
1221 }\r
1222 }\r
1223 #endif \r
1224 } \r
1225 }\r
1226 \r
1227 void Rm_freeHandler (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1228 {\r
1229 Rm_AllocatorOpInfo opInfo;\r
1230 int32_t retVal = transaction->state;\r
1231 \r
1232 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1233 {\r
1234 /* TEMP: Forward all free requests to the Server */\r
1235 Rm_transactionForwarder(rmInst, transaction);\r
1236 \r
1237 #if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
1238 /* Check local policy to see if the request can be satisfied with the\r
1239 * resources stored locally */\r
1240 Rm_policy...API()\r
1241 \r
1242 if (policy check approves the free)\r
1243 {\r
1244 /* call the allocator to free the resource */\r
1245 /* Run a resource pool check to see if the free combined a resource block\r
1246 * that can be returned to the server */\r
1247 if (resource block has been combined)\r
1248 {\r
1249 /* allocator ran out of resources, need to contact Server for more\r
1250 * resources */\r
1251 Rm_resourcePoolModRequest(free pool block to server...);\r
1252 }\r
1253 else\r
1254 {\r
1255 /* Populate the receipt with the freed resources and the result */\r
1256 transaction->state = approve reason;\r
1257 return ...\r
1258 }\r
1259 }\r
1260 else if (policy check denies resource free)\r
1261 {\r
1262 /* Policy check denied resource. */\r
1263 transaction->state = deny reason;\r
1264 return ...\r
1265 }\r
1266 else if (policy check says forward to Server for validation)\r
1267 {\r
1268 /* Forward the transaction to the Server */\r
1269 Rm_transactionForwarder(rmInst, transaction);\r
1270 }\r
1271 #endif \r
1272 }\r
1273 else if (rmInst->instType == Rm_instType_SERVER)\r
1274 {\r
1275 /* TEMP: Free the resources if resources are allocated to the source instance. */\r
1276 \r
1277 /* Fill out the allocator operation general information */\r
1278 opInfo.resourceInfo = &transaction->resourceInfo;\r
1279 opInfo.srcInstName = transaction->sourceInstName;\r
1280 \r
1281 if (strlen(transaction->resourceInfo.nsName) > 0)\r
1282 {\r
1283 /* See if a NameServer name is being used to allocate a resource */\r
1284 if (transaction->resourceInfo.base != 0)\r
1285 {\r
1286 /* A name and a value cannot be specified for the request. It's one\r
1287 * or the other. */\r
1288 retVal = RM_SERVICE_ERROR_NAMESERVER_NAME_AND_RESOURCE_RANGE_BOTH_DEFINED;\r
1289 }\r
1290 else\r
1291 {\r
1292 /* Get the resource information from the NameServer */\r
1293 retVal = Rm_nsFindObject(rmInst, opInfo.resourceInfo);\r
1294 }\r
1295 }\r
1296 \r
1297 /* Call allocator as long as an error or denial hasn't occurred */\r
1298 if (retVal == RM_SERVICE_PROCESSING)\r
1299 {\r
1300 opInfo.operation = Rm_allocatorOp_FREE;\r
1301 \r
1302 retVal = Rm_allocatorOperation(rmInst, &opInfo);\r
1303 }\r
1304 \r
1305 transaction->state = retVal;\r
1306 \r
1307 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1308 {\r
1309 /* Source of allocation was not the server instance, provide the transaction\r
1310 * to the transaction responder */\r
1311 Rm_transactionResponder(rmInst, transaction);\r
1312 }\r
1313 /* Otherwise let the return stack return the transaction to the serviceHandler */ \r
1314 \r
1315 #if 0 /* Policy psuedo-code. Will be implemented after basic allocate functionality is ready and tested */ \r
1316 /* Check global policy to see if resource can be freed. return result\r
1317 * no matter what */\r
1318 Rm_policy...API()\r
1319 if (policy approves)\r
1320 {\r
1321 /* call allocator to free resources */\r
1322 }\r
1323 \r
1324 transaction->state = approve or deny reason;\r
1325 transaction->resourceInfo.base = ...;\r
1326 transaction->resourceInfo.length = ...;\r
1327 \r
1328 /* If source instance name does not match the current instance\r
1329 * name the allocation request came from a client. The result\r
1330 * must be sent back to the Client */\r
1331 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1332 {\r
1333 /* Names don't match. Send the transaction back to the Client Delegate or Client */\r
1334 Rm_transactionResponder(rmInst, transaction);\r
1335 }\r
1336 else\r
1337 {\r
1338 /* Resource allocation request originated locally on the active\r
1339 * instance. Send the response via the service responder. */\r
1340 Rm_serviceResponder(rmInst, transaction); \r
1341 }\r
1342 #endif \r
1343 } \r
1344 }\r
1345 \r
1346 /* Function used to send RM response transactions to lower level agents */\r
1347 void Rm_transactionResponder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1348 {\r
1349 Rm_TransportNode *dstTransportNode = NULL;\r
1350 Rm_Packet *rmPkt = NULL;\r
1351 \r
1352 /* Find the transport for the RM instance that sent the request. */\r
1353 dstTransportNode = Rm_transportNodeFindRemoteName(rmInst, transaction->sourceInstName);\r
1354 \r
1355 /* Create a RM packet using the service information */\r
1356 switch (transaction->type)\r
1357 {\r
1358 case Rm_service_RESOURCE_ALLOCATE:\r
1359 case Rm_service_RESOURCE_FREE:\r
1360 case Rm_service_RESOURCE_GET_BY_NAME:\r
1361 rmPkt = Rm_transportCreateResourceResponsePkt(rmInst, dstTransportNode, \r
1362 transaction);\r
1363 break;\r
1364 case Rm_service_RESOURCE_MAP_TO_NAME:\r
1365 case Rm_service_RESOURCE_UNMAP_NAME:\r
1366 rmPkt = Rm_transportCreateNsResponsePkt(rmInst, dstTransportNode,\r
1367 transaction);\r
1368 break;\r
1369 default:\r
1370 /* Invalid service type. Flag the error and return */\r
1371 transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1372 break;\r
1373 }\r
1374 \r
1375 if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
1376 {\r
1377 /* Delete the transaction and return immediately because an error occurred \r
1378 * allocating the packet */\r
1379 Rm_transactionQueueDelete(rmInst, transaction->localId);\r
1380 return;\r
1381 }\r
1382 \r
1383 /* Send the RM packet to the application transport */\r
1384 if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
1385 {\r
1386 /* Negative value returned by transport send. An error occurred\r
1387 * in the transport while attempting to send the packet.*/\r
1388 transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1389 /* Clean up the packet */\r
1390 if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
1391 {\r
1392 /* Non-NULL value returned by transport packet free. Flag the\r
1393 * error */\r
1394 transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1395 }\r
1396 return;\r
1397 }\r
1398 \r
1399 /* NEED TO DO SOMETHING IF GET AN ERROR IN THE transaction->state FIELD. CREATE\r
1400 * NEW TRANSACTION WITH DATA FROM ORIGINAL? THEN TRY TO SEND FAILED REQUEST BACK\r
1401 * TO REQUESTER??? KEEP RETRYING SEND OF RESPONSE??? */\r
1402 \r
1403 /* Delete the transaction */\r
1404 Rm_transactionQueueDelete(rmInst, transaction->localId);\r
1405 }\r
1406 \r
1407 /* Function used to forward RM transactions to higher level agents */\r
1408 void Rm_transactionForwarder (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1409 {\r
1410 Rm_TransportNode *dstTransportNode = NULL;\r
1411 Rm_Packet *rmPkt = NULL;\r
1412 \r
1413 /* Make sure the RM instance has a transport registered with a higher level agent */\r
1414 if (rmInst->registeredWithDelegateOrServer == false)\r
1415 {\r
1416 transaction->state = RM_SERVICE_ERROR_NOT_REGISTERED_WITH_DEL_OR_SERVER;\r
1417 return;\r
1418 }\r
1419 \r
1420 /* Find the transport for the higher level agent. Check for a connection to a Client Delegate\r
1421 * or a Server. Clients will be connected to either a Client Delegate or a Server. Client\r
1422 * Delegates will be connected to a Server. */\r
1423 if (rmInst->instType == Rm_instType_CLIENT)\r
1424 {\r
1425 dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_CLIENT_DELEGATE);\r
1426 \r
1427 if (!dstTransportNode)\r
1428 {\r
1429 /* No Client Delegate connection found. Check for a Server connection */\r
1430 dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1431 }\r
1432 } \r
1433 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE)\r
1434 {\r
1435 dstTransportNode = Rm_transportNodeFindRemoteInstType(rmInst, Rm_instType_SERVER);\r
1436 }\r
1437 \r
1438 /* Create a RM packet using the service information */\r
1439 switch (transaction->type)\r
1440 {\r
1441 case Rm_service_RESOURCE_ALLOCATE:\r
1442 case Rm_service_RESOURCE_FREE:\r
1443 case Rm_service_RESOURCE_GET_BY_NAME:\r
1444 rmPkt = Rm_transportCreateResourceReqPkt(rmInst, dstTransportNode, \r
1445 transaction);\r
1446 break;\r
1447 case Rm_service_RESOURCE_MAP_TO_NAME:\r
1448 case Rm_service_RESOURCE_UNMAP_NAME:\r
1449 rmPkt = Rm_transportCreateNsRequestPkt(rmInst, dstTransportNode,\r
1450 transaction);\r
1451 break;\r
1452 default:\r
1453 /* Invalid service type. Flag the error and return */\r
1454 transaction->state = RM_SERVICE_ERROR_INVALID_SERVICE_TYPE;\r
1455 break;\r
1456 }\r
1457 \r
1458 if (transaction->state <= RM_SERVICE_ERROR_BASE)\r
1459 {\r
1460 /* Return immediately because an error occurred allocating the packet */\r
1461 return;\r
1462 }\r
1463 \r
1464 /* Send the RM packet to the application transport */\r
1465 if (rmInst->transport.rmSend((Rm_TransportHandle) dstTransportNode, rmPkt) < RM_TRANSPORT_SUCCESSFUL)\r
1466 {\r
1467 /* Negative value returned by transport send. An error occurred\r
1468 * in the transport while attempting to send the packet.*/\r
1469 transaction->state = RM_SERVICE_ERROR_TRANPSPORT_SEND_ERROR;\r
1470 /* Clean up the packet */\r
1471 if (rmInst->transport.rmFreePkt((Rm_TransportHandle) dstTransportNode, rmPkt))\r
1472 {\r
1473 /* Non-NULL value returned by transport packet free. Flag the\r
1474 * error */\r
1475 transaction->state = RM_SERVICE_ERROR_TRANSPORT_FREE_PKT_ERROR;\r
1476 }\r
1477 return;\r
1478 }\r
1479 \r
1480 /* Transaction is not deleted because it is awaiting a response from the higher level\r
1481 * RM instance */\r
1482 }\r
1483 \r
1484 void Rm_transactionProcessor (Rm_Inst *rmInst, Rm_Transaction *transaction)\r
1485 {\r
1486 /* Handle auto-forwarded transactions. These transactions include:\r
1487 * - All request transactions received on Clients are forwarded to the Client Delegate\r
1488 * - NameServer requests received on the Client Delegate are forwarded to the Server */\r
1489 if ((rmInst->instType == Rm_instType_CLIENT) ||\r
1490 ((rmInst->instType == Rm_instType_CLIENT_DELEGATE) &&\r
1491 ((transaction->type == Rm_service_RESOURCE_MAP_TO_NAME) ||\r
1492 (transaction->type == Rm_service_RESOURCE_GET_BY_NAME) ||\r
1493 (transaction->type == Rm_service_RESOURCE_UNMAP_NAME))))\r
1494 { \r
1495 /* Check if the transaction is a transaction that received a response to its\r
1496 * request. */\r
1497 if (transaction->state != RM_SERVICE_PROCESSING)\r
1498 {\r
1499 \r
1500 /* A transaction has received a response. Send the response to either the \r
1501 * transaction or service responder based on the source instance */\r
1502 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1503 {\r
1504 /* Transaction originated from another instance. Use the \r
1505 * transaction responder to send the result to the source instance. This\r
1506 * is not possible on RM Clients since they can't forward RM services */\r
1507 Rm_transactionResponder(rmInst, transaction);\r
1508 }\r
1509 else\r
1510 {\r
1511 /* Transaction originated on this instance. Send to the\r
1512 * service responder */\r
1513 Rm_serviceResponder(rmInst, transaction);\r
1514 }\r
1515 }\r
1516 else\r
1517 {\r
1518 /* This is a new transaction that must be forwarded to a higher level RM instance. */\r
1519 Rm_transactionForwarder(rmInst, transaction);\r
1520 }\r
1521 }\r
1522 else\r
1523 {\r
1524 /* Client Delegate and Server transaction processors. */\r
1525 switch (transaction->type)\r
1526 {\r
1527 case Rm_service_RESOURCE_ALLOCATE:\r
1528 case Rm_service_RESOURCE_FREE: \r
1529 /* Check if the transaction is fulfilled request */\r
1530 if (transaction->state != RM_SERVICE_PROCESSING)\r
1531 {\r
1532 /* If source instance name does not match the current instance\r
1533 * name the allocation request came from a client. The result\r
1534 * must be sent back to the Client */\r
1535 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1536 {\r
1537 Rm_transactionResponder(rmInst, transaction);\r
1538 }\r
1539 else\r
1540 {\r
1541 /* Resource allocation request originated locally. Send the response\r
1542 * via the service responder. */\r
1543 Rm_serviceResponder(rmInst, transaction); \r
1544 }\r
1545 }\r
1546 else\r
1547 {\r
1548 /* This is a new transaction request originating from an RM instance with fewer\r
1549 * allocate/free privileges. Run the allocation or free handler to see if the resource\r
1550 * request can be handled locally or if it needs to be forwarded to a higher level\r
1551 * agent */\r
1552 if (transaction->type == Rm_service_RESOURCE_ALLOCATE)\r
1553 {\r
1554 Rm_allocationHandler(rmInst, transaction);\r
1555 }\r
1556 else\r
1557 {\r
1558 Rm_freeHandler(rmInst, transaction);\r
1559 }\r
1560 }\r
1561 break;\r
1562 case Rm_service_RESOURCE_MAP_TO_NAME:\r
1563 case Rm_service_RESOURCE_GET_BY_NAME:\r
1564 case Rm_service_RESOURCE_UNMAP_NAME: \r
1565 /* Server is the only RM instance capable of adding NameServer objects */\r
1566 if (rmInst->instType == Rm_instType_SERVER)\r
1567 {\r
1568 if (transaction->type == Rm_service_RESOURCE_MAP_TO_NAME)\r
1569 {\r
1570 /* Create a new NameServer object with the request transaction information.\r
1571 * Transaction will contain the state result of the NameServer addition. */\r
1572 if (Rm_nsAddObject(rmInst, &transaction->resourceInfo) == RM_NS_ACTION_APPROVED)\r
1573 {\r
1574 transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1575 }\r
1576 else\r
1577 {\r
1578 /* TEMP: UPDATE THIS STATE VALUE */\r
1579 transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1580 }\r
1581 }\r
1582 else if (transaction->type == Rm_service_RESOURCE_GET_BY_NAME)\r
1583 {\r
1584 /* Create a new NameServer object with the request transaction information.\r
1585 * Transaction will contain the state result of the NameServer addition. */\r
1586 if (Rm_nsFindObject(rmInst, &transaction->resourceInfo) == RM_NS_ACTION_APPROVED)\r
1587 {\r
1588 transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1589 }\r
1590 else\r
1591 {\r
1592 /* TEMP: UPDATE THIS STATE VALUE */\r
1593 transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1594 } \r
1595 }\r
1596 else\r
1597 {\r
1598 /* Delete an existing NameServer object with the request transaction information\r
1599 * Transaction will contain the state result of the NameServer addition. */\r
1600 if (Rm_nsDeleteObject(rmInst, &transaction->resourceInfo) == \r
1601 RM_NS_ACTION_APPROVED)\r
1602 {\r
1603 transaction->state = RM_SERVICE_APPROVED_AND_COMPLETED;\r
1604 }\r
1605 else\r
1606 {\r
1607 /* TEMP: UPDATE THIS STATE VALUE */\r
1608 transaction->state = RM_SERVICE_DENIED_BEGIN;\r
1609 }\r
1610 }\r
1611 \r
1612 /* If source instance name does not match the local instance\r
1613 * name the NameServer request came from a Client or Client Delegate. The \r
1614 * result must be sent back to the Client or Client Delegate. Just return if it does\r
1615 * match since the NameServer transaction result can be returned immediately by the\r
1616 * Rm_serviceHandler. */\r
1617 if (strcmp(transaction->sourceInstName, rmInst->name))\r
1618 {\r
1619 Rm_transactionResponder(rmInst, transaction);\r
1620 }\r
1621 }\r
1622 else\r
1623 {\r
1624 transaction->state = RM_SERVICE_ERROR_NAMESERVER_OBJECT_MOD_ON_INVALID_INSTANCE;\r
1625 }\r
1626 break;\r
1627 }\r
1628 }\r
1629 }\r
1630 \r
1631 int32_t Rm_reserveLinuxResource(Rm_Inst *rmInst, Rm_LinuxAlias *linuxAlias, \r
1632 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)\r
1633 {\r
1634 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1635 bool baseFound = FALSE;\r
1636 bool lengthFound = FALSE;\r
1637 uint32_t valueIndex = 0;\r
1638 \r
1639 while ((linuxValues != NULL) && (!baseFound || !lengthFound))\r
1640 {\r
1641 if (linuxAlias->baseOffset == valueIndex)\r
1642 {\r
1643 /* Found the resource base. Store it in the operation info structure */\r
1644 opInfo->resourceInfo->base = linuxValues->value;\r
1645 baseFound = TRUE;\r
1646 \r
1647 /* length will always be 1 if there is no length specified in the Linux DTB */\r
1648 if (linuxAlias->lengthOffset == RM_DTB_LINUX_ALIAS_OFFSET_NOT_SET)\r
1649 {\r
1650 opInfo->resourceInfo->length = 1;\r
1651 lengthFound = TRUE;\r
1652 }\r
1653 }\r
1654 else if (linuxAlias->lengthOffset == valueIndex)\r
1655 {\r
1656 /* Found the resource length. Store it in the operation info structure */\r
1657 opInfo->resourceInfo->length = linuxValues->value;\r
1658 lengthFound = TRUE;\r
1659 }\r
1660 \r
1661 linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;\r
1662 valueIndex++;\r
1663 }\r
1664 \r
1665 if (!baseFound || !lengthFound)\r
1666 {\r
1667 retVal = -33; /* TODO: ERROR BASE OR LENGTH OFFSET IN LINUX DTB WAS INCORRECT */\r
1668 }\r
1669 else\r
1670 {\r
1671 /* Allocate the resource to Linux */\r
1672 retVal = Rm_allocatorOperation(rmInst, opInfo);\r
1673 }\r
1674 \r
1675 return (retVal);\r
1676 }\r
1677 \r
1678 int32_t Rm_findAndReserveLinuxResource(Rm_Inst *rmInst, const char *resourceName, void *linuxDtb, \r
1679 Rm_LinuxAlias *linuxAlias)\r
1680 {\r
1681 Rm_AllocatorOpInfo opInfo;\r
1682 Rm_ResourceInfo resourceInfo;\r
1683 uint32_t pathOffset;\r
1684 int32_t propOffset;\r
1685 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1686 int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
1687 int32_t depth;\r
1688 int32_t propertyLen;\r
1689 const char *propertyName;\r
1690 const void *propertyData; \r
1691 Rm_LinuxValueRange *linuxValueRange;\r
1692 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY; \r
1693 \r
1694 /* Initialize the allocator opInfo and resourceInfo structures that will be used to \r
1695 * reserve the resources taken by the Linux kernel */\r
1696 memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));\r
1697 memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
1698 \r
1699 strcpy(resourceInfo.name, resourceName);\r
1700 \r
1701 /* Set the source instance name for allocation to be the Linux Kernel */\r
1702 opInfo.srcInstName = RM_ALLOCATED_TO_LINUX;\r
1703 opInfo.operation = Rm_allocatorOp_ALLOCATE;\r
1704 opInfo.resourceInfo = &resourceInfo; \r
1705 \r
1706 /* Find each resource specified in the Linux resource alias list and reserve that \r
1707 * resource as used */\r
1708 while(linuxAlias != NULL)\r
1709 {\r
1710 /* Reset the parsing variables */\r
1711 pathOffset = 0;\r
1712 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
1713 prevDepth = RM_DTB_UTIL_STARTING_DEPTH; \r
1714 resourceInfo.base = 0;\r
1715 resourceInfo.length = 0;\r
1716 \r
1717 while(pathOffset < linuxAlias->pathListLenBytes)\r
1718 {\r
1719 /* Move through the DTB nodes until the next alias path node is found */\r
1720 if (strcmp(linuxAlias->pathList + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL)))\r
1721 {\r
1722 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);\r
1723 \r
1724 if (depth < prevDepth)\r
1725 {\r
1726 /* Returning from subnode that matched part of alias path without finding\r
1727 * the resource values */\r
1728 retVal = (-31); /* TODO: COULD NOT FIND RESOURCE AT ALIAS PATH */\r
1729 break;\r
1730 }\r
1731 }\r
1732 else\r
1733 {\r
1734 /* Found the next alias path node */\r
1735 pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
1736 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);\r
1737 \r
1738 /* Check the properties of the node to see if they match the next alias\r
1739 * path string */\r
1740 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);\r
1741 \r
1742 /* Search the properties for the next alias path string */\r
1743 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&\r
1744 (pathOffset < linuxAlias->pathListLenBytes))\r
1745 {\r
1746 propertyData = fdt_getprop_by_offset(linuxDtb, propOffset, \r
1747 &propertyName, &propertyLen);\r
1748 \r
1749 if (strcmp(linuxAlias->pathList + pathOffset, propertyName) == 0)\r
1750 {\r
1751 pathOffset += (strlen(linuxAlias->pathList + pathOffset) + 1);\r
1752 /* Found the alias property. Extract the values that will\r
1753 * contain the resource information that must be reserved. */\r
1754 linuxValueRange = Rm_linuxExtractValues(propertyData, propertyLen);\r
1755 /* Use the values to reserve resources for the Linux kernel */\r
1756 retVal = Rm_reserveLinuxResource(rmInst, linuxAlias, \r
1757 linuxValueRange, &opInfo);\r
1758 \r
1759 /* Free the memory used to store the values */\r
1760 Rm_linuxFreeValues(linuxValueRange);\r
1761 }\r
1762 \r
1763 propOffset = fdt_next_property_offset(linuxDtb, propOffset);\r
1764 } \r
1765 \r
1766 if (propOffset < -FDT_ERR_NOTFOUND)\r
1767 {\r
1768 /* Error was returned by LIBFDT when parsing the properties */\r
1769 retVal = propOffset;\r
1770 break;\r
1771 }\r
1772 }\r
1773 }\r
1774 \r
1775 if (retVal < RM_DTB_UTIL_RESULT_OKAY)\r
1776 {\r
1777 /* Error occurred during parsing of Linux DTB. Return the error */\r
1778 break;\r
1779 }\r
1780 linuxAlias = (Rm_LinuxAlias *) linuxAlias->nextLinuxAlias;\r
1781 }\r
1782 \r
1783 return (retVal);\r
1784 }\r
1785 \r
1786 int32_t Rm_createAndInitAllocator(Rm_Inst *rmInst, const char *resourceName, \r
1787 Rm_ResourceProperties *resourceProperties, void *linuxDtb)\r
1788 {\r
1789 Rm_ResourceRange *range = NULL;\r
1790 Rm_ResourceRange *rangeBasePtr = NULL;\r
1791 Rm_NsAssignment *nsAssignments = NULL;\r
1792 Rm_NsAssignment *nsAssignmentBasePtr = NULL;\r
1793 Rm_LinuxAlias *linuxAlias = NULL;\r
1794 Rm_ResourceInfo resourceInfo;\r
1795 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1796 \r
1797 if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0))\r
1798 {\r
1799 /* Extract the resource properties from the DTB */\r
1800 range = rangeBasePtr = Rm_resourceExtractRange(resourceProperties->rangeData, \r
1801 resourceProperties->rangeLen);\r
1802 \r
1803 /* Create a tree allocator using the resource properties */\r
1804 retVal = Rm_createTreeAllocator(rmInst, resourceName, range); \r
1805 \r
1806 if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1807 {\r
1808 if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen)\r
1809 {\r
1810 /* Reserve the resources taken by the Linux kernel specified in the Linux DTB */\r
1811 linuxAlias = Rm_resourceExtractLinuxAlias(resourceProperties->linuxAliasData,\r
1812 resourceProperties->linuxAliasLen);\r
1813 \r
1814 retVal = Rm_findAndReserveLinuxResource(rmInst, resourceName, linuxDtb, linuxAlias); \r
1815 }\r
1816 }\r
1817 }\r
1818 \r
1819 if (retVal >= RM_DTB_UTIL_RESULT_OKAY)\r
1820 {\r
1821 /* Create entries in the NameServer if any NameServer assignments were specified */\r
1822 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen)\r
1823 {\r
1824 nsAssignments = Rm_resourceExtractNsAssignment(resourceProperties->nsAssignData, \r
1825 resourceProperties->nsAssignLen);\r
1826 \r
1827 /* Cycle through the list of assignments and add them to the NameServer */\r
1828 nsAssignmentBasePtr = nsAssignments;\r
1829 while (nsAssignments)\r
1830 {\r
1831 memset((void *)&resourceInfo, 0, sizeof(Rm_ResourceInfo));\r
1832 \r
1833 resourceInfo.base = nsAssignments->resourceBase;\r
1834 resourceInfo.length = nsAssignments->resourceLength;\r
1835 strcpy(resourceInfo.nsName, nsAssignments->nsName);\r
1836 \r
1837 /* TODO: RETURN IF ANY OF THE ADDS FAIL??? */\r
1838 Rm_nsAddObject(rmInst, &resourceInfo);\r
1839 nsAssignments = nsAssignments->nextNsAssignment;\r
1840 }\r
1841 /* Free the memory allocated for the NameServer assignments */\r
1842 Rm_resourceFreeNsAssignmentList(nsAssignmentBasePtr);\r
1843 }\r
1844 }\r
1845 \r
1846 /* Free the memory allocated for the resource properties */\r
1847 Rm_resourceFreeRange(rangeBasePtr);\r
1848 Rm_resourceFreeLinuxAlias(linuxAlias);\r
1849 \r
1850 return(retVal);\r
1851 }\r
1852 \r
1853 int32_t Rm_parseResourceProperty(void *globalResourceDtb, int32_t offset, Rm_ResourceProperties *propertyInfo)\r
1854 {\r
1855 int32_t propertyLen;\r
1856 const char *propertyName;\r
1857 const void *propertyData;\r
1858 Rm_ResourcePropType propertyType;\r
1859 int32_t retVal = RM_DTB_UTIL_RESULT_OKAY;\r
1860 \r
1861 /* Get the property data and store it in the corresponding propertyInfo field */\r
1862 propertyData = fdt_getprop_by_offset(globalResourceDtb, offset, &propertyName, &propertyLen);\r
1863 if (propertyData)\r
1864 {\r
1865 propertyType = Rm_resourceGetPropertyType(propertyName);\r
1866 if (propertyType == Rm_resourcePropType_RESOURCE_RANGE)\r
1867 {\r
1868 if (propertyInfo->rangeData || propertyInfo->rangeLen)\r
1869 {\r
1870 /* The range fields have already been populated. Return an error.\r
1871 * The resource list has specified a property field more than once\r
1872 * for a resource node */\r
1873 retVal = -18; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1874 }\r
1875 else\r
1876 {\r
1877 propertyInfo->rangeData = propertyData;\r
1878 propertyInfo->rangeLen = propertyLen;\r
1879 }\r
1880 }\r
1881 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT)\r
1882 {\r
1883 if (propertyInfo->nsAssignData || propertyInfo->nsAssignLen)\r
1884 {\r
1885 /* The nsAssign fields have already been populated. Return an error.\r
1886 * The resource list has specified a property field more than once\r
1887 * for a resource node */\r
1888 retVal = -19; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1889 }\r
1890 else\r
1891 {\r
1892 propertyInfo->nsAssignData = propertyData;\r
1893 propertyInfo->nsAssignLen = propertyLen;\r
1894 }\r
1895 }\r
1896 else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS)\r
1897 {\r
1898 if (propertyInfo->linuxAliasData || propertyInfo->linuxAliasLen)\r
1899 {\r
1900 /* The linuxAlias fields have already been populated. Return an error.\r
1901 * The resource list has specified a property field more than once\r
1902 * for a resource node */\r
1903 retVal = -28; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1904 }\r
1905 else\r
1906 {\r
1907 propertyInfo->linuxAliasData = propertyData;\r
1908 propertyInfo->linuxAliasLen = propertyLen;\r
1909 }\r
1910 } \r
1911 else\r
1912 {\r
1913 retVal = -20; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1914 }\r
1915 }\r
1916 else\r
1917 {\r
1918 retVal = -16; /* TEMP ERROR: Can't conflict with LIBFDT errors */\r
1919 }\r
1920 \r
1921 /* Don't get anymore properties if error occurred */\r
1922 if (retVal == RM_DTB_UTIL_RESULT_OKAY)\r
1923 {\r
1924 offset = fdt_next_property_offset(globalResourceDtb, offset);\r
1925 if (offset >= 0)\r
1926 {\r
1927 retVal = Rm_parseResourceProperty(globalResourceDtb, offset, propertyInfo);\r
1928 }\r
1929 else if (offset != -FDT_ERR_NOTFOUND)\r
1930 {\r
1931 /* Error was returned by LIBFDT when parsing the properties */\r
1932 retVal = offset;\r
1933 }\r
1934 }\r
1935 \r
1936 return (retVal);\r
1937 }\r
1938 \r
1939 int32_t Rm_parseResourceNode(Rm_Inst *rmInst, void *globalResourceDtb, int32_t nodeOffset, int32_t depth,\r
1940 void *linuxDtb)\r
1941 {\r
1942 const char *resourceName = fdt_get_name(globalResourceDtb, nodeOffset, NULL);\r
1943 Rm_ResourceProperties resourceProperties;\r
1944 int32_t error = RM_DTB_UTIL_RESULT_OKAY;\r
1945 int32_t offset;\r
1946 \r
1947 /* Initialize the resource properties structure */\r
1948 memset((void *)&resourceProperties, 0, sizeof(Rm_ResourceProperties));\r
1949 \r
1950 /* Ignore properties of the base node */\r
1951 if (strcmp(resourceName, rmDtbStartingNode))\r
1952 {\r
1953 /* Get the properties for the resource node if any exist */\r
1954 offset = fdt_first_property_offset(globalResourceDtb, nodeOffset);\r
1955 if (offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET)\r
1956 {\r
1957 /* Since at least one property exists attempt to parse the property nodes and \r
1958 * use them to create and initialize a resource allocator */\r
1959 error = Rm_parseResourceProperty(globalResourceDtb, offset, &resourceProperties);\r
1960 if (error < -FDT_ERR_NOTFOUND)\r
1961 {\r
1962 return (error);\r
1963 }\r
1964 \r
1965 /* Initialize an allocator with the resource properties if no error was returned */\r
1966 Rm_createAndInitAllocator(rmInst, resourceName, &resourceProperties, linuxDtb);\r
1967 }\r
1968 else if (offset != -FDT_ERR_NOTFOUND)\r
1969 {\r
1970 /* Error was returned by LIBFDT when parsing the properties */\r
1971 return (offset);\r
1972 }\r
1973 }\r
1974 \r
1975 /* Get the next resource node */\r
1976 offset = fdt_next_node(globalResourceDtb, nodeOffset, &depth);\r
1977 /* Check the offset and depth of the next node to make sure the current node\r
1978 * wasn't the last node in the Resource List. A depth less than the depth set\r
1979 * at the start of the recursion will signal the end of the resource list */\r
1980 if ((offset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (depth >= RM_DTB_UTIL_STARTING_DEPTH))\r
1981 {\r
1982 error = Rm_parseResourceNode(rmInst, globalResourceDtb, offset, depth, linuxDtb);\r
1983 if (error < -FDT_ERR_NOTFOUND)\r
1984 {\r
1985 return (error);\r
1986 }\r
1987 }\r
1988 else if (offset != -FDT_ERR_NOTFOUND)\r
1989 {\r
1990 /* Error was returned by LIBFDT when parsing the nodes */\r
1991 return (offset);\r
1992 }\r
1993 \r
1994 return (RM_DTB_UTIL_RESULT_OKAY);\r
1995 }\r
1996 \r
1997 int32_t Rm_initializeAllocators(Rm_Inst *rmInst, void *globalResourceDtb, void *linuxDtb)\r
1998 {\r
1999 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;\r
2000 int32_t startDepth = RM_DTB_UTIL_STARTING_DEPTH;\r
2001 int32_t result = RM_DTB_UTIL_RESULT_OKAY;\r
2002 \r
2003 /* Recursively parse the Global Resource List, creating an allocator for\r
2004 * each resource as specified in the node */\r
2005 result = Rm_parseResourceNode(rmInst, globalResourceDtb, nodeOffset, startDepth, linuxDtb);\r
2006 \r
2007 return(result);\r
2008 }\r
2009 \r
2010 /**********************************************************************\r
2011 ********************** Application visible APIs **********************\r
2012 **********************************************************************/\r
2013 \r
2014 /* Server Only */\r
2015 void Rm_printResourceStatus(Rm_Handle *rmHandle)\r
2016 {\r
2017 Rm_Inst *rmInst = (Rm_Inst *) rmHandle;\r
2018 Rm_Allocator *allocator = rmInst->allocators;\r
2019 Rm_ResourceTree *treeRoot;\r
2020 Rm_ResourceTreeNode *treeNode;\r
2021 uint32_t numLinuxResources;\r
2022 \r
2023 while (allocator != NULL)\r
2024 {\r
2025 numLinuxResources = 0;\r
2026 \r
2027 Rm_osalLog("Resource: %s\n", allocator->resourceName);\r
2028 \r
2029 treeRoot = allocator->allocatorRootEntry;\r
2030 \r
2031 RB_FOREACH(treeNode, _Rm_ResourceTree, treeRoot)\r
2032 { \r
2033 Rm_osalLog(" %10d - %10d ", treeNode->base, \r
2034 treeNode->base + treeNode->length -1);\r
2035 \r
2036 if (strcmp(treeNode->allocatedTo, RM_NOT_ALLOCATED_STRING) == 0)\r
2037 {\r
2038 Rm_osalLog("NOT ALLOCATED\n");\r
2039 }\r
2040 else\r
2041 {\r
2042 Rm_osalLog("allocated to %s\n", treeNode->allocatedTo);\r
2043 }\r
2044 \r
2045 if (strcmp(treeNode->allocatedTo, RM_ALLOCATED_TO_LINUX) == 0)\r
2046 {\r
2047 numLinuxResources += treeNode->length;\r
2048 }\r
2049 }\r
2050 \r
2051 Rm_osalLog("Total allocated to Linux: %d\n", numLinuxResources);\r
2052 \r
2053 allocator = allocator->nextAllocator;\r
2054 }\r
2055 \r
2056 Rm_nsPrintObjects(rmInst);\r
2057 }\r
2058 \r
2059 Rm_Handle Rm_init(Rm_InitCfg *initCfg)\r
2060 {\r
2061 Rm_Inst *rmInst;\r
2062 void *globalResourceDtb = NULL;\r
2063 void *linuxResourceDtb = NULL;\r
2064 \r
2065 /* Instance creation checks. Add one to strlen calculation for null character */\r
2066 if ((strlen(initCfg->instName) + 1) > RM_INSTANCE_NAME_MAX_CHARS)\r
2067 {\r
2068 /* Failure: Instance name is too big */\r
2069 return (NULL);\r
2070 }\r
2071 \r
2072 /* Get memory for RM instance from local memory */\r
2073 rmInst = Rm_osalMalloc (sizeof(Rm_Inst));\r
2074 /* Populate instance based on input parameters */\r
2075 strcpy (&rmInst->name[0], initCfg->instName);\r
2076 rmInst->instType = initCfg->instType;\r
2077 rmInst->registeredWithDelegateOrServer = false;\r
2078 rmInst->policyDtb = NULL;\r
2079 \r
2080 /* Initialize the transport routing map linked list pointer to NULL. The linked list\r
2081 * nodes will be created when the application registers transports */\r
2082 rmInst->routeMap = NULL;\r
2083 \r
2084 /* Initialize the allocators linked list pointer to NULL. The linked list nodes will\r
2085 * be created on the Server instance when the application reads in the resource list.\r
2086 * Nodes will also be created on Client Delegates when blocks of resources are requested\r
2087 * for allocation to clients. */\r
2088 rmInst->allocators = NULL;\r
2089 \r
2090 /* Initialize the NameServer pointer to NULL. The NameServer should only be located\r
2091 * on the RM Server */\r
2092 rmInst->nameServer = NULL;\r
2093 \r
2094 /* Initialize the transaction queue elements. */\r
2095 rmInst->transactionSeqNum = Rm_transactionInitSequenceNum();\r
2096 rmInst->transactionQueue= NULL;\r
2097 \r
2098 /* RM Server specific actions */\r
2099 if (rmInst->instType == Rm_instType_SERVER)\r
2100 {\r
2101 /* Initialize the NameServer */\r
2102 Rm_nsInit(rmInst);\r
2103 \r
2104 /* Open the ResourceList file and provide it to the resource initializer. The Linux\r
2105 * DTB will be parsed simultaneously for resource's consumed by the kernel. The resources\r
2106 * used by the kernel will be marked as used in the resource allocators. */\r
2107 if (initCfg->globalResourceList)\r
2108 {\r
2109 globalResourceDtb = initCfg->globalResourceList;\r
2110 fdt_open_into(globalResourceDtb, globalResourceDtb, fdt_totalsize(globalResourceDtb));\r
2111 \r
2112 if (initCfg->linuxDtb)\r
2113 {\r
2114 linuxResourceDtb = initCfg->linuxDtb;\r
2115 fdt_open_into(linuxResourceDtb, linuxResourceDtb, fdt_totalsize(linuxResourceDtb)); \r
2116 }\r
2117 \r
2118 Rm_initializeAllocators(rmInst, globalResourceDtb, linuxResourceDtb);\r
2119 }\r
2120 }\r
2121 \r
2122 /* Instance startup policies are only used for Servers and Client Delegates */\r
2123 if (rmInst->instType != Rm_instType_CLIENT)\r
2124 {\r
2125 /* Open the instance's policy and store it */\r
2126 if (initCfg->startupPolicy)\r
2127 {\r
2128 rmInst->policyDtb = initCfg->startupPolicy;\r
2129 fdt_open_into(rmInst->policyDtb, rmInst->policyDtb, fdt_totalsize(rmInst->policyDtb)); \r
2130 }\r
2131 \r
2132 /* Store policy via policy APIs ... */\r
2133 }\r
2134 \r
2135 /* Return the RM Handle */\r
2136 return ((Rm_Handle) rmInst);\r
2137 }\r
2138 \r
2139 uint32_t Rm_getVersion (void)\r
2140 {\r
2141 return RM_VERSION_ID;\r
2142 }\r
2143 \r
2144 \r
2145 const char* Rm_getVersionStr (void)\r
2146 {\r
2147 return rmVersionStr;\r
2148 }\r
2149 \r
2150 /**\r
2151 @}\r
2152 */\r