1 /**
2 * @file rm_allocator.c
3 *
4 * @brief
5 * This is the Resource Manager allocator source.
6 *
7 * \par
8 * ============================================================================
9 * @n (C) Copyright 2012-2013, Texas Instruments, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 * \par
40 */
42 /* RM external includes */
43 #include <ti/drv/rm/rm.h>
45 /* RM internal includes */
46 #include <ti/drv/rm/include/rm_loc.h>
47 #include <ti/drv/rm/include/rm_allocatorloc.h>
48 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
49 #include <ti/drv/rm/include/rm_policyloc.h>
50 #include <ti/drv/rm/include/rm_treeloc.h>
52 /* RM LIBFDT includes */
53 #include <ti/drv/rm/util/libfdt/libfdt.h>
55 /* Tree algorithm includes */
56 #include <ti/drv/rm/util/tree.h>
58 /* RM OSAL layer */
59 #include <rm_osal.h>
61 /**********************************************************************
62 ************************ Local Functions *****************************
63 **********************************************************************/
65 /* FUNCTION PURPOSE: Creates a resource allocator
66 ***********************************************************************
67 * DESCRIPTION: Returns a newly Created and initialized resource
68 * The allocator is also stored in the RM instance
69 * allocator list.
70 */
71 static Rm_Allocator *allocatorAdd(Rm_Handle rmHandle, const char *resourceName)
72 {
73 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
74 Rm_Allocator *allocators = rmInst->u.server.allocators;
75 Rm_Allocator *newAllocator = NULL;
77 newAllocator = Rm_osalMalloc(sizeof(Rm_Allocator));
79 if (newAllocator) {
80 memset((void *)newAllocator, 0, sizeof(Rm_Allocator));
81 strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
82 newAllocator->allocatorRootEntry = NULL;
83 newAllocator->nextAllocator = NULL;
85 /* Add allocator to end of list */
86 if (allocators) {
87 while (allocators->nextAllocator) {
88 allocators = allocators->nextAllocator;
89 }
90 allocators->nextAllocator = newAllocator;
91 }
92 else {
93 rmInst->u.server.allocators = newAllocator;
94 }
95 }
96 return (newAllocator);
97 }
99 /* FUNCTION PURPOSE: Deletes a resource allocator
100 ***********************************************************************
101 * DESCRIPTION: Deletes a resource allocator based on the given
102 * resource name. The resource allocator will be
103 * removed from the RM instance allocator list.
104 */
105 static int32_t allocatorDelete(Rm_Handle rmHandle, char *resourceName)
106 {
107 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
108 Rm_Allocator *allocator = rmInst->u.server.allocators;
109 Rm_Allocator *prevAllocator = NULL;
110 int32_t retVal = RM_OK;
112 while (allocator) {
113 if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
114 break;
115 }
116 prevAllocator = allocator;
117 allocator = allocator->nextAllocator;
118 }
120 if (allocator) {
121 if (prevAllocator == NULL) {
122 rmInst->u.server.allocators = allocator->nextAllocator;
123 }
124 else {
125 prevAllocator->nextAllocator = allocator->nextAllocator;
126 }
127 Rm_osalFree((void *)allocator, sizeof(Rm_Allocator));
128 }
129 else {
130 retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
131 }
132 return (retVal);
133 }
135 /* FUNCTION PURPOSE: Creates a new resource tree
136 ***********************************************************************
137 * DESCRIPTION: Creates and populates a new resource tree allocator
138 * using the provided resource name and value range. The
139 * name and value originate from the GRL.
140 */
141 static int32_t allocatorCreate(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceRange *range)
142 {
143 Rm_Allocator *allocator = NULL;
144 Rm_ResourceTree *treeRootEntry = NULL;
145 Rm_ResourceNode *treeNode = NULL;
146 Rm_ResourceNode *collidingNode = NULL;
148 allocator = allocatorAdd(rmHandle, resourceName);
149 treeRootEntry = Rm_osalMalloc(sizeof(Rm_ResourceTree));
150 RB_INIT(treeRootEntry);
152 while (range != NULL) {
153 treeNode = rmResourceNodeNew(range->base, range->length);
154 collidingNode = RB_INSERT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
156 if (collidingNode) {
157 Rm_ResourceNode *nextNode = NULL;
159 /* Node that was inserted collides with existing node. Destroy tree and return error */
160 for (treeNode = RB_MIN(_Rm_AllocatorResourceTree, treeRootEntry); treeNode != NULL; treeNode = nextNode) {
161 nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRootEntry, treeNode);
162 RB_REMOVE(_Rm_AllocatorResourceTree, treeRootEntry, nextNode);
163 rmResourceNodeFree(treeNode);
164 }
165 Rm_osalFree((void *)treeRootEntry, sizeof(Rm_ResourceTree));
166 allocatorDelete(rmHandle, allocator->resourceName);
167 return (RM_ERROR_GRL_RES_SPECIFIED_MORE_THAN_ONCE);
168 }
169 range = range->nextRange;
170 }
172 allocator->allocatorRootEntry = treeRootEntry;
173 return(RM_OK);
174 }
176 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
177 ***********************************************************************
178 * DESCRIPTION: Adds a RM instance node to a resource node's
179 * list of owners.
180 */
181 static void allocatorResNodeOwnerAdd(Rm_ResourceNode *node, void *serviceInstNode)
182 {
183 Rm_Owner *ownerList = node->ownerList;
184 Rm_Owner *newOwner = NULL;
186 newOwner = Rm_osalMalloc(sizeof(Rm_Owner));
188 if (newOwner) {
189 newOwner->instNameNode = serviceInstNode;
190 newOwner->nextOwner = NULL;
192 /* Add owner entry to end of list */
193 if (ownerList) {
194 while (ownerList->nextOwner) {
195 ownerList = ownerList->nextOwner;
196 }
197 ownerList->nextOwner = newOwner;
198 }
199 else {
200 node->ownerList = newOwner;
201 }
203 node->allocationCount++;
204 newOwner->instNameNode->allocRefCount++;
205 }
206 }
208 /* FUNCTION PURPOSE: Compares two resource node's owners
209 ***********************************************************************
210 * DESCRIPTION: Returns TRUE if the owners of two resource nodes
211 * are equivalent. Otherwise, returns FALSE.
212 */
213 static bool allocatorResNodeOwnerCompare(Rm_ResourceNode *node1, Rm_ResourceNode *node2)
214 {
215 Rm_Owner *node1Owners = node1->ownerList;
216 Rm_Owner *node2Owners = node2->ownerList;
217 bool matchedInst;
219 if (node1->allocationCount == node2->allocationCount) {
220 while (node1Owners) {
221 matchedInst = false;
222 while (node2Owners) {
223 if (node1Owners->instNameNode == node2Owners->instNameNode) {
224 matchedInst = true;
225 break;
226 }
227 node2Owners = node2Owners->nextOwner;
228 }
230 if (matchedInst) {
231 node2Owners = node2->ownerList;
232 node1Owners = node1Owners->nextOwner;
233 }
234 else {
235 return(false);
236 }
237 }
238 }
239 else {
240 return(false);
241 }
243 return(true);
244 }
246 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
247 ***********************************************************************
248 * DESCRIPTION: Removes a RM instance node from a resource node's
249 * list of owners.
250 */
251 static void allocatorResNodeOwnerDelete(Rm_ResourceNode *node, void *serviceInstNode)
252 {
253 Rm_Owner *owner = node->ownerList;
254 Rm_Owner *prevOwner = NULL;
256 while (owner) {
257 if (owner->instNameNode == serviceInstNode) {
258 break;
259 }
260 prevOwner = owner;
261 owner = owner->nextOwner;
262 }
264 if (prevOwner == NULL) {
265 node->ownerList = owner->nextOwner;
266 }
267 else {
268 prevOwner->nextOwner = owner->nextOwner;
269 }
271 node->allocationCount--;
272 owner->instNameNode->allocRefCount--;
273 Rm_osalFree((void *)owner, sizeof(Rm_Owner));
274 }
276 /* FUNCTION PURPOSE: Copies the owners of a resource node
277 ***********************************************************************
278 * DESCRIPTION: Creates a list of resource owners for the destination
279 * resource node that is equivalent to the the
280 * source resource node's owners
281 */
282 static void allocatorResNodeOwnerCopy(Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
283 {
284 Rm_Owner *srcOwnerList = srcNode->ownerList;
285 Rm_Owner *dstNewOwner;
286 Rm_Owner *dstPrevOwner;
288 dstNode->allocationCount = srcNode->allocationCount;
290 while (srcOwnerList) {
291 dstNewOwner = Rm_osalMalloc(sizeof(Rm_Owner));
292 dstNewOwner->instNameNode = srcOwnerList->instNameNode;
293 dstNewOwner->nextOwner = NULL;
295 if (dstNode->ownerList == NULL) {
296 dstNode->ownerList = dstNewOwner;
297 }
298 else {
299 dstPrevOwner->nextOwner = dstNewOwner;
300 }
301 dstPrevOwner = dstNewOwner;
302 srcOwnerList = srcOwnerList->nextOwner;
303 }
304 }
306 /* FUNCTION PURPOSE: Clears a resource node's owners
307 ***********************************************************************
308 * DESCRIPTION: Deletes all owners from the owners list of a
309 * resource node.
310 */
311 static void allocatorResNodeOwnerClear(Rm_ResourceNode *node)
312 {
313 Rm_Owner *owner = node->ownerList;
314 Rm_Owner *nextOwner;
316 while (owner) {
317 nextOwner = owner->nextOwner;
318 node->allocationCount--;
319 owner->instNameNode->allocRefCount--;
320 Rm_osalFree((void *)owner, sizeof(Rm_Owner));
321 owner = nextOwner;
322 }
323 }
325 /* FUNCTION PURPOSE: Checks a resource node's ownership
326 ***********************************************************************
327 * DESCRIPTION: Returns TRUE if the provided instance node is
328 * in the list of resource node owners. Otherwise,
329 * returns FALSE.
330 */
331 static bool allocatorResNodeIsOwnedBy(Rm_ResourceNode *node, void *serviceInstNode)
332 {
333 Rm_Owner *owner = node->ownerList;
335 while (owner) {
336 if (owner->instNameNode == serviceInstNode) {
337 return(true);
338 }
339 owner = owner->nextOwner;
340 }
341 return(false);
342 }
344 /* FUNCTION PURPOSE: Preallocates an allocator resource
345 ***********************************************************************
346 * DESCRIPTION: Called when an allocate request is made but the base
347 * is unspecified. The preallocation algorithm looks at
348 * available resources as well as policy permissions to
349 * determine a resource range that satisfies the request.
350 * If a valid range is found it will be returned for the
351 * treeAllocate algorithm to handle.
352 */
353 static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
354 Rm_AllocatorOpInfo *opInfo)
355 {
356 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
357 Rm_ResourceNode findNode;
358 Rm_ResourceNode *matchingNode = NULL;
359 uint32_t matchingEnd;
360 uint32_t rangeIndex;
361 bool resourceFound = false;
362 Rm_PolicyCheckType policyCheckType;
363 Rm_PolicyCheckCfg policyCheckCfg;
364 bool nodePassesPolicy;
365 int32_t retVal = RM_SERVICE_PROCESSING;
367 opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode,
368 resourcePolicy, opInfo->allocType,
369 &retVal);
370 if (retVal != RM_SERVICE_PROCESSING) {
371 return (retVal);
372 }
374 if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {
375 /* Get alignment from policy */
376 opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy);
377 }
379 if (opInfo->resourceInfo->alignment == 0) {
380 opInfo->resourceInfo->alignment = 1;
381 }
383 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
384 findNode.base = opInfo->resourceInfo->base;
385 findNode.length = opInfo->resourceInfo->length;
387 /* Configure policy checking structure */
388 memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
389 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
390 policyCheckType = Rm_policyCheck_INIT;
391 }
392 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
393 policyCheckType = Rm_policyCheck_USE;
394 }
395 policyCheckCfg.policyDtb = opInfo->policy;
396 policyCheckCfg.resourceOffset = resourcePolicy;
398 do {
399 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
401 if (matchingNode) {
402 if (!allocatorResNodeIsOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
403 /* Attempt to preallocate from node only if not owned by instance requesting the allocation */
404 nodePassesPolicy = false;
405 policyCheckCfg.type = policyCheckType;
406 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
407 policyCheckCfg.resourceBase = findNode.base;
408 policyCheckCfg.resourceLength = findNode.length;
409 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
411 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
412 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
414 if (allocatorResNodeIsOwnedBy(matchingNode, rmPolicyGetLinuxInstNode(rmInst->u.server.globalValidInstTree))) {
415 /* Check if instance requesting resource has privileges to share
416 * a resource already reserved by Linux */
417 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
418 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
419 }
421 if (nodePassesPolicy) {
422 /* Check exclusive privileges of instance requesting resource. Requesting
423 * instance with exclusive privileges can't reserve resource if already owned*/
424 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
425 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
426 }
427 }
429 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
430 /* Check exclusive privileges of instance that currently owns resource */
431 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
432 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
433 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
434 }
436 if (retVal != RM_SERVICE_PROCESSING) {
437 break;
438 }
440 if (nodePassesPolicy) {
441 matchingEnd = matchingNode->base + matchingNode->length - 1;
442 /* Initialize indexer to be first resource value that alignment */
443 rangeIndex = findNode.base;
444 if (rangeIndex % opInfo->resourceInfo->alignment) {
445 rangeIndex += (opInfo->resourceInfo->alignment -
446 (rangeIndex % opInfo->resourceInfo->alignment));
447 }
449 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
450 /* Block of unallocated resources within matchingNode that satisfies
451 * allocate requirements */
452 opInfo->resourceInfo->base = rangeIndex;
453 resourceFound = true;
454 }
455 }
456 }
458 if (!resourceFound) {
459 /* Check next resource node for available resources */
460 findNode.base = matchingNode->base + matchingNode->length;
461 }
462 }
463 else {
464 retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
465 }
466 } while ((!resourceFound) &&
467 (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
469 return(retVal);
470 }
472 /* FUNCTION PURPOSE: Allocates an allocator resource
473 ***********************************************************************
474 * DESCRIPTION: Will attempt to allocate the resource with specified
475 * base and length from the resource's allocator. The
476 * allocation algorithm will verify the allocation against
477 * the policy permissions for the instance requesting the
478 * allocation. If the policy allows the allocation the
479 * algorithm will allocate the resource then combine any
480 * resource nodes that may have become equivalent (in terms
481 * of ownership) after the allocation.
482 */
483 static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
484 Rm_AllocatorOpInfo *opInfo)
485 {
486 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
487 Rm_ResourceNode findNode;
488 Rm_ResourceNode *matchingNode = NULL;
489 Rm_ResourceNode *leftNode = NULL;
490 Rm_ResourceNode *rightNode = NULL;
491 Rm_PolicyCheckType policyCheckType;
492 Rm_PolicyCheckCfg policyCheckCfg;
493 bool allocPassesPolicy;
494 bool combineLeft = false;
495 bool combineRight = false;
496 uint32_t findEnd;
497 uint32_t matchingEnd;
498 int32_t retVal = RM_SERVICE_PROCESSING;
500 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
501 findNode.base = opInfo->resourceInfo->base;
502 findNode.length = opInfo->resourceInfo->length;
503 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
505 /* Prepare privilege checks */
506 memset((void *)&policyCheckCfg, 0, sizeof(Rm_PolicyCheckCfg));
507 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
508 policyCheckType = Rm_policyCheck_INIT;
509 }
510 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
511 policyCheckType = Rm_policyCheck_USE;
512 }
514 if (matchingNode) {
515 findEnd = findNode.base + findNode.length - 1;
516 matchingEnd = matchingNode->base + matchingNode->length - 1;
518 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
519 if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmInst->u.server.globalValidInstTree)) {
520 /* Bypass policy checks since Linux Kernel has full privileges */
521 allocPassesPolicy = true;
522 }
523 else {
524 policyCheckCfg.policyDtb = opInfo->policy;
525 policyCheckCfg.resourceOffset = resourcePolicy;
526 policyCheckCfg.type = policyCheckType;
527 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
528 policyCheckCfg.resourceBase = findNode.base;
529 policyCheckCfg.resourceLength = findNode.length;
530 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
531 if (!allocPassesPolicy) {
532 if (policyCheckType == Rm_policyCheck_INIT) {
533 retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
534 }
535 else {
536 retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
537 }
538 }
540 if (!allocatorResNodeIsOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
541 if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
542 if (allocatorResNodeIsOwnedBy(matchingNode, rmPolicyGetLinuxInstNode(rmInst->u.server.globalValidInstTree))) {
543 /* Check if instance requesting resource has privileges to share
544 * a resource already reserved by Linux */
545 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
546 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
547 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
548 if (!allocPassesPolicy) {
549 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
550 }
551 }
552 if (allocPassesPolicy) {
553 /* Check exclusive privileges of instance requesting resource. Requesting
554 * instance with exclusive privileges can't reserve resource if already owned*/
555 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
556 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
557 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
558 if (!allocPassesPolicy) {
559 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
560 }
561 }
562 }
563 if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
564 /* Check exclusive privileges of instance that currently owns resource */
565 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
566 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
567 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
568 if (!allocPassesPolicy) {
569 retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
570 }
571 }
572 }
573 }
575 if (allocPassesPolicy) {
576 if (!allocatorResNodeIsOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
577 /* Handle any possible node combinations if requesting instance is
578 * not already in resource's owner list. Automatic approval if requesting
579 * instance is already in owner list. */
580 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
581 /* findNode range matches matchingNode range
582 *
583 * |<--left node-->||<--matched node-->||<--right node-->| => existing node
584 * |<--alloc request-->| => requested resources
585 */
586 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
587 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
588 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
589 allocatorResNodeOwnerAdd(matchingNode, opInfo->serviceSrcInstNode);
591 if (leftNode && allocatorResNodeOwnerCompare(leftNode, matchingNode)) {
592 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
593 combineLeft = true;
594 }
595 if (rightNode && allocatorResNodeOwnerCompare(rightNode, matchingNode)) {
596 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
597 combineRight = true;
598 }
600 if (combineLeft && combineRight) {
601 /* Combine all three nodes into matchingNode */
602 matchingNode->base = leftNode->base;
603 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
605 allocatorResNodeOwnerClear(leftNode);
606 rmResourceNodeFree(leftNode);
607 allocatorResNodeOwnerClear(rightNode);
608 rmResourceNodeFree(rightNode);
609 }
610 else if (combineLeft) {
611 /* Combine left and matching nodes. Reinsert right. */
612 matchingNode->base = leftNode->base;
613 matchingNode->length += leftNode->length;
615 allocatorResNodeOwnerClear(leftNode);
616 rmResourceNodeFree(leftNode);
617 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
618 }
619 else if (combineRight) {
620 /* Combine right and matching nodes. Reinsert left. */
621 matchingNode->length += rightNode->length;
623 allocatorResNodeOwnerClear(rightNode);
624 rmResourceNodeFree(rightNode);
625 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
626 }
627 else {
628 /* No combine. */
629 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
630 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
631 }
633 /* Always reinsert matchingNode */
634 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
635 }
636 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
637 /* findNode range is subset of matchingNode range and neither boundary is
638 * equivalent.
639 *
640 * |<----------matched node---------->|
641 * |<---alloc request--->|
642 */
643 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
644 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
645 allocatorResNodeOwnerCopy(leftNode, matchingNode);
646 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
647 allocatorResNodeOwnerCopy(rightNode, matchingNode);
649 matchingNode->base = findNode.base;
650 matchingNode->length = findNode.length;
651 allocatorResNodeOwnerAdd(matchingNode, opInfo->serviceSrcInstNode);
653 /* Insert all the nodes */
654 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
655 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
656 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
657 }
658 else {
659 if (findNode.base == matchingNode->base) {
660 /* findNode base and matchingNode base are equivalent. May be combine
661 * possibilities to the left
662 *
663 * |<---left node (alloc'd)--->||<----------matched node---------->|
664 * |<---findNode (alloc req)--->|
665 */
666 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
667 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
668 /* Add allocating instance to owner list for compare with leftNode */
669 allocatorResNodeOwnerAdd(matchingNode, opInfo->serviceSrcInstNode);
671 if (leftNode && allocatorResNodeOwnerCompare(leftNode, matchingNode)) {
672 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
673 /* Combine leftNode and findNode */
674 leftNode->length += findNode.length;
675 }
676 else {
677 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
678 allocatorResNodeOwnerCopy(leftNode, matchingNode);
679 }
681 /* Account for leftNode in matchingNode */
682 matchingNode->base = findNode.base + findNode.length;
683 matchingNode->length = matchingEnd - findEnd;
685 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
686 }
687 else if (findEnd == matchingEnd) {
688 /* findNode end and matchingNode end are equivalent. May be combine
689 * possibilities to the right
690 *
691 * |<----------matched node---------->||<---right node (alloc'd)--->|
692 * |<---findNode (alloc req)--->|
693 */
694 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
695 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
696 /* Add allocating instance to owner list for compare with rightNode */
697 allocatorResNodeOwnerAdd(matchingNode, opInfo->serviceSrcInstNode);
699 if (rightNode && allocatorResNodeOwnerCompare(rightNode, matchingNode)) {
700 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
701 /* Combine rightNode and findNode */
702 rightNode->base = findNode.base;
703 rightNode->length += findNode.length;
704 }
705 else {
706 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
707 allocatorResNodeOwnerCopy(rightNode, matchingNode);
708 }
710 /* Account for rightNode in matchingNode */
711 matchingNode->length -= findNode.length;
713 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
714 }
715 /* Remove allocating instance from leftover matchingNode */
716 allocatorResNodeOwnerDelete(matchingNode, opInfo->serviceSrcInstNode);
717 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
718 }
719 }
720 retVal = RM_SERVICE_APPROVED;
721 }
722 }
723 else {
724 retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
725 }
726 }
727 else {
728 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
729 }
731 return(retVal);
732 }
734 /* FUNCTION PURPOSE: Frees an allocator resource
735 ***********************************************************************
736 * DESCRIPTION: Will attempt to free the resource with specified
737 * base and length from the resource's allocator. The
738 * free algorithm will verify the free request parameters
739 * match an allocated range for the resource and that the
740 * range is owned by the instance requesting the free. If
741 * the free is validated the algorithm will free the
742 * resource then combine any resource nodes that may have
743 * become equivalent (in terms of ownership) after the
744 * allocation.
745 */
746 static int32_t allocatorFree(Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
747 {
748 Rm_ResourceNode findNode;
749 Rm_ResourceNode *matchingNode = NULL;
750 Rm_ResourceNode *leftNode = NULL;
751 Rm_ResourceNode *rightNode = NULL;
752 bool combineLeft = false;
753 bool combineRight = false;
754 uint32_t findEnd;
755 uint32_t matchingEnd;
756 int32_t retVal;
758 memset((void *)&findNode, 0, sizeof(Rm_ResourceNode));
759 findNode.base = opInfo->resourceInfo->base;
760 findNode.length = opInfo->resourceInfo->length;
761 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
763 if (matchingNode) {
764 findEnd = findNode.base + findNode.length - 1;
765 matchingEnd = matchingNode->base + matchingNode->length - 1;
767 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
768 if (matchingNode->allocationCount) {
769 if (allocatorResNodeIsOwnedBy(matchingNode, opInfo->serviceSrcInstNode)) {
770 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
771 {
772 /* Case 1: Free range equals allocated matched node exactly. Attempt to combine
773 * freed node with nodes to left and right.
774 *
775 * |<--left node-->||<---matched node--->||<--right node-->|
776 * |<---free request--->|
777 */
778 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
779 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
780 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
781 allocatorResNodeOwnerDelete(matchingNode, opInfo->serviceSrcInstNode);
783 if (leftNode && allocatorResNodeOwnerCompare(leftNode, matchingNode)) {
784 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
785 combineLeft = true;
786 }
787 if (rightNode && allocatorResNodeOwnerCompare(rightNode, matchingNode)) {
788 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
789 combineRight = true;
790 }
792 if (combineLeft && combineRight) {
793 /* Combine all three nodes into matchingNode */
794 matchingNode->base = leftNode->base;
795 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
797 allocatorResNodeOwnerClear(leftNode);
798 rmResourceNodeFree(leftNode);
799 allocatorResNodeOwnerClear(rightNode);
800 rmResourceNodeFree(rightNode);
801 }
802 else if (combineLeft) {
803 /* Combine left and matching nodes. Reinsert right. */
804 matchingNode->base = leftNode->base;
805 matchingNode->length += leftNode->length;
807 allocatorResNodeOwnerClear(leftNode);
808 rmResourceNodeFree(leftNode);
809 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
810 }
811 else if (combineRight) {
812 /* Combine right and matching nodes. Reinsert left. */
813 matchingNode->length += rightNode->length;
815 allocatorResNodeOwnerClear(rightNode);
816 rmResourceNodeFree(rightNode);
817 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
818 }
819 else {
820 /* No combine. */
821 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
822 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
823 }
825 /* Always reinsert matchingNode */
826 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
827 }
828 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
829 /* Case 2: Free range is less than range in matched node. Split
830 * matched node into three nodes.
831 *
832 * |<----------matched node---------->|
833 * |<---free request--->|
834 *
835 * Remove instance from AllocatedTo list then add it back in for side nodes for
836 * proper accounting of allocations in validInstance list
837 */
838 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
839 allocatorResNodeOwnerDelete(matchingNode, opInfo->serviceSrcInstNode);
841 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
842 allocatorResNodeOwnerCopy(leftNode, matchingNode);
843 allocatorResNodeOwnerAdd(leftNode, opInfo->serviceSrcInstNode);
844 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
846 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
847 allocatorResNodeOwnerCopy(rightNode, matchingNode);
848 allocatorResNodeOwnerAdd(rightNode, opInfo->serviceSrcInstNode);
849 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
851 matchingNode->base = findNode.base;
852 matchingNode->length = findNode.length;
853 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
854 }
855 else {
856 if (findNode.base == matchingNode->base) {
857 /* Case 3: Free range is on left boundary of matched node. Try to
858 * combine free range with left node.
859 *
860 * |<---left node (free)--->||<----------matched node---------->|
861 * |<---findNode (free req)--->|
862 */
864 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
865 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
866 /* Remove freeing instance from owner list for compare with leftNode */
867 allocatorResNodeOwnerDelete(matchingNode, opInfo->serviceSrcInstNode);
869 if (leftNode && allocatorResNodeOwnerCompare(leftNode, matchingNode)) {
870 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
871 /* Combine leftNode and findNode */
872 leftNode->length += findNode.length;
873 }
874 else {
875 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
876 allocatorResNodeOwnerCopy(leftNode, matchingNode);
877 }
879 /* Remove leftNode range from matchingNode */
880 matchingNode->base = findNode.base + findNode.length;
881 matchingNode->length = matchingEnd - findEnd;
882 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
883 }
884 else if (findEnd == matchingEnd) {
885 /* Case 4: Free range is on right boundary of matched node. Try to
886 * combine free range with right node.
887 *
888 * |<----------matched node---------->||<---right node (free)--->|
889 * |<---findNode (free req)--->|
890 */
892 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
893 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
894 /* Remove freeing instance from owner list for compare with rightNode */
895 allocatorResNodeOwnerDelete(matchingNode, opInfo->serviceSrcInstNode);
897 if (rightNode && allocatorResNodeOwnerCompare(rightNode, matchingNode)) {
898 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
899 /* Combine rightNode and findNode */
900 rightNode->base = findNode.base;
901 rightNode->length += findNode.length;
902 }
903 else {
904 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
905 allocatorResNodeOwnerCopy(rightNode, matchingNode);
906 }
908 /* Remove rightNode range from matchingNode */
909 matchingNode->length -= findNode.length;
910 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
911 }
913 /* Add freeing instance back into matchingNode allocations */
914 allocatorResNodeOwnerAdd(matchingNode, opInfo->serviceSrcInstNode);
915 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
916 }
918 retVal = RM_SERVICE_APPROVED;
919 }
920 else {
921 retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
922 }
923 }
924 else {
925 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
926 }
927 }
928 else {
929 retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
930 }
931 }
932 else {
933 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
934 }
935 return(retVal);
936 }
938 /* FUNCTION PURPOSE: Reserves a Linux resource
939 ***********************************************************************
940 * DESCRIPTION: Reserves resources for Linux using the base and length
941 * values retrieved from the Linux DTB via the
942 * "linux-dtb-alias" properties within the GRL.
943 */
944 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias,
945 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
946 {
947 int32_t retVal = RM_OK;
948 bool baseFound = false;
949 bool lengthFound = false;
950 uint32_t valueIndex = 0;
952 while ((linuxValues) && (!baseFound || !lengthFound)) {
953 if (linuxAlias->baseOffset == valueIndex) {
954 opInfo->resourceInfo->base = linuxValues->value;
955 baseFound = true;
957 if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
958 opInfo->resourceInfo->length = 1;
959 lengthFound = true;
960 }
961 }
962 else if (linuxAlias->lengthOffset == valueIndex) {
963 opInfo->resourceInfo->length = linuxValues->value;
964 lengthFound = true;
965 }
967 linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
968 valueIndex++;
969 }
971 if (!baseFound || !lengthFound) {
972 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
973 }
974 else {
975 /* Allocate resource to Linux */
976 retVal = rmAllocatorOperation(rmHandle, opInfo);
977 if (retVal == RM_SERVICE_APPROVED) {
978 retVal = RM_OK;
979 }
980 }
981 return (retVal);
982 }
984 /* FUNCTION PURPOSE: Finds and reserves Linux resources
985 ***********************************************************************
986 * DESCRIPTION: Parses the Linux DTB for resources consumed by the
987 * Linux kernel. If the resource is found via the
988 * "linux-dtb-alias" property defined in the GRL it is
989 * reserved.
990 */
991 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb,
992 Rm_LinuxAlias *linuxAlias)
993 {
994 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
995 Rm_AllocatorOpInfo opInfo;
996 Rm_ResourceInfo resourceInfo;
997 uint32_t pathOffset;
998 uint32_t pathSize;
999 char *spacePtr;
1000 int32_t propOffset;
1001 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1002 int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1003 int32_t depth;
1004 int32_t propertyLen;
1005 const char *propertyName;
1006 const void *propertyData;
1007 Rm_LinuxValueRange *linuxValueRange;
1008 int32_t retVal = RM_OK;
1010 memset((void *) &opInfo, 0, sizeof(Rm_AllocatorOpInfo));
1011 memset((void *) &resourceInfo, 0, sizeof(Rm_ResourceInfo));
1013 strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1014 opInfo.policy = rmInst->u.server.globalPolicy;
1015 opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmInst->u.server.globalValidInstTree);
1016 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1017 opInfo.resourceInfo = &resourceInfo;
1019 while(linuxAlias) {
1020 /* Reset parsing variables */
1021 pathOffset = 0;
1022 pathSize = strlen(linuxAlias->path) + 1;
1023 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1024 prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1025 resourceInfo.base = 0;
1026 resourceInfo.length = 0;
1028 spacePtr = strpbrk(linuxAlias->path, " ");
1029 if (spacePtr) {
1030 *spacePtr = '\0';
1031 }
1033 while(pathOffset < pathSize) {
1034 /* Move through DTB nodes until next alias path node found */
1035 if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1036 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1038 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1039 /* Returning from subnode that matched part of alias path without finding
1040 * resource values */
1041 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1042 break;
1043 }
1044 }
1045 else {
1046 /* Found next alias path node. Move to next node name in path string. */
1047 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1048 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1049 if (spacePtr) {
1050 *spacePtr = '\0';
1051 }
1053 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1054 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1055 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1056 (pathOffset < pathSize)) {
1057 propertyData = fdt_getprop_by_offset(linuxDtb, propOffset,
1058 &propertyName, &propertyLen);
1060 if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1061 /* Found resource at end of alias path */
1062 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1063 linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1064 retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias,
1065 linuxValueRange, &opInfo);
1066 rmDtbUtilLinuxFreeValues(linuxValueRange);
1067 }
1068 propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1069 }
1071 if (propOffset < -FDT_ERR_NOTFOUND) {
1072 retVal = propOffset;
1073 break;
1074 }
1075 }
1076 }
1078 if (retVal < RM_OK) {
1079 break;
1080 }
1081 linuxAlias = linuxAlias->nextLinuxAlias;
1082 }
1083 return (retVal);
1084 }
1086 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1087 ***********************************************************************
1088 * DESCRIPTION: Creates a resource allocator for the provided
1089 * resource name and resource properties retrieved
1090 * from the GRL. Resources will be reserved for
1091 * the Linux kernel if the Linux DTB is provided
1092 * and there are "linux-dtb-alias" properties
1093 * specified in the GRL.
1094 */
1095 static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName,
1096 Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1097 {
1098 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1099 Rm_ResourceRange *range = NULL;
1100 Rm_ResourceRange *rangeBasePtr = NULL;
1101 Rm_NsAssignment *nsAssignments = NULL;
1102 Rm_NsAssignment *nsAssignmentBasePtr = NULL;
1103 Rm_LinuxAlias *linuxAlias = NULL;
1104 Rm_NameServerObjCfg nameServerObjCfg;
1105 int32_t retVal = RM_OK;
1107 if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1108 range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData,
1109 resourceProperties->rangeLen);
1111 if ((retVal = allocatorCreate(rmHandle, resourceName, range)) >= RM_OK) {
1112 if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1113 if (linuxDtb) {
1114 linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1115 resourceProperties->linuxAliasLen, &retVal);
1116 if (linuxAlias) {
1117 retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias);
1118 }
1119 }
1120 else {
1121 retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB;
1122 }
1123 }
1124 }
1125 }
1127 if (retVal >= RM_OK) {
1128 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1129 nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData,
1130 resourceProperties->nsAssignLen, &retVal);
1131 if (nsAssignments) {
1132 nsAssignmentBasePtr = nsAssignments;
1133 while (nsAssignments) {
1134 memset((void *)&nameServerObjCfg, 0, sizeof(Rm_NameServerObjCfg));
1135 nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
1136 nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1137 nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1138 nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1139 nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;
1140 rmNameServerAddObject(&nameServerObjCfg);
1141 nsAssignments = nsAssignments->nextNsAssignment;
1142 }
1143 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1144 }
1145 }
1146 }
1148 rmDtbUtilResFreeRange(rangeBasePtr);
1149 if (linuxAlias) {
1150 rmDtbUtilResFreeLinuxAlias(linuxAlias);
1151 }
1152 return(retVal);
1153 }
1155 /**********************************************************************
1156 ********************** Internal Functions ****************************
1157 **********************************************************************/
1159 /* FUNCTION PURPOSE: Finds an allocator
1160 ***********************************************************************
1161 * DESCRIPTION: Returns a pointer to an allocator that matches the
1162 * provided resource name.
1163 */
1164 Rm_Allocator *rmAllocatorFind(Rm_Allocator *allocatorList, char *resourceName)
1165 {
1166 while (allocatorList) {
1167 if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1168 break;
1169 }
1170 allocatorList = allocatorList->nextAllocator;
1171 }
1173 return (allocatorList);
1174 }
1176 /* FUNCTION PURPOSE: Issues an allocator operation
1177 ***********************************************************************
1178 * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1179 * for an RM resource.
1180 */
1181 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1182 {
1183 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1184 Rm_Allocator *allocator = NULL;
1185 int32_t resourceOffsetInPolicy;
1186 int32_t retVal;
1188 resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name);
1189 allocator = rmAllocatorFind(rmInst->u.server.allocators, opInfo->resourceInfo->name);
1191 if ((resourceOffsetInPolicy > 0) && allocator) {
1192 if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1193 retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1194 }
1195 else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1196 retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1197 }
1198 else if (opInfo->operation == Rm_allocatorOp_FREE) {
1199 retVal = allocatorFree(allocator, opInfo);
1200 }
1201 }
1202 else {
1203 /* Resource could not be found in policy and/or allocator */
1204 retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1205 }
1206 return(retVal);
1207 }
1209 /* FUNCTION PURPOSE: Initializes server allocators
1210 ***********************************************************************
1211 * DESCRIPTION: Creates and initializes a server instance's
1212 * resource allocators using the GRL and, if
1213 * provided, Linux DTB.
1214 */
1215 int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb)
1216 {
1217 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1218 int32_t nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1219 Rm_ResourceProperties resProperties;
1220 int32_t propOffset;
1221 int32_t propertyLen;
1222 const char *propertyName;
1223 const void *propertyData;
1224 Rm_ResourcePropType propertyType;
1225 int32_t retVal = RM_OK;
1227 /* Parse the Global Resource List, creating an allocator for each specified resource node */
1228 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1229 memset((void *)&resProperties, 0, sizeof(Rm_ResourceProperties));
1230 /* Get properties of resource node */
1231 propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1232 while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1233 propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen);
1234 propertyType = rmDtbUtilResGetPropertyType(propertyName);
1235 if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1236 resProperties.rangeData = propertyData;
1237 resProperties.rangeLen = propertyLen;
1238 }
1239 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1240 resProperties.nsAssignData = propertyData;
1241 resProperties.nsAssignLen = propertyLen;
1242 }
1243 else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1244 resProperties.linuxAliasData = propertyData;
1245 resProperties.linuxAliasLen = propertyLen;
1246 }
1247 else {
1248 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1249 goto exitAllocInit;
1250 }
1252 propOffset = fdt_next_property_offset(globalResourceDtb, propOffset);
1253 if (propOffset == -FDT_ERR_NOTFOUND) {
1254 /* No more resource properties but at least one found. Extract the property values */
1255 retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL),
1256 &resProperties, linuxDtb);
1257 if (retVal < RM_OK) {
1258 goto exitAllocInit;
1259 }
1260 }
1261 else if (propOffset < -FDT_ERR_NOTFOUND) {
1262 /* Error returned by LIBFDT */
1263 retVal = propOffset;
1264 goto exitAllocInit;
1265 }
1266 }
1267 if (propOffset < -FDT_ERR_NOTFOUND) {
1268 /* Error returned by LIBFDT */
1269 retVal = propOffset;
1270 goto exitAllocInit;
1271 }
1273 nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth);
1274 if (nodeOffset < -FDT_ERR_NOTFOUND) {
1275 /* Error returned by LIBFDT */
1276 retVal = nodeOffset;
1277 goto exitAllocInit;
1278 }
1279 }
1280 exitAllocInit:
1281 return(retVal);
1282 }
1284 /* FUNCTION PURPOSE: Deletes server allocators
1285 ***********************************************************************
1286 * DESCRIPTION: Removes all resource nodes for each
1287 * resource allocator and then deletes the allocator
1288 * itself. Used to free all memory consumed
1289 * by the allocators.
1290 */
1291 void rmAllocatorDeleteResources(Rm_Allocator *allocatorList)
1292 {
1293 Rm_Allocator *nextAllocator;
1294 Rm_ResourceTree *resTree;
1295 Rm_ResourceNode *resNode;
1296 Rm_ResourceNode *nextResNode;
1298 while (allocatorList) {
1299 nextAllocator = allocatorList->nextAllocator;
1300 resTree = allocatorList->allocatorRootEntry;
1302 /* Delete each resource node in the allocator */
1303 for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) {
1304 nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode);
1305 RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1306 if (resNode->allocationCount) {
1307 /* Delete all the owners in the resource's owner list */
1308 allocatorResNodeOwnerClear(resNode);
1309 }
1310 rmResourceNodeFree(resNode);
1311 }
1312 if (RB_MIN(_Rm_AllocatorResourceTree, resTree) == NULL) {
1313 /* No more resource nodes in allocator */
1314 Rm_osalFree((void *)resTree, sizeof(Rm_ResourceTree));
1315 }
1316 Rm_osalFree((void *)allocatorList, sizeof(Rm_Allocator));
1317 allocatorList = nextAllocator;
1318 }
1319 }