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(*allocators));
79 if (newAllocator) {
80 memset((void *)newAllocator, 0, sizeof(*newAllocator));
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 RM_SS_OBJ_WB(allocators, Rm_Allocator);
92 }
93 else {
94 rmInst->u.server.allocators = newAllocator;
95 }
96 }
97 return (newAllocator);
98 }
100 /* FUNCTION PURPOSE: Creates a new resource tree
101 ***********************************************************************
102 * DESCRIPTION: Creates and populates a new resource tree allocator
103 * using the provided resource name and value range. The
104 * name and value originate from the GRL.
105 */
106 static int32_t allocatorCreate(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceRange *range)
107 {
108 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
109 Rm_Allocator *allocator = NULL;
110 Rm_ResourceTree *treeRoot = NULL;
111 Rm_ResourceNode *treeNode = NULL;
113 allocator = allocatorAdd(rmHandle, resourceName);
114 treeRoot = Rm_osalMalloc(sizeof(*treeRoot));
115 RB_INIT(treeRoot);
117 while (range != NULL) {
118 treeNode = rmResourceNodeNew(range->base, range->length);
119 RB_INSERT(_Rm_AllocatorResourceTree, treeRoot, treeNode);
120 range = range->nextRange;
121 }
122 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
123 rmResourceTreeWb(treeRoot);
124 }
126 allocator->allocatorRootEntry = treeRoot;
127 RM_SS_OBJ_WB(allocator, Rm_Allocator);
128 return(RM_OK);
129 }
131 /* FUNCTION PURPOSE: Deletes a resource allocator
132 ***********************************************************************
133 * DESCRIPTION: Deletes a resource allocator based on the given
134 * resource name. The resource allocator will be
135 * removed from the RM instance allocator list.
136 */
137 static int32_t allocatorDelete(Rm_Handle rmHandle, const char *resourceName)
138 {
139 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
140 Rm_Allocator *allocator = rmInst->u.server.allocators;
141 Rm_Allocator *prevAllocator = NULL;
142 Rm_ResourceTree *treeRoot;
143 Rm_ResourceNode *node = NULL;
144 Rm_ResourceNode *nextNode = NULL;
145 int32_t retVal = RM_OK;
147 while (allocator) {
148 if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
149 break;
150 }
151 prevAllocator = allocator;
152 allocator = allocator->nextAllocator;
153 }
155 if (allocator) {
156 if (prevAllocator == NULL) {
157 rmInst->u.server.allocators = allocator->nextAllocator;
158 }
159 else {
160 prevAllocator->nextAllocator = allocator->nextAllocator;
161 RM_SS_OBJ_WB(prevAllocator, Rm_Allocator);
162 }
164 /* Destroy tree and return error */
165 treeRoot = allocator->allocatorRootEntry;
166 for (node = RB_MIN(_Rm_AllocatorResourceTree, treeRoot); node != NULL; node = nextNode) {
167 nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRoot, node);
168 RB_REMOVE(_Rm_AllocatorResourceTree, treeRoot, nextNode);
169 rmResourceNodeFree(node);
170 }
171 Rm_osalFree((void *)treeRoot, sizeof(*treeRoot));
172 Rm_osalFree((void *)allocator, sizeof(*allocator));
173 }
174 else {
175 retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
176 }
177 return (retVal);
178 }
180 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
181 ***********************************************************************
182 * DESCRIPTION: Adds a RM instance node to a resource node's
183 * list of owners.
184 */
185 static void allocatorResNodeOwnerAdd(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
186 {
187 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
188 Rm_Owner *ownerList = node->ownerList;
189 Rm_Owner *newOwner = NULL;
191 newOwner = Rm_osalMalloc(sizeof(*newOwner));
193 if (newOwner) {
194 newOwner->instNameNode = serviceInstNode;
195 newOwner->nextOwner = NULL;
197 /* Add owner entry to end of list */
198 if (ownerList) {
199 RM_SS_OBJ_INV(ownerList, Rm_Owner);
200 while (ownerList->nextOwner) {
201 ownerList = ownerList->nextOwner;
202 RM_SS_OBJ_INV(ownerList, Rm_Owner);
203 }
204 ownerList->nextOwner = newOwner;
205 RM_SS_OBJ_WB(ownerList, Rm_Owner);
206 }
207 else {
208 node->ownerList = newOwner;
209 }
211 node->allocationCount++;
212 newOwner->instNameNode->allocRefCount++;
213 RM_SS_OBJ_WB(newOwner, Rm_Owner);
214 RM_SS_OBJ_WB(newOwner->instNameNode, Rm_PolicyValidInstNode);
215 }
216 }
218 /* FUNCTION PURPOSE: Compares two resource node's owners
219 ***********************************************************************
220 * DESCRIPTION: Returns TRUE if the owners of two resource nodes
221 * are equivalent. Otherwise, returns FALSE.
222 */
223 static int allocatorResNodeOwnerCompare(Rm_Handle rmHandle, Rm_ResourceNode *node1, Rm_ResourceNode *node2)
224 {
225 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
226 Rm_Owner *node1Owners = node1->ownerList;
227 Rm_Owner *node2Owners = node2->ownerList;
228 int matchedInst;
230 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
231 while(node2Owners) {
232 Rm_osalBeginMemAccess((void *)node2Owners, sizeof(*node2Owners));
233 node2Owners = node2Owners->nextOwner;
234 }
235 node2Owners = node2->ownerList;
236 }
238 if (node1->allocationCount == node2->allocationCount) {
239 while (node1Owners) {
240 RM_SS_OBJ_INV(node1Owners, Rm_Owner);
241 matchedInst = RM_FALSE;
242 while (node2Owners) {
243 if (node1Owners->instNameNode == node2Owners->instNameNode) {
244 matchedInst = RM_TRUE;
245 break;
246 }
247 node2Owners = node2Owners->nextOwner;
248 }
250 if (matchedInst) {
251 node2Owners = node2->ownerList;
252 node1Owners = node1Owners->nextOwner;
253 }
254 else {
255 return(RM_FALSE);
256 }
257 }
258 }
259 else {
260 return(RM_FALSE);
261 }
263 return(RM_TRUE);
264 }
266 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
267 ***********************************************************************
268 * DESCRIPTION: Removes a RM instance node from a resource node's
269 * list of owners.
270 */
271 static void allocatorResNodeOwnerDelete(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
272 {
273 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
274 Rm_Owner *owner = node->ownerList;
275 Rm_Owner *prevOwner = NULL;
277 while (owner) {
278 RM_SS_OBJ_INV(owner, Rm_Owner);
279 if (owner->instNameNode == serviceInstNode) {
280 break;
281 }
282 prevOwner = owner;
283 owner = owner->nextOwner;
284 }
286 if (prevOwner == NULL) {
287 node->ownerList = owner->nextOwner;
288 }
289 else {
290 prevOwner->nextOwner = owner->nextOwner;
291 RM_SS_OBJ_WB(prevOwner, Rm_Owner);
292 }
294 node->allocationCount--;
295 owner->instNameNode->allocRefCount--;
296 RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
297 Rm_osalFree((void *)owner, sizeof(*owner));
298 }
300 /* FUNCTION PURPOSE: Copies the owners of a resource node
301 ***********************************************************************
302 * DESCRIPTION: Creates a list of resource owners for the destination
303 * resource node that is equivalent to the the
304 * source resource node's owners
305 */
306 static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle, Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
307 {
308 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
309 Rm_Owner *srcOwnerList = srcNode->ownerList;
310 Rm_Owner *dstNewOwner;
311 Rm_Owner *dstPrevOwner;
313 dstNode->allocationCount = srcNode->allocationCount;
315 while (srcOwnerList) {
316 RM_SS_OBJ_INV(srcOwnerList, Rm_Owner);
317 dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner));
318 dstNewOwner->instNameNode = srcOwnerList->instNameNode;
319 dstNewOwner->nextOwner = NULL;
320 RM_SS_OBJ_WB(dstNewOwner, Rm_Owner);
322 if (dstNode->ownerList == NULL) {
323 dstNode->ownerList = dstNewOwner;
324 }
325 else {
326 dstPrevOwner->nextOwner = dstNewOwner;
327 RM_SS_OBJ_WB(dstPrevOwner, Rm_Owner);
328 }
329 dstPrevOwner = dstNewOwner;
330 srcOwnerList = srcOwnerList->nextOwner;
331 }
332 }
334 /* FUNCTION PURPOSE: Clears a resource node's owners
335 ***********************************************************************
336 * DESCRIPTION: Deletes all owners from the owners list of a
337 * resource node.
338 */
339 static void allocatorResNodeOwnerClear(Rm_Handle rmHandle, Rm_ResourceNode *node)
340 {
341 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
342 Rm_Owner *owner = node->ownerList;
343 Rm_Owner *nextOwner;
345 while (owner) {
346 RM_SS_OBJ_INV(owner, Rm_Owner);
347 nextOwner = owner->nextOwner;
348 node->allocationCount--;
349 owner->instNameNode->allocRefCount--;
350 RM_SS_OBJ_WB(owner->instNameNode, Rm_PolicyValidInstNode);
351 Rm_osalFree((void *)owner, sizeof(*owner));
352 owner = nextOwner;
353 }
354 }
356 /* FUNCTION PURPOSE: Checks a resource node's ownership
357 ***********************************************************************
358 * DESCRIPTION: Returns TRUE if the provided instance node is
359 * in the list of resource node owners. Otherwise,
360 * returns FALSE.
361 */
362 static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
363 {
364 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
365 Rm_Owner *owner = node->ownerList;
367 while (owner) {
368 RM_SS_OBJ_INV(owner, Rm_Owner);
369 if (owner->instNameNode == serviceInstNode) {
370 return(RM_TRUE);
371 }
372 owner = owner->nextOwner;
373 }
374 return(RM_FALSE);
375 }
377 /* FUNCTION PURPOSE: Preallocates an allocator resource
378 ***********************************************************************
379 * DESCRIPTION: Called when an allocate request is made but the base
380 * is unspecified. The preallocation algorithm looks at
381 * available resources as well as policy permissions to
382 * determine a resource range that satisfies the request.
383 * If a valid range is found it will be returned for the
384 * treeAllocate algorithm to handle.
385 */
386 static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
387 Rm_AllocatorOpInfo *opInfo)
388 {
389 Rm_ResourceNode findNode;
390 Rm_ResourceNode *matchingNode = NULL;
391 uint32_t matchingEnd;
392 uint32_t rangeIndex;
393 int resourceFound = RM_FALSE;
394 Rm_PolicyCheckType policyCheckType;
395 Rm_PolicyCheckCfg policyCheckCfg;
396 int nodePassesPolicy;
397 int32_t retVal = RM_SERVICE_PROCESSING;
399 opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode,
400 resourcePolicy, opInfo->allocType,
401 &retVal);
402 if (retVal != RM_SERVICE_PROCESSING) {
403 return (retVal);
404 }
406 if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {
407 /* Get alignment from policy */
408 opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy);
409 }
411 if (opInfo->resourceInfo->alignment == 0) {
412 opInfo->resourceInfo->alignment = 1;
413 }
415 memset((void *)&findNode, 0, sizeof(findNode));
416 findNode.base = opInfo->resourceInfo->base;
417 findNode.length = opInfo->resourceInfo->length;
419 /* Configure policy checking structure */
420 memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
421 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
422 policyCheckType = Rm_policyCheck_INIT;
423 }
424 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
425 policyCheckType = Rm_policyCheck_USE;
426 }
427 policyCheckCfg.policyDtb = opInfo->policy;
428 policyCheckCfg.resourceOffset = resourcePolicy;
430 do {
431 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
433 if (matchingNode) {
434 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
435 /* Attempt to preallocate from node only if not owned by instance requesting the allocation */
436 nodePassesPolicy = RM_FALSE;
437 policyCheckCfg.type = policyCheckType;
438 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
439 policyCheckCfg.resourceBase = findNode.base;
440 policyCheckCfg.resourceLength = findNode.length;
441 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
443 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
444 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
446 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
447 /* Check if instance requesting resource has privileges to share
448 * a resource already reserved by Linux */
449 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
450 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
451 }
453 if (nodePassesPolicy) {
454 /* Check exclusive privileges of instance requesting resource. Requesting
455 * instance with exclusive privileges can't reserve resource if already owned*/
456 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
457 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
458 }
459 }
461 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
462 /* Check exclusive privileges of instance that currently owns resource */
463 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
464 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
465 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
466 }
468 if (retVal != RM_SERVICE_PROCESSING) {
469 break;
470 }
472 if (nodePassesPolicy) {
473 matchingEnd = matchingNode->base + matchingNode->length - 1;
474 /* Initialize indexer to be first resource value that alignment */
475 rangeIndex = findNode.base;
476 if (rangeIndex % opInfo->resourceInfo->alignment) {
477 rangeIndex += (opInfo->resourceInfo->alignment -
478 (rangeIndex % opInfo->resourceInfo->alignment));
479 }
481 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
482 /* Block of unallocated resources within matchingNode that satisfies
483 * allocate requirements */
484 opInfo->resourceInfo->base = rangeIndex;
485 resourceFound = RM_TRUE;
486 }
487 }
488 }
490 if (!resourceFound) {
491 /* Check next resource node for available resources */
492 findNode.base = matchingNode->base + matchingNode->length;
493 }
494 }
495 else {
496 retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
497 }
498 } while ((!resourceFound) &&
499 (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
501 return(retVal);
502 }
504 /* FUNCTION PURPOSE: Allocates an allocator resource
505 ***********************************************************************
506 * DESCRIPTION: Will attempt to allocate the resource with specified
507 * base and length from the resource's allocator. The
508 * allocation algorithm will verify the allocation against
509 * the policy permissions for the instance requesting the
510 * allocation. If the policy allows the allocation the
511 * algorithm will allocate the resource then combine any
512 * resource nodes that may have become equivalent (in terms
513 * of ownership) after the allocation.
514 */
515 static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
516 Rm_AllocatorOpInfo *opInfo)
517 {
518 Rm_ResourceNode findNode;
519 Rm_ResourceNode *matchingNode = NULL;
520 Rm_ResourceNode *leftNode = NULL;
521 Rm_ResourceNode *rightNode = NULL;
522 Rm_PolicyCheckType policyCheckType;
523 Rm_PolicyCheckCfg policyCheckCfg;
524 int allocPassesPolicy;
525 int combineLeft = RM_FALSE;
526 int combineRight = RM_FALSE;
527 uint32_t findEnd;
528 uint32_t matchingEnd;
529 int32_t retVal = RM_SERVICE_PROCESSING;
531 memset((void *)&findNode, 0, sizeof(findNode));
532 findNode.base = opInfo->resourceInfo->base;
533 findNode.length = opInfo->resourceInfo->length;
534 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
536 /* Prepare privilege checks */
537 memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
538 if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_INIT_SHIFT)) {
539 policyCheckType = Rm_policyCheck_INIT;
540 }
541 else if (RM_policy_GET_PERM(opInfo->allocType, RM_POLICY_PERM_USE_SHIFT)) {
542 policyCheckType = Rm_policyCheck_USE;
543 }
545 if (matchingNode) {
546 findEnd = findNode.base + findNode.length - 1;
547 matchingEnd = matchingNode->base + matchingNode->length - 1;
549 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
550 if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmHandle)) {
551 /* Bypass policy checks since Linux Kernel has full privileges */
552 allocPassesPolicy = RM_TRUE;
553 }
554 else {
555 policyCheckCfg.policyDtb = opInfo->policy;
556 policyCheckCfg.resourceOffset = resourcePolicy;
557 policyCheckCfg.type = policyCheckType;
558 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
559 policyCheckCfg.resourceBase = findNode.base;
560 policyCheckCfg.resourceLength = findNode.length;
561 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
562 if (!allocPassesPolicy) {
563 if (policyCheckType == Rm_policyCheck_INIT) {
564 retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
565 }
566 else {
567 retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
568 }
569 }
571 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
572 if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
573 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
574 /* Check if instance requesting resource has privileges to share
575 * a resource already reserved by Linux */
576 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
577 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
578 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
579 if (!allocPassesPolicy) {
580 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
581 }
582 }
583 if (allocPassesPolicy) {
584 /* Check exclusive privileges of instance requesting resource. Requesting
585 * instance with exclusive privileges can't reserve resource if already owned*/
586 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
587 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
588 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
589 if (!allocPassesPolicy) {
590 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
591 }
592 }
593 }
594 if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
595 /* Check exclusive privileges of instance that currently owns resource */
596 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
597 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
598 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
599 if (!allocPassesPolicy) {
600 retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
601 }
602 }
603 }
604 }
606 if (allocPassesPolicy) {
607 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
608 /* Handle any possible node combinations if requesting instance is
609 * not already in resource's owner list. Automatic approval if requesting
610 * instance is already in owner list. */
611 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
612 /* findNode range matches matchingNode range
613 *
614 * |<--left node-->||<--matched node-->||<--right node-->| => existing node
615 * |<--alloc request-->| => requested resources
616 */
617 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
618 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
619 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
620 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
622 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
623 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
624 combineLeft = RM_TRUE;
625 }
626 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
627 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
628 combineRight = RM_TRUE;
629 }
631 if (combineLeft && combineRight) {
632 /* Combine all three nodes into matchingNode */
633 matchingNode->base = leftNode->base;
634 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
636 allocatorResNodeOwnerClear(rmHandle, leftNode);
637 rmResourceNodeFree(leftNode);
638 allocatorResNodeOwnerClear(rmHandle, rightNode);
639 rmResourceNodeFree(rightNode);
640 }
641 else if (combineLeft) {
642 /* Combine left and matching nodes. Reinsert right. */
643 matchingNode->base = leftNode->base;
644 matchingNode->length += leftNode->length;
646 allocatorResNodeOwnerClear(rmHandle, leftNode);
647 rmResourceNodeFree(leftNode);
648 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
649 }
650 else if (combineRight) {
651 /* Combine right and matching nodes. Reinsert left. */
652 matchingNode->length += rightNode->length;
654 allocatorResNodeOwnerClear(rmHandle, rightNode);
655 rmResourceNodeFree(rightNode);
656 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
657 }
658 else {
659 /* No combine. */
660 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
661 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
662 }
664 /* Always reinsert matchingNode */
665 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
667 /* Matching node contains new reference count after alloc. Return new owner count. */
668 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
669 }
670 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
671 /* findNode range is subset of matchingNode range and neither boundary is
672 * equivalent.
673 *
674 * |<----------matched node---------->|
675 * |<---alloc request--->|
676 */
677 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
678 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
679 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
680 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
681 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
683 matchingNode->base = findNode.base;
684 matchingNode->length = findNode.length;
685 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
687 /* Insert all the nodes */
688 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
689 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
690 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
692 /* Matching node contains new reference count after alloc. Return new owner count. */
693 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
694 }
695 else {
696 if (findNode.base == matchingNode->base) {
697 /* findNode base and matchingNode base are equivalent. May be combine
698 * possibilities to the left
699 *
700 * |<---left node (alloc'd)--->||<----------matched node---------->|
701 * |<---findNode (alloc req)--->|
702 */
703 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
704 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
705 /* Add allocating instance to owner list for compare with leftNode */
706 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
708 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
709 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
710 /* Combine leftNode and findNode */
711 leftNode->length += findNode.length;
712 }
713 else {
714 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
715 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
716 }
718 /* Account for leftNode in matchingNode */
719 matchingNode->base = findNode.base + findNode.length;
720 matchingNode->length = matchingEnd - findEnd;
722 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
723 /* Left node contains new reference count after alloc. Return new owner count. */
724 opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
725 }
726 else if (findEnd == matchingEnd) {
727 /* findNode end and matchingNode end are equivalent. May be combine
728 * possibilities to the right
729 *
730 * |<----------matched node---------->||<---right node (alloc'd)--->|
731 * |<---findNode (alloc req)--->|
732 */
733 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
734 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
735 /* Add allocating instance to owner list for compare with rightNode */
736 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
738 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
739 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
740 /* Combine rightNode and findNode */
741 rightNode->base = findNode.base;
742 rightNode->length += findNode.length;
743 }
744 else {
745 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
746 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
747 }
749 /* Account for rightNode in matchingNode */
750 matchingNode->length -= findNode.length;
752 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
753 /* Right node contains new reference count after alloc. Return new owner count. */
754 opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
755 }
756 /* Remove allocating instance from leftover matchingNode */
757 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
758 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
759 }
760 }
761 retVal = RM_SERVICE_APPROVED;
762 }
763 }
764 else {
765 retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
766 }
767 }
768 else {
769 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
770 }
772 return(retVal);
773 }
775 /* FUNCTION PURPOSE: Frees an allocator resource
776 ***********************************************************************
777 * DESCRIPTION: Will attempt to free the resource with specified
778 * base and length from the resource's allocator. The
779 * free algorithm will verify the free request parameters
780 * match an allocated range for the resource and that the
781 * range is owned by the instance requesting the free. If
782 * the free is validated the algorithm will free the
783 * resource then combine any resource nodes that may have
784 * become equivalent (in terms of ownership) after the
785 * allocation.
786 */
787 static int32_t allocatorFree(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
788 {
789 Rm_ResourceNode findNode;
790 Rm_ResourceNode *matchingNode = NULL;
791 Rm_ResourceNode *leftNode = NULL;
792 Rm_ResourceNode *rightNode = NULL;
793 int combineLeft = RM_FALSE;
794 int combineRight = RM_FALSE;
795 uint32_t findEnd;
796 uint32_t matchingEnd;
797 int32_t retVal;
799 memset((void *)&findNode, 0, sizeof(findNode));
800 findNode.base = opInfo->resourceInfo->base;
801 findNode.length = opInfo->resourceInfo->length;
802 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
804 if (matchingNode) {
805 findEnd = findNode.base + findNode.length - 1;
806 matchingEnd = matchingNode->base + matchingNode->length - 1;
808 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
809 if (matchingNode->allocationCount) {
810 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
811 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
812 {
813 /* Case 1: Free range equals allocated matched node exactly. Attempt to combine
814 * freed node with nodes to left and right.
815 *
816 * |<--left node-->||<---matched node--->||<--right node-->|
817 * |<---free request--->|
818 */
819 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
820 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
821 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
822 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
824 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
825 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
826 combineLeft = RM_TRUE;
827 }
828 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
829 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
830 combineRight = RM_TRUE;
831 }
833 if (combineLeft && combineRight) {
834 /* Combine all three nodes into matchingNode */
835 matchingNode->base = leftNode->base;
836 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
838 allocatorResNodeOwnerClear(rmHandle, leftNode);
839 rmResourceNodeFree(leftNode);
840 allocatorResNodeOwnerClear(rmHandle, rightNode);
841 rmResourceNodeFree(rightNode);
842 }
843 else if (combineLeft) {
844 /* Combine left and matching nodes. Reinsert right. */
845 matchingNode->base = leftNode->base;
846 matchingNode->length += leftNode->length;
848 allocatorResNodeOwnerClear(rmHandle, leftNode);
849 rmResourceNodeFree(leftNode);
850 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
851 }
852 else if (combineRight) {
853 /* Combine right and matching nodes. Reinsert left. */
854 matchingNode->length += rightNode->length;
856 allocatorResNodeOwnerClear(rmHandle, rightNode);
857 rmResourceNodeFree(rightNode);
858 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
859 }
860 else {
861 /* No combine. */
862 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
863 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
864 }
866 /* Always reinsert matchingNode */
867 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
869 /* Matching node is what remains after free. Return remaining owner count. */
870 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
871 }
872 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
873 /* Case 2: Free range is less than range in matched node. Split
874 * matched node into three nodes.
875 *
876 * |<----------matched node---------->|
877 * |<---free request--->|
878 *
879 * Remove instance from AllocatedTo list then add it back in for side nodes for
880 * proper accounting of allocations in validInstance list
881 */
882 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
883 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
885 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
886 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
887 allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceSrcInstNode);
888 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
890 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
891 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
892 allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceSrcInstNode);
893 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
895 matchingNode->base = findNode.base;
896 matchingNode->length = findNode.length;
897 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
899 /* Matching node is what remains after free. Return remaining owner count. */
900 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
901 }
902 else {
903 if (findNode.base == matchingNode->base) {
904 /* Case 3: Free range is on left boundary of matched node. Try to
905 * combine free range with left node.
906 *
907 * |<---left node (free)--->||<----------matched node---------->|
908 * |<---findNode (free req)--->|
909 */
911 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
912 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
913 /* Remove freeing instance from owner list for compare with leftNode */
914 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
916 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode)) {
917 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
918 /* Combine leftNode and findNode */
919 leftNode->length += findNode.length;
920 }
921 else {
922 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
923 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
924 }
926 /* Remove leftNode range from matchingNode */
927 matchingNode->base = findNode.base + findNode.length;
928 matchingNode->length = matchingEnd - findEnd;
929 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
931 /* Left node is what remains after free. Return remaining owner count. */
932 opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
933 }
934 else if (findEnd == matchingEnd) {
935 /* Case 4: Free range is on right boundary of matched node. Try to
936 * combine free range with right node.
937 *
938 * |<----------matched node---------->||<---right node (free)--->|
939 * |<---findNode (free req)--->|
940 */
942 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
943 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
944 /* Remove freeing instance from owner list for compare with rightNode */
945 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
947 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode)) {
948 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
949 /* Combine rightNode and findNode */
950 rightNode->base = findNode.base;
951 rightNode->length += findNode.length;
952 }
953 else {
954 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
955 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
956 }
958 /* Remove rightNode range from matchingNode */
959 matchingNode->length -= findNode.length;
960 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
962 /* Right node is what remains after free. Return remaining owner count. */
963 opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
964 }
966 /* Add freeing instance back into matchingNode allocations */
967 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
968 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
969 }
970 retVal = RM_SERVICE_APPROVED;
971 }
972 else {
973 retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
974 }
975 }
976 else {
977 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
978 }
979 }
980 else {
981 retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
982 }
983 }
984 else {
985 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
986 }
987 return(retVal);
988 }
990 /* FUNCTION PURPOSE: Reserves a Linux resource
991 ***********************************************************************
992 * DESCRIPTION: Reserves resources for Linux using the base and length
993 * values retrieved from the Linux DTB via the
994 * "linux-dtb-alias" properties within the GRL.
995 */
996 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias,
997 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
998 {
999 int32_t retVal = RM_OK;
1000 int baseFound = RM_FALSE;
1001 int lengthFound = RM_FALSE;
1002 uint32_t valueIndex = 0;
1004 while ((linuxValues) && (!baseFound || !lengthFound)) {
1005 if (linuxAlias->baseOffset == valueIndex) {
1006 opInfo->resourceInfo->base = linuxValues->value;
1007 baseFound = RM_TRUE;
1009 if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1010 opInfo->resourceInfo->length = 1;
1011 lengthFound = RM_TRUE;
1012 }
1013 }
1014 else if (linuxAlias->lengthOffset == valueIndex) {
1015 opInfo->resourceInfo->length = linuxValues->value;
1016 lengthFound = RM_TRUE;
1017 }
1019 linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1020 valueIndex++;
1021 }
1023 if (!baseFound || !lengthFound) {
1024 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1025 }
1026 else {
1027 /* Allocate resource to Linux */
1028 retVal = rmAllocatorOperation(rmHandle, opInfo);
1029 if (retVal == RM_SERVICE_APPROVED) {
1030 retVal = RM_OK;
1031 }
1032 }
1033 return (retVal);
1034 }
1036 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1037 ***********************************************************************
1038 * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1039 * Linux kernel. If the resource is found via the
1040 * "linux-dtb-alias" property defined in the GRL it is
1041 * reserved.
1042 */
1043 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb,
1044 Rm_LinuxAlias *linuxAlias)
1045 {
1046 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1047 Rm_AllocatorOpInfo opInfo;
1048 Rm_ResourceInfo resourceInfo;
1049 uint32_t pathOffset;
1050 uint32_t pathSize;
1051 char *spacePtr;
1052 int32_t propOffset;
1053 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1054 int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1055 int32_t depth;
1056 int32_t propertyLen;
1057 const char *propertyName;
1058 const void *propertyData;
1059 Rm_LinuxValueRange *linuxValueRange;
1060 int32_t retVal = RM_OK;
1062 memset((void *)&opInfo, 0, sizeof(opInfo));
1063 memset((void *)&resourceInfo, 0, sizeof(resourceInfo));
1065 strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1066 opInfo.policy = rmInst->u.server.globalPolicy;
1067 opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmHandle);
1068 opInfo.operation = Rm_allocatorOp_ALLOCATE;
1069 opInfo.resourceInfo = &resourceInfo;
1071 while(linuxAlias) {
1072 /* Reset parsing variables */
1073 pathOffset = 0;
1074 pathSize = strlen(linuxAlias->path) + 1;
1075 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1076 prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1077 resourceInfo.base = 0;
1078 resourceInfo.length = 0;
1080 spacePtr = strpbrk(linuxAlias->path, " ");
1081 if (spacePtr) {
1082 *spacePtr = '\0';
1083 }
1085 while(pathOffset < pathSize) {
1086 /* Move through DTB nodes until next alias path node found */
1087 if (strcmp(linuxAlias->path + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1088 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1090 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1091 /* Returning from subnode that matched part of alias path without finding
1092 * resource values */
1093 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1094 break;
1095 }
1096 }
1097 else {
1098 /* Found next alias path node. Move to next node name in path string. */
1099 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1100 spacePtr = strpbrk(linuxAlias->path + pathOffset, " ");
1101 if (spacePtr) {
1102 *spacePtr = '\0';
1103 }
1105 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1106 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1107 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1108 (pathOffset < pathSize)) {
1109 propertyData = fdt_getprop_by_offset(linuxDtb, propOffset,
1110 &propertyName, &propertyLen);
1112 if (strcmp(linuxAlias->path + pathOffset, propertyName) == 0) {
1113 /* Found resource at end of alias path */
1114 pathOffset += (strlen(linuxAlias->path + pathOffset) + 1);
1115 linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1116 retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias,
1117 linuxValueRange, &opInfo);
1118 rmDtbUtilLinuxFreeValues(linuxValueRange);
1119 }
1120 propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1121 }
1123 if (propOffset < -FDT_ERR_NOTFOUND) {
1124 retVal = propOffset;
1125 break;
1126 }
1127 }
1128 }
1130 if (retVal < RM_OK) {
1131 break;
1132 }
1133 linuxAlias = linuxAlias->nextLinuxAlias;
1134 }
1135 return (retVal);
1136 }
1138 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1139 ***********************************************************************
1140 * DESCRIPTION: Creates a resource allocator for the provided
1141 * resource name and resource properties retrieved
1142 * from the GRL. Resources will be reserved for
1143 * the Linux kernel if the Linux DTB is provided
1144 * and there are "linux-dtb-alias" properties
1145 * specified in the GRL.
1146 */
1147 static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName,
1148 Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1149 {
1150 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1151 Rm_ResourceRange *range = NULL;
1152 Rm_ResourceRange *rangeBasePtr = NULL;
1153 Rm_NsAssignment *nsAssignments = NULL;
1154 Rm_NsAssignment *nsAssignmentBasePtr = NULL;
1155 Rm_LinuxAlias *linuxAlias = NULL;
1156 Rm_NameServerObjCfg nameServerObjCfg;
1157 int32_t retVal = RM_OK;
1159 if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1160 range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData,
1161 resourceProperties->rangeLen);
1163 if ((retVal = allocatorCreate(rmHandle, resourceName, range)) >= RM_OK) {
1164 if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1165 if (linuxDtb) {
1166 linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1167 resourceProperties->linuxAliasLen, &retVal);
1168 if (linuxAlias) {
1169 retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias);
1170 }
1171 }
1172 else {
1173 retVal = RM_ERROR_GRL_LINUX_ALIAS_BUT_NO_DTB;
1174 }
1175 }
1176 }
1177 }
1179 if (retVal >= RM_OK) {
1180 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1181 nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData,
1182 resourceProperties->nsAssignLen, &retVal);
1183 if (nsAssignments) {
1184 nsAssignmentBasePtr = nsAssignments;
1185 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1186 rmNameServerTreeInv(rmInst->u.server.nameServer);
1187 }
1188 while (nsAssignments) {
1189 memset((void *)&nameServerObjCfg, 0, sizeof(nameServerObjCfg));
1190 nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
1191 nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1192 nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1193 nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1194 nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;
1195 rmNameServerAddObject(&nameServerObjCfg);
1196 nsAssignments = nsAssignments->nextNsAssignment;
1197 }
1198 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1199 rmNameServerTreeWb(rmInst->u.server.nameServer);
1200 }
1201 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1202 }
1203 }
1204 }
1205 else {
1206 allocatorDelete(rmHandle, resourceName);
1207 }
1209 rmDtbUtilResFreeRange(rangeBasePtr);
1210 if (linuxAlias) {
1211 rmDtbUtilResFreeLinuxAlias(linuxAlias);
1212 }
1213 return(retVal);
1214 }
1216 /**********************************************************************
1217 ********************** Internal Functions ****************************
1218 **********************************************************************/
1220 /* FUNCTION PURPOSE: Finds an allocator
1221 ***********************************************************************
1222 * DESCRIPTION: Returns a pointer to an allocator that matches the
1223 * provided resource name.
1224 */
1225 Rm_Allocator *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName)
1226 {
1227 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1228 Rm_Allocator *allocatorList = rmInst->u.server.allocators;
1230 while (allocatorList) {
1231 RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1232 if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1233 break;
1234 }
1235 allocatorList = allocatorList->nextAllocator;
1236 }
1238 return (allocatorList);
1239 }
1241 /* FUNCTION PURPOSE: Issues an allocator operation
1242 ***********************************************************************
1243 * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1244 * for an RM resource.
1245 */
1246 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1247 {
1248 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1249 Rm_Allocator *allocator = NULL;
1250 int32_t resourceOffsetInPolicy;
1251 int32_t retVal;
1253 resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name);
1254 allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name);
1256 if ((resourceOffsetInPolicy > 0) && allocator) {
1257 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1258 rmResourceTreeInv(allocator->allocatorRootEntry);
1259 }
1261 if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE) {
1262 retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1263 }
1264 else if (opInfo->operation == Rm_allocatorOp_ALLOCATE) {
1265 retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1266 }
1267 else if (opInfo->operation == Rm_allocatorOp_FREE) {
1268 retVal = allocatorFree(rmHandle, allocator, opInfo);
1269 }
1271 if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
1272 (retVal == RM_SERVICE_APPROVED)) {
1273 rmResourceTreeWb(allocator->allocatorRootEntry);
1274 }
1275 }
1276 else {
1277 /* Resource could not be found in policy and/or allocator */
1278 retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1279 }
1280 return(retVal);
1281 }
1283 /* FUNCTION PURPOSE: Initializes server allocators
1284 ***********************************************************************
1285 * DESCRIPTION: Creates and initializes a server instance's
1286 * resource allocators using the GRL and, if
1287 * provided, Linux DTB.
1288 */
1289 int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb)
1290 {
1291 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1292 int32_t nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1293 Rm_ResourceProperties resProperties;
1294 int32_t propOffset;
1295 int32_t propertyLen;
1296 const char *propertyName;
1297 const void *propertyData;
1298 Rm_ResourcePropType propertyType;
1299 int32_t retVal = RM_OK;
1301 /* Parse the Global Resource List, creating an allocator for each specified resource node */
1302 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1303 memset((void *)&resProperties, 0, sizeof(resProperties));
1304 /* Get properties of resource node */
1305 propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1306 while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1307 propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen);
1308 propertyType = rmDtbUtilResGetPropertyType(propertyName);
1309 if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1310 resProperties.rangeData = propertyData;
1311 resProperties.rangeLen = propertyLen;
1312 }
1313 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1314 resProperties.nsAssignData = propertyData;
1315 resProperties.nsAssignLen = propertyLen;
1316 }
1317 else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1318 resProperties.linuxAliasData = propertyData;
1319 resProperties.linuxAliasLen = propertyLen;
1320 }
1321 else {
1322 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1323 goto exitAllocInit;
1324 }
1326 propOffset = fdt_next_property_offset(globalResourceDtb, propOffset);
1327 if (propOffset == -FDT_ERR_NOTFOUND) {
1328 /* No more resource properties but at least one found. Extract the property values */
1329 retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL),
1330 &resProperties, linuxDtb);
1331 if (retVal < RM_OK) {
1332 goto exitAllocInit;
1333 }
1334 }
1335 else if (propOffset < -FDT_ERR_NOTFOUND) {
1336 /* Error returned by LIBFDT */
1337 retVal = propOffset;
1338 goto exitAllocInit;
1339 }
1340 }
1341 if (propOffset < -FDT_ERR_NOTFOUND) {
1342 /* Error returned by LIBFDT */
1343 retVal = propOffset;
1344 goto exitAllocInit;
1345 }
1347 nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth);
1348 if (nodeOffset < -FDT_ERR_NOTFOUND) {
1349 /* Error returned by LIBFDT */
1350 retVal = nodeOffset;
1351 goto exitAllocInit;
1352 }
1353 }
1354 exitAllocInit:
1355 return(retVal);
1356 }
1358 /* FUNCTION PURPOSE: Deletes server allocators
1359 ***********************************************************************
1360 * DESCRIPTION: Removes all resource nodes for each
1361 * resource allocator and then deletes the allocator
1362 * itself. Used to free all memory consumed
1363 * by the allocators.
1364 */
1365 void rmAllocatorDeleteResources(Rm_Handle rmHandle)
1366 {
1367 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1368 Rm_Allocator *allocatorList = rmInst->u.server.allocators;
1369 Rm_Allocator *nextAllocator;
1370 Rm_ResourceTree *resTree;
1371 Rm_ResourceNode *resNode;
1372 Rm_ResourceNode *nextResNode;
1374 while (allocatorList) {
1375 RM_SS_OBJ_INV(allocatorList, Rm_Allocator);
1376 nextAllocator = allocatorList->nextAllocator;
1377 resTree = allocatorList->allocatorRootEntry;
1379 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1380 rmResourceTreeInv(resTree);
1381 }
1382 /* Delete each resource node in the allocator */
1383 for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) {
1384 nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode);
1385 RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1386 if (resNode->allocationCount) {
1387 /* Delete all the owners in the resource's owner list */
1388 allocatorResNodeOwnerClear(rmHandle, resNode);
1389 }
1390 rmResourceNodeFree(resNode);
1391 }
1393 Rm_osalFree((void *)resTree, sizeof(*resTree));
1394 Rm_osalFree((void *)allocatorList, sizeof(*allocatorList));
1395 allocatorList = nextAllocator;
1396 }
1397 rmInst->u.server.allocators = NULL;
1398 }