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