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