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