]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - src/rm_allocator.c
420fffd5330a10e3df23f79d4b4cbf3841c0540a
[keystone-rtos/rm-lld.git] / src / rm_allocator.c
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-2015, 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: Checks a resource node's ownership
67  ***********************************************************************
68  * DESCRIPTION: Returns the owner reference count if the provided
69  *              instance node is in the list of resource node owners.
70  *              Otherwise, returns 0.
71  */
72 static int allocatorResNodeIsOwnedBy(Rm_Handle rmHandle, Rm_ResourceNode *node,
73                                      Rm_PolicyValidInstNode *serviceInstNode)
74 {
75     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
76     Rm_Owner *owner = node->ownerList;
78     while (owner) {
79         RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
80         if (owner->instNameNode == serviceInstNode) {
81             return(owner->refCnt);
82         }
83         owner = owner->nextOwner;
84     }
85     return(0);
86 }
88 /* FUNCTION PURPOSE: Increments an owner's refCnt
89  ***********************************************************************
90  * DESCRIPTION: Increments a resource owner's reference count
91  */
92 static void allocatorResNodeOwnerRefCntInc(Rm_Handle rmHandle,
93                                            Rm_ResourceNode *node,
94                                            Rm_PolicyValidInstNode *serviceInstNode)
95 {
96     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
97     Rm_Owner *owner = node->ownerList;
99     while (owner) {
100         RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
101         if (owner->instNameNode == serviceInstNode) {
102             owner->refCnt++;
103             RM_SS_OBJ_WB(rmInst, owner, Rm_Owner);
104             break;
105         }
106         owner = owner->nextOwner;
107     }
110 /* FUNCTION PURPOSE: Decrements an owner's refCnt
111  ***********************************************************************
112  * DESCRIPTION: Decrements a resource owner's reference count
113  */
114 static void allocatorResNodeOwnerRefCntDec(Rm_Handle rmHandle,
115                                            Rm_ResourceNode *node,
116                                            Rm_PolicyValidInstNode *serviceInstNode)
118     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
119     Rm_Owner *owner = node->ownerList;
121     while (owner) {
122         RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
123         if (owner->instNameNode == serviceInstNode) {
124             owner->refCnt--;
125             RM_SS_OBJ_WB(rmInst, owner, Rm_Owner);
126             break;
127         }
128         owner = owner->nextOwner;
129     }
132 /* FUNCTION PURPOSE: Returns an owner's refCnt
133  ***********************************************************************
134  * DESCRIPTION: Returns a resource owner's reference count
135  */
136 static uint16_t allocatorResNodeOwnerGetRefCnt(Rm_Handle rmHandle,
137                                                Rm_ResourceNode *node,
138                                                Rm_PolicyValidInstNode *serviceInstNode)
140     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
141     Rm_Owner *owner = node->ownerList;
143     while (owner) {
144         RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
145         if (owner->instNameNode == serviceInstNode) {
146             return (owner->refCnt);
147         }
148         owner = owner->nextOwner;
149     }
151     return(0);
154 /* FUNCTION PURPOSE: Adds an owner to an allocator resource
155  ***********************************************************************
156  * DESCRIPTION: Adds a RM instance node to a resource node's
157  *              list of owners.  If the owner is already present that
158  *              owner's reference count is incremented
159  */
160 static void allocatorResNodeOwnerAdd(Rm_Handle rmHandle, Rm_ResourceNode *node,
161                                      Rm_PolicyValidInstNode *serviceInstNode)
163     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
164     Rm_Owner *ownerList = node->ownerList;
165     Rm_Owner *newOwner = NULL;
167     if (allocatorResNodeIsOwnedBy(rmHandle, node, serviceInstNode)) {
168         allocatorResNodeOwnerRefCntInc(rmHandle, node, serviceInstNode);
169     }
170     else {
171         newOwner = Rm_osalMalloc(sizeof(*newOwner));
173         if (newOwner) {
174             newOwner->instNameNode = serviceInstNode;
175             newOwner->refCnt = 0;
176             newOwner->nextOwner = NULL;  
178             /* Add owner entry to end of list */
179             if (ownerList) {
180                 RM_SS_OBJ_INV(rmInst, ownerList, Rm_Owner);
181                 while (ownerList->nextOwner) {
182                     ownerList = ownerList->nextOwner;
183                     RM_SS_OBJ_INV(rmInst, ownerList, Rm_Owner);
184                 }
185                 ownerList->nextOwner = newOwner;
186                 RM_SS_OBJ_WB(rmInst, ownerList, Rm_Owner);
187             }
188             else {
189                 node->ownerList = newOwner;
190             }
192             node->allocationCount++;
193             newOwner->refCnt++;
194             newOwner->instNameNode->allocRefCount++;
195             RM_SS_OBJ_WB(rmInst, newOwner, Rm_Owner);
196             RM_SS_OBJ_WB(rmInst, newOwner->instNameNode, Rm_PolicyValidInstNode);
197         }
198     }
201 /* FUNCTION PURPOSE: Compares two resource node's boundaries
202  ***********************************************************************
203  * DESCRIPTION: Returns TRUE if the resource nodes are neighbors from
204  *              a base+length perspective.  Otherwise, returns FALSE.
205  */
206 static int allocatorResNodeBoundaryCompare(Rm_ResourceNode *node1,
207                                            Rm_ResourceNode *node2)
209     uint32_t node1End;
210     uint32_t node2End;
212     if (node1 && node2) {
213         node1End = node1->base + node1->length - 1;
214         node2End = node2->base + node2->length - 1;
215         
216         if (node1->base < node2->base) {
217             if (node1End == (node2->base - 1)) {
218                 return(RM_TRUE);
219             }
220         }
221         else if (node2->base < node1->base) {
222             if (node2End == (node1->base - 1)) {
223                 return(RM_TRUE);
224             }     
225         }
226     }
227     return(RM_FALSE);
230 /* FUNCTION PURPOSE: Compares two resource node's owners
231  ***********************************************************************
232  * DESCRIPTION: Returns TRUE if the owners of two resource nodes 
233  *              are equivalent.  Otherwise, returns FALSE.
234  */
235 static int allocatorResNodeOwnerCompare(Rm_Handle rmHandle,
236                                         Rm_ResourceNode *node1,
237                                         Rm_ResourceNode *node2)
239     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
240     Rm_Owner *node1Owners = node1->ownerList;
241     Rm_Owner *node2Owners = node2->ownerList;
242     int       matchedInst;
244     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
245         while(node2Owners) {
246             Rm_osalBeginMemAccess((void *)node2Owners, sizeof(*node2Owners));
247             node2Owners = node2Owners->nextOwner;
248         }
249         node2Owners = node2->ownerList;
250     }
252     if (node1->allocationCount == node2->allocationCount) {
253         while (node1Owners) {
254             RM_SS_OBJ_INV(rmInst, node1Owners, Rm_Owner);
255             matchedInst = RM_FALSE;
256             while (node2Owners) {
257                 if ((node1Owners->instNameNode == node2Owners->instNameNode) &&
258                     (node1Owners->refCnt == node2Owners->refCnt)) {
259                     matchedInst = RM_TRUE;
260                     break;
261                 }
262                 node2Owners = node2Owners->nextOwner;
263             }
265             if (matchedInst) {
266                 node2Owners = node2->ownerList;
267                 node1Owners = node1Owners->nextOwner;
268             }
269             else {
270                 return(RM_FALSE);
271             }                
272         }
273     }
274     else {
275         return(RM_FALSE);
276     }  
277     
278     return(RM_TRUE);
281 /* FUNCTION PURPOSE: Deletes an owner from an allocator resource
282  ***********************************************************************
283  * DESCRIPTION: Removes a RM owner entry from a resource node's
284  *              list of owners.  If the refCnt for the specified
285  *              owner is greater than 1 only the refCnt is
286  *              decremented
287  */
288 static void allocatorResNodeOwnerDelete(Rm_Handle rmHandle,
289                                         Rm_ResourceNode *node,
290                                         void *serviceInstNode)
292     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;    
293     Rm_Owner *owner = node->ownerList;
294     Rm_Owner *prevOwner = NULL;
296     if (allocatorResNodeIsOwnedBy(rmHandle, node, serviceInstNode) > 1) {
297         allocatorResNodeOwnerRefCntDec(rmHandle, node, serviceInstNode);
298     }
299     else {
300         while (owner) {
301             RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
302             if (owner->instNameNode == serviceInstNode) {
303                 break;             
304             }
305             prevOwner = owner;
306             owner = owner->nextOwner;
307         }
309         if (owner) {
310             if (prevOwner == NULL) {
311                 node->ownerList = owner->nextOwner;
312             }
313             else {
314                 prevOwner->nextOwner = owner->nextOwner;
315                 RM_SS_OBJ_WB(rmInst, prevOwner, Rm_Owner);
316             }
317             
318             node->allocationCount--;
319             owner->instNameNode->allocRefCount--;
320             RM_SS_OBJ_WB(rmInst, owner->instNameNode, Rm_PolicyValidInstNode);
321             Rm_osalFree((void *)owner, sizeof(*owner));
322         }
323     }
326 /* FUNCTION PURPOSE: Copies the owners of a resource node
327  ***********************************************************************
328  * DESCRIPTION: Creates a list of resource owners for the destination
329  *              resource node that is equivalent to the source resource
330  *              node's owners
331  *
332  *              dstNode must be a newly created node without any owners.
333  */
334 static void allocatorResNodeOwnerCopy(Rm_Handle rmHandle,
335                                       Rm_ResourceNode *dstNode,
336                                       Rm_ResourceNode *srcNode)
338     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
339     Rm_Owner *srcOwnerList = srcNode->ownerList;
340     Rm_Owner *dstNewOwner;
341     Rm_Owner *dstPrevOwner;
343     if (dstNode->ownerList != NULL) {
344         return;
345     }
346     dstNode->allocationCount = srcNode->allocationCount;
348     while (srcOwnerList) {
349         RM_SS_OBJ_INV(rmInst, srcOwnerList, Rm_Owner);
350         dstNewOwner = Rm_osalMalloc(sizeof(*dstNewOwner));
351         dstNewOwner->instNameNode = srcOwnerList->instNameNode;
352         dstNewOwner->refCnt = srcOwnerList->refCnt;
353         dstNewOwner->nextOwner = NULL;
354         RM_SS_OBJ_WB(rmInst, dstNewOwner, Rm_Owner);
356         if (dstNode->ownerList == NULL) {
357             dstNode->ownerList = dstNewOwner;
358         }
359         else {
360             dstPrevOwner->nextOwner = dstNewOwner;
361             RM_SS_OBJ_WB(rmInst, dstPrevOwner, Rm_Owner);
362         }
363         dstPrevOwner = dstNewOwner;
364         srcOwnerList = srcOwnerList->nextOwner;
365     }
368 /* FUNCTION PURPOSE: Clears a resource node's owners
369  ***********************************************************************
370  * DESCRIPTION: Deletes all owners from the owners list of a 
371  *              resource node.
372  */
373 static void allocatorResNodeOwnerClear(Rm_Handle rmHandle,
374                                        Rm_ResourceNode *node)
376     Rm_Inst  *rmInst = (Rm_Inst *)rmHandle;
377     Rm_Owner *owner = node->ownerList;
378     Rm_Owner *nextOwner;
380     while (owner) {
381         RM_SS_OBJ_INV(rmInst, owner, Rm_Owner);
382         nextOwner = owner->nextOwner;
383         node->allocationCount--;
384         owner->instNameNode->allocRefCount--;
385         RM_SS_OBJ_WB(rmInst, owner->instNameNode, Rm_PolicyValidInstNode);
386         Rm_osalFree((void *)owner, sizeof(*owner));
387         owner = nextOwner;
388     }
391 /* FUNCTION PURPOSE: Get the status for an allocator resource
392  ***********************************************************************
393  * DESCRIPTION: Called when a resource status request is made.  The
394  *              resource's allocator is searched for the resource base
395  *              and length specified in the transaction.  The 
396  *              resource's owner reference count is returned if the 
397  *              resource range is found.
398  */
399 static int32_t allocatorStatus(Rm_Handle rmHandle, Rm_AllocatorNode *allocator,
400                                Rm_AllocatorOpInfo *opInfo)
402     Rm_ResourceNode  findNode;
403     Rm_ResourceNode *matchingNode = NULL;
404     uint32_t         matchingEnd;
405     uint32_t         findEnd;
406     int32_t          retVal;
408     memset((void *)&findNode, 0, sizeof(findNode));
409     findNode.base = opInfo->resourceInfo->base;
410     findNode.length = opInfo->resourceInfo->length;
411     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot,
412                            &findNode);
414     if (matchingNode) {
415         matchingEnd = matchingNode->base + matchingNode->length - 1;
416         findEnd = findNode.base + findNode.length - 1;
417         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
418             opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
419             opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle,
420                                                                                   matchingNode,
421                                                                                   opInfo->serviceInstNode);
422             retVal = RM_SERVICE_APPROVED;
423         }
424         else {
425             retVal = RM_SERVICE_DENIED_PARTIAL_STATUS;
426         }
427     }
428     else {
429         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
430     }
432     return(retVal);
435 /* FUNCTION PURPOSE: Preallocates an allocator resource
436  ***********************************************************************
437  * DESCRIPTION: Called when an allocate request is made but the base 
438  *              is unspecified.  The preallocation algorithm looks at 
439  *              available resources as well as policy permissions to 
440  *              determine a resource range that satisfies the request.
441  *              If a valid range is found it will be returned for the 
442  *              treeAllocate algorithm to handle.
443  */
444 static int32_t allocatorPreAllocate(Rm_Handle rmHandle,
445                                     Rm_AllocatorNode *allocator,
446                                     Rm_AllocatorOpInfo *opInfo)
447 {   
448     Rm_Inst           *rmInst = (Rm_Inst *)rmHandle;
449     Rm_ResourceNode    findNode;
450     Rm_ResourceNode   *matchingNode = NULL;
451     Rm_ResourceNode   *nextNode;
452     uint32_t           matchingEnd;
453     uint32_t           findEnd;
454     uint32_t           rangeIndex;
455     int                resourceFound = RM_FALSE;
456     Rm_PolicyCheckType policyCheckType;
457     Rm_PolicyCheckCfg  policyCheckCfg;
458     int                nodePassesPolicy;
459     int32_t            retVal = RM_OK;
461     if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) {
462         policyCheckType = Rm_policyCheck_INIT;
463     } else if (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE) {
464         policyCheckType = Rm_policyCheck_USE;
465     } else {
466         retVal = RM_ERROR_INVALID_SERVICE_TYPE;
467         return(retVal);
468     }
470     if (rmInst->instType == Rm_instType_CLIENT_DELEGATE) {
471         /* Set base to first node's base since CD will not have all resources
472          * like Server */
473         matchingNode = RB_MIN(_Rm_AllocatorResourceTree, allocator->resourceRoot);
474         opInfo->resourceInfo->base = matchingNode->base;
475     } else {
476         opInfo->resourceInfo->base = rmPolicyGetResourceBase(allocator->policyRoot,
477                                                              opInfo->serviceInstNode,
478                                                              policyCheckType);
479     }
480     
481     if (retVal != RM_OK) {
482         return (retVal);
483     }
485     if (opInfo->resourceInfo->alignment == RM_RESOURCE_ALIGNMENT_UNSPECIFIED) {
486         /* Get alignment from policy */
487         opInfo->resourceInfo->alignment = rmPolicyGetAllocAlign(allocator->policyRoot);
488     } 
490     if (opInfo->resourceInfo->alignment == 0) {
491         opInfo->resourceInfo->alignment = 1;
492     } 
494     memset((void *)&findNode, 0, sizeof(findNode));
495     findNode.base = opInfo->resourceInfo->base;
496     findNode.length = opInfo->resourceInfo->length;
498     /* Configure policy checking structure */
499     memset((void *)&policyCheckCfg, 0, sizeof(policyCheckCfg));
500     policyCheckCfg.polTree = allocator->policyRoot;
502     do {
503         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot, &findNode);
504         
505         if (matchingNode) {
506             matchingEnd = matchingNode->base + matchingNode->length - 1;
507             findEnd = findNode.base + findNode.length - 1;
508             nodePassesPolicy = RM_BOOL_UNDEF;
509             if ((matchingNode->allocationCount == 0) &&
510                 (findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
511                 /* Attempt to preallocate from node only if not owned by anyone and sits
512                  * within a matching node. */
513                 policyCheckCfg.type = policyCheckType;
514                 policyCheckCfg.validInstNode = opInfo->serviceInstNode;
515                 policyCheckCfg.resourceBase = findNode.base;
516                 policyCheckCfg.resourceLength = findNode.length;
517                 nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg);
519                 if (nodePassesPolicy && (matchingNode->allocationCount > 0)) {
520                     if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
521                         /* Check if instance requesting resource has privileges to share
522                          * a resource already reserved by Linux */
523                         policyCheckCfg.type = Rm_policyCheck_SHARED_LINUX;
524                         nodePassesPolicy = rmPolicyCheckPrivilege(&policyCheckCfg);
525                     }
527                     if (nodePassesPolicy) {
528                         /* Check exclusive privileges of instance requesting resource.  Requesting
529                          * instance with exclusive privileges can't reserve resource if already owned*/
530                         policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
531                         nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg);
532                     }
533                 }
534                 
535                 if (nodePassesPolicy && (matchingNode->allocationCount == 1)) {
536                     /* Check exclusive privileges of instance that currently owns resource */
537                     policyCheckCfg.type = Rm_policyCheck_EXCLUSIVE;
538                     policyCheckCfg.validInstNode = matchingNode->ownerList->instNameNode;
539                     nodePassesPolicy = !rmPolicyCheckPrivilege(&policyCheckCfg);
540                 }
542                 if (retVal != RM_OK) {
543                     break;
544                 }
546                 if (nodePassesPolicy) {
547                     /* Initialize indexer to be first resource value that
548                      * alignment satisfies */
549                     rangeIndex = findNode.base;
550                     if (rangeIndex % opInfo->resourceInfo->alignment) {
551                         rangeIndex += (opInfo->resourceInfo->alignment -
552                                       (rangeIndex %
553                                        opInfo->resourceInfo->alignment));
554                     }
556                     if ((rangeIndex + opInfo->resourceInfo->length - 1) <=
557                         matchingEnd) {
558                         /* Block of unallocated resources within matchingNode
559                          * that satisfies allocate requirements */
560                         opInfo->resourceInfo->base = rangeIndex;
561                         resourceFound = RM_TRUE;
562                         retVal = RM_SERVICE_PROCESSING;
563                     }
564                 }
565             }
567             if (!resourceFound) {
568                 /* Check next resource node for available resources */
569                 if (findNode.base < matchingNode->base) {
570                     findNode.base = matchingNode->base;
571                 }
572                 else {
573                     if (!nodePassesPolicy) {
574                         findNode.base += findNode.length;
575                     }
576                     else {
577                         /* Matching node allocated, move to next node */
578                         if ((nextNode = RB_NEXT(_Rm_AllocatorResourceTree,
579                                                 allocator->resourceRoot,
580                                                 matchingNode))) {
581                             findNode.base = nextNode->base;
582                         }
583                         else {
584                             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
585                         }
586                     }
587                 }
588             }
589         }
590         else {
591             retVal = RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET;
592         }
593     } while ((!resourceFound) && 
594              (retVal != RM_SERVICE_DENIED_RES_ALLOC_REQS_NOT_MET));
596     return(retVal); 
599 /* FUNCTION PURPOSE: Allocates an allocator resource
600  ***********************************************************************
601  * DESCRIPTION: Will attempt to allocate the resource with specified
602  *              base and length from the resource's allocator.  The
603  *              allocation algorithm will verify the allocation against
604  *              the policy permissions for the instance requesting the
605  *              allocation.  If the policy allows the allocation the 
606  *              algorithm will allocate the resource then combine any
607  *              resource nodes that may have become equivalent (in terms
608  *              of ownership) after the allocation.
609  */
610 static int32_t allocatorAllocate(Rm_Handle rmHandle,
611                                  Rm_AllocatorNode *allocator,
612                                  Rm_AllocatorOpInfo *opInfo)
614     Rm_ResourceNode     findNode;
615     Rm_ResourceNode    *matchingNode = NULL;
616     Rm_ResourceNode    *leftNode = NULL;
617     Rm_ResourceNode    *rightNode = NULL;
618     Rm_PolicyCheckType  policyCheckType;
619     Rm_PolicyCheckCfg   checkCfg;
620     int32_t             allocPassesPolicy;
621     int                 combineLeft = RM_FALSE;
622     int                 combineRight = RM_FALSE;
623     uint32_t            findEnd;
624     uint32_t            matchingEnd;
625     int32_t             retVal;
627     if (opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) {
628         policyCheckType = Rm_policyCheck_INIT;
629     } else if (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE) {
630         policyCheckType = Rm_policyCheck_USE;
631     } else {
632         retVal = RM_ERROR_INVALID_SERVICE_TYPE;
633         return (retVal);
634     }
636     memset((void *)&findNode, 0, sizeof(findNode));
637     findNode.base = opInfo->resourceInfo->base;
638     findNode.length = opInfo->resourceInfo->length;
639     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot,
640                            &findNode);
642     /* Prepare privilege checks */
643     memset((void *)&checkCfg, 0, sizeof(checkCfg));
645     if (matchingNode) {
646         findEnd = findNode.base + findNode.length - 1;
647         matchingEnd = matchingNode->base + matchingNode->length - 1;
648         
649         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
650             if (opInfo->serviceInstNode == rmPolicyGetLinuxInstNode(rmHandle)) {
651                 /* Bypass policy checks since Linux Kernel has full
652                  * privileges */
653                 allocPassesPolicy = RM_TRUE;
654             } else {
655                 checkCfg.type           = policyCheckType;
656                 checkCfg.polTree        = allocator->policyRoot;
657                 checkCfg.validInstNode  = opInfo->serviceInstNode;
658                 checkCfg.resourceBase   = findNode.base;
659                 checkCfg.resourceLength = findNode.length;
660                 allocPassesPolicy = rmPolicyCheckPrivilege(&checkCfg);
661                 if (!allocPassesPolicy) {
662                     if (policyCheckType == Rm_policyCheck_INIT) {
663                         retVal = RM_SERVICE_DENIED_INIT_PERM_NOT_GIVEN;
664                     } else {
665                         retVal = RM_SERVICE_DENIED_USE_PERM_NOT_GIVEN;
666                     }
667                 }
669                 if (!allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceInstNode)) {
670                     if (allocPassesPolicy && (matchingNode->allocationCount > 0)) {
671                         if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, rmPolicyGetLinuxInstNode(rmHandle))) {
672                             /* Check if instance requesting resource has privileges to share
673                              * a resource already reserved by Linux */
674                             checkCfg.type = Rm_policyCheck_SHARED_LINUX;
675                             checkCfg.validInstNode = opInfo->serviceInstNode;
676                             allocPassesPolicy = rmPolicyCheckPrivilege(&checkCfg);
677                             if (!allocPassesPolicy) {
678                                 retVal = RM_SERVICE_DENIED_RES_NOT_SHARED_LINUX;
679                             }
680                         }
681                         if (allocPassesPolicy) {
682                             /* Check exclusive privileges of instance requesting resource.  Requesting
683                              * instance with exclusive privileges can't reserve resource if already owned*/
684                             checkCfg.type = Rm_policyCheck_EXCLUSIVE;
685                             checkCfg.validInstNode = opInfo->serviceInstNode;
686                             allocPassesPolicy = !rmPolicyCheckPrivilege(&checkCfg);
687                             if (!allocPassesPolicy) {
688                                 retVal = RM_SERVICE_DENIED_EXCLUSIVE_RES_ALLOCD;
689                             }
690                         }
691                     }
692                     if (allocPassesPolicy && (matchingNode->allocationCount == 1)) {
693                         /* Check exclusive privileges of instance that currently owns resource */
694                         checkCfg.type = Rm_policyCheck_EXCLUSIVE;
695                         checkCfg.validInstNode = matchingNode->ownerList->instNameNode;
696                         allocPassesPolicy = !rmPolicyCheckPrivilege(&checkCfg);
697                         if (!allocPassesPolicy) {
698                             retVal = RM_SERVICE_DENIED_ALLOCD_TO_EXCLUSIVE_INST;
699                         }                
700                     }  
701                 }
702             }
703             
704             if (allocPassesPolicy) {
705                 /* Handle any possible node combinations if requesting instance is
706                  * not already in resource's owner list.  Automatic approval if requesting
707                  * instance is already in owner list. */
708                 if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
709                     /* findNode range matches matchingNode range
710                      *
711                      *   |<--left node-->||<--matched  node-->||<--right node-->| => existing node
712                      *                    |<--alloc request-->|  => requested resources
713                      */                     
714                     leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
715                     rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
716                     RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
717                     allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceInstNode);
719                     if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
720                         allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
721                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
722                         combineLeft = RM_TRUE;
723                     }
724                     if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
725                         allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
726                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
727                         combineRight = RM_TRUE;
728                     }
730                     if (combineLeft && combineRight) {
731                         /* Combine all three nodes into matchingNode */
732                         matchingNode->base = leftNode->base;
733                         matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
735                         allocatorResNodeOwnerClear(rmHandle, leftNode);
736                         rmResourceNodeFree(leftNode);
737                         allocatorResNodeOwnerClear(rmHandle, rightNode);
738                         rmResourceNodeFree(rightNode);                        
739                     }
740                     else if (combineLeft) {
741                         /* Combine left and matching nodes.  Reinsert right. */
742                         matchingNode->base = leftNode->base;
743                         matchingNode->length += leftNode->length;
745                         allocatorResNodeOwnerClear(rmHandle, leftNode);
746                         rmResourceNodeFree(leftNode);
747                         if (rightNode) {
748                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);  
749                         }
750                     }
751                     else if (combineRight) {
752                         /* Combine right and matching nodes.  Reinsert left. */
753                         matchingNode->length += rightNode->length;
755                         allocatorResNodeOwnerClear(rmHandle, rightNode);
756                         rmResourceNodeFree(rightNode);
757                         if (leftNode) {
758                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
759                         }
760                     }
761                     else {
762                         /* No combine. */
763                         if (leftNode) {
764                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
765                         }
766                         if (rightNode) {
767                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
768                         }
769                     }
771                     /* Always reinsert matchingNode */                
772                     RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
773                     
774                     /* Matching node contains new reference count after alloc.  Return new owner count
775                      * and originating instance allocation reference count. */
776                     opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
777                     opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
778                                                                                           opInfo->serviceInstNode);
779                 }   
780                 else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
781                     /* findNode range is subset of matchingNode range and neither boundary is
782                      * equivalent.
783                      *
784                      * |<----------matched node---------->|
785                      *        |<---alloc request--->|
786                      */ 
787                     RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
788                     leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
789                     allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
790                     rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
791                     allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
793                     matchingNode->base = findNode.base;                                    
794                     matchingNode->length = findNode.length;
795                     allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceInstNode);
797                     /* Insert all the nodes */
798                     RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
799                     RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
800                     RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
801                     
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->serviceInstNode);
807                 }  
808                 else {    
809                     if (findNode.base == matchingNode->base) {
810                         /* findNode base and matchingNode base are equivalent.  May be combine
811                          * possibilities to the left
812                          *
813                          * |<---left node (alloc'd)--->||<----------matched node---------->|
814                          *                              |<---findNode (alloc req)--->|
815                          */                         
816                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
817                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
818                         /* Add allocating instance to owner list for compare with leftNode */
819                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceInstNode);
820                         
821                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
822                             allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
823                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
824                             /* Combine leftNode and findNode */
825                             leftNode->length += findNode.length;
826                         }
827                         else {
828                             leftNode = rmResourceNodeNew(findNode.base, findNode.length);
829                             allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
830                         }
832                         /* Account for leftNode in matchingNode */
833                         matchingNode->base = findNode.base + findNode.length;
834                         matchingNode->length = matchingEnd - findEnd;  
836                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
837                         /* Left node contains new reference count after alloc.  Return new owner count
838                          * and originating instance allocation reference count. */
839                         opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
840                         opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, leftNode, 
841                                                                                               opInfo->serviceInstNode);
842                     }
843                     else if (findEnd == matchingEnd) {
844                         /* findNode end and matchingNode end are equivalent.  May be combine
845                          * possibilities to the right
846                          *
847                          * |<----------matched node---------->||<---right node (alloc'd)--->|
848                          *       |<---findNode (alloc req)--->|
849                          */                        
850                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
851                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
852                         /* Add allocating instance to owner list for compare with rightNode */
853                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceInstNode);
854                         
855                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
856                             allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
857                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
858                             /* Combine rightNode and findNode */
859                             rightNode->base = findNode.base;
860                             rightNode->length += findNode.length;
861                         }
862                         else {
863                             rightNode = rmResourceNodeNew(findNode.base, findNode.length);
864                             allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
865                         }
867                         /* Account for rightNode in matchingNode */
868                         matchingNode->length -= findNode.length;  
870                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
871                         /* Right node contains new reference count after alloc.  Return new owner count
872                          * and originating instance allocation reference count. */
873                         opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
874                         opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, rightNode, 
875                                                                                               opInfo->serviceInstNode);
876                     }
877                     /* Remove allocating instance from leftover matchingNode */
878                     allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceInstNode);
879                     RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
880                 }
881                 retVal = RM_SERVICE_APPROVED;
882             }
883         }
884         else {
885             retVal = RM_SERVICE_DENIED_PARTIAL_ALLOCATION;
886         }
887     }
888     else {
889         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
890     }
892     return(retVal);
895 /* FUNCTION PURPOSE: Frees an allocator resource
896  ***********************************************************************
897  * DESCRIPTION: Will attempt to free the resource with specified
898  *              base and length from the resource's allocator.  The
899  *              free algorithm will verify the free request parameters
900  *              match an allocated range for the resource and that the
901  *              range is owned by the instance requesting the free. If
902  *              the free is validated the algorithm will free the 
903  *              resource then combine any resource nodes that may have
904  *              become equivalent (in terms of ownership) after the
905  *              allocation.
906  */
907 static int32_t allocatorFree(Rm_Handle rmHandle, Rm_AllocatorNode *allocator,
908                              Rm_AllocatorOpInfo *opInfo)
910     Rm_ResourceNode  findNode;
911     Rm_ResourceNode *matchingNode = NULL;
912     Rm_ResourceNode *leftNode = NULL;
913     Rm_ResourceNode *rightNode = NULL;
914     int              combineLeft = RM_FALSE;
915     int              combineRight = RM_FALSE;
916     uint32_t         findEnd;
917     uint32_t         matchingEnd;
918     int32_t          retVal;
920     memset((void *)&findNode, 0, sizeof(findNode));
921     findNode.base = opInfo->resourceInfo->base;
922     findNode.length = opInfo->resourceInfo->length;
923     matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot, &findNode);
925     if (matchingNode) {
926         findEnd = findNode.base + findNode.length - 1;
927         matchingEnd = matchingNode->base + matchingNode->length - 1;
928         
929         if ((findNode.base >= matchingNode->base) && (findEnd <= matchingEnd)) {
930             if (matchingNode->allocationCount) {
931                 if (allocatorResNodeIsOwnedBy(rmHandle, matchingNode, opInfo->serviceInstNode)) {
932                     if ((findNode.base == matchingNode->base) && (findEnd == matchingEnd)) {
933                         /* Case 1: Free range equals allocated matched node exactly. Attempt to combine 
934                          *         freed node with nodes to left and right.
935                          *
936                          * |<--left node-->||<---matched node--->||<--right node-->|
937                          *                  |<---free request--->|
938                          */ 
939                         leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
940                         rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
941                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
942                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceInstNode);
944                         if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
945                             allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
946                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
947                             combineLeft = RM_TRUE;
948                         }
949                         if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
950                             allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
951                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
952                             combineRight = RM_TRUE;
953                         }
955                         if (combineLeft && combineRight) {
956                             /* Combine all three nodes into matchingNode */
957                             matchingNode->base = leftNode->base;
958                             matchingNode->length = leftNode->length + matchingNode->length + rightNode->length;
960                             allocatorResNodeOwnerClear(rmHandle, leftNode);
961                             rmResourceNodeFree(leftNode);
962                             allocatorResNodeOwnerClear(rmHandle, rightNode);
963                             rmResourceNodeFree(rightNode);                        
964                         }
965                         else if (combineLeft) {
966                             /* Combine left and matching nodes.  Reinsert right. */
967                             matchingNode->base = leftNode->base;
968                             matchingNode->length += leftNode->length;
970                             allocatorResNodeOwnerClear(rmHandle, leftNode);
971                             rmResourceNodeFree(leftNode);
972                             if (rightNode) {
973                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode); 
974                             }
975                         }
976                         else if (combineRight) {
977                             /* Combine right and matching nodes.  Reinsert left. */
978                             matchingNode->length += rightNode->length;
980                             allocatorResNodeOwnerClear(rmHandle, rightNode);
981                             rmResourceNodeFree(rightNode);
982                             if (leftNode) {
983                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
984                             }
985                         }
986                         else {
987                             /* No combine. */
988                             if (leftNode) {
989                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
990                             }
991                             if (rightNode) {
992                                 RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
993                             }
994                         }
996                         /* Always reinsert matchingNode */
997                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
998                         
999                         /* Matching node is what remains after free.  Return remaining owner count
1000                          * and originating instance allocation reference count. */
1001                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1002                         opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1003                                                                                               opInfo->serviceInstNode);
1004                     }
1005                     else if ((findNode.base > matchingNode->base) && (findEnd < matchingEnd)) {
1006                         /* Case 2: Free range is less than range in matched node. Split
1007                          *         matched node into three nodes.
1008                          *
1009                          * |<----------matched node---------->|
1010                          *        |<---free request--->|
1011                          *
1012                          * Remove instance from owner list then add it back in for side nodes for
1013                          * proper accounting of allocations in validInstance list
1014                          */ 
1015                         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1016                         allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceInstNode);
1017                         
1018                         leftNode = rmResourceNodeNew(matchingNode->base, findNode.base - matchingNode->base);
1019                         allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
1020                         allocatorResNodeOwnerAdd(rmHandle, leftNode, opInfo->serviceInstNode);
1021                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
1022                         
1023                         rightNode = rmResourceNodeNew(findNode.base + findNode.length, matchingEnd - findEnd);
1024                         allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
1025                         allocatorResNodeOwnerAdd(rmHandle, rightNode, opInfo->serviceInstNode);
1026                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
1028                         matchingNode->base = findNode.base;                                    
1029                         matchingNode->length = findNode.length;
1030                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1031                         
1032                         /* Matching node is what remains after free.  Return remaining owner count
1033                          * and originating instance allocation reference count. */
1034                         opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1035                         opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1036                                                                                               opInfo->serviceInstNode);
1037                     }
1038                     else {                        
1039                         if (findNode.base == matchingNode->base) {
1040                             /* Case 3: Free range is on left boundary of matched node. Try to 
1041                              *         combine free range with left node.
1042                              *
1043                              * |<---left node (free)--->||<----------matched node---------->|
1044                              *                           |<---findNode (free req)--->|
1045                              */ 
1047                             leftNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1048                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1049                             /* Remove freeing instance from owner list for compare with leftNode */
1050                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceInstNode);
1051                             
1052                             if (leftNode && allocatorResNodeOwnerCompare(rmHandle, leftNode, matchingNode) &&
1053                                 allocatorResNodeBoundaryCompare(leftNode, matchingNode)) {
1054                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
1055                                 /* Combine leftNode and findNode */
1056                                 leftNode->length += findNode.length;
1057                             }
1058                             else {
1059                                 leftNode = rmResourceNodeNew(findNode.base, findNode.length);
1060                                 allocatorResNodeOwnerCopy(rmHandle, leftNode, matchingNode);
1061                             }
1063                             /* Remove leftNode range from matchingNode */
1064                             matchingNode->base = findNode.base + findNode.length;
1065                             matchingNode->length = matchingEnd - findEnd;  
1066                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, leftNode);
1067                             
1068                             /* Left node is what remains after free.  Return remaining owner count
1069                              * and originating instance allocation reference count. */
1070                             opInfo->resourceInfo->ownerCount = leftNode->allocationCount;
1071                             opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, leftNode,
1072                                                                                                   opInfo->serviceInstNode);
1073                         }
1074                         else if (findEnd == matchingEnd) {
1075                             /* Case 4: Free range is on right boundary of matched node. Try to 
1076                              *         combine free range with right node.
1077                              *
1078                              * |<----------matched node---------->||<---right node (free)--->|
1079                              *        |<---findNode (free req)--->|
1080                              */ 
1081                             
1082                             rightNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1083                             RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode); 
1084                             /* Remove freeing instance from owner list for compare with rightNode */
1085                             allocatorResNodeOwnerDelete(rmHandle, matchingNode, opInfo->serviceInstNode);
1086                             
1087                             if (rightNode && allocatorResNodeOwnerCompare(rmHandle, rightNode, matchingNode) &&
1088                                 allocatorResNodeBoundaryCompare(rightNode, matchingNode)) {
1089                                 RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
1090                                 /* Combine rightNode and findNode */
1091                                 rightNode->base = findNode.base;
1092                                 rightNode->length += findNode.length;
1093                             }
1094                             else {
1095                                 rightNode = rmResourceNodeNew(findNode.base, findNode.length);
1096                                 allocatorResNodeOwnerCopy(rmHandle, rightNode, matchingNode);
1097                             }
1099                             /* Remove rightNode range from matchingNode */
1100                             matchingNode->length -= findNode.length;  
1101                             RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, rightNode);
1102                             
1103                             /* Right node is what remains after free.  Return remaining owner count
1104                              * and originating instance allocation reference count. */
1105                             opInfo->resourceInfo->ownerCount = rightNode->allocationCount;
1106                             opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, rightNode,
1107                                                                                                   opInfo->serviceInstNode);
1108                         }
1110                         /* Add freeing instance back into matchingNode allocations */
1111                         allocatorResNodeOwnerAdd(rmHandle, matchingNode, opInfo->serviceInstNode);
1112                         RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1113                     }
1114                     retVal = RM_SERVICE_APPROVED;
1115                 }
1116                 else {
1117                     /* Return owner count and instance alloc count.  In case it's a reference count
1118                      * check in application */
1119                     opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1120                     opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1121                                                                                           opInfo->serviceInstNode);
1122                     retVal = RM_SERVICE_DENIED_RES_NOT_ALLOCD_TO_INST;
1123                 }
1124             }
1125             else {
1126                 /* Return owner count and instance alloc count.  In case it's a reference count
1127                  * check in application */
1128                 opInfo->resourceInfo->ownerCount = matchingNode->allocationCount;
1129                 opInfo->resourceInfo->instAllocCount = allocatorResNodeOwnerGetRefCnt(rmHandle, matchingNode,
1130                                                                                       opInfo->serviceInstNode);
1131                 retVal = RM_SERVICE_DENIED_RES_ALREADY_FREE;
1132             }
1133         }
1134         else {
1135             retVal = RM_SERVICE_DENIED_PARTIAL_FREE;
1136         }
1137     }
1138     else {
1139         retVal = RM_SERVICE_DENIED_RES_RANGE_DOES_NOT_EXIST;
1140     }
1141     return(retVal);  
1144 /* FUNCTION PURPOSE: Reserves a Linux resource
1145  ***********************************************************************
1146  * DESCRIPTION: Reserves resources for Linux using the base and length
1147  *              values retrieved from the Linux DTB via the
1148  *              "linux-dtb-alias" properties within the GRL.
1149  */
1150 static int32_t allocatorReserveLinuxResource(Rm_Handle rmHandle,
1151                                              Rm_LinuxAlias *linuxAlias,
1152                                              Rm_LinuxValueRange *linuxValues,
1153                                              Rm_AllocatorOpInfo *opInfo)
1155     int32_t  retVal = RM_OK;
1156     int      baseFound = RM_FALSE;
1157     int      lengthFound = RM_FALSE;
1158     uint32_t valueIndex = 0;
1160     while ((linuxValues) && (!baseFound || !lengthFound)) {
1161         if (linuxAlias->baseOffset == valueIndex) {
1162             opInfo->resourceInfo->base = linuxValues->value;
1163             baseFound = RM_TRUE;
1165             if (linuxAlias->lengthOffset ==
1166                 RM_DTB_UTIL_LINUX_ALIAS_OFFSET_NOT_SET) {
1167                 opInfo->resourceInfo->length = 1;
1168                 lengthFound = RM_TRUE;
1169             }
1170         } else if (linuxAlias->lengthOffset == valueIndex) {
1171             opInfo->resourceInfo->length = linuxValues->value;
1172             lengthFound = RM_TRUE;
1173         }
1175         linuxValues = (Rm_LinuxValueRange *)linuxValues->nextValue;
1176         valueIndex++;
1177     }
1179     if (!baseFound || !lengthFound) {
1180         retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1181     } else {
1182         /* Allocate resource to Linux */
1183         retVal = rmAllocatorOperation(rmHandle, opInfo);
1184         if (retVal == RM_SERVICE_APPROVED) {
1185             retVal = RM_OK;
1186         }
1187     }
1188     return(retVal);
1191 /* FUNCTION PURPOSE: Finds and reserves Linux resources
1192  ***********************************************************************
1193  * DESCRIPTION: Parses the Linux DTB for resources consumed by the
1194  *              Linux kernel.  If the resource is found via the
1195  *              "linux-dtb-alias" property defined in the GRL it is 
1196  *              reserved.
1197  */
1198 static int32_t allocatorFindLinuxResource(Rm_Handle rmHandle,
1199                                           const char *resourceName,
1200                                           void *linuxDtb,
1201                                           Rm_LinuxAlias *linuxAlias)
1203     Rm_AllocatorOpInfo  opInfo;
1204     Rm_ResourceInfo     resourceInfo;
1205     uint32_t            pathOffset;
1206     uint32_t            pathSize;
1207     char               *tempAliasPath;
1208     char               *spacePtr;
1209     int32_t             propOffset;
1210     int32_t             nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1211     int32_t             prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1212     int32_t             depth = RM_DTB_UTIL_STARTING_DEPTH;
1213     int32_t             propertyLen;
1214     const char         *propertyName;
1215     const void         *propertyData;
1216     Rm_LinuxValueRange *linValRange;
1217     int32_t             retVal = RM_OK;
1219     memset((void *)&opInfo, 0, sizeof(opInfo));
1220     memset((void *)&resourceInfo, 0, sizeof(resourceInfo));
1222     rm_strncpy(resourceInfo.name, resourceName, RM_NAME_MAX_CHARS);
1223     opInfo.serviceInstNode = rmPolicyGetLinuxInstNode(rmHandle);
1224     opInfo.operation       = Rm_allocatorOp_ALLOCATE_INIT;
1225     opInfo.resourceInfo    = &resourceInfo;
1227     if (!opInfo.serviceInstNode) {
1228         retVal = RM_SERVICE_DENIED_INST_NAME_NOT_VALID;
1229         goto errorExit;
1230     }
1232     while(linuxAlias) {
1233         /* Reset parsing variables */
1234         pathOffset = 0;
1235         pathSize = strlen(linuxAlias->path) + 1;
1236         tempAliasPath = Rm_osalMalloc(pathSize);
1237         rm_strncpy(tempAliasPath, linuxAlias->path, pathSize);
1238         nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1239         prevDepth = RM_DTB_UTIL_STARTING_DEPTH;
1240         resourceInfo.base = 0;
1241         resourceInfo.length = 0;
1243         spacePtr = strpbrk(tempAliasPath, " ");
1244         if (spacePtr) {
1245             *spacePtr = '\0';
1246         }
1248         while(pathOffset < pathSize) {
1249             /* Move through DTB nodes until next alias path node found */
1250             if (strcmp(tempAliasPath + pathOffset,
1251                        fdt_get_name(linuxDtb, nodeOffset, NULL))) {
1252                 nodeOffset = fdt_next_node(linuxDtb, nodeOffset, &depth);
1254                 if ((depth < prevDepth) || (nodeOffset == -FDT_ERR_NOTFOUND)) {
1255                     /* Returning from subnode that matched part of alias path
1256                      * without finding resource values */
1257                     retVal = RM_ERROR_DATA_NOT_FOUND_AT_LINUX_ALIAS;
1258                     break;
1259                 }
1260             } else {
1261                 /* Found next alias path node.  Move to next node name in path
1262                  * string. */
1263                 pathOffset += (strlen(tempAliasPath + pathOffset) + 1);
1264                 spacePtr = strpbrk(tempAliasPath + pathOffset, " ");
1265                 if (spacePtr) {
1266                     *spacePtr = '\0';
1267                 }
1269                 prevDepth = fdt_node_depth(linuxDtb, nodeOffset);
1270                 propOffset = fdt_first_property_offset(linuxDtb, nodeOffset);
1271                 while ((propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1272                        (pathOffset < pathSize)) {
1273                     propertyData = fdt_getprop_by_offset(linuxDtb, propOffset,
1274                                                          &propertyName,
1275                                                          &propertyLen);
1277                     if (strcmp(tempAliasPath + pathOffset, propertyName) == 0) {
1278                         /* Found resource at end of alias path */
1279                         pathOffset += (strlen(tempAliasPath + pathOffset) + 1);
1280                         linValRange = rmDtbUtilLinuxExtractValues(propertyData,
1281                                                                   propertyLen);
1282                         retVal = allocatorReserveLinuxResource(rmHandle,
1283                                                                linuxAlias,
1284                                                                linValRange,
1285                                                                &opInfo);
1286                         rmDtbUtilLinuxFreeValues(linValRange);
1287                     }
1288                     propOffset = fdt_next_property_offset(linuxDtb, propOffset);
1289                 }
1291                 if (propOffset < -FDT_ERR_NOTFOUND) {
1292                     retVal = propOffset;
1293                     break;
1294                 }
1295             }
1296         }
1298         Rm_osalFree(tempAliasPath, pathSize);
1299         if (retVal < RM_OK) {
1300             break;
1301         }
1302         linuxAlias = linuxAlias->nextLinuxAlias;
1303     }
1304 errorExit:
1305     return(retVal);
1308 /* FUNCTION PURPOSE: Populates an allocator's resource tree
1309  ***********************************************************************
1310  * DESCRIPTION: Uses resource range information pulled from GRL to
1311  *              populate an allocator's resource tree
1312  */
1313 static int32_t allocatorPopulateResTree(Rm_ResourceTree *resTree,
1314                                         Rm_ResourceRange *range)
1316     Rm_ResourceNode *resNode = NULL;
1317     int32_t retVal = RM_OK;
1319     while (range != NULL) {
1320         if (resNode = rmResourceNodeNew(range->base, range->length)) {
1321             RB_INSERT(_Rm_AllocatorResourceTree, resTree,
1322                       resNode);
1323         } else {
1324             retVal = RM_ERROR_MALLOC_FAILED_RES_NODE;
1325             break;
1326         }
1327         range = range->nextRange;
1328     }
1330     return(retVal);
1333 /* FUNCTION PURPOSE: Initializes a new allocator
1334  ***********************************************************************
1335  * DESCRIPTION: allocates and initializes a new allocator for the
1336  *              provided resource name.  The resource and policy tree
1337  *              root nodes are allocated and initialized as part of
1338  *              the allocator node initialization.
1339  */
1340 static Rm_AllocatorNode *allocatorInitNode(Rm_Inst *rmInst,
1341                                            const char *resourceName,
1342                                            int32_t *retVal)
1344     Rm_AllocatorTree *allocTree  = rmInst->allocatorTree;
1345     Rm_AllocatorNode *newAllocNode = NULL;
1346     Rm_ResourceTree  *resTree = NULL;
1347     Rm_PolicyTree    *polTree = NULL;
1349     *retVal = RM_OK;
1351     if ((strlen(resourceName) + 1) > RM_NAME_MAX_CHARS) {
1352         *retVal = RM_ERROR_RESOURCE_NAME_TOO_LONG;
1353         goto errorExit;
1354     }
1356     newAllocNode = rmAllocatorNodeNew(resourceName);
1357     if (newAllocNode) {
1358         if (RB_INSERT(_Rm_AllocatorTree, allocTree, newAllocNode)) {
1359             /* Collision */
1360             *retVal = RM_ERROR_RES_SPECIFIED_MORE_THAN_ONCE;
1361             goto errorExit;
1362         }
1364         if (resTree = Rm_osalMalloc(sizeof(*resTree))) {
1365             RB_INIT(resTree);
1366             newAllocNode->resourceRoot = resTree;
1367         } else {
1368             *retVal = RM_ERROR_MALLOC_FAILED_RES_TREE;
1369             goto errorExit;
1370         }
1372         if (polTree = Rm_osalMalloc(sizeof(*polTree))) {
1373             RB_INIT(polTree);
1374             newAllocNode->policyRoot = polTree;
1375         } else {
1376             *retVal = RM_ERROR_MALLOC_FAILED_POL_TREE;
1377             goto errorExit;
1378         }
1379     } else {
1380         *retVal = RM_ERROR_COULD_NOT_CREATE_NEW_ALLOCATOR;
1381         goto errorExit;
1382     }
1384 errorExit:
1385     if ((*retVal != RM_OK) && newAllocNode) {
1386         rmAllocatorNodeFree(newAllocNode);
1387     }
1388     return(newAllocNode);
1391 /* FUNCTION PURPOSE: Creates and initializes an allocator node
1392  ***********************************************************************
1393  * DESCRIPTION: Creates an allocator for the provided resource name.
1394  *              The resource properties retrieved from the GRL are used
1395  *              to create a resource tree.  Resources will be reserved
1396  *              for the Linux kernel if the Linux DTB is provided and
1397  *              there are "linux-dtb-alias" properties specified in
1398  *              the GRL.  A policy tree will be created using the
1399  *              resource's entry in the policy.
1400  */
1401 static int32_t allocatorCreateNode(Rm_Inst *rmInst, void *policyDtb,
1402                                    void *linuxDtb, const char *resourceName,
1403                                    Rm_ResourceProperties *resProps)
1405     Rm_AllocatorNode *allocNode = NULL;
1406     Rm_ResourceRange *range = NULL;
1407     Rm_LinuxAlias    *linuxAlias = NULL;
1408     int32_t           retVal = RM_OK;
1410     allocNode = allocatorInitNode(rmInst, resourceName, &retVal);
1411     if (allocNode) {
1412         range = rmDtbUtilResExtractRange(resProps->rangeData,
1413                                          resProps->rangeLen);
1414         retVal = allocatorPopulateResTree(allocNode->resourceRoot, range);
1415         if (retVal != RM_OK) {
1416             goto errorExit;
1417         }
1418         /* Create the companion policy tree for the resource */
1419         retVal = rmPolicyPopulateTree((Rm_Handle)rmInst, allocNode->policyRoot,
1420                                       policyDtb, resourceName);
1421         if (retVal != RM_OK) {
1422             goto errorExit;
1423         }
1425         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1426             /* Writeback resource tree for Linux resource reservation which
1427              * uses path through rmAllocatorOperation function.  This function
1428              * performs an invalidate of resource tree */
1429             rmResourceTreeWb(allocNode->resourceRoot);
1430         }
1432         if (resProps->linuxAliasData && linuxDtb) {
1433             linuxAlias = rmDtbUtilResExtractLinuxAlias(resProps->linuxAliasData,
1434                                                        resProps->linuxAliasLen,
1435                                                        &retVal);
1436             /* linuxAlias will be NULL if retVal contains error code */
1437             if (linuxAlias) {
1438                 retVal = allocatorFindLinuxResource(rmInst, resourceName,
1439                                                     linuxDtb, linuxAlias);
1440             }
1442             if (retVal != RM_OK) {
1443                 goto errorExit;
1444             }
1445         }
1447 errorExit:
1448         if (range) {
1449             rmDtbUtilResFreeRange(range);
1450         }
1451         if (linuxAlias) {
1452             rmDtbUtilResFreeLinuxAlias(linuxAlias);
1453         }
1454     }
1455     return(retVal);
1458 /* FUNCTION PURPOSE: Creates NameServer assignment entries
1459  ***********************************************************************
1460  * DESCRIPTION: Creates a NameServer entry for each NameServer assignment
1461  *              found in a GRL's resource node
1462  */
1463 static int32_t allocatorNsAdd(Rm_Inst *rmInst, const char *resourceName,
1464                               Rm_ResourceProperties *resProps)
1466     Rm_NsAssignment     *nsAssigns = NULL;
1467     Rm_NsAssignment     *nsAssignsBase = NULL;
1468     Rm_NameServerObjCfg  nsCfg;
1469     int32_t              retVal = RM_OK;
1471     if (resProps->nsAssignData) {
1472         nsAssigns = rmDtbUtilResExtractNsAssignment(resProps->nsAssignData,
1473                                                     resProps->nsAssignLen,
1474                                                     &retVal);
1475         /* nsAssignments will be NULL if retVal contains error code */
1476         if (nsAssigns) {
1477             nsAssignsBase = nsAssigns;
1478             while (nsAssigns) {
1479                 memset((void *)&nsCfg, 0, sizeof(nsCfg));
1480                 nsCfg.nameServerTree = rmInst->u.server.nameServer;
1481                 nsCfg.nodeCfg.objName = nsAssigns->nsName;
1482                 nsCfg.nodeCfg.resourceName = (char *)resourceName;
1483                 nsCfg.nodeCfg.resourceBase= nsAssigns->resourceBase;
1484                 nsCfg.nodeCfg.resourceLength = nsAssigns->resourceLength;
1485                 rmNameServerAddObject(&nsCfg);
1486                 nsAssigns = nsAssigns->nextNsAssignment;
1487             }
1488             rmDtbUtilResFreeNsAssignmentList(nsAssignsBase);
1489         }
1490     }
1492     return(retVal);
1496 /* FUNCTION PURPOSE: Populate the allocator tree based on the GRL
1497  ***********************************************************************
1498  * DESCRIPTION: Populates the allocator tree using the GRL and policy DTBs.
1499  *              Optionally, the Linux DTB will be scanned for resources used
1500  *              by the Kernel if the Linux DTB is non-NULL.
1501  */
1502 static int32_t allocatorPopulateGrlBased(Rm_Inst *rmInst, void *grlDtb,
1503                                          void *policyDtb, void *linuxDtb)
1505     int32_t                nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1506     int32_t                nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1507     Rm_ResourceProperties  resProps;
1508     int32_t                propOffset;
1509     int32_t                propertyLen;
1510     const char            *propertyName;
1511     const void            *propertyData;
1512     Rm_ResourcePropType    propertyType;
1513     int32_t                retVal = RM_OK;
1515     /* Create allocator tree node with resource and policy trees for
1516      * each resource found in the GRL. */
1517     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1518            (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1520         memset((void *)&resProps, 0, sizeof(resProps));
1521         /* Get properties of resource node */
1522         propOffset = fdt_first_property_offset(grlDtb, nodeOffset);
1524         while (propOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1525             propertyData = fdt_getprop_by_offset(grlDtb, propOffset,
1526                                                  &propertyName, &propertyLen);
1527             propertyType = rmDtbUtilResGetPropertyType(propertyName);
1528             switch(propertyType) {
1529                 case Rm_resourcePropType_RESOURCE_RANGE:
1530                     resProps.rangeData = propertyData;
1531                     resProps.rangeLen = propertyLen;
1532                     break;
1533                 case Rm_resourcePropType_NSASSIGNMENT:
1534                     resProps.nsAssignData = propertyData;
1535                     resProps.nsAssignLen = propertyLen;
1536                     break;
1537                 case Rm_resourcePropType_RESOURCE_LINUX_ALIAS:
1538                     resProps.linuxAliasData = propertyData;
1539                     resProps.linuxAliasLen = propertyLen;
1540                     break;
1541                 default:
1542                     retVal = RM_ERROR_GRL_UNKNOWN_RESOURCE_PROPERTY;
1543                     goto errorExit;
1544             }
1546             propOffset = fdt_next_property_offset(grlDtb, propOffset);
1547             if (propOffset == -FDT_ERR_NOTFOUND) {
1548                 const char *resName = fdt_get_name(grlDtb, nodeOffset,
1549                                                    NULL);
1551                 if ((!resProps.rangeData) && (!resProps.nsAssignData)) {
1552                     retVal = RM_ERROR_GRL_INVALID_NODE_DEF;
1553                     goto errorExit;
1554                 }
1556                 if (resProps.rangeData) {
1557                     /* At least range property found.  Create allocator node
1558                      * using extracted values for resource tree and
1559                      * resource's policy entry for policy tree */
1560                     retVal = allocatorCreateNode(rmInst, policyDtb, linuxDtb,
1561                                                  resName, &resProps);
1562                     if (retVal != RM_OK) {
1563                         goto errorExit;
1564                     }
1565                 }
1567                 if (resProps.nsAssignData) {
1568                     retVal = allocatorNsAdd(rmInst, resName, &resProps);
1569                     if (retVal != RM_OK) {
1570                         goto errorExit;
1571                     }
1572                 }
1573             } else if (propOffset < -FDT_ERR_NOTFOUND) {
1574                 /* Error returned by LIBFDT */
1575                 retVal = propOffset;
1576                 goto errorExit;
1577             }
1578         }
1579         if (propOffset < -FDT_ERR_NOTFOUND) {
1580             /* Error returned by LIBFDT */
1581             retVal = propOffset;
1582             goto errorExit;
1583         }
1585         nodeOffset = fdt_next_node(grlDtb, nodeOffset, &nodeDepth);
1586         if (nodeOffset < -FDT_ERR_NOTFOUND) {
1587             /* Error returned by LIBFDT */
1588             retVal = nodeOffset;
1589             goto errorExit;
1590         }
1591     }
1593 errorExit:
1594     return(retVal);
1597 /* FUNCTION PURPOSE: Populate the allocator tree based on the GRL
1598  ***********************************************************************
1599  * DESCRIPTION: Populates the allocator tree using the policy DTB.  The
1600  *              resource trees in each allocator will be created on the fly
1601  *              as a CD requests resources from the server.  Client instances
1602  *              will never create resource trees since they'll only use the
1603  *              allocator's policy trees for the static initialization phase.
1604  */
1605 static int32_t allocatorPopulatePolicyBased(Rm_Inst *rmInst, void *policyDtb)
1607     int32_t            nodeOffset = RM_DTB_UTIL_STARTING_NODE_OFFSET;
1608     int32_t            nodeDepth = RM_DTB_UTIL_STARTING_DEPTH;
1609     int32_t            propOffset;
1610     const char        *resName;
1611     const char        *propName;
1612     Rm_PolicyPropType  propType;
1613     Rm_AllocatorNode  *newAllocNode = NULL;
1614     int32_t            retVal = RM_OK;
1616     /* Search for resource node definitions in the policy */
1617     while ((nodeOffset >= RM_DTB_UTIL_STARTING_NODE_OFFSET) &&
1618            (nodeDepth >= RM_DTB_UTIL_STARTING_DEPTH)) {
1620         propOffset = fdt_first_property_offset(policyDtb, nodeOffset);
1621         while (propOffset > RM_DTB_UTIL_STARTING_NODE_OFFSET) {
1622             fdt_getprop_by_offset(policyDtb, propOffset, &propName, NULL);
1623             propType = rmDtbUtilPolicyGetPropertyType(propName);
1624             if (propType == Rm_policyPropType_ASSIGNMENTS) {
1625                 /* Found a resource node's assignment property.  Create an
1626                  * allocator node for the resource and populate it with a
1627                  * policy tree */
1628                 resName = fdt_get_name(policyDtb, nodeOffset, NULL);
1630                 newAllocNode = allocatorInitNode(rmInst, resName, &retVal);
1631                 if (newAllocNode) {
1632                     retVal = rmPolicyPopulateTree((Rm_Handle)rmInst,
1633                                                   newAllocNode->policyRoot,
1634                                                   policyDtb, resName);
1635                     if (retVal != RM_OK) {
1636                         goto errorExit;
1637                     }
1638                 } else {
1639                     goto errorExit;
1640                 }
1642                 /* Move on to next resource node */
1643                 break;
1644             } else if (propType == Rm_policyPropType_UNKNOWN) {
1645                 retVal = RM_ERROR_UNKNOWN_POLICY_RESOURCE_PROPERTY;
1646                 goto errorExit;
1647             }
1649             propOffset = fdt_next_property_offset(policyDtb, propOffset);
1650         }
1651         if (propOffset < -FDT_ERR_NOTFOUND) {
1652             /* Error returned by LIBFDT */
1653             retVal = propOffset;
1654             goto errorExit;
1655         }
1657         nodeOffset = fdt_next_node(policyDtb, nodeOffset, &nodeDepth);
1658         if (nodeOffset < -FDT_ERR_NOTFOUND) {
1659             /* Error returned by LIBFDT */
1660             retVal = nodeOffset;
1661             goto errorExit;
1662         }
1663     }
1665 errorExit:
1666     return(retVal);
1669 /* FUNCTION PURPOSE: Initializes the allocator tree root
1670  ***********************************************************************
1671  * DESCRIPTION: Initializes the allocator tree root structure
1672  */
1673 static int32_t allocatorTreeRootInit(Rm_Inst *rmInst)
1675     Rm_AllocatorTree *root = NULL;
1676     int32_t           retVal = RM_OK;
1678     root = Rm_osalMalloc(sizeof(*root));
1679     if (root) {
1680         RB_INIT(root);
1681         rmInst->allocatorTree = root;
1682     } else {
1683         retVal = RM_ERROR_COULD_NOT_INIT_ALLOC_TREE;
1684     }
1685     return(retVal);
1688 /**********************************************************************
1689  ********************** Internal Functions ****************************
1690  **********************************************************************/
1692 /* FUNCTION PURPOSE: Finds an allocator
1693  ***********************************************************************
1694  * DESCRIPTION: Returns a pointer to an allocator that matches the 
1695  *              provided resource name.
1696  */
1697 Rm_AllocatorNode *rmAllocatorFind(Rm_Handle rmHandle, const char *resourceName)
1699     Rm_Inst          *rmInst = (Rm_Inst *)rmHandle;
1700     Rm_AllocatorTree *tree = rmInst->allocatorTree;
1701     Rm_AllocatorNode  findNode;
1703     memset((void *)&findNode, 0, sizeof(findNode));
1704     rm_strncpy(findNode.resourceName, resourceName, RM_NAME_MAX_CHARS);
1706     return(RB_FIND(_Rm_AllocatorTree, tree, &findNode));
1709 /* FUNCTION PURPOSE: Checks if a resource node is localized
1710  ***********************************************************************
1711  * DESCRIPTION: Checks if a resource node is localized.  A localized
1712  *              node is one that is free and has no neighboring nodes
1713  *              or neighboring nodes that do not have resource values
1714  *              contiguous with the node being checked.  The function
1715  *              will return RM_TRUE if the node is localized.  
1716  *              Otherwise, the function returns RM_FALSE
1717  */
1718 int rmAllocatorGetNodeLocalization(Rm_Handle rmHandle, char *resourceName,
1719                                    int32_t *resBase, uint32_t *resLen)
1721     uint32_t          allocSize;
1722     Rm_AllocatorNode *allocator = NULL;
1723     Rm_ResourceNode   findNode;
1724     Rm_ResourceNode  *matchingNode = NULL;
1725     Rm_ResourceNode  *neighborNode = NULL;
1726     int               nodeIsLocalized = RM_FALSE;
1728     allocator = rmAllocatorFind(rmHandle, resourceName);
1729     allocSize = rmPolicyGetCdAllocSize(allocator->policyRoot);
1731     /* Nothing to free back to server if policy never specified blocks could
1732      * be allocated to CD */
1733     if (allocSize) {
1734         memset((void *)&findNode, 0, sizeof(findNode));
1735         findNode.base = *resBase;
1736         findNode.length = *resLen;
1737         matchingNode = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot, &findNode);
1739         if (matchingNode) {
1740             /* Node can be freed back to Server from CD if:
1741              * - allocationCount == 0
1742              * - node's resource range is multiple of policy allocation size
1743              * - node's resource range boundaries are not contiguous with surrounding nodes */
1744             if (matchingNode->allocationCount) {
1745                 goto exitLocalization;
1746             }
1748             if (matchingNode->length % allocSize) {
1749                 goto exitLocalization;
1750             }
1752             /* Check left neighbor */
1753             neighborNode = RB_PREV(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1754             if (neighborNode && allocatorResNodeBoundaryCompare(neighborNode, matchingNode)) {
1755                 goto exitLocalization; 
1756             }
1758             /* Check right neighbor */
1759             neighborNode = RB_NEXT(_Rm_AllocatorResourceTree, allocator->resourceRoot, matchingNode);
1760             if (neighborNode && allocatorResNodeBoundaryCompare(neighborNode, matchingNode)) {
1761                 goto exitLocalization; 
1762             }
1764             /* All localization checks passed.  Return the base and length of localized node. */
1765             nodeIsLocalized = RM_TRUE;
1766             *resBase = matchingNode->base;
1767             *resLen = matchingNode->length;
1768         }
1769         else {
1770             nodeIsLocalized = RM_FALSE;
1771         }
1772     }
1774 exitLocalization:
1775     return (nodeIsLocalized);
1778 /* FUNCTION PURPOSE: Issues an allocator operation
1779  ***********************************************************************
1780  * DESCRIPTION: Issues an allocator preallocate, allocate, or free
1781  *              for an RM resource.
1782  */
1783 int32_t rmAllocatorOperation(Rm_Handle rmHandle, Rm_AllocatorOpInfo *opInfo)
1785     Rm_Inst          *rmInst = (Rm_Inst *)rmHandle;
1786     Rm_AllocatorNode *allocator = NULL;
1787     int32_t           retVal;
1789     if (allocator = rmAllocatorFind(rmHandle, opInfo->resourceInfo->name)) {
1790         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1791             rmResourceTreeInv(allocator->resourceRoot);
1792         }
1794         if (opInfo->operation == Rm_allocatorOp_GET_STATUS) {
1795             retVal = allocatorStatus(rmHandle, allocator, opInfo);
1796         } else if ((opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_INIT) ||
1797                    (opInfo->operation == Rm_allocatorOp_PRE_ALLOCATE_USE)) {
1798             retVal = allocatorPreAllocate(rmHandle, allocator, opInfo);
1799         } else if ((opInfo->operation == Rm_allocatorOp_ALLOCATE_INIT) ||
1800                    (opInfo->operation == Rm_allocatorOp_ALLOCATE_USE)) {
1801             retVal = allocatorAllocate(rmHandle, allocator, opInfo);
1802         } else if (opInfo->operation == Rm_allocatorOp_FREE) {
1803             retVal = allocatorFree(rmHandle, allocator, opInfo);
1804         }
1806         if ((rmInst->instType == Rm_instType_SHARED_SERVER) &&
1807             (opInfo->operation != Rm_allocatorOp_GET_STATUS) &&
1808             (retVal == RM_SERVICE_APPROVED)) {
1809             rmResourceTreeWb(allocator->resourceRoot);
1810         }
1811     } else {
1812         /* Resource could not be found in policy and/or allocator */
1813         retVal = RM_SERVICE_DENIED_RES_DOES_NOT_EXIST;
1814     }
1815     return(retVal);
1818 /* FUNCTION PURPOSE: Initializes the allocator tree
1819  ***********************************************************************
1820  * DESCRIPTION: Initializes a RM instance's allocator tree using the
1821  *              supplied GRL and policy
1822  */
1823 int32_t rmAllocatorTreeInit(Rm_Handle rmHandle, void *grlDtb,
1824                             void *policyDtb, void *linuxDtb)
1826     Rm_Inst *rmInst = (Rm_Inst *)rmHandle;
1827     int32_t  retVal = RM_OK;
1829     if ((retVal = allocatorTreeRootInit(rmInst)) != RM_OK) {
1830         goto errorExit;
1831     }
1833     if (grlDtb && policyDtb &&
1834         (rmInst->instType == Rm_instType_SERVER) ||
1835         (rmInst->instType == Rm_instType_SHARED_SERVER)) {
1836         /* Create an allocator for each resource node in GRL.  Companion
1837          * policy info will be pulled and placed into policy tree */
1838         retVal = allocatorPopulateGrlBased(rmInst, grlDtb, policyDtb, linuxDtb);
1839     } else if (policyDtb &&
1840                (rmInst->instType == Rm_instType_CLIENT_DELEGATE) ||
1841                (rmInst->instType == Rm_instType_CLIENT)) {
1842         /* Create an allocator for each resource node in the policy.
1843          * Resource tree portion of the allocator will be NULL.  Resource
1844          * trees will be added at run time for Client Delegate instances.
1845          * Client instances with static policy just need allocators with
1846          * policy information for each resource. */
1847         retVal = allocatorPopulatePolicyBased(rmInst, policyDtb);
1848     } else if ((rmInst->instType != Rm_instType_CLIENT) &&
1849                (rmInst->instType != Rm_instType_SHARED_CLIENT)) {
1850         retVal = RM_ERROR_INVALID_ALLOCATOR_INIT;
1851     }
1853 errorExit:
1854     return(retVal);
1857 /* FUNCTION PURPOSE: Adds a node to a resource tree
1858  ***********************************************************************
1859  * DESCRIPTION: Adds a node to an allocator's resource tree based on the
1860  *              given base and length.
1861  */
1862 int32_t rmAllocatorAddResNode(Rm_Handle rmHandle, Rm_AllocatorNode *allocator,
1863                               int32_t resBase, uint32_t resLen)
1865     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;
1866     Rm_ResourceNode *resNode = NULL;
1867     int32_t retVal = RM_OK;
1869     if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1870         rmResourceTreeInv(allocator->resourceRoot);
1871     }
1873     if (resNode = rmResourceNodeNew(resBase, resLen)) {
1874         if (RB_INSERT(_Rm_AllocatorResourceTree, allocator->resourceRoot,
1875                       resNode)) {
1876             retVal = RM_ERROR_RES_SPECIFIED_MORE_THAN_ONCE;
1877         }
1878     } else {
1879         retVal = RM_ERROR_MALLOC_FAILED_RES_NODE;
1880     }
1882     return(retVal);
1885 /* FUNCTION PURPOSE: Deletes a node from a resource tree
1886  ***********************************************************************
1887  * DESCRIPTION: Deletes a node from an allocator's resource tree based on the
1888  *              given base and length.
1889  */
1890 void rmAllocatorDeleteResNode(Rm_Handle rmHandle, Rm_AllocatorNode *allocator,
1891                               int32_t resBase, uint32_t resLen)
1893     Rm_Inst         *rmInst = (Rm_Inst *)rmHandle;
1894     Rm_ResourceNode  find;
1895     Rm_ResourceNode *match;
1897     memset((void *)&find, 0, sizeof(find));
1898     find.base = resBase;
1899     find.length = resLen;
1900     match = RB_FIND(_Rm_AllocatorResourceTree, allocator->resourceRoot,
1901                     &find);
1902     
1903     if (match) {
1904         RB_REMOVE(_Rm_AllocatorResourceTree, allocator->resourceRoot,
1905                   match);
1906         rmResourceNodeFree(match);
1907         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1908             rmResourceTreeWb(allocator->resourceRoot);
1909         }
1910     }
1913 /* FUNCTION PURPOSE: Deletes allocator tree
1914  ***********************************************************************
1915  * DESCRIPTION: Removes all resource nodes for each allocator node and then
1916  *              deletes the allocator tree root.
1917  */
1918 void rmAllocatorTreeDelete(Rm_Handle rmHandle)
1920     Rm_Inst          *rmInst = (Rm_Inst *)rmHandle;
1921     Rm_AllocatorTree *allocTree = rmInst->allocatorTree;
1922     Rm_AllocatorNode *allocNode;
1923     Rm_AllocatorNode *nextAllocNode;
1924     Rm_ResourceTree  *resTree;
1925     Rm_ResourceNode  *resNode;
1926     Rm_ResourceNode  *nextResNode;
1927     Rm_PolicyTree    *polTree;
1928     Rm_PolicyNode    *polNode;
1929     Rm_PolicyNode    *nextPolNode;
1931     if (allocTree) {
1932         if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1933             rmAllocatorTreeInv(allocTree);
1934         }
1936         for (allocNode = RB_MIN(_Rm_AllocatorTree, allocTree);
1937              allocNode != NULL;
1938              allocNode = nextAllocNode) {
1939             nextAllocNode = RB_NEXT(_Rm_AllocatorTree, allocTree, allocNode);
1941             resTree = allocNode->resourceRoot;
1942             polTree = allocNode->policyRoot;
1944             if (rmInst->instType == Rm_instType_SHARED_SERVER) {
1945                 rmResourceTreeInv(resTree);
1946                 rmPolicyTreeInv(polTree);
1947             }
1949             /* Delete each node in the resource tree */
1950             for (resNode = RB_MIN(_Rm_AllocatorResourceTree, resTree);
1951                  resNode != NULL;
1952                  resNode = nextResNode) {
1953                 nextResNode = RB_NEXT(_Rm_AllocatorResourceTree, resTree,
1954                                       resNode);
1955                 RB_REMOVE(_Rm_AllocatorResourceTree, resTree, resNode);
1956                 if (resNode->allocationCount) {
1957                     /* Delete all the owners in the resource's owner list */
1958                     allocatorResNodeOwnerClear(rmHandle, resNode);
1959                 }
1960                 rmResourceNodeFree(resNode);
1961             }
1962             Rm_osalFree((void *)resTree, sizeof(*resTree));
1964             /* Delete each node in the policy tree */
1965             for (polNode = RB_MIN(_Rm_AllocatorPolicyTree, polTree);
1966                  polNode != NULL;
1967                  polNode = nextPolNode) {
1968                 nextPolNode = RB_NEXT(_Rm_AllocatorPolicyTree, polTree,
1969                                       polNode);
1970                 RB_REMOVE(_Rm_AllocatorPolicyTree, polTree, polNode);
1971                 rmPolicyNodeFree(polNode);
1972             }
1973             Rm_osalFree((void *)polTree, sizeof(*polTree));
1975             RB_REMOVE(_Rm_AllocatorTree, allocTree, allocNode);
1976             rmAllocatorNodeFree(allocNode);
1977         }
1978         Rm_osalFree((void *)allocTree, sizeof(*allocTree));
1979         RM_SS_OBJ_WB(rmInst, rmInst, Rm_Inst);
1980     }