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-2014, 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_internal.h>
47 #include <ti/drv/rm/include/rm_loc.h>
48 #include <ti/drv/rm/include/rm_allocatorloc.h>
49 #include <ti/drv/rm/include/rm_dtb_utilloc.h>
50 #include <ti/drv/rm/include/rm_policyloc.h>
51 #include <ti/drv/rm/include/rm_treeloc.h>
53 /* RM LIBFDT includes */
54 #include <ti/drv/rm/util/libfdt/libfdt.h>
56 /* Tree algorithm includes */
57 #include <ti/drv/rm/util/tree.h>
59 /* RM OSAL layer */
60 #include <rm_osal.h>
62 /**********************************************************************
63 ************************ Local Functions *****************************
64 **********************************************************************/
66 /* FUNCTION PURPOSE: Creates a resource allocator
67 ***********************************************************************
68 * DESCRIPTION: Returns a newly Created and initialized resource
69 * The allocator is also stored in the RM instance
70 * allocator list.
71 */
72 static Rm_Allocator *allocatorAdd(Rm_Handle rmHandle, const char *resourceName)
73 {
74 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
75 Rm_Allocator *allocators = rmAllocatorGetAllocatorList(rmHandle);
76 Rm_Allocator *newAllocator = NULL;
78 newAllocator = Rm_osalMalloc(sizeof(*allocators));
80 if (newAllocator) {
81 memset((void *)newAllocator, 0, sizeof(*newAllocator));
82 rm_strncpy(newAllocator->resourceName, resourceName, RM_NAME_MAX_CHARS);
83 newAllocator->allocatorRootEntry = NULL;
84 newAllocator->nextAllocator = NULL;
86 /* Add allocator to end of list */
87 if (allocators) {
88 while (allocators->nextAllocator) {
89 allocators = allocators->nextAllocator;
90 }
91 allocators->nextAllocator = newAllocator;
92 RM_SS_OBJ_WB(rmInst, allocators, Rm_Allocator);
93 }
94 else {
95 if ((rmInst->instType == Rm_instType_SERVER) ||
96 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
97 rmInst->u.server.allocators = newAllocator;
98 }
99 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
100 rmInst->u.cd.allocators = newAllocator;
101 }
102 else {
103 /* Free allocator because instance type doesn't support allocators */
104 Rm_osalFree(newAllocator, sizeof(*newAllocator));
105 newAllocator = NULL;
106 }
107 }
108 }
109 return (newAllocator);
110 }
112 /* FUNCTION PURPOSE: Checks a resource node's ownership
113 ***********************************************************************
114 * DESCRIPTION: Returns the owner reference count if the provided
115 * instance node is in the list of resource node owners. Otherwise,
116 * returns 0.
117 */
118 static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node, Rm_PolicyValidInstNode *serviceInstNode)
119 {
120 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
121 Rm_Owner *owner = node->ownerList;
123 while (owner) {
124 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
125 if (owner->instNameNode == serviceInstNode) {
126 return(owner->refCnt);
127 }
128 owner = owner->nextOwner;
129 }
130 return(0);
131 }
133 /* FUNCTION PURPOSE: Increments an owner's refCnt
134 ***********************************************************************
135 * DESCRIPTION: Increments a resource owner's reference count
136 */
137 static void allocatorResNodeOwnerRefCntInc(Rm_Handle rmHandle, Rm_ResourceNode *node, Rm_PolicyValidInstNode *serviceInstNode)
138 {
139 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
140 Rm_Owner *owner = node->ownerList;
142 while (owner) {
143 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
144 if (owner->instNameNode == serviceInstNode) {
145 owner->refCnt++;
146 RM_SS_OBJ_WB(rmInst, owner, Rm_Owner);
147 break;
148 }
149 owner = owner->nextOwner;
150 }
151 }
153 /* FUNCTION PURPOSE: Decrements an owner's refCnt
154 ***********************************************************************
155 * DESCRIPTION: Decrements a resource owner's reference count
156 */
157 static void allocatorResNodeOwnerRefCntDec(Rm_Handle rmHandle, Rm_ResourceNode *node, Rm_PolicyValidInstNode *serviceInstNode)
158 {
159 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
160 Rm_Owner *owner = node->ownerList;
162 while (owner) {
163 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
164 if (owner->instNameNode == serviceInstNode) {
165 owner->refCnt--;
166 RM_SS_OBJ_WB(rmInst, owner, Rm_Owner);
167 break;
168 }
169 owner = owner->nextOwner;
170 }
171 }
173 /* FUNCTION PURPOSE: Returns an owner's refCnt
174 ***********************************************************************
175 * DESCRIPTION: Returns a resource owner's reference count
176 */
177 static uint16_t allocatorResNodeOwnerGetRefCnt(Rm_Handle rmHandle, Rm_ResourceNode *node, Rm_PolicyValidInstNode *serviceInstNode)
178 {
179 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
180 Rm_Owner *owner = node->ownerList;
182 while (owner) {
183 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
184 if (owner->instNameNode == serviceInstNode) {
185 return (owner->refCnt);
186 }
187 owner = owner->nextOwner;
188 }
190 return(0);
191 }
193 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
194 ***********************************************************************
195 * DESCRIPTION: Adds a RM instance node to a resource node's
196 * list of owners. If the owner is already present that
197 * owner's reference count is incremented
198 */
199 static void allocatorResNodeOwnerAdd(Rm_Handle rmHandle, Rm_ResourceNode *node, Rm_PolicyValidInstNode *serviceInstNode)
200 {
201 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
202 Rm_Owner *ownerList = node->ownerList;
203 Rm_Owner *newOwner = NULL;
205 if (allocatorResNodeIsOwnedBy(rmHandle, node, serviceInstNode)) {
206 allocatorResNodeOwnerRefCntInc(rmHandle, node, serviceInstNode);
207 }
208 else {
209 newOwner = Rm_osalMalloc(sizeof(*newOwner));
211 if (newOwner) {
212 newOwner->instNameNode = serviceInstNode;
213 newOwner->refCnt = 0;
214 newOwner->nextOwner = NULL;
216 /* Add owner entry to end of list */
217 if (ownerList) {
218 RM_SS_OBJ_INV(rmInst, ownerList, Rm_Owner);
219 while (ownerList->nextOwner) {
220 ownerList = ownerList->nextOwner;
221 RM_SS_OBJ_INV(rmInst, ownerList, Rm_Owner);
222 }
223 ownerList->nextOwner = newOwner;
224 RM_SS_OBJ_WB(rmInst, ownerList, Rm_Owner);
225 }
226 else {
227 node->ownerList = newOwner;
228 }
230 node->allocationCount++;
231 newOwner->refCnt++;
232 newOwner->instNameNode->allocRefCount++;
233 RM_SS_OBJ_WB(rmInst, newOwner, Rm_Owner);
234 RM_SS_OBJ_WB(rmInst, newOwner->instNameNode, Rm_PolicyValidInstNode);
235 }
236 }
237 }
239 /* FUNCTION PURPOSE: Compares two resource node's boundaries
240 ***********************************************************************
241 * DESCRIPTION: Returns TRUE if the resource nodes are neighbors from
242 * a base+length perspective. Otherwise, returns FALSE.
243 */
244 static int allocatorResNodeBoundaryCompare(Rm_ResourceNode *node1, Rm_ResourceNode *node2)
245 {
246 uint32_t node1End;
247 uint32_t node2End;
249 if (node1 && node2) {
250 node1End = node1->base + node1->length - 1;
251 node2End = node2->base + node2->length - 1;
253 if (node1->base < node2->base) {
254 if (node1End == (node2->base - 1)) {
255 return(RM_TRUE);
256 }
257 }
258 else if (node2->base < node1->base) {
259 if (node2End == (node1->base - 1)) {
260 return(RM_TRUE);
261 }
262 }
263 }
264 return(RM_FALSE);
265 }
267 /* FUNCTION PURPOSE: Compares two resource node's owners
268 ***********************************************************************
269 * DESCRIPTION: Returns TRUE if the owners of two resource nodes
270 * are equivalent. Otherwise, returns FALSE.
271 */
272 static int allocatorResNodeOwnerCompare(Rm_Handle rmHandle, Rm_ResourceNode *node1, Rm_ResourceNode *node2)
273 {
274 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
275 Rm_Owner *node1Owners = node1->ownerList;
276 Rm_Owner *node2Owners = node2->ownerList;
277 int matchedInst;
279 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
280 while(node2Owners) {
281 Rm_osalBeginMemAccess((void *)node2Owners, sizeof(*node2Owners));
282 node2Owners = node2Owners->nextOwner;
283 }
284 node2Owners = node2->ownerList;
285 }
287 if (node1->allocationCount == node2->allocationCount) {
288 while (node1Owners) {
289 RM_SS_OBJ_INV(rmInst, node1Owners, Rm_Owner);
290 matchedInst = RM_FALSE;
291 while (node2Owners) {
292 if ((node1Owners->instNameNode == node2Owners->instNameNode) &&
293 (node1Owners->refCnt == node2Owners->refCnt)) {
294 matchedInst = RM_TRUE;
295 break;
296 }
297 node2Owners = node2Owners->nextOwner;
298 }
300 if (matchedInst) {
301 node2Owners = node2->ownerList;
302 node1Owners = node1Owners->nextOwner;
303 }
304 else {
305 return(RM_FALSE);
306 }
307 }
308 }
309 else {
310 return(RM_FALSE);
311 }
313 return(RM_TRUE);
314 }
316 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
317 ***********************************************************************
318 * DESCRIPTION: Removes a RM owner entry from a resource node's
319 * list of owners. If the refCnt for the specified
320 * owner is greater than 1 only the refCnt is
321 * decremented
322 */
323 static void allocatorResNodeOwnerDelete(Rm_Handle rmHandle, Rm_ResourceNode *node, void *serviceInstNode)
324 {
325 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
326 Rm_Owner *owner = node->ownerList;
327 Rm_Owner *prevOwner = NULL;
329 if (allocatorResNodeIsOwnedBy(rmHandle, node, serviceInstNode) > 1) {
330 allocatorResNodeOwnerRefCntDec(rmHandle, node, serviceInstNode);
331 }
332 else {
333 while (owner) {
334 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
335 if (owner->instNameNode == serviceInstNode) {
336 break;
337 }
338 prevOwner = owner;
339 owner = owner->nextOwner;
340 }
342 if (owner) {
343 if (prevOwner == NULL) {
344 node->ownerList = owner->nextOwner;
345 }
346 else {
347 prevOwner->nextOwner = owner->nextOwner;
348 RM_SS_OBJ_WB(rmInst, prevOwner, Rm_Owner);
349 }
351 node->allocationCount--;
352 owner->instNameNode->allocRefCount--;
353 RM_SS_OBJ_WB(rmInst, owner->instNameNode, Rm_PolicyValidInstNode);
354 Rm_osalFree((void *)owner, sizeof(*owner));
355 }
356 }
357 }
359 /* FUNCTION PURPOSE: Copies the owners of a resource node
360 ***********************************************************************
361 * DESCRIPTION: Creates a list of resource owners for the destination
362 * resource node that is equivalent to the source resource
363 * node's owners
364 *
365 * dstNode must be a newly created node without any owners.
366 */
367 static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle, Rm_ResourceNode *dstNode, Rm_ResourceNode *srcNode)
368 {
369 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
370 Rm_Owner *srcOwnerList = srcNode->ownerList;
371 Rm_Owner *dstNewOwner;
372 Rm_Owner *dstPrevOwner;
374 if (dstNode->ownerList != NULL) {
375 return;
376 }
377 dstNode->allocationCount = srcNode->allocationCount;
379 while (srcOwnerList) {
380 RM_SS_OBJ_INV(rmInst, srcOwnerList, Rm_Owner);
381 dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner));
382 dstNewOwner->instNameNode = srcOwnerList->instNameNode;
383 dstNewOwner->refCnt = srcOwnerList->refCnt;
384 dstNewOwner->nextOwner = NULL;
385 RM_SS_OBJ_WB(rmInst, dstNewOwner, Rm_Owner);
387 if (dstNode->ownerList == NULL) {
388 dstNode->ownerList = dstNewOwner;
389 }
390 else {
391 dstPrevOwner->nextOwner = dstNewOwner;
392 RM_SS_OBJ_WB(rmInst, dstPrevOwner, Rm_Owner);
393 }
394 dstPrevOwner = dstNewOwner;
395 srcOwnerList = srcOwnerList->nextOwner;
396 }
397 }
399 /* FUNCTION PURPOSE: Clears a resource node's owners
400 ***********************************************************************
401 * DESCRIPTION: Deletes all owners from the owners list of a
402 * resource node.
403 */
404 static void allocatorResNodeOwnerClear(Rm_Handle rmHandle, Rm_ResourceNode *node)
405 {
406 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
407 Rm_Owner *owner = node->ownerList;
408 Rm_Owner *nextOwner;
410 while (owner) {
411 RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
412 nextOwner = owner->nextOwner;
413 node->allocationCount--;
414 owner->instNameNode->allocRefCount--;
415 RM_SS_OBJ_WB(rmInst, owner->instNameNode, Rm_PolicyValidInstNode);
416 Rm_osalFree((void *)owner, sizeof(*owner));
417 owner = nextOwner;
418 }
419 }
421 /* FUNCTION PURPOSE: Get the status for an allocator resource
422 ***********************************************************************
423 * DESCRIPTION: Called when a resource status request is made. The
424 * resource's allocator is searched for the resource base
425 * and length specified in the transaction. The
426 * resource's owner reference count is returned if the
427 * resource range is found.
428 */
429 static int32_t allocatorStatus(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
430 {
431 Rm_ResourceNode findNode;
432 Rm_ResourceNode *matchingNode = NULL;
433 uint32_t matchingEnd;
434 uint32_t findEnd;
435 int32_t retVal;
437 memset((void *)&findNode, 0, sizeof(findNode));
438 findNode.base = opInfo->resourceInfo->base;
439 findNode.length = opInfo->resourceInfo->length;
440 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
442 if (matchingNode) {
443 matchingEnd = matchingNode->base + matchingNode->length - 1;
444 findEnd = findNode.base + findNode.length - 1;
445 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
446 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
447 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
448 opInfo->serviceSrcInstNode);
449 retVal = RM_SERVICE_APPROVED;
450 }
451 else {
452 retVal = RM_SERVICE_DENIED_PARTIAL_STATUS;
453 }
454 }
455 else {
456 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
457 }
459 return(retVal);
460 }
462 /* FUNCTION PURPOSE: Preallocates an allocator resource
463 ***********************************************************************
464 * DESCRIPTION: Called when an allocate request is made but the base
465 * is unspecified. The preallocation algorithm looks at
466 * available resources as well as policy permissions to
467 * determine a resource range that satisfies the request.
468 * If a valid range is found it will be returned for the
469 * treeAllocate algorithm to handle.
470 */
471 static int32_t allocatorPreAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
472 Rm_AllocatorOpInfo *opInfo)
473 {
474 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
475 Rm_ResourceNode findNode;
476 Rm_ResourceNode *matchingNode = NULL;
477 Rm_ResourceNode *nextNode;
478 uint32_t matchingEnd;
479 uint32_t findEnd;
480 uint32_t rangeIndex;
481 int resourceFound = RM_FALSE;
482 Rm_PolicyCheckType policyCheckType;
483 Rm_PolicyCheckCfg policyCheckCfg;
484 int nodePassesPolicy;
485 int32_t retVal = RM_OK;
487 if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) {
488 policyCheckType = Rm_policyCheck_INIT;
489 }
490 else if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE) {
491 policyCheckType = Rm_policyCheck_USE;
492 }
493 else {
494 retVal = RM_ERROR_INVALID_SERVICE_TYPE;
495 return (retVal);
496 }
498 if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
499 /* Set base to first node's base since CD will not have all resources like Server */
500 matchingNode = RB_MIN(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry);
501 opInfo->resourceInfo->base = matchingNode->base;
502 }
503 else {
504 opInfo->resourceInfo->base = rmPolicyGetResourceBase(opInfo->policy, opInfo->serviceSrcInstNode,
505 resourcePolicy, policyCheckType,
506 &retVal);
507 }
509 if (retVal != RM_OK) {
510 return (retVal);
511 }
513 if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {
514 /* Get alignment from policy */
515 opInfo->resourceInfo->alignment = rmPolicyGetResourceAlignment(opInfo->policy, resourcePolicy);
516 }
518 if (opInfo->resourceInfo->alignment == 0) {
519 opInfo->resourceInfo->alignment = 1;
520 }
522 memset((void *)&findNode, 0, sizeof(findNode));
523 findNode.base = opInfo->resourceInfo->base;
524 findNode.length = opInfo->resourceInfo->length;
526 /* Configure policy checking structure */
527 memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
528 policyCheckCfg.policyDtb = opInfo->policy;
529 policyCheckCfg.resourceOffset = resourcePolicy;
531 do {
532 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
534 if (matchingNode) {
535 matchingEnd = matchingNode->base + matchingNode->length - 1;
536 findEnd = findNode.base + findNode.length - 1;
537 nodePassesPolicy = RM_BOOL_UNDEF;
538 if ((matchingNode->allocationCount == 0) &&
539 (findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
540 /* Attempt to preallocate from node only if not owned by anyone and sits
541 * within a matching node. */
542 policyCheckCfg.type = policyCheckType;
543 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
544 policyCheckCfg.resourceBase = findNode.base;
545 policyCheckCfg.resourceLength = findNode.length;
546 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
548 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
549 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
551 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
552 /* Check if instance requesting resource has privileges to share
553 * a resource already reserved by Linux */
554 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
555 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
556 }
558 if (nodePassesPolicy) {
559 /* Check exclusive privileges of instance requesting resource. Requesting
560 * instance with exclusive privileges can't reserve resource if already owned*/
561 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
562 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
563 }
564 }
566 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
567 /* Check exclusive privileges of instance that currently owns resource */
568 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
569 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
570 nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
571 }
573 if (retVal != RM_OK) {
574 break;
575 }
577 if (nodePassesPolicy) {
578 /* Initialize indexer to be first resource value that alignment satisfies */
579 rangeIndex = findNode.base;
580 if (rangeIndex % opInfo->resourceInfo->alignment) {
581 rangeIndex += (opInfo->resourceInfo->alignment -
582 (rangeIndex % opInfo->resourceInfo->alignment));
583 }
585 if ((rangeIndex + opInfo->resourceInfo->length - 1) <= matchingEnd) {
586 /* Block of unallocated resources within matchingNode that satisfies
587 * allocate requirements */
588 opInfo->resourceInfo->base = rangeIndex;
589 resourceFound = RM_TRUE;
590 retVal = RM_SERVICE_PROCESSING;
591 }
592 }
593 }
595 if (!resourceFound) {
596 /* Check next resource node for available resources */
597 if (findNode.base < matchingNode->base) {
598 findNode.base = matchingNode->base;
599 }
600 else {
601 if (!nodePassesPolicy) {
602 findNode.base += findNode.length;
603 }
604 else {
605 /* Matching node allocated, move to next node */
606 if (nextNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode)) {
607 findNode.base = nextNode->base;
608 }
609 else {
610 retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
611 }
612 }
613 }
614 }
615 }
616 else {
617 retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
618 }
619 } while ((!resourceFound) &&
620 (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
622 return(retVal);
623 }
625 /* FUNCTION PURPOSE: Allocates an allocator resource
626 ***********************************************************************
627 * DESCRIPTION: Will attempt to allocate the resource with specified
628 * base and length from the resource's allocator. The
629 * allocation algorithm will verify the allocation against
630 * the policy permissions for the instance requesting the
631 * allocation. If the policy allows the allocation the
632 * algorithm will allocate the resource then combine any
633 * resource nodes that may have become equivalent (in terms
634 * of ownership) after the allocation.
635 */
636 static int32_t allocatorAllocate(Rm_Handle rmHandle, Rm_Allocator *allocator, int32_t resourcePolicy,
637 Rm_AllocatorOpInfo *opInfo)
638 {
639 Rm_ResourceNode findNode;
640 Rm_ResourceNode *matchingNode = NULL;
641 Rm_ResourceNode *leftNode = NULL;
642 Rm_ResourceNode *rightNode = NULL;
643 Rm_PolicyCheckType policyCheckType;
644 Rm_PolicyCheckCfg policyCheckCfg;
645 int allocPassesPolicy;
646 int combineLeft = RM_FALSE;
647 int combineRight = RM_FALSE;
648 uint32_t findEnd;
649 uint32_t matchingEnd;
650 int32_t retVal;
652 if (opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) {
653 policyCheckType = Rm_policyCheck_INIT;
654 }
655 else if (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE) {
656 policyCheckType = Rm_policyCheck_USE;
657 }
658 else {
659 retVal = RM_ERROR_INVALID_SERVICE_TYPE;
660 return (retVal);
661 }
663 memset((void *)&findNode, 0, sizeof(findNode));
664 findNode.base = opInfo->resourceInfo->base;
665 findNode.length = opInfo->resourceInfo->length;
666 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
668 /* Prepare privilege checks */
669 memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
671 if (matchingNode) {
672 findEnd = findNode.base + findNode.length - 1;
673 matchingEnd = matchingNode->base + matchingNode->length - 1;
675 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
676 if (opInfo->serviceSrcInstNode == rmPolicyGetLinuxInstNode(rmHandle)) {
677 /* Bypass policy checks since Linux Kernel has full privileges */
678 allocPassesPolicy = RM_TRUE;
679 }
680 else {
681 policyCheckCfg.policyDtb = opInfo->policy;
682 policyCheckCfg.resourceOffset = resourcePolicy;
683 policyCheckCfg.type = policyCheckType;
684 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
685 policyCheckCfg.resourceBase = findNode.base;
686 policyCheckCfg.resourceLength = findNode.length;
687 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
688 if (!allocPassesPolicy) {
689 if (policyCheckType == Rm_policyCheck_INIT) {
690 retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
691 }
692 else {
693 retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
694 }
695 }
697 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
698 if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
699 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
700 /* Check if instance requesting resource has privileges to share
701 * a resource already reserved by Linux */
702 policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
703 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
704 allocPassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
705 if (!allocPassesPolicy) {
706 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
707 }
708 }
709 if (allocPassesPolicy) {
710 /* Check exclusive privileges of instance requesting resource. Requesting
711 * instance with exclusive privileges can't reserve resource if already owned*/
712 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
713 policyCheckCfg.validInstNode = opInfo->serviceSrcInstNode;
714 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
715 if (!allocPassesPolicy) {
716 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
717 }
718 }
719 }
720 if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
721 /* Check exclusive privileges of instance that currently owns resource */
722 policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
723 policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
724 allocPassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg, &retVal);
725 if (!allocPassesPolicy) {
726 retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
727 }
728 }
729 }
730 }
732 if (allocPassesPolicy) {
733 /* Handle any possible node combinations if requesting instance is
734 * not already in resource's owner list. Automatic approval if requesting
735 * instance is already in owner list. */
736 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
737 /* findNode range matches matchingNode range
738 *
739 * |<--left node-->||<--matched node-->||<--right node-->| => existing node
740 * |<--alloc request-->| => requested resources
741 */
742 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
743 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
744 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
745 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
747 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
748 allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
749 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
750 combineLeft = RM_TRUE;
751 }
752 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
753 allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
754 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
755 combineRight = RM_TRUE;
756 }
758 if (combineLeft && combineRight) {
759 /* Combine all three nodes into matchingNode */
760 matchingNode->base = leftNode->base;
761 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
763 allocatorResNodeOwnerClear(rmHandle, leftNode);
764 rmResourceNodeFree(leftNode);
765 allocatorResNodeOwnerClear(rmHandle, rightNode);
766 rmResourceNodeFree(rightNode);
767 }
768 else if (combineLeft) {
769 /* Combine left and matching nodes. Reinsert right. */
770 matchingNode->base = leftNode->base;
771 matchingNode->length += leftNode->length;
773 allocatorResNodeOwnerClear(rmHandle, leftNode);
774 rmResourceNodeFree(leftNode);
775 if (rightNode) {
776 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
777 }
778 }
779 else if (combineRight) {
780 /* Combine right and matching nodes. Reinsert left. */
781 matchingNode->length += rightNode->length;
783 allocatorResNodeOwnerClear(rmHandle, rightNode);
784 rmResourceNodeFree(rightNode);
785 if (leftNode) {
786 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
787 }
788 }
789 else {
790 /* No combine. */
791 if (leftNode) {
792 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
793 }
794 if (rightNode) {
795 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
796 }
797 }
799 /* Always reinsert matchingNode */
800 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
802 /* Matching node contains new reference count after alloc. Return new owner count
803 * and originating instance allocation reference count. */
804 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
805 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
806 opInfo->serviceSrcInstNode);
807 }
808 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
809 /* findNode range is subset of matchingNode range and neither boundary is
810 * equivalent.
811 *
812 * |<----------matched node---------->|
813 * |<---alloc request--->|
814 */
815 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
816 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
817 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
818 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
819 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
821 matchingNode->base = findNode.base;
822 matchingNode->length = findNode.length;
823 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
825 /* Insert all the nodes */
826 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
827 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
828 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
830 /* Matching node contains new reference count after alloc. Return new owner count
831 * and originating instance allocation reference count. */
832 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
833 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
834 opInfo->serviceSrcInstNode);
835 }
836 else {
837 if (findNode.base == matchingNode->base) {
838 /* findNode base and matchingNode base are equivalent. May be combine
839 * possibilities to the left
840 *
841 * |<---left node (alloc'd)--->||<----------matched node---------->|
842 * |<---findNode (alloc req)--->|
843 */
844 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
845 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
846 /* Add allocating instance to owner list for compare with leftNode */
847 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
849 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
850 allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
851 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
852 /* Combine leftNode and findNode */
853 leftNode->length += findNode.length;
854 }
855 else {
856 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
857 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
858 }
860 /* Account for leftNode in matchingNode */
861 matchingNode->base = findNode.base + findNode.length;
862 matchingNode->length = matchingEnd - findEnd;
864 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
865 /* Left node contains new reference count after alloc. Return new owner count
866 * and originating instance allocation reference count. */
867 opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
868 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, leftNode,
869 opInfo->serviceSrcInstNode);
870 }
871 else if (findEnd == matchingEnd) {
872 /* findNode end and matchingNode end are equivalent. May be combine
873 * possibilities to the right
874 *
875 * |<----------matched node---------->||<---right node (alloc'd)--->|
876 * |<---findNode (alloc req)--->|
877 */
878 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
879 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
880 /* Add allocating instance to owner list for compare with rightNode */
881 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
883 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
884 allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
885 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
886 /* Combine rightNode and findNode */
887 rightNode->base = findNode.base;
888 rightNode->length += findNode.length;
889 }
890 else {
891 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
892 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
893 }
895 /* Account for rightNode in matchingNode */
896 matchingNode->length -= findNode.length;
898 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
899 /* Right node contains new reference count after alloc. Return new owner count
900 * and originating instance allocation reference count. */
901 opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
902 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, rightNode,
903 opInfo->serviceSrcInstNode);
904 }
905 /* Remove allocating instance from leftover matchingNode */
906 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
907 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
908 }
909 retVal = RM_SERVICE_APPROVED;
910 }
911 }
912 else {
913 retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
914 }
915 }
916 else {
917 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
918 }
920 return(retVal);
921 }
923 /* FUNCTION PURPOSE: Frees an allocator resource
924 ***********************************************************************
925 * DESCRIPTION: Will attempt to free the resource with specified
926 * base and length from the resource's allocator. The
927 * free algorithm will verify the free request parameters
928 * match an allocated range for the resource and that the
929 * range is owned by the instance requesting the free. If
930 * the free is validated the algorithm will free the
931 * resource then combine any resource nodes that may have
932 * become equivalent (in terms of ownership) after the
933 * allocation.
934 */
935 static int32_t allocatorFree(Rm_Handle rmHandle, Rm_Allocator *allocator, Rm_AllocatorOpInfo *opInfo)
936 {
937 Rm_ResourceNode findNode;
938 Rm_ResourceNode *matchingNode = NULL;
939 Rm_ResourceNode *leftNode = NULL;
940 Rm_ResourceNode *rightNode = NULL;
941 int combineLeft = RM_FALSE;
942 int combineRight = RM_FALSE;
943 uint32_t findEnd;
944 uint32_t matchingEnd;
945 int32_t retVal;
947 memset((void *)&findNode, 0, sizeof(findNode));
948 findNode.base = opInfo->resourceInfo->base;
949 findNode.length = opInfo->resourceInfo->length;
950 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
952 if (matchingNode) {
953 findEnd = findNode.base + findNode.length - 1;
954 matchingEnd = matchingNode->base + matchingNode->length - 1;
956 if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
957 if (matchingNode->allocationCount) {
958 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceSrcInstNode)) {
959 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd))
960 {
961 /* Case 1: Free range equals allocated matched node exactly. Attempt to combine
962 * freed node with nodes to left and right.
963 *
964 * |<--left node-->||<---matched node--->||<--right node-->|
965 * |<---free request--->|
966 */
967 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
968 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
969 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
970 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
972 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
973 allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
974 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
975 combineLeft = RM_TRUE;
976 }
977 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
978 allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
979 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
980 combineRight = RM_TRUE;
981 }
983 if (combineLeft && combineRight) {
984 /* Combine all three nodes into matchingNode */
985 matchingNode->base = leftNode->base;
986 matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
988 allocatorResNodeOwnerClear(rmHandle, leftNode);
989 rmResourceNodeFree(leftNode);
990 allocatorResNodeOwnerClear(rmHandle, rightNode);
991 rmResourceNodeFree(rightNode);
992 }
993 else if (combineLeft) {
994 /* Combine left and matching nodes. Reinsert right. */
995 matchingNode->base = leftNode->base;
996 matchingNode->length += leftNode->length;
998 allocatorResNodeOwnerClear(rmHandle, leftNode);
999 rmResourceNodeFree(leftNode);
1000 if (rightNode) {
1001 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1002 }
1003 }
1004 else if (combineRight) {
1005 /* Combine right and matching nodes. Reinsert left. */
1006 matchingNode->length += rightNode->length;
1008 allocatorResNodeOwnerClear(rmHandle, rightNode);
1009 rmResourceNodeFree(rightNode);
1010 if (leftNode) {
1011 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
1012 }
1013 }
1014 else {
1015 /* No combine. */
1016 if (leftNode) {
1017 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
1018 }
1019 if (rightNode) {
1020 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1021 }
1022 }
1024 /* Always reinsert matchingNode */
1025 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1027 /* Matching node is what remains after free. Return remaining owner count
1028 * and originating instance allocation reference count. */
1029 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1030 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1031 opInfo->serviceSrcInstNode);
1032 }
1033 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
1034 /* Case 2: Free range is less than range in matched node. Split
1035 * matched node into three nodes.
1036 *
1037 * |<----------matched node---------->|
1038 * |<---free request--->|
1039 *
1040 * Remove instance from owner list then add it back in for side nodes for
1041 * proper accounting of allocations in validInstance list
1042 */
1043 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1044 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1046 leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
1047 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
1048 allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceSrcInstNode);
1049 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
1051 rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
1052 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
1053 allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceSrcInstNode);
1054 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1056 matchingNode->base = findNode.base;
1057 matchingNode->length = findNode.length;
1058 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1060 /* Matching node is what remains after free. Return remaining owner count
1061 * and originating instance allocation reference count. */
1062 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1063 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1064 opInfo->serviceSrcInstNode);
1065 }
1066 else {
1067 if (findNode.base == matchingNode->base) {
1068 /* Case 3: Free range is on left boundary of matched node. Try to
1069 * combine free range with left node.
1070 *
1071 * |<---left node (free)--->||<----------matched node---------->|
1072 * |<---findNode (free req)--->|
1073 */
1075 leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1076 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1077 /* Remove freeing instance from owner list for compare with leftNode */
1078 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1080 if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
1081 allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
1082 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
1083 /* Combine leftNode and findNode */
1084 leftNode->length += findNode.length;
1085 }
1086 else {
1087 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
1088 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
1089 }
1091 /* Remove leftNode range from matchingNode */
1092 matchingNode->base = findNode.base + findNode.length;
1093 matchingNode->length = matchingEnd - findEnd;
1094 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, leftNode);
1096 /* Left node is what remains after free. Return remaining owner count
1097 * and originating instance allocation reference count. */
1098 opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
1099 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, leftNode,
1100 opInfo->serviceSrcInstNode);
1101 }
1102 else if (findEnd == matchingEnd) {
1103 /* Case 4: Free range is on right boundary of matched node. Try to
1104 * combine free range with right node.
1105 *
1106 * |<----------matched node---------->||<---right node (free)--->|
1107 * |<---findNode (free req)--->|
1108 */
1110 rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1111 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1112 /* Remove freeing instance from owner list for compare with rightNode */
1113 allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1115 if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
1116 allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
1117 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1118 /* Combine rightNode and findNode */
1119 rightNode->base = findNode.base;
1120 rightNode->length += findNode.length;
1121 }
1122 else {
1123 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
1124 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
1125 }
1127 /* Remove rightNode range from matchingNode */
1128 matchingNode->length -= findNode.length;
1129 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, rightNode);
1131 /* Right node is what remains after free. Return remaining owner count
1132 * and originating instance allocation reference count. */
1133 opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
1134 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, rightNode,
1135 opInfo->serviceSrcInstNode);
1136 }
1138 /* Add freeing instance back into matchingNode allocations */
1139 allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceSrcInstNode);
1140 RB_INSERT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1141 }
1142 retVal = RM_SERVICE_APPROVED;
1143 }
1144 else {
1145 /* Return owner count and instance alloc count. In case it's a reference count
1146 * check in application */
1147 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1148 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1149 opInfo->serviceSrcInstNode);
1150 retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
1151 }
1152 }
1153 else {
1154 /* Return owner count and instance alloc count. In case it's a reference count
1155 * check in application */
1156 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1157 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1158 opInfo->serviceSrcInstNode);
1159 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
1160 }
1161 }
1162 else {
1163 retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
1164 }
1165 }
1166 else {
1167 retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
1168 }
1169 return(retVal);
1170 }
1172 /* FUNCTION PURPOSE: Reserves a Linux resource
1173 ***********************************************************************
1174 * DESCRIPTION: Reserves resources for Linux using the base and length
1175 * values retrieved from the Linux DTB via the
1176 * "linux-dtb-alias" properties within the GRL.
1177 */
1178 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle, Rm_LinuxAlias *linuxAlias,
1179 Rm_LinuxValueRange *linuxValues, Rm_AllocatorOpInfo *opInfo)
1180 {
1181 int32_t retVal = RM_OK;
1182 int baseFound = RM_FALSE;
1183 int lengthFound = RM_FALSE;
1184 uint32_t valueIndex = 0;
1186 while ((linuxValues) && (!baseFound || !lengthFound)) {
1187 if (linuxAlias->baseOffset == valueIndex) {
1188 opInfo->resourceInfo->base = linuxValues->value;
1189 baseFound = RM_TRUE;
1191 if (linuxAlias->lengthOffset == RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1192 opInfo->resourceInfo->length = 1;
1193 lengthFound = RM_TRUE;
1194 }
1195 }
1196 else if (linuxAlias->lengthOffset == valueIndex) {
1197 opInfo->resourceInfo->length = linuxValues->value;
1198 lengthFound = RM_TRUE;
1199 }
1201 linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1202 valueIndex++;
1203 }
1205 if (!baseFound || !lengthFound) {
1206 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1207 }
1208 else {
1209 /* Allocate resource to Linux */
1210 retVal = rmAllocatorOperation(rmHandle, opInfo);
1211 if (retVal == RM_SERVICE_APPROVED) {
1212 retVal = RM_OK;
1213 }
1214 }
1215 return (retVal);
1216 }
1218 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1219 ***********************************************************************
1220 * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1221 * Linux kernel. If the resource is found via the
1222 * "linux-dtb-alias" property defined in the GRL it is
1223 * reserved.
1224 */
1225 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle, const char *resourceName, void *linuxDtb,
1226 Rm_LinuxAlias *linuxAlias)
1227 {
1228 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1229 Rm_AllocatorOpInfo opInfo;
1230 Rm_ResourceInfo resourceInfo;
1231 uint32_t pathOffset;
1232 uint32_t pathSize;
1233 char *tempAliasPath;
1234 char *spacePtr;
1235 int32_t propOffset;
1236 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1237 int32_t prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1238 int32_t depth = RM_DTB_UTIL_STARTING_DEPTH;
1239 int32_t propertyLen;
1240 const char *propertyName;
1241 const void *propertyData;
1242 Rm_LinuxValueRange *linuxValueRange;
1243 int32_t retVal = RM_OK;
1245 memset((void *)&opInfo, 0, sizeof(opInfo));
1246 memset((void *)&resourceInfo, 0, sizeof(resourceInfo));
1248 rm_strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1249 opInfo.policy = rmInst->u.server.globalPolicy;
1250 opInfo.serviceSrcInstNode = rmPolicyGetLinuxInstNode(rmHandle);
1251 opInfo.operation = Rm_allocatorOp_ALLOCATE_INIT;
1252 opInfo.resourceInfo = &resourceInfo;
1254 while(linuxAlias) {
1255 /* Reset parsing variables */
1256 pathOffset = 0;
1257 pathSize = strlen(linuxAlias->path) + 1;
1258 tempAliasPath = Rm_osalMalloc(pathSize);
1259 rm_strncpy(tempAliasPath, linuxAlias->path, pathSize);
1260 nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1261 prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1262 resourceInfo.base = 0;
1263 resourceInfo.length = 0;
1265 spacePtr = strpbrk(tempAliasPath, " ");
1266 if (spacePtr) {
1267 *spacePtr = '\0';
1268 }
1270 while(pathOffset < pathSize) {
1271 /* Move through DTB nodes until next alias path node found */
1272 if (strcmp(tempAliasPath + pathOffset, fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1273 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1275 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1276 /* Returning from subnode that matched part of alias path without finding
1277 * resource values */
1278 retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1279 break;
1280 }
1281 }
1282 else {
1283 /* Found next alias path node. Move to next node name in path string. */
1284 pathOffset += (strlen(tempAliasPath + pathOffset) + 1);
1285 spacePtr = strpbrk(tempAliasPath + pathOffset, " ");
1286 if (spacePtr) {
1287 *spacePtr = '\0';
1288 }
1290 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1291 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1292 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1293 (pathOffset < pathSize)) {
1294 propertyData = fdt_getprop_by_offset(linuxDtb, propOffset,
1295 &propertyName, &propertyLen);
1297 if (strcmp(tempAliasPath + pathOffset, propertyName) == 0) {
1298 /* Found resource at end of alias path */
1299 pathOffset += (strlen(tempAliasPath + pathOffset) + 1);
1300 linuxValueRange = rmDtbUtilLinuxExtractValues(propertyData, propertyLen);
1301 retVal = allocatorReserveLinuxResource(rmHandle, linuxAlias,
1302 linuxValueRange, &opInfo);
1303 rmDtbUtilLinuxFreeValues(linuxValueRange);
1304 }
1305 propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1306 }
1308 if (propOffset < -FDT_ERR_NOTFOUND) {
1309 retVal = propOffset;
1310 break;
1311 }
1312 }
1313 }
1315 Rm_osalFree(tempAliasPath, pathSize);
1316 if (retVal < RM_OK) {
1317 break;
1318 }
1319 linuxAlias = linuxAlias->nextLinuxAlias;
1320 }
1321 return (retVal);
1322 }
1324 /* FUNCTION PURPOSE: Creates and initializes a resource allocator
1325 ***********************************************************************
1326 * DESCRIPTION: Creates a resource allocator for the provided
1327 * resource name and resource properties retrieved
1328 * from the GRL. Resources will be reserved for
1329 * the Linux kernel if the Linux DTB is provided
1330 * and there are "linux-dtb-alias" properties
1331 * specified in the GRL.
1332 */
1333 static int32_t allocatorExtractGrlResProps(Rm_Handle rmHandle, const char *resourceName,
1334 Rm_ResourceProperties *resourceProperties, void *linuxDtb)
1335 {
1336 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1337 Rm_ResourceRange *range = NULL;
1338 Rm_ResourceRange *rangeBasePtr = NULL;
1339 Rm_NsAssignment *nsAssignments = NULL;
1340 Rm_NsAssignment *nsAssignmentBasePtr = NULL;
1341 Rm_LinuxAlias *linuxAlias = NULL;
1342 Rm_NameServerObjCfg nameServerObjCfg;
1343 int32_t retVal = RM_OK;
1345 if ((strlen(resourceName) + 1) > RM_NAME_MAX_CHARS) {
1346 retVal = RM_ERROR_RESOURCE_NAME_TOO_LONG;
1347 return(retVal);
1348 }
1350 if (resourceProperties->rangeData && (resourceProperties->rangeLen > 0)) {
1351 range = rangeBasePtr = rmDtbUtilResExtractRange(resourceProperties->rangeData,
1352 resourceProperties->rangeLen);
1354 if ((retVal = rmAllocatorCreate(rmHandle, resourceName, range)) >= RM_OK) {
1355 if (resourceProperties->linuxAliasData && resourceProperties->linuxAliasLen) {
1356 if (linuxDtb) {
1357 linuxAlias = rmDtbUtilResExtractLinuxAlias(resourceProperties->linuxAliasData,
1358 resourceProperties->linuxAliasLen, &retVal);
1359 if (linuxAlias) {
1360 retVal = allocatorFindLinuxResource(rmHandle, resourceName, linuxDtb, linuxAlias);
1361 }
1362 }
1363 }
1364 }
1365 }
1367 if (retVal >= RM_OK) {
1368 if (resourceProperties->nsAssignData && resourceProperties->nsAssignLen) {
1369 nsAssignments = rmDtbUtilResExtractNsAssignment(resourceProperties->nsAssignData,
1370 resourceProperties->nsAssignLen, &retVal);
1371 if (nsAssignments) {
1372 nsAssignmentBasePtr = nsAssignments;
1373 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1374 rmNameServerTreeInv(rmInst->u.server.nameServer);
1375 }
1376 while (nsAssignments) {
1377 memset((void *)&nameServerObjCfg, 0, sizeof(nameServerObjCfg));
1378 nameServerObjCfg.nameServerTree = rmInst->u.server.nameServer;
1379 nameServerObjCfg.nodeCfg.objName = nsAssignments->nsName;
1380 nameServerObjCfg.nodeCfg.resourceName = (char *)resourceName;
1381 nameServerObjCfg.nodeCfg.resourceBase= nsAssignments->resourceBase;
1382 nameServerObjCfg.nodeCfg.resourceLength = nsAssignments->resourceLength;
1383 rmNameServerAddObject(&nameServerObjCfg);
1384 nsAssignments = nsAssignments->nextNsAssignment;
1385 }
1386 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1387 rmNameServerTreeWb(rmInst->u.server.nameServer);
1388 }
1389 rmDtbUtilResFreeNsAssignmentList(nsAssignmentBasePtr);
1390 }
1391 }
1392 }
1393 else if (retVal != RM_ERROR_COULD_NOT_CREATE_NEW_ALLOCATOR) {
1394 rmAllocatorDelete(rmHandle, resourceName);
1395 }
1397 rmDtbUtilResFreeRange(rangeBasePtr);
1398 if (linuxAlias) {
1399 rmDtbUtilResFreeLinuxAlias(linuxAlias);
1400 }
1401 return(retVal);
1402 }
1404 /**********************************************************************
1405 ********************** Internal Functions ****************************
1406 **********************************************************************/
1408 /* FUNCTION PURPOSE: Creates a new resource tree
1409 ***********************************************************************
1410 * DESCRIPTION: Creates and populates a new resource tree allocator
1411 * using the provided resource name and value range. The
1412 * name and value originate from the GRL.
1413 */
1414 int32_t rmAllocatorCreate(Rm_Handle rmHandle, const char *resourceName, Rm_ResourceRange *range)
1415 {
1416 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1417 Rm_Allocator *allocator = NULL;
1418 Rm_ResourceTree *treeRoot = NULL;
1419 Rm_ResourceNode *treeNode = NULL;
1421 allocator = allocatorAdd(rmHandle, resourceName);
1423 if (allocator) {
1424 treeRoot = Rm_osalMalloc(sizeof(*treeRoot));
1425 RB_INIT(treeRoot);
1427 while (range != NULL) {
1428 treeNode = rmResourceNodeNew(range->base, range->length);
1429 RB_INSERT(_Rm_AllocatorResourceTree, treeRoot, treeNode);
1430 range = range->nextRange;
1431 }
1432 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1433 rmResourceTreeWb(treeRoot);
1434 }
1436 allocator->allocatorRootEntry = treeRoot;
1437 RM_SS_OBJ_WB(rmInst, allocator, Rm_Allocator);
1438 return (RM_OK);
1439 }
1440 else {
1441 return (RM_ERROR_COULD_NOT_CREATE_NEW_ALLOCATOR);
1442 }
1443 }
1445 /* FUNCTION PURPOSE: Returns a pointer to the allocator list
1446 ***********************************************************************
1447 * DESCRIPTION: Returns a pointer to the instance's allocator list
1448 * based on the instance type
1449 */
1450 Rm_Allocator *rmAllocatorGetAllocatorList(Rm_Handle rmHandle)
1451 {
1452 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1453 Rm_Allocator *list = NULL;
1455 if ((rmInst->instType == Rm_instType_SERVER) ||
1456 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1457 list = rmInst->u.server.allocators;
1458 }
1459 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1460 list = rmInst->u.cd.allocators;
1461 }
1462 return(list);
1463 }
1465 /* FUNCTION PURPOSE: Finds an allocator
1466 ***********************************************************************
1467 * DESCRIPTION: Returns a pointer to an allocator that matches the
1468 * provided resource name.
1469 */
1470 Rm_Allocator *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName)
1471 {
1472 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1473 Rm_Allocator *allocatorList = rmAllocatorGetAllocatorList(rmHandle);
1475 while (allocatorList) {
1476 RM_SS_OBJ_INV(rmInst, allocatorList, Rm_Allocator);
1477 if (strncmp(allocatorList->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1478 break;
1479 }
1480 allocatorList = allocatorList->nextAllocator;
1481 }
1483 return (allocatorList);
1484 }
1486 /* FUNCTION PURPOSE: Checks if a resource node is localized
1487 ***********************************************************************
1488 * DESCRIPTION: Checks if a resource node is localized. A localized
1489 * node is one that is free and has no neighboring nodes
1490 * or neighboring nodes that do not have resource values
1491 * contiguous with the node being checked. The function
1492 * will return RM_TRUE if the node is localized.
1493 * Otherwise, the function returns RM_FALSE
1494 */
1495 int rmAllocatorGetNodeLocalization(Rm_Handle rmHandle, char *resourceName,
1496 int32_t *resBase, uint32_t *resLen)
1497 {
1498 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1499 void * policy = rmPolicyGetPolicy((Rm_Handle)rmInst);
1500 int32_t resOffsetInPolicy = rmPolicyGetResourceOffset(policy, resourceName);
1501 uint32_t allocSize = rmPolicyGetResourceCdAllocSize(policy, resOffsetInPolicy);
1502 Rm_Allocator *allocator = rmAllocatorFind(rmHandle, resourceName);
1503 Rm_ResourceNode findNode;
1504 Rm_ResourceNode *matchingNode = NULL;
1505 Rm_ResourceNode *neighborNode = NULL;
1506 int nodeIsLocalized = RM_FALSE;
1508 /* Nothing to free back to server if policy never specified blocks could be allocated
1509 * to CD */
1510 if (allocSize) {
1511 memset((void *)&findNode, 0, sizeof(findNode));
1512 findNode.base = *resBase;
1513 findNode.length = *resLen;
1514 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
1516 if (matchingNode) {
1517 /* Node can be freed back to Server from CD if:
1518 * - allocationCount == 0
1519 * - node's resource range is multiple of policy allocation size
1520 * - node's resource range boundaries are not contiguous with surrounding nodes */
1521 if (matchingNode->allocationCount) {
1522 goto exitLocalization;
1523 }
1525 if (matchingNode->length % allocSize) {
1526 goto exitLocalization;
1527 }
1529 /* Check left neighbor */
1530 neighborNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1531 if (neighborNode && allocatorResNodeBoundaryCompare(neighborNode, matchingNode)) {
1532 goto exitLocalization;
1533 }
1535 /* Check right neighbor */
1536 neighborNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1537 if (neighborNode && allocatorResNodeBoundaryCompare(neighborNode, matchingNode)) {
1538 goto exitLocalization;
1539 }
1541 /* All localization checks passed. Return the base and length of localized node. */
1542 nodeIsLocalized = RM_TRUE;
1543 *resBase = matchingNode->base;
1544 *resLen = matchingNode->length;
1545 }
1546 else {
1547 nodeIsLocalized = RM_FALSE;
1548 }
1549 }
1551 exitLocalization:
1552 return (nodeIsLocalized);
1553 }
1555 /* FUNCTION PURPOSE: Issues an allocator operation
1556 ***********************************************************************
1557 * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1558 * for an RM resource.
1559 */
1560 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1561 {
1562 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1563 Rm_Allocator *allocator = NULL;
1564 int32_t resourceOffsetInPolicy;
1565 int32_t retVal;
1567 resourceOffsetInPolicy = rmPolicyGetResourceOffset(opInfo->policy, opInfo->resourceInfo->name);
1568 allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name);
1570 if ((resourceOffsetInPolicy > 0) && allocator) {
1571 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1572 rmResourceTreeInv(allocator->allocatorRootEntry);
1573 }
1575 if (opInfo->operation == Rm_allocatorOp_GET_STATUS) {
1576 retVal = allocatorStatus(rmHandle, allocator, opInfo);
1577 }
1578 else if ((opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) ||
1579 (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE)) {
1580 retVal = allocatorPreAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1581 }
1582 else if ((opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) ||
1583 (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE)) {
1584 retVal = allocatorAllocate(rmHandle, allocator, resourceOffsetInPolicy, opInfo);
1585 }
1586 else if (opInfo->operation == Rm_allocatorOp_FREE) {
1587 retVal = allocatorFree(rmHandle, allocator, opInfo);
1588 }
1590 if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
1591 (opInfo->operation != Rm_allocatorOp_GET_STATUS) &&
1592 (retVal == RM_SERVICE_APPROVED)) {
1593 rmResourceTreeWb(allocator->allocatorRootEntry);
1594 }
1595 }
1596 else {
1597 /* Resource could not be found in policy and/or allocator */
1598 retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1599 }
1600 return(retVal);
1601 }
1603 /* FUNCTION PURPOSE: Initializes server allocators
1604 ***********************************************************************
1605 * DESCRIPTION: Creates and initializes a server instance's
1606 * resource allocators using the GRL and, if
1607 * provided, Linux DTB.
1608 */
1609 int32_t rmAllocatorInitializeResources(Rm_Handle rmHandle, void *globalResourceDtb, void *linuxDtb)
1610 {
1611 int32_t nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1612 int32_t nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1613 Rm_ResourceProperties resProperties;
1614 int32_t propOffset;
1615 int32_t propertyLen;
1616 const char *propertyName;
1617 const void *propertyData;
1618 Rm_ResourcePropType propertyType;
1619 int32_t retVal = RM_OK;
1621 /* Parse the Global Resource List, creating an allocator for each specified resource node */
1622 while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) && (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1623 memset((void *)&resProperties, 0, sizeof(resProperties));
1624 /* Get properties of resource node */
1625 propOffset = fdt_first_property_offset(globalResourceDtb, nodeOffset);
1626 while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1627 propertyData = fdt_getprop_by_offset(globalResourceDtb, propOffset, &propertyName, &propertyLen);
1628 propertyType = rmDtbUtilResGetPropertyType(propertyName);
1629 if (propertyType == Rm_resourcePropType_RESOURCE_RANGE) {
1630 resProperties.rangeData = propertyData;
1631 resProperties.rangeLen = propertyLen;
1632 }
1633 else if (propertyType == Rm_resourcePropType_NSASSIGNMENT) {
1634 resProperties.nsAssignData = propertyData;
1635 resProperties.nsAssignLen = propertyLen;
1636 }
1637 else if (propertyType == Rm_resourcePropType_RESOURCE_LINUX_ALIAS) {
1638 resProperties.linuxAliasData = propertyData;
1639 resProperties.linuxAliasLen = propertyLen;
1640 }
1641 else {
1642 retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1643 goto exitAllocInit;
1644 }
1646 propOffset = fdt_next_property_offset(globalResourceDtb, propOffset);
1647 if (propOffset == -FDT_ERR_NOTFOUND) {
1648 /* No more resource properties but at least one found. Extract the property values */
1649 retVal = allocatorExtractGrlResProps(rmHandle, fdt_get_name(globalResourceDtb, nodeOffset, NULL),
1650 &resProperties, linuxDtb);
1651 if (retVal < RM_OK) {
1652 goto exitAllocInit;
1653 }
1654 }
1655 else if (propOffset < -FDT_ERR_NOTFOUND) {
1656 /* Error returned by LIBFDT */
1657 retVal = propOffset;
1658 goto exitAllocInit;
1659 }
1660 }
1661 if (propOffset < -FDT_ERR_NOTFOUND) {
1662 /* Error returned by LIBFDT */
1663 retVal = propOffset;
1664 goto exitAllocInit;
1665 }
1667 nodeOffset = fdt_next_node(globalResourceDtb, nodeOffset, &nodeDepth);
1668 if (nodeOffset < -FDT_ERR_NOTFOUND) {
1669 /* Error returned by LIBFDT */
1670 retVal = nodeOffset;
1671 goto exitAllocInit;
1672 }
1673 }
1674 exitAllocInit:
1675 return(retVal);
1676 }
1678 /* FUNCTION PURPOSE: Deletes a resource allocator resource node
1679 ***********************************************************************
1680 * DESCRIPTION: Deletes a resource allocator's node based on the given
1681 * resource name, base and length.
1682 */
1683 void rmAllocatorDeleteNode(Rm_Handle rmHandle, const char *resName, int32_t resBase, uint32_t resLen)
1684 {
1685 Rm_Allocator *allocator = rmAllocatorFind(rmHandle, resName);
1686 Rm_ResourceNode findNode;
1687 Rm_ResourceNode *matchingNode;
1689 memset((void *)&findNode, 0, sizeof(findNode));
1690 findNode.base = resBase;
1691 findNode.length = resLen;
1692 matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, &findNode);
1694 if (matchingNode) {
1695 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->allocatorRootEntry, matchingNode);
1696 rmResourceNodeFree(matchingNode);
1697 }
1698 }
1700 /* FUNCTION PURPOSE: Deletes a resource allocator
1701 ***********************************************************************
1702 * DESCRIPTION: Deletes a resource allocator based on the given
1703 * resource name. The resource allocator will be
1704 * removed from the RM instance allocator list.
1705 */
1706 int32_t rmAllocatorDelete(Rm_Handle rmHandle, const char *resourceName)
1707 {
1708 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1709 Rm_Allocator *allocator = rmAllocatorGetAllocatorList(rmHandle);
1710 Rm_Allocator *prevAllocator = NULL;
1711 Rm_ResourceTree *treeRoot;
1712 Rm_ResourceNode *node = NULL;
1713 Rm_ResourceNode *nextNode = NULL;
1714 int32_t retVal = RM_OK;
1716 while (allocator) {
1717 if (strncmp(allocator->resourceName, resourceName, RM_NAME_MAX_CHARS) == 0) {
1718 break;
1719 }
1720 prevAllocator = allocator;
1721 allocator = allocator->nextAllocator;
1722 }
1724 if (allocator) {
1725 if (prevAllocator == NULL) {
1726 if ((rmInst->instType == Rm_instType_SERVER) ||
1727 (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1728 rmInst->u.server.allocators = allocator->nextAllocator;
1729 }
1730 else if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
1731 rmInst->u.cd.allocators = allocator->nextAllocator;
1732 }
1733 }
1734 else {
1735 prevAllocator->nextAllocator = allocator->nextAllocator;
1736 RM_SS_OBJ_WB(rmInst, prevAllocator, Rm_Allocator);
1737 }
1739 /* Destroy tree and return error */
1740 treeRoot = allocator->allocatorRootEntry;
1741 for (node = RB_MIN(_Rm_AllocatorResourceTree, treeRoot); node != NULL; node = nextNode) {
1742 nextNode = RB_NEXT(_Rm_AllocatorResourceTree, treeRoot, node);
1743 RB_REMOVE(_Rm_AllocatorResourceTree, treeRoot, nextNode);
1744 rmResourceNodeFree(node);
1745 }
1746 Rm_osalFree((void *)treeRoot, sizeof(*treeRoot));
1747 Rm_osalFree((void *)allocator, sizeof(*allocator));
1748 }
1749 else {
1750 retVal = RM_ERROR_RES_ALLOCATOR_DOES_NOT_EXIST;
1751 }
1752 return (retVal);
1753 }
1755 /* FUNCTION PURPOSE: Deletes server allocators
1756 ***********************************************************************
1757 * DESCRIPTION: Removes all resource nodes for each
1758 * resource allocator and then deletes the allocator
1759 * itself. Used to free all memory consumed
1760 * by the allocators.
1761 */
1762 void rmAllocatorDeleteResources(Rm_Handle rmHandle)
1763 {
1764 Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1765 Rm_Allocator *allocatorList = rmAllocatorGetAllocatorList(rmHandle);
1766 Rm_Allocator *nextAllocator;
1767 Rm_ResourceTree *resTree;
1768 Rm_ResourceNode *resNode;
1769 Rm_ResourceNode *nextResNode;
1771 while (allocatorList) {
1772 RM_SS_OBJ_INV(rmInst, allocatorList, Rm_Allocator);
1773 nextAllocator = allocatorList->nextAllocator;
1774 resTree = allocatorList->allocatorRootEntry;
1776 if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1777 rmResourceTreeInv(resTree);
1778 }
1779 /* Delete each resource node in the allocator */
1780 for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree); resNode != NULL; resNode = nextResNode) {
1781 nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree, resNode);
1782 RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1783 if (resNode->allocationCount) {
1784 /* Delete all the owners in the resource's owner list */
1785 allocatorResNodeOwnerClear(rmHandle, resNode);
1786 }
1787 rmResourceNodeFree(resNode);
1788 }
1790 Rm_osalFree((void *)resTree, sizeof(*resTree));
1791 Rm_osalFree((void *)allocatorList, sizeof(*allocatorList));
1792 allocatorList = nextAllocator;
1793 }
1794 }