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