1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #if defined(NVRM)
25 #   include "os/os.h"
26 #else
27 #   include "shrdebug.h"
28 #   include "nvos.h"
29 #endif
30 #include "containers/eheap_old.h"
31 
32 #if !defined(SRT_BUILD)
33 #include "os/os.h"
34 #endif
35 
36 static void         initPublicObjectFunctionPointers_EHeap(POBJEHEAP pHeap);
37 static NV_STATUS  eheapInit(POBJEHEAP, NvU64, NvU64, NvU32, NvU32);
38 static NV_STATUS  eheapDestruct(POBJEHEAP);
39 static NV_STATUS  eheapAlloc(POBJEHEAP, NvU32, NvU32 *, NvU64 *, NvU64 *,NvU64, NvU64, PEMEMBLOCK*, void*, EHeapOwnershipComparator*);
40 static NV_STATUS  eheapFree(POBJEHEAP, NvU64);
41 static void       eheapInfo(POBJEHEAP, NvU64 *, NvU64 *, NvU64 *,  NvU64 *, NvU32 *, NvU64 *);
42 static void       eheapInfoForRange(POBJEHEAP, NV_RANGE, NvU64 *,  NvU64 *, NvU32 *, NvU64 *);
43 static NV_STATUS  eheapGetSize(POBJEHEAP, NvU64 *);
44 static NV_STATUS  eheapGetFree(POBJEHEAP, NvU64 *);
45 static NV_STATUS  eheapGetBase(POBJEHEAP, NvU64 *);
46 static PEMEMBLOCK   eheapGetBlock(POBJEHEAP, NvU64, NvBool);
47 static NV_STATUS  eheapSetAllocRange(POBJEHEAP, NvU64, NvU64);
48 static NV_STATUS  eheapTraverse(POBJEHEAP, void *, EHeapTraversalFn, NvS32);
49 static NV_STATUS  _eheapBlockFree(POBJEHEAP pHeap, PEMEMBLOCK block);
50 static NvU32        eheapGetNumBlocks(POBJEHEAP);
51 static NV_STATUS  eheapGetBlockInfo(POBJEHEAP, NvU32, NVOS32_HEAP_DUMP_BLOCK *);
52 static NV_STATUS  eheapSetOwnerIsolation(POBJEHEAP, NvBool, NvU32);
53 static NvBool     _eheapCheckOwnership(POBJEHEAP, void*, NvU64, NvU64, PEMEMBLOCK, EHeapOwnershipComparator*);
54 
55 void
56 constructObjEHeap(POBJEHEAP pHeap, NvU64 Base, NvU64 LimitPlusOne, NvU32 sizeofMemBlock, NvU32 numPreAllocMemStruct)
57 {
58     initPublicObjectFunctionPointers_EHeap(pHeap);
59 
60     eheapInit(pHeap, Base, LimitPlusOne, sizeofMemBlock, numPreAllocMemStruct);
61 }
62 
63 static void
64 initPublicObjectFunctionPointers_EHeap(POBJEHEAP pHeap)
65 {
66     pHeap->eheapDestruct              = eheapDestruct;
67     pHeap->eheapAlloc                 = eheapAlloc;
68     pHeap->eheapFree                  = eheapFree;
69     pHeap->eheapInfo                  = eheapInfo;
70     pHeap->eheapInfoForRange          = eheapInfoForRange;
71     pHeap->eheapGetSize               = eheapGetSize;
72     pHeap->eheapGetFree               = eheapGetFree;
73     pHeap->eheapGetBase               = eheapGetBase;
74     pHeap->eheapGetBlock              = eheapGetBlock;
75     pHeap->eheapSetAllocRange         = eheapSetAllocRange;
76     pHeap->eheapTraverse              = eheapTraverse;
77     pHeap->eheapGetNumBlocks          = eheapGetNumBlocks;
78     pHeap->eheapGetBlockInfo          = eheapGetBlockInfo;
79     pHeap->eheapSetOwnerIsolation     = eheapSetOwnerIsolation;
80 }
81 
82 static NV_STATUS
83 _eheapAllocMemStruct
84 (
85     POBJEHEAP   pHeap,
86     PEMEMBLOCK* ppMemBlock
87 )
88 {
89     if (pHeap->numPreAllocMemStruct > 0)
90     {
91         // We are out of pre-allocated mem data structs
92         if (NULL == pHeap->pFreeMemStructList)
93         {
94             NV_ASSERT(0);
95             return NV_ERR_OPERATING_SYSTEM;
96         }
97 
98         *ppMemBlock = pHeap->pFreeMemStructList;
99         pHeap->pFreeMemStructList = pHeap->pFreeMemStructList->next;
100     }
101     else
102     {
103         *ppMemBlock = portMemAllocNonPaged(pHeap->sizeofMemBlock);
104 
105         if (*ppMemBlock == NULL)
106         {
107             NV_ASSERT(0);
108             return NV_ERR_OPERATING_SYSTEM;
109         }
110         portMemSet(*ppMemBlock, 0, pHeap->sizeofMemBlock);
111     }
112 
113     return NV_OK;
114 }
115 
116 static NV_STATUS
117 _eheapFreeMemStruct
118 (
119     POBJEHEAP   pHeap,
120     PEMEMBLOCK* ppMemBlock
121 )
122 {
123     if (pHeap->numPreAllocMemStruct > 0)
124     {
125         portMemSet(*ppMemBlock, 0, pHeap->sizeofMemBlock);
126 
127         (*ppMemBlock)->next = pHeap->pFreeMemStructList;
128         pHeap->pFreeMemStructList = *ppMemBlock;
129 
130         *ppMemBlock = NULL;
131     }
132     else
133     {
134         portMemFree(*ppMemBlock);
135         *ppMemBlock = NULL;
136     }
137 
138     return NV_OK;
139 }
140 
141 //
142 // Create a heap.  Even though we can return error here the resultant
143 // object must be self consistent (zero pointers, etc) if there were
144 // alloc failures, etc.
145 //
146 static NV_STATUS
147 eheapInit
148 (
149     POBJEHEAP pHeap,
150     NvU64     Base,
151     NvU64     LimitPlusOne,
152     NvU32     sizeofData,
153     NvU32     numPreAllocMemStruct
154 )
155 {
156     PEMEMBLOCK block;
157     NvU32      i;
158 
159     //
160     // Simply create a free heap.
161     //
162     pHeap->base  = Base;
163     pHeap->total = LimitPlusOne - Base;
164     pHeap->rangeLo = pHeap->base;
165     pHeap->rangeHi = pHeap->base + pHeap->total - 1;
166     pHeap->free  = pHeap->total;
167     pHeap->sizeofMemBlock = sizeofData + sizeof(EMEMBLOCK);
168 
169     pHeap->numPreAllocMemStruct = 0;
170     pHeap->pPreAllocAddr        = NULL;
171     pHeap->pBlockList           = NULL;
172     pHeap->pFreeBlockList       = NULL;
173     pHeap->pFreeMemStructList   = NULL;
174     pHeap->numBlocks            = 0;
175     pHeap->pBlockTree           = NULL;
176     pHeap->bOwnerIsolation      = NV_FALSE;
177     pHeap->ownerGranularity     = 0;
178 
179     //
180     // User requested a static eheap that has a list of pre-allocated
181     // EMEMBLOCK data structure.
182     //
183     if (numPreAllocMemStruct > 0)
184     {
185         ++numPreAllocMemStruct; // reserve one for us - see below
186 
187         pHeap->pPreAllocAddr = portMemAllocNonPaged(pHeap->sizeofMemBlock * numPreAllocMemStruct);
188 
189         if (pHeap->pPreAllocAddr)
190         {
191             pHeap->numPreAllocMemStruct = numPreAllocMemStruct;
192             pHeap->pFreeMemStructList = pHeap->pPreAllocAddr;
193 
194             portMemSet(pHeap->pFreeMemStructList, 0, pHeap->sizeofMemBlock * numPreAllocMemStruct);
195 
196             //
197             // Form the list of free mem structures. Just need to utilize the next field of EMEMBLOCK.
198             //
199             for (i = 0; i < numPreAllocMemStruct - 1; i++)
200             {
201                 ((PEMEMBLOCK)((NvU8 *)pHeap->pFreeMemStructList + (i * pHeap->sizeofMemBlock)))->next
202                     = (PEMEMBLOCK)((NvU8 *)pHeap->pFreeMemStructList + (i + 1) * pHeap->sizeofMemBlock);
203             }
204         }
205     }
206 
207     if (_eheapAllocMemStruct(pHeap, &block) != NV_OK)
208     {
209         return NV_ERR_OPERATING_SYSTEM;
210     }
211 
212     block->owner    = NVOS32_BLOCK_TYPE_FREE;
213     block->refCount = 0;
214     block->begin    = Base;
215     block->align    = Base;
216     block->end      = LimitPlusOne - 1;
217     block->prevFree = block;
218     block->nextFree = block;
219     block->next     = block;
220     block->prev     = block;
221     block->pData    = (void*)(block+1);
222 
223     //
224     // Fill in the heap bank info.
225     //
226     pHeap->pBlockList     = block;
227     pHeap->pFreeBlockList = block;
228     pHeap->numBlocks      = 1;
229 
230     portMemSet((void *)&block->node, 0, sizeof(NODE));
231     block->node.keyStart = block->begin;
232     block->node.keyEnd   = block->end;
233     block->node.Data     = (void *)block;
234     if (btreeInsert(&block->node, &pHeap->pBlockTree) != NV_OK)
235     {
236         eheapDestruct(pHeap);
237         return NV_ERR_OPERATING_SYSTEM;
238     }
239 
240     return NV_OK;
241 }
242 
243 static NV_STATUS
244 eheapDestruct
245 (
246     POBJEHEAP pHeap
247 )
248 {
249     PEMEMBLOCK block, blockFirst, blockNext;
250     NvBool     headptr_updated;
251 
252     if (!pHeap->pBlockList)
253         return NV_OK;
254 
255     //
256     // Free all allocated blocks
257     //
258     do {
259         block = blockFirst = pHeap->pBlockList;
260         headptr_updated = NV_FALSE;
261 
262         do {
263             blockNext = block->next;
264 
265             _eheapBlockFree(pHeap, block);
266 
267             // restart scanning the list, if the heap->pBlockList changed
268             if (blockFirst != pHeap->pBlockList) {
269                 headptr_updated = NV_TRUE;
270                 break;
271             }
272 
273             block = blockNext;
274 
275         } while (block != pHeap->pBlockList);
276 
277     } while (headptr_updated);
278 
279     if (pHeap->numPreAllocMemStruct > 0)
280     {
281         // free static blocks
282         portMemFree(pHeap->pPreAllocAddr);
283         pHeap->pPreAllocAddr = NULL;
284     }
285     else
286     {
287         portMemFree(pHeap->pBlockList);
288         pHeap->pBlockList = NULL;
289     }
290 
291     return NV_OK;
292 }
293 
294 // 'flags' using NVOS32_ALLOC_FLAGS_* though some are n/a
295 static NV_STATUS
296 eheapAlloc
297 (
298     POBJEHEAP pHeap,
299     NvU32 owner,
300     NvU32 *flags,
301     NvU64 *offset,
302     NvU64 *size,
303     NvU64 offsetAlign,
304     NvU64 sizeAlign,
305     PEMEMBLOCK * ppMemBlock, // not generally useful over e.g. a split!
306     void *pIsolationID,
307     EHeapOwnershipComparator *checker
308 )
309 {
310     NvU64      allocLo, allocAl, allocHi;
311     PEMEMBLOCK blockFirstFree, blockFree;
312     PEMEMBLOCK blockNew = NULL, blockSplit = NULL;
313     NvU64      desiredOffset;
314     NvU64      allocSize;
315     NvU64      rangeLo, rangeHi;
316 
317     if ((*flags & NVOS32_ALLOC_FLAGS_FORCE_INTERNAL_INDEX) &&
318         (*flags & NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE))
319     {
320         return NV_ERR_INVALID_ARGUMENT;
321     }
322 
323     // Save the offset for fixed address requests, or it's likely uninitialized.
324     desiredOffset = (*flags & NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE) ? *offset: 0;
325 
326     //
327     // zero result so that apps that ignore return code have another
328     // chance to see the error of their ways...
329     //
330     *offset = 0;
331 
332     //
333     // Check for valid size.
334     //
335     if (*size == 0)
336         return NV_ERR_INVALID_ARGUMENT;
337 
338     //
339     // Range-limited the request.
340     //
341     rangeLo = pHeap->rangeLo;
342     rangeHi = pHeap->rangeHi;
343 
344     if (rangeLo == 0 && rangeHi == 0) {
345         rangeLo = pHeap->base;
346         rangeHi = pHeap->base + pHeap->total - 1;
347     }
348     if (rangeHi > pHeap->base + pHeap->total - 1) {
349         rangeHi = pHeap->base + pHeap->total - 1;
350     }
351     if (rangeLo > rangeHi)
352         return NV_ERR_INVALID_ARGUMENT;
353 
354     // Align size up.
355     allocSize = ((*size + (sizeAlign - 1)) / sizeAlign) * sizeAlign;
356 
357     //
358     // Trivial reject size vs. free.
359     //
360     if (pHeap->free < allocSize)
361         return NV_ERR_NO_MEMORY;
362 
363     /* This flag will force an exclusive allocation of the request
364      * within the range of ownerGranularity
365      */
366 
367     if ( *flags & NVOS32_ALLOC_FLAGS_FORCE_INTERNAL_INDEX )
368     {
369         NvU64 desiredOffsetLo, desiredOffsetHi;
370 
371         NV_ASSERT_OR_RETURN(pHeap->ownerGranularity, NV_ERR_INVALID_ARGUMENT);
372         NV_ASSERT_OR_RETURN(pHeap->bOwnerIsolation && checker, NV_ERR_INVALID_ARGUMENT);
373 
374         blockFree = pHeap->pFreeBlockList;
375 
376         if (blockFree == NULL)
377             goto failed;
378 
379         do
380         {
381             desiredOffset = NV_ALIGN_DOWN(blockFree->begin, pHeap->ownerGranularity) + offsetAlign;
382 
383             while (desiredOffset + allocSize - 1 <= blockFree->end)
384             {
385                 desiredOffsetLo = NV_ALIGN_DOWN(desiredOffset, pHeap->ownerGranularity);
386                 desiredOffsetHi = (((desiredOffset % pHeap->ownerGranularity) == 0) ?
387                                     NV_ALIGN_UP((desiredOffset + 1), pHeap->ownerGranularity) :
388                                     NV_ALIGN_UP(desiredOffset, pHeap->ownerGranularity));
389 
390                 if ((desiredOffset >= blockFree->begin) &&
391                     ((desiredOffsetLo >= blockFree->begin) &&
392                      (desiredOffsetHi <= blockFree->end)))
393                 {
394                     if (_eheapCheckOwnership(pHeap, pIsolationID, desiredOffset,
395                             desiredOffset + allocSize - 1, blockFree, checker))
396                     {
397                         allocLo = desiredOffset;
398                         allocHi = desiredOffset + allocSize - 1;
399                         allocAl = allocLo;
400                         goto got_one;
401                     }
402                 }
403 
404                 desiredOffset += pHeap->ownerGranularity;
405             }
406 
407             blockFree = blockFree->nextFree;
408 
409         } while (blockFree != pHeap->pFreeBlockList);
410 
411         /* return error if can't get that particular address */
412         goto failed;
413     }
414 
415     // Ensure a valid allocation type was passed in
416     //if (type > NVOS32_NUM_MEM_TYPES - 1)
417     //return NV_ERR_INVALID_ARGUMENT;
418 
419     //
420     // Check for fixed address request.
421     // This allows caller to say: I really want this memory at a particular
422     //   offset.  Returns error if can't get that offset.
423     //
424     if ( *flags & NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE )
425     {
426         // is our desired offset suitably aligned?
427         if (desiredOffset % offsetAlign)
428             goto failed;
429 
430         blockFree = pHeap->pFreeBlockList;
431 
432         if (blockFree == NULL)
433         {
434             goto failed;
435         }
436 
437         do
438         {
439             //
440             // Allocate from the bottom of the memory block.
441             //
442             blockFree = blockFree->nextFree;
443 
444             // Does this block contain our desired range?
445             if ( (desiredOffset >= blockFree->begin) &&
446                  (desiredOffset + allocSize - 1) <= blockFree->end )
447             {
448                 //
449                 // Make sure no allocated block between ALIGN_DOWN(allocLo, granularity)
450                 // and ALIGN_UP(allocHi, granularity) have a different owner than the current allocation
451                 //
452                 if (pHeap->bOwnerIsolation)
453                 {
454                     NV_ASSERT(NULL != checker);
455                     if (!_eheapCheckOwnership(pHeap, pIsolationID, desiredOffset,
456                              desiredOffset + allocSize - 1, blockFree, checker))
457                     {
458                         break;
459                     }
460                 }
461 
462                 // we have a match, now remove it from the pool
463                 allocLo = desiredOffset;
464                 allocHi = desiredOffset + allocSize - 1;
465                 allocAl = allocLo;
466                 goto got_one;
467             }
468 
469         } while (blockFree != pHeap->pFreeBlockList);
470 
471         // return error if can't get that particular address
472         goto failed;
473     }
474 
475     blockFirstFree = pHeap->pFreeBlockList;
476     if (!blockFirstFree)
477         goto failed;
478 
479     //
480     // When scanning upwards, start at the bottom - 1 so the following loop looks symmetric.
481     //
482     if ( *flags & NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN ) {
483         blockFirstFree = blockFirstFree->prevFree;
484     }
485     blockFree = blockFirstFree;
486     do
487     {
488         NvU64 blockLo;
489         NvU64 blockHi;
490 
491         //
492         // Is this block completely out of range?
493         //
494         if ( ( blockFree->end < rangeLo ) || ( blockFree->begin > rangeHi ) )
495         {
496             if ( *flags & NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN )
497                 blockFree = blockFree->prevFree;
498             else
499                 blockFree = blockFree->nextFree;
500             continue;
501         }
502 
503         //
504         // Find the intersection of the free block and the specified range.
505         //
506         blockLo = (rangeLo > blockFree->begin) ? rangeLo : blockFree->begin;
507         blockHi = (rangeHi < blockFree->end) ? rangeHi : blockFree->end;
508 
509         if ( *flags & NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN )
510         {
511             //
512             // Allocate from the top of the memory block.
513             //
514             allocLo   = (blockHi - allocSize + 1) / offsetAlign * offsetAlign;
515             allocAl   = allocLo;
516             allocHi   = allocAl + allocSize - 1;
517         }
518         else
519         {
520             //
521             // Allocate from the bottom of the memory block.
522             //
523             allocAl   = (blockLo + (offsetAlign - 1)) / offsetAlign * offsetAlign;
524             allocLo   = allocAl;
525             allocHi   = allocAl + allocSize - 1;
526         }
527 
528         //
529         // Make sure no allocated block between ALIGN_DOWN(allocLo, granularity)
530         // and ALIGN_UP(allocHi, granularity) have a different owner than the current allocation
531         //
532         if (pHeap->bOwnerIsolation)
533         {
534             NV_ASSERT(NULL != checker);
535 
536             if (_eheapCheckOwnership(pHeap, pIsolationID, allocLo, allocHi, blockFree, checker))
537             {
538                 goto alloc_done;
539             }
540 
541             //
542             // Try realloc if we still have enough free memory in current free block
543             //
544             if (*flags & NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN)
545             {
546                 NvU64 checkLo = NV_ALIGN_DOWN(allocLo, pHeap->ownerGranularity);
547 
548                 if (checkLo > blockFree->begin)
549                 {
550                     blockHi = checkLo;
551 
552                     allocLo = (blockHi - allocSize + 1) / offsetAlign * offsetAlign;
553                     allocAl = allocLo;
554                     allocHi = allocAl + allocSize - 1;
555 
556                     if (_eheapCheckOwnership(pHeap, pIsolationID, allocLo, allocHi, blockFree, checker))
557                     {
558                         goto alloc_done;
559                     }
560                 }
561             }
562             else
563             {
564                 NvU64 checkHi = NV_ALIGN_UP(allocHi, pHeap->ownerGranularity);
565 
566                 if (checkHi < blockFree->end)
567                 {
568                     blockLo = checkHi;
569 
570                     allocAl = (blockLo + (offsetAlign - 1)) / offsetAlign * offsetAlign;
571                     allocLo = allocAl;
572                     allocHi = allocAl + allocSize - 1;
573 
574                     if (_eheapCheckOwnership(pHeap, pIsolationID, allocLo, allocHi, blockFree, checker))
575                     {
576                         goto alloc_done;
577                     }
578                 }
579             }
580 
581             //
582             // Cannot find any available memory in current free block, go to the next
583             //
584             goto next_free;
585         }
586 
587 alloc_done:
588         //
589         // Does the desired range fall completely within this block?
590         // Also make sure it does not wrap-around.
591         // Also make sure it is within the desired range.
592         //
593         if ((allocLo >= blockFree->begin) && (allocHi <= blockFree->end))
594         {
595             if (allocLo <= allocHi)
596                 if ((allocLo >= rangeLo) && (allocHi <= rangeHi))
597                     goto got_one;
598 
599         }
600 
601 next_free:
602         if ( *flags & NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN )
603             blockFree = blockFree->prevFree;
604         else
605             blockFree = blockFree->nextFree;
606 
607     } while (blockFree != blockFirstFree);
608 
609     //
610     // Out of memory.
611     //
612     goto failed;
613 
614     //
615     // We have a match.  Now link it in, trimming or splitting
616     // any slop from the enclosing block as needed.
617     //
618 
619  got_one:
620 
621     if ((allocLo == blockFree->begin) && (allocHi == blockFree->end))
622     {
623         //
624         // Wow, exact match so replace free block.
625         // Remove from free list.
626         //
627         blockFree->nextFree->prevFree = blockFree->prevFree;
628         blockFree->prevFree->nextFree = blockFree->nextFree;
629         if (pHeap->pFreeBlockList == blockFree)
630         {
631             //
632             // This could be the last free block.
633             //
634             if (blockFree->nextFree == blockFree)
635                 pHeap->pFreeBlockList = NULL;
636             else
637                 pHeap->pFreeBlockList = blockFree->nextFree;
638         }
639 
640         //
641         // Set owner/type values here.  Don't move because some fields are unions.
642         //
643         blockFree->owner    = owner;
644         blockFree->refCount = 1;
645         blockFree->align    = allocAl;
646 
647         // tail end code below assumes 'blockFree' is the new block
648         blockNew = blockFree;
649     }
650     else if ((allocLo >= blockFree->begin) && (allocHi <= blockFree->end))
651     {
652         //
653         // Found a fit.
654         // It isn't exact, so we'll have to do a split
655         //
656         if (_eheapAllocMemStruct(pHeap, &blockNew) != NV_OK)
657         {
658             goto failed;
659         }
660 
661         blockNew->owner     = owner;
662         blockNew->refCount  = 1;
663         blockNew->begin     = allocLo;
664         blockNew->align     = allocAl;
665         blockNew->end       = allocHi;
666 
667         if ((blockFree->begin < blockNew->begin) && (blockFree->end > blockNew->end))
668         {
669             //
670             // Split free block in two.
671             //
672             if (_eheapAllocMemStruct(pHeap, &blockSplit) != NV_OK)
673             {
674                 goto failed;
675             }
676 
677             //
678             // Remove free block from rb-tree since node's range will be
679             // changed.
680             //
681             if (btreeUnlink(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
682             {
683                 goto failed;
684             }
685 
686             blockSplit->owner = NVOS32_BLOCK_TYPE_FREE;
687             blockSplit->refCount = 0;
688             blockSplit->begin = blockNew->end + 1;
689             blockSplit->align = blockSplit->begin;
690             blockSplit->end   = blockFree->end;
691             blockSplit->pData = (void*)(blockNew+1);
692             blockFree->end    = blockNew->begin - 1;
693             //
694             // Insert free split block into free list.
695             //
696             blockSplit->nextFree = blockFree->nextFree;
697             blockSplit->prevFree = blockFree;
698             blockSplit->nextFree->prevFree = blockSplit;
699             blockFree->nextFree = blockSplit;
700             //
701             //  Insert new and split blocks into block list.
702             //
703             blockNew->next   = blockSplit;
704             blockNew->prev   = blockFree;
705             blockSplit->next = blockFree->next;
706             blockSplit->prev = blockNew;
707             blockFree->next  = blockNew;
708             blockSplit->next->prev = blockSplit;
709 
710             // update numBlocks count
711             pHeap->numBlocks++;
712 
713             // re-insert updated free block into rb-tree
714             blockFree->node.keyEnd = blockFree->end;
715             if (btreeInsert(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
716             {
717                 goto failed;
718             }
719 
720             // insert new and split blocks into rb-tree
721             portMemSet((void *)&blockNew->node, 0, sizeof(NODE));
722             portMemSet((void *)&blockSplit->node, 0, sizeof(NODE));
723             blockNew->node.keyStart   = blockNew->begin;
724             blockNew->node.keyEnd     = blockNew->end;
725             blockNew->node.Data       = (void *)blockNew;
726             blockSplit->node.keyStart = blockSplit->begin;
727             blockSplit->node.keyEnd   = blockSplit->end;
728             blockSplit->node.Data     = (void *)blockSplit;
729             if (btreeInsert(&blockNew->node, &pHeap->pBlockTree) != NV_OK)
730             {
731                 goto failed;
732             }
733             if (btreeInsert(&blockSplit->node, &pHeap->pBlockTree) != NV_OK)
734             {
735                 goto failed;
736             }
737         }
738         else if (blockFree->end == blockNew->end)
739         {
740             //
741             // Remove free block from rb-tree since node's range will be
742             // changed.
743             //
744             if (btreeUnlink(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
745             {
746                 goto failed;
747             }
748 
749             //
750             // New block inserted after free block.
751             //
752             blockFree->end = blockNew->begin - 1;
753             blockNew->next = blockFree->next;
754             blockNew->prev = blockFree;
755             blockFree->next->prev = blockNew;
756             blockFree->next       = blockNew;
757 
758             // re-insert updated free block into rb-tree
759             blockFree->node.keyEnd = blockFree->end;
760             if (btreeInsert(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
761             {
762                 goto failed;
763             }
764 
765             // insert new block into rb-tree
766             portMemSet((void *)&blockNew->node, 0, sizeof(NODE));
767             blockNew->node.keyStart = blockNew->begin;
768             blockNew->node.keyEnd   = blockNew->end;
769             blockNew->node.Data     = (void *)blockNew;
770             if (btreeInsert(&blockNew->node, &pHeap->pBlockTree) != NV_OK)
771             {
772                 goto failed;
773             }
774         }
775         else if (blockFree->begin == blockNew->begin)
776         {
777             //
778             // Remove free block from rb-tree since node's range will be
779             // changed.
780             //
781             if (btreeUnlink(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
782             {
783                 goto failed;
784             }
785 
786             //
787             // New block inserted before free block.
788             //
789             blockFree->begin = blockNew->end + 1;
790             blockFree->align = blockFree->begin;
791             blockNew->next   = blockFree;
792             blockNew->prev   = blockFree->prev;
793             blockFree->prev->next = blockNew;
794             blockFree->prev       = blockNew;
795             if (pHeap->pBlockList == blockFree)
796                 pHeap->pBlockList  = blockNew;
797 
798             // re-insert updated free block into rb-tree
799             blockFree->node.keyStart = blockFree->begin;
800             if (btreeInsert(&blockFree->node, &pHeap->pBlockTree) != NV_OK)
801             {
802                 goto failed;
803             }
804 
805             // insert new block into rb-tree
806             portMemSet((void *)&blockNew->node, 0, sizeof(NODE));
807             blockNew->node.keyStart = blockNew->begin;
808             blockNew->node.keyEnd   = blockNew->end;
809             blockNew->node.Data     = (void *)blockNew;
810             if (btreeInsert(&blockNew->node, &pHeap->pBlockTree) != NV_OK)
811             {
812                 goto failed;
813             }
814         }
815         else
816         {
817     failed:
818             if (blockNew)   _eheapFreeMemStruct(pHeap, &blockNew);
819             if (blockSplit) _eheapFreeMemStruct(pHeap, &blockSplit);
820             return NV_ERR_NO_MEMORY;
821         }
822 
823         pHeap->numBlocks++;
824     }
825 
826     NV_ASSERT(blockNew != NULL); // assert is for Coverity
827     pHeap->free -= blockNew->end - blockNew->begin + 1;  // Reduce free amount by allocated block size.
828 
829     // Initialize a pointer to the outer wrapper's specific control structure, tacked to the end of the EMEMBLOCK
830     blockNew->pData    = (void*)(blockNew+1);
831 
832     // Return values
833     *size       = allocSize;
834     *offset     = blockNew->align;
835     if ( ppMemBlock) *ppMemBlock = blockNew;
836 
837     return NV_OK;
838 }
839 
840 static NV_STATUS
841 _eheapBlockFree
842 (
843     POBJEHEAP  pHeap,
844     PEMEMBLOCK block
845 )
846 {
847     PEMEMBLOCK blockTmp;
848 
849     //
850     // Check for valid owner.
851     //
852     if (block->owner == NVOS32_BLOCK_TYPE_FREE) return NV_ERR_INVALID_ARGUMENT;
853 
854     //
855     // Check refCount.
856     //
857     if (--block->refCount != 0)
858         return NV_OK;
859 
860     //
861     // Update free count.
862     //
863     pHeap->free += block->end - block->begin + 1;
864 
865     //
866     //
867     // Can this merge with any surrounding free blocks?
868     //
869     if ((block->prev->owner == NVOS32_BLOCK_TYPE_FREE) && (block != pHeap->pBlockList))
870     {
871         //
872         // Remove block to be freed and previous one since nodes will be
873         // combined into single one.
874         //
875         if (btreeUnlink(&block->node, &pHeap->pBlockTree) != NV_OK)
876         {
877             return NV_ERR_INVALID_OFFSET;
878         }
879         if (btreeUnlink(&block->prev->node, &pHeap->pBlockTree) != NV_OK)
880         {
881             return NV_ERR_INVALID_OFFSET;
882         }
883 
884         //
885         // Merge with previous block.
886         //
887         block->prev->next = block->next;
888         block->next->prev = block->prev;
889         block->prev->end  = block->end;
890         blockTmp = block;
891         block    = block->prev;
892         pHeap->numBlocks--;
893         _eheapFreeMemStruct(pHeap, &blockTmp);
894 
895         // re-insert updated free block into rb-tree
896         block->node.keyEnd = block->end;
897         if (btreeInsert(&block->node, &pHeap->pBlockTree) != NV_OK)
898         {
899             return NV_ERR_INVALID_OFFSET;
900         }
901     }
902     if ((block->next->owner == NVOS32_BLOCK_TYPE_FREE) && (block->next != pHeap->pBlockList))
903     {
904         //
905         // Remove block to be freed and next one since nodes will be
906         // combined into single one.
907         //
908         if (btreeUnlink(&block->node, &pHeap->pBlockTree) != NV_OK)
909         {
910             return NV_ERR_INVALID_OFFSET;
911         }
912         if (btreeUnlink(&block->next->node, &pHeap->pBlockTree) != NV_OK)
913         {
914             return NV_ERR_INVALID_OFFSET;
915         }
916 
917         //
918         // Merge with next block.
919         //
920         block->prev->next    = block->next;
921         block->next->prev    = block->prev;
922         block->next->begin   = block->begin;
923         if (pHeap->pBlockList == block)
924             pHeap->pBlockList  = block->next;
925         if (block->owner == NVOS32_BLOCK_TYPE_FREE)
926         {
927             if (pHeap->pFreeBlockList == block)
928                 pHeap->pFreeBlockList  = block->nextFree;
929             block->nextFree->prevFree = block->prevFree;
930             block->prevFree->nextFree = block->nextFree;
931         }
932         blockTmp = block;
933         block    = block->next;
934         pHeap->numBlocks--;
935         _eheapFreeMemStruct(pHeap, &blockTmp);
936 
937         // re-insert updated free block into rb-tree
938         block->node.keyStart = block->begin;
939         if (btreeInsert(&block->node, &pHeap->pBlockTree) != NV_OK)
940         {
941             return NV_ERR_INVALID_OFFSET;
942         }
943     }
944     if (block->owner != NVOS32_BLOCK_TYPE_FREE)
945     {
946         //
947         // Nothing was merged.  Add to free list.
948         //
949         blockTmp = pHeap->pFreeBlockList;
950         if (!blockTmp)
951         {
952             pHeap->pFreeBlockList = block;
953             block->nextFree       = block;
954             block->prevFree       = block;
955         }
956         else
957         {
958             if (blockTmp->begin > block->begin)
959                 //
960                 // Insert into beginning of free list.
961                 //
962                 pHeap->pFreeBlockList = block;
963             else if (blockTmp->prevFree->begin > block->begin)
964                 //
965                 // Insert into free list.
966                 //
967                 do
968                 {
969                     blockTmp = blockTmp->nextFree;
970                 } while (blockTmp->begin < block->begin);
971                 /*
972             else
973                  * Insert at end of list.
974                  */
975             block->nextFree = blockTmp;
976             block->prevFree = blockTmp->prevFree;
977             block->prevFree->nextFree = block;
978             blockTmp->prevFree           = block;
979         }
980     }
981     block->owner   = NVOS32_BLOCK_TYPE_FREE;
982     //block->mhandle = 0x0;
983     block->align   = block->begin;
984 
985     portMemSet((block+1), 0, pHeap->sizeofMemBlock - sizeof(EMEMBLOCK));
986 
987     return NV_OK;
988 }
989 
990 static NV_STATUS
991 eheapFree
992 (
993     POBJEHEAP pHeap,
994     NvU64 offset
995 )
996 {
997     PEMEMBLOCK block;
998 
999     block = (PEMEMBLOCK) eheapGetBlock(pHeap, offset, 0);
1000     if (!block)
1001         return NV_ERR_INVALID_OFFSET;
1002 
1003     return _eheapBlockFree(pHeap, block);
1004 }
1005 
1006 static PEMEMBLOCK
1007 eheapGetBlock
1008 (
1009     POBJEHEAP  pHeap,
1010     NvU64      offset,
1011     NvBool     bReturnFreeBlock
1012 )
1013 {
1014     PEMEMBLOCK block;
1015     PNODE pNode;
1016 
1017     if (btreeSearch(offset, &pNode, pHeap->pBlockTree) != NV_OK)
1018     {
1019         return NULL;
1020     }
1021 
1022     block = (PEMEMBLOCK)pNode->Data;
1023     if ((block->owner == NVOS32_BLOCK_TYPE_FREE ) && !bReturnFreeBlock)
1024     {
1025         return NULL;
1026     }
1027 
1028     return block;
1029 }
1030 
1031 static NV_STATUS
1032 eheapGetSize
1033 (
1034     POBJEHEAP pHeap,
1035     NvU64     *size
1036 )
1037 {
1038     *size = pHeap->total;
1039     return NV_OK;
1040 }
1041 
1042 static NV_STATUS
1043 eheapGetFree
1044 (
1045     POBJEHEAP pHeap,
1046     NvU64     *free
1047 )
1048 {
1049     *free = pHeap->free;
1050     return NV_OK;
1051 }
1052 
1053 static NV_STATUS
1054 eheapGetBase
1055 (
1056     POBJEHEAP pHeap,
1057     NvU64 *base
1058 )
1059 {
1060     *base = pHeap->base;
1061     return NV_OK;
1062 }
1063 
1064 static void
1065 eheapInfo
1066 (
1067     POBJEHEAP pHeap,
1068     NvU64 *pBytesFree,           // in all of the space managed
1069     NvU64 *pBytesTotal,          // in all of the space managed
1070     NvU64 *pLargestFreeOffset,   // constrained to pHeap->rangeLo, pHeap->rangeHi
1071     NvU64 *pLargestFreeSize,     // constrained to pHeap->rangeLo, pHeap->rangeHi
1072     NvU32 *pNumFreeBlocks,
1073     NvU64 *pUsableBytesFree      // constrained to pHeap->rangeLo, pHeap->rangeHi
1074 )
1075 {
1076     NV_RANGE range = rangeMake(pHeap->rangeLo, pHeap->rangeHi);
1077 
1078     if (pBytesFree)
1079     {
1080         *pBytesFree  = pHeap->free;
1081     }
1082     if (pBytesTotal)
1083     {
1084         *pBytesTotal = pHeap->total;
1085     }
1086     eheapInfoForRange(pHeap, range, pLargestFreeOffset, pLargestFreeSize, pNumFreeBlocks, pUsableBytesFree);
1087 }
1088 
1089 static void
1090 eheapInfoForRange
1091 (
1092     POBJEHEAP pHeap,
1093     NV_RANGE  range,
1094     NvU64 *pLargestFreeOffset,   // constrained to rangeLo, rangeHi
1095     NvU64 *pLargestFreeSize,     // constrained to rangeLo, rangeHi
1096     NvU32 *pNumFreeBlocks,
1097     NvU64 *pUsableBytesFree      // constrained to rangeLo, rangeHi
1098 )
1099 {
1100     PEMEMBLOCK blockFirstFree, blockFree;
1101     NvU64 freeBlockSize = 0;
1102     NvU64 largestFreeOffset = 0;
1103     NvU64 largestFreeSize = 0;
1104     NvU32 numFreeBlocks = 0;
1105 
1106     if (pUsableBytesFree)
1107         *pUsableBytesFree = 0;
1108 
1109     blockFirstFree = pHeap->pFreeBlockList;
1110     if (blockFirstFree)
1111     {
1112         NV_ASSERT( range.lo <= range.hi );
1113 
1114         blockFree = blockFirstFree;
1115         do {
1116             NvU64 clampedBlockBegin = (blockFree->begin >= range.lo) ?
1117                 blockFree->begin : range.lo;
1118             NvU64 clampedBlockEnd = (blockFree->end <= range.hi) ?
1119                 blockFree->end : range.hi;
1120             if (clampedBlockBegin <= clampedBlockEnd)
1121             {
1122                 numFreeBlocks++;
1123                 freeBlockSize = clampedBlockEnd - clampedBlockBegin + 1;
1124 
1125                 if (pUsableBytesFree)
1126                     *pUsableBytesFree += freeBlockSize;
1127 
1128                 if ( freeBlockSize > largestFreeSize )
1129                 {
1130                     largestFreeOffset = clampedBlockBegin;
1131                     largestFreeSize   = freeBlockSize;
1132                 }
1133             }
1134             blockFree = blockFree->nextFree;
1135         } while (blockFree != blockFirstFree);
1136     }
1137 
1138     if (pLargestFreeOffset)
1139     {
1140         *pLargestFreeOffset = largestFreeOffset;
1141     }
1142     if (pLargestFreeSize)
1143     {
1144         *pLargestFreeSize = largestFreeSize;
1145     }
1146     if (pNumFreeBlocks)
1147     {
1148         *pNumFreeBlocks = numFreeBlocks;
1149     }
1150 }
1151 
1152 static NV_STATUS
1153 eheapSetAllocRange
1154 (
1155     POBJEHEAP pHeap,
1156     NvU64 rangeLo,
1157     NvU64 rangeHi
1158 )
1159 {
1160 
1161     if ( rangeLo < pHeap->base )
1162         rangeLo = pHeap->base;
1163 
1164     if ( rangeHi > (pHeap->base + pHeap->total - 1) )
1165         rangeHi = (pHeap->base + pHeap->total - 1);
1166 
1167     if ( rangeHi < rangeLo )
1168         return NV_ERR_INVALID_ARGUMENT;
1169 
1170     pHeap->rangeLo = rangeLo;
1171     pHeap->rangeHi = rangeHi;
1172 
1173     return NV_OK;
1174 }
1175 
1176 static NV_STATUS
1177 eheapTraverse
1178 (
1179     POBJEHEAP pHeap,
1180     void *pEnv,
1181     EHeapTraversalFn traversalFn,
1182     NvS32 direction
1183 )
1184 {
1185     NvU32 cont = 1, backAtFirstBlock = 0;
1186     PEMEMBLOCK pBlock, pBlockNext;
1187     NV_STATUS rc;
1188     NvU64 cursorOffset;                   // for dealing with cursor invalidates.
1189     NvU64 firstBlockBegin, firstBlockEnd; // we'll never call the traversal fn twice on the same (sub)extent.
1190 
1191     pBlock = (direction > 0) ? pHeap->pBlockList : pHeap->pBlockList->prev;
1192     NV_ASSERT_OR_RETURN(pBlock != NULL, NV_ERR_INVALID_STATE);
1193 
1194     //
1195     // Cursor invalidates mean we can't compare with 'pHeap->pBlockList'.
1196     // Instead we'll compare with the extent.  If we intersect it at all in
1197     // a later block then we'll consider that as having returned to the first block.
1198     //
1199     firstBlockBegin = pBlock->begin;
1200     firstBlockEnd   = pBlock->end;
1201 
1202     do
1203     {
1204         NvU32 invalCursor = 0;
1205 
1206         if ( direction > 0 )
1207         {
1208             pBlockNext = pBlock->next;
1209             cursorOffset = pBlockNext->begin;
1210         }
1211         else
1212         {
1213             pBlockNext = pBlock->prev;
1214             cursorOffset = pBlockNext->end;
1215         }
1216 
1217         rc = traversalFn(pHeap, pEnv, pBlock, &cont, &invalCursor);
1218 
1219         if ( invalCursor )
1220         {
1221             // A block was added at or freed.  So far only freeing the current block.
1222             pBlock = eheapGetBlock(pHeap, cursorOffset, 1 /*return even if it is a free block*/);
1223 
1224             // Advance to the next block if the cursor block was merged.
1225             if ((direction > 0) && (pBlock->begin < cursorOffset))
1226             {
1227                 pBlock = pBlock->next;
1228             }
1229             else if ((direction <= 0) && (pBlock->end > cursorOffset))
1230             {
1231                 pBlock = pBlock->prev;
1232             }
1233         }
1234         else
1235         {
1236             // No change to the list, use the fast way to find the next block.
1237             pBlock = pBlockNext;
1238 
1239         }
1240 
1241         NV_ASSERT_OR_RETURN(pBlock != NULL, NV_ERR_INVALID_STATE); // 1. list is circular, 2. cursorOffset should always be found unless the list is badly malformed.
1242 
1243         //
1244         // Back to first block?  Defined as being at a block for which the
1245         // intersection with the original first block is non-null.
1246         //
1247         if ( ((firstBlockBegin >= pBlock->begin ) && (firstBlockBegin <= pBlock->end)) ||
1248              ((firstBlockEnd   <= pBlock->end )   && (firstBlockEnd >= pBlock->begin)) )
1249         {
1250             backAtFirstBlock = 1;
1251         }
1252 
1253     } while (cont && !backAtFirstBlock);
1254 
1255     return rc;
1256 }
1257 
1258 /*!
1259  * @brief returns number of blocks in eHeap.
1260  *
1261  * @param[in] pHeap: pointer to eHeap struct to get data from
1262  *
1263  * @returns the number of blocks (free or allocated) currently in the heap
1264  */
1265 static NvU32
1266 eheapGetNumBlocks
1267 (
1268     POBJEHEAP pHeap
1269 )
1270 {
1271     return pHeap->numBlocks;
1272 }
1273 
1274 /*!
1275  * @brief Copies over block information for each block
1276  * in the heap into the provided buffer.
1277  *
1278  * @param[in] pHeap: pointer to eHeap struct to get data from
1279  * @param[in] numBlocks: number of blocks passed in block buffer
1280  * @param[out] pBlockBuffer: pointer to buffer where info will be copied to
1281  *
1282  * @return 'NV_OK' Operation completed successfully
1283  *         'NV_ERR_INVALID_ARGUMENT' size of buffer passed in is
1284  *          incorrect
1285  *         'NV_ERR_INVALID_STATE' if the blocklist doesn't match the
1286  *          heapSize
1287  */
1288 static NV_STATUS
1289 eheapGetBlockInfo
1290 (
1291     POBJEHEAP pHeap,
1292     NvU32 numBlocks,
1293     NVOS32_HEAP_DUMP_BLOCK *pBlockBuffer
1294 )
1295 {
1296     PEMEMBLOCK pBlock;
1297     NvU32 heapSize, i;
1298     NV_STATUS rmStatus = NV_OK;
1299 
1300     // ensure buffer is the same numBlocks
1301     heapSize = eheapGetNumBlocks(pHeap);
1302     NV_ASSERT_OR_RETURN(heapSize == numBlocks, NV_ERR_INVALID_ARGUMENT);
1303 
1304     pBlock = pHeap->pBlockList;
1305     for (i = 0; i < heapSize; i++)
1306     {
1307         pBlockBuffer->begin = pBlock->begin;
1308         pBlockBuffer->align = pBlock->align;
1309         pBlockBuffer->end = pBlock->end;
1310         pBlockBuffer->owner = pBlock->owner;
1311         pBlockBuffer->format = 0; // EMEMBLOCK does not have format, ignore for now
1312         pBlock = pBlock->next;
1313         if (pBlock == NULL)
1314         {
1315             return NV_ERR_INVALID_STATE;
1316         }
1317         pBlockBuffer++;
1318     }
1319 
1320     return rmStatus;
1321 }
1322 
1323 /**
1324  * @brief Set up block owner isolation
1325  *
1326  * Owner isolation means that no two block owners can own allocations which live within a specified range.
1327  *
1328  * @param[in] pHeap         pointer to EHEAP object
1329  * @param[in] bEnable       NV_TRUE to enable the allocation isolation
1330  * @param[in] granularity   allocation granularity
1331  *
1332  * @return NV_OK on success
1333  */
1334 NV_STATUS
1335 eheapSetOwnerIsolation
1336 (
1337     POBJEHEAP pHeap,
1338     NvBool    bEnable,
1339     NvU32     granularity
1340 )
1341 {
1342     // This can only be set before any allocations have occurred.
1343     if (pHeap->free != pHeap->total)
1344     {
1345         return NV_ERR_INVALID_STATE;
1346     }
1347     // Saying no 2 block owners can share the same block doesn't make sense.
1348     if (bEnable && granularity < 2)
1349     {
1350         return NV_ERR_INVALID_ARGUMENT;
1351     }
1352 
1353     if (bEnable && (granularity & (granularity-1)))
1354     {
1355         return NV_ERR_INVALID_ARGUMENT;
1356     }
1357     pHeap->bOwnerIsolation = bEnable;
1358     pHeap->ownerGranularity = granularity;
1359 
1360     return NV_OK;
1361 }
1362 
1363 /**
1364  * @brief Check heap block ownership
1365  *
1366  * @param[in] pHeap         Pointer to EHEAP object
1367  * @param[in] pIsolationID  Unique isolation ID constructed by the caller
1368  * @param[in] allocLo       Allocated range low
1369  * @param[in] allocHi       Allocated range high
1370  * @param[in] blockFree     Free block list
1371  * @param[in] pChecker      Caller defined ownership ID comparator
1372  *
1373  * @return NV_TRUE if success
1374  */
1375 static NvBool
1376 _eheapCheckOwnership
1377 (
1378     POBJEHEAP                 pHeap,
1379     void                     *pIsolationID,
1380     NvU64                     allocLo,
1381     NvU64                     allocHi,
1382     PEMEMBLOCK                blockFree,
1383     EHeapOwnershipComparator *pComparator
1384 )
1385 {
1386     EMEMBLOCK *pTmpBlock;
1387     NvU64      checkLo = NV_ALIGN_DOWN(allocLo, pHeap->ownerGranularity);
1388     NvU64      checkHi = (((allocHi % pHeap->ownerGranularity) == 0) ?
1389                             NV_ALIGN_UP((allocHi + 1), pHeap->ownerGranularity) :
1390                             NV_ALIGN_UP(allocHi, pHeap->ownerGranularity));
1391     NvU64      check;
1392 
1393     checkLo = (checkLo <= pHeap->base) ? pHeap->base : checkLo;
1394     checkHi = (checkHi >= pHeap->base + pHeap->total - 1) ? (pHeap->base + pHeap->total - 1) : checkHi;
1395 
1396     NV_ASSERT(NULL != blockFree);
1397 
1398     if (blockFree->begin > checkLo || blockFree->end < checkHi)
1399     {
1400         for (check = checkLo; check < checkHi; /* in-loop */)
1401         {
1402             pTmpBlock = pHeap->eheapGetBlock(pHeap, check, NV_TRUE);
1403             NV_ASSERT(pTmpBlock);
1404 
1405             if (pTmpBlock->owner != NVOS32_BLOCK_TYPE_FREE)
1406             {
1407                 if (!pComparator(pIsolationID, pTmpBlock->pData))
1408                 {
1409                     return NV_FALSE;
1410                 }
1411             }
1412 
1413             check = pTmpBlock->end + 1;
1414         }
1415     }
1416 
1417     return NV_TRUE;
1418 }
1419