1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-2024 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 /*!
25  * @file
26  * @brief  Memory descriptor handling utility routines.
27  */
28 
29 #include "gpu/mem_mgr/mem_desc.h"
30 
31 #include "gpu/bif/kernel_bif.h"
32 
33 #include "os/os.h"
34 
35 #include "gpu_mgr/gpu_mgr.h"
36 #include "core/locks.h"
37 #include "mem_mgr/io_vaspace.h"
38 #include "mem_mgr/virt_mem_mgr.h"
39 #include "core/system.h"
40 #include "vgpu/vgpu_util.h"
41 #include "platform/sli/sli.h"
42 #include "resserv/rs_client.h"
43 
44 #include "gpu/mem_mgr/virt_mem_allocator.h"
45 
46 #include "rmconfig.h"
47 #include "vgpu/rpc.h"
48 #include "mem_mgr/mem.h"
49 
50 #include "gpu/mem_mgr/mem_mgr.h"
51 #include "gpu/mem_mgr/mem_utils.h"
52 
53 #include "gpu/mem_mgr/heap.h"
54 
55 #include "gpu/mem_sys/kern_mem_sys.h"
56 #include "mem_mgr/video_mem.h"
57 
58 #include "mem_mgr/ctx_buf_pool.h"
59 
60 #include "nvrm_registry.h" // For memdescOverrideInstLoc*()
61 
62 #include "rmapi/rmapi.h"
63 #include "rmapi/rs_utils.h"
64 #include "class/cl0071.h" // NV01_MEMORY_SYSTEM_OS_DESCRIPTOR
65 
66 #include "gpu/bus/kern_bus.h"
67 
68 // Structure for keeping track of BAR1 mappings
69 typedef struct
70 {
71     NvU64 FbAperture;
72     NvU64 FbApertureLen;
73     NvP64 pPriv;
74 } FB_MAPPING_INFO;
75 
76 //
77 // Common address space lists
78 //
79 const NV_ADDRESS_SPACE ADDRLIST_FBMEM_PREFERRED[] = {ADDR_FBMEM, ADDR_SYSMEM, ADDR_UNKNOWN};
80 const NV_ADDRESS_SPACE ADDRLIST_SYSMEM_PREFERRED[] = {ADDR_SYSMEM, ADDR_FBMEM, ADDR_UNKNOWN};
81 const NV_ADDRESS_SPACE ADDRLIST_FBMEM_ONLY[] = {ADDR_FBMEM, ADDR_UNKNOWN};
82 const NV_ADDRESS_SPACE ADDRLIST_SYSMEM_ONLY[] = {ADDR_SYSMEM, ADDR_UNKNOWN};
83 
84 // XXX These could probably encode the whole list in the u32 bits.
memdescAddrSpaceListToU32(const NV_ADDRESS_SPACE * addrlist)85 NvU32 memdescAddrSpaceListToU32(const NV_ADDRESS_SPACE *addrlist)
86 {
87     if (addrlist == ADDRLIST_FBMEM_PREFERRED)
88         return 1;
89     else if (addrlist == ADDRLIST_SYSMEM_PREFERRED)
90         return 2;
91     else if (addrlist == ADDRLIST_FBMEM_ONLY)
92         return 3;
93     else if (addrlist == ADDRLIST_SYSMEM_ONLY)
94         return 4;
95     else
96         return 0;
97 }
98 
memdescU32ToAddrSpaceList(NvU32 index)99 const NV_ADDRESS_SPACE *memdescU32ToAddrSpaceList(NvU32 index)
100 {
101     switch (index)
102     {
103         case 1: return ADDRLIST_FBMEM_PREFERRED;
104         case 2: return ADDRLIST_SYSMEM_PREFERRED;
105         case 3: return ADDRLIST_FBMEM_ONLY;
106         case 4: return ADDRLIST_SYSMEM_ONLY;
107         default:
108             return NULL;
109     }
110 }
111 
112 /*
113  * @brief Setting a MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE has to initialize
114  *        pHeap and bUsingSubAllocator flags
115  */
_memdescSetSubAllocatorFlag(OBJGPU * pGpu,PMEMORY_DESCRIPTOR pMemDesc,NvBool bSet)116 static NV_STATUS _memdescSetSubAllocatorFlag
117 (
118     OBJGPU *pGpu,
119     PMEMORY_DESCRIPTOR pMemDesc,
120     NvBool  bSet
121 )
122 {
123     NV_ASSERT_OR_RETURN(pGpu != NULL, NV_ERR_INVALID_ARGUMENT);
124 
125     if (!bSet)
126     {
127         NV_PRINTF(LEVEL_ERROR,
128                   "Unsetting MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE not supported\n");
129         NV_ASSERT(0);
130         return NV_ERR_INVALID_ARGUMENT;
131     }
132 
133     NV_ASSERT(!(pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL));
134 
135     // Set flag forcing the allocation to fall into suballocator
136     pMemDesc->_flags |= MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE;
137 
138     {
139         Heap *pHeap = pMemDesc->pHeap;
140         NvBool bForceSubheap = NV_FALSE;
141 
142         NV_ASSERT(pHeap == NULL || pHeap->heapType == HEAP_TYPE_PHYS_MEM_SUBALLOCATOR);
143 
144         if (pMemDesc->_flags & MEMDESC_FLAGS_FORCE_ALLOC_FROM_SUBHEAP)
145         {
146             bForceSubheap = NV_TRUE;
147         }
148 
149         if (pHeap == NULL)
150             pHeap = memmgrGetDeviceSuballocator(GPU_GET_MEMORY_MANAGER(pGpu), bForceSubheap);
151 
152         NV_ASSERT_OR_RETURN(pHeap != NULL, NV_ERR_INVALID_STATE);
153 
154         if (pHeap->heapType == HEAP_TYPE_PHYS_MEM_SUBALLOCATOR)
155         {
156             NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &pMemDesc->gfid));
157             pMemDesc->bUsingSuballocator = NV_TRUE;
158         }
159     }
160 
161     return NV_OK;
162 }
163 
164 /*!
165  * @brief Initializing GFID for guest allocated memdescs
166  */
_memdescSetGuestAllocatedFlag(OBJGPU * pGpu,PMEMORY_DESCRIPTOR pMemDesc,NvBool bSet)167 static NV_STATUS _memdescSetGuestAllocatedFlag
168 (
169     OBJGPU *pGpu,
170     PMEMORY_DESCRIPTOR pMemDesc,
171     NvBool  bSet
172 )
173 {
174 // for VGPU header scrubbing in Open Orin package
175 
176     NV_ASSERT_OR_RETURN(pGpu != NULL, NV_ERR_INVALID_ARGUMENT);
177 
178     if (!bSet)
179     {
180         NV_PRINTF(LEVEL_ERROR,
181                   "Unsetting MEMDESC_FLAGS_GUEST_ALLOCATED not supported\n");
182         NV_ASSERT(0);
183         return NV_ERR_INVALID_ARGUMENT;
184     }
185 
186     NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &pMemDesc->gfid));
187     pMemDesc->_flags |= MEMDESC_FLAGS_GUEST_ALLOCATED;
188 
189     return NV_OK;
190 }
191 
192 /*!
193  *  @brief Allocate and initialize a new empty memory descriptor
194  *
195  *  Allocate a new memory descriptor. This allocates the memory descriptor
196  *  only. memdescAlloc or memdescDescribe are later used to allocate or associate
197  *  memory to the memory descriptor.
198  *
199  *  This routine takes size and the physical contiguous of the future allocation
200  *  in order to size the PTE array for non-contiguous requests.
201  *
202  *  memdescDestroy should be called to free a memory descriptor.
203  *
204  *  If MEMDESC_FLAGS_PRE_ALLOCATED is specified, use the memory descriptor
205  *  supplied by the client instead of allocating a new one.
206  *
207  *  @param[out]  ppMemDesc              Return pointer to new memory descriptor
208  *  @param[in]   pGpu
209  *  @param[in]   Size                   Size of memory descriptor in bytes.
210  *  @param[in]   PhysicallyContiguous   Need physical contig or can it be scattered?
211  *  @param[in]   AddressSpace           NV_ADDRESS_SPACE requested
212  *  @param[in]   CpuCacheAttrib         CPU cacheability requested
213  *  @param[in]   Flags                  MEMDESC_FLAGS_*
214  *
215  *  @returns NV_OK on success
216  */
217 NV_STATUS
memdescCreate(MEMORY_DESCRIPTOR ** ppMemDesc,OBJGPU * pGpu,NvU64 Size,NvU64 Alignment,NvBool PhysicallyContiguous,NV_ADDRESS_SPACE AddressSpace,NvU32 CpuCacheAttrib,NvU64 Flags)218 memdescCreate
219 (
220     MEMORY_DESCRIPTOR **ppMemDesc,
221     OBJGPU *pGpu,
222     NvU64 Size,
223     NvU64 Alignment,
224     NvBool PhysicallyContiguous,
225     NV_ADDRESS_SPACE AddressSpace,
226     NvU32 CpuCacheAttrib,
227     NvU64 Flags
228 )
229 {
230     MEMORY_DESCRIPTOR *pMemDesc;
231     NvU64              allocSize, MdSize, PageCount;
232     NvU32              gpuCacheAttrib = NV_MEMORY_UNCACHED;
233     NV_STATUS          status         = NV_OK;
234 
235 
236     allocSize = Size;
237 
238     //
239     // this memdesc may have gotten forced to sysmem if no carveout,
240     // but for VPR it needs to be in vidmem, so check and re-direct here,
241     // unless running with zero-FB
242     //
243     if ((AddressSpace != ADDR_UNKNOWN) &&
244         (Flags & MEMDESC_ALLOC_FLAGS_PROTECTED) &&
245         (!pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) ||
246          gpuIsCacheOnlyModeEnabled(pGpu)))
247     {
248         AddressSpace = ADDR_FBMEM;
249     }
250 
251     if (pGpu != NULL)
252     {
253         MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
254 
255         if (((AddressSpace == ADDR_SYSMEM) || (AddressSpace == ADDR_UNKNOWN)) &&
256             !(Flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL))
257         {
258             if (pMemoryManager && pMemoryManager->sysmemPageSize)
259             {
260                 allocSize = RM_ALIGN_UP(allocSize, pMemoryManager->sysmemPageSize);
261                 if (allocSize < Size)
262                 {
263                     return NV_ERR_INVALID_ARGUMENT;
264                 }
265             }
266         }
267 
268         if (RMCFG_FEATURE_PLATFORM_MODS || IsT194(pGpu) || IsT234(pGpu))
269         {
270             if ( (AddressSpace == ADDR_FBMEM) &&
271                 !(Flags & MEMDESC_ALLOC_FLAGS_PROTECTED) &&
272                 memmgrGetUsableMemSizeMB_HAL(pGpu, pMemoryManager) == 0 &&
273                 gpuIsUnifiedMemorySpaceEnabled(pGpu))
274             {
275                 // On Tegra, force sysmem if carveout and SMMU are not available
276                 AddressSpace = ADDR_SYSMEM;
277                 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_ALL_INST_IN_SYSMEM))
278                 {
279                     CpuCacheAttrib = pGpu->instCacheOverride;
280                 }
281             }
282 
283             //
284             // Support for aligned contiguous SYSMEM allocations.
285             //
286             if ((AddressSpace == ADDR_SYSMEM || AddressSpace == ADDR_UNKNOWN) &&
287                 PhysicallyContiguous && (Alignment > RM_PAGE_SIZE))
288             {
289                 if (!portSafeAddU64(allocSize, (Alignment - RM_PAGE_SIZE), &allocSize))
290                 {
291                     return NV_ERR_INVALID_ARGUMENT;
292                 }
293             }
294         }
295     }
296 
297     //
298     //
299     // Note that we allocate one extra PTE, since we don't know what the PteAdjust
300     // is yet; if the PteAdjust is zero, we simply won't use it.  This is in the
301     // MEMORY_DESCRIPTOR structure definition.
302     //
303     // RM_PAGE_SIZE is 4k and RM_PAGE_SHIFT is 12, so shift operation can be
304     // modified from ((allocSize + RM_PAGE_SIZE-1) >> RM_PAGE_SHIFT) to below as
305     // (4k >> 12 = 1). This modification helps us to avoid overflow of variable
306     // allocSize, in case caller of this function passes highest value of NvU64.
307     //
308     // If allocSize is passed as 0, PageCount should be returned as 0.
309     //
310     if (allocSize == 0)
311     {
312         PageCount = 0;
313     }
314     else
315     {
316         PageCount = ((allocSize - 1) >> RM_PAGE_SHIFT) + 1;
317     }
318 
319     if (PhysicallyContiguous)
320     {
321         MdSize = sizeof(MEMORY_DESCRIPTOR);
322     }
323     else
324     {
325         MdSize = sizeof(MEMORY_DESCRIPTOR) +
326             (sizeof(RmPhysAddr) * PageCount);
327         NV_ASSERT(MdSize <= 0xffffffffULL);
328         if (MdSize > 0xffffffffULL)
329             return NV_ERR_INSUFFICIENT_RESOURCES;
330     }
331 
332     if (Flags & MEMDESC_FLAGS_PAGED_SYSMEM)
333     {
334         // The flag MEMDESC_FLAGS_PAGED_SYSMEM is only for Windows
335         return NV_ERR_NOT_SUPPORTED;
336     }
337 
338     if (Flags & MEMDESC_FLAGS_PRE_ALLOCATED)
339     {
340         // Only fixed sized memDesc can be supported
341         if (PhysicallyContiguous == NV_FALSE)
342         {
343             return NV_ERR_BUFFER_TOO_SMALL;
344         }
345 
346         NV_ASSERT_OR_RETURN(*ppMemDesc, NV_ERR_NOT_SUPPORTED);
347 
348         pMemDesc = *ppMemDesc;
349     }
350     else
351     {
352         pMemDesc = portMemAllocNonPaged((NvU32)MdSize);
353         if (pMemDesc == NULL)
354         {
355             return NV_ERR_NO_MEMORY;
356         }
357     }
358 
359     portMemSet(pMemDesc, 0, (NvU32)MdSize);
360 
361     // Fill in initial non-zero parameters
362     pMemDesc->pGpu                 = pGpu;
363     pMemDesc->Size                 = Size;
364     pMemDesc->PageCount            = PageCount;
365     pMemDesc->ActualSize           = allocSize;
366     pMemDesc->_addressSpace        = AddressSpace;
367     pMemDesc->RefCount             = 1;
368     pMemDesc->DupCount             = 1;
369     pMemDesc->_subDeviceAllocCount = 1;
370     pMemDesc->_flags               = Flags;
371     pMemDesc->_gpuCacheAttrib      = gpuCacheAttrib;
372     pMemDesc->_gpuP2PCacheAttrib   = NV_MEMORY_UNCACHED;
373     pMemDesc->Alignment            = Alignment;
374     pMemDesc->gfid                 = GPU_GFID_PF;
375     pMemDesc->bUsingSuballocator   = NV_FALSE;
376     pMemDesc->bDeferredFree        = NV_FALSE;
377     pMemDesc->numaNode             = NV0000_CTRL_NO_NUMA_NODE;
378 
379     pMemDesc->libosRegionHandle    = 0;
380     pMemDesc->baseVirtualAddress   = 0;
381 
382     // parameter to determine page granularity
383     pMemDesc->pageArrayGranularity = RM_PAGE_SIZE;
384 
385     memdescSetCpuCacheAttrib(pMemDesc, CpuCacheAttrib);
386 
387     // Set any additional flags
388     pMemDesc->_flags               |= MEMDESC_FLAGS_KERNEL_MODE;
389     if (PhysicallyContiguous)
390         pMemDesc->_flags |= MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS;
391     else
392         pMemDesc->_flags &= ~MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS;
393 
394     // OBJHEAP may not be created at this time and pMemDesc->pHeap may be NULL after this if-else
395     if (Flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL)
396     {
397         pMemDesc->_flags |= MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL;
398         pMemDesc->_flags &= ~MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE;
399     }
400     else if (Flags & MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE)
401     {
402         NV_ASSERT_OK_OR_GOTO(status, _memdescSetSubAllocatorFlag(pGpu, pMemDesc, NV_TRUE), failed);
403     }
404 
405     // In case of guest allocated memory, just initialize GFID
406     if (Flags & MEMDESC_FLAGS_GUEST_ALLOCATED)
407     {
408         NV_ASSERT_OK_OR_GOTO(status, _memdescSetGuestAllocatedFlag(pGpu, pMemDesc, NV_TRUE), failed);
409     }
410 
411 failed:
412     if (status != NV_OK)
413     {
414         if (!(Flags & MEMDESC_FLAGS_PRE_ALLOCATED))
415         {
416             portMemFree(pMemDesc);
417         }
418     }
419     else
420     {
421         *ppMemDesc = pMemDesc;
422     }
423 
424     return status;
425 }
426 
427 /*!
428  *  @brief Initialize an caller allocated memory descriptor
429  *
430  *  Helper to make it easier to get the memDesc **, and typically used
431  *  with memdescDescribe.
432  *
433  *  Only can be used for physically contiguous regions with a fixed
434  *  size PTE array.
435  *
436  *  memdescDestroy should be called to free a memory descriptor.
437  *
438  *  If MEMDESC_FLAGS_PRE_ALLOCATED is specified, use the memory descriptor
439  *  supplied by the client instead of allocating a new one.
440  *
441  *  @param[out]  pMemDesc               Return pointer to new memory descriptor
442  *  @param[in]   pGpu
443  *  @param[in]   Size                   Size of memory descriptor in bytes
444  *  @param[in]   AddressSpace           NV_ADDRESS_SPACE requested
445  *  @param[in]   CpuCacheAttrib         CPU cacheability requested
446  *  @param[in]   Flags                  MEMDESC_FLAGS_*
447  *
448  *  @returns void with no malloc there should be no failure cases
449  */
450 void
memdescCreateExisting(MEMORY_DESCRIPTOR * pMemDesc,OBJGPU * pGpu,NvU64 Size,NV_ADDRESS_SPACE AddressSpace,NvU32 CpuCacheAttrib,NvU64 Flags)451 memdescCreateExisting
452 (
453     MEMORY_DESCRIPTOR *pMemDesc,
454     OBJGPU *pGpu,
455     NvU64 Size,
456     NV_ADDRESS_SPACE AddressSpace,
457     NvU32 CpuCacheAttrib,
458     NvU64 Flags
459 )
460 {
461     NV_STATUS status;
462     status = memdescCreate(&pMemDesc, pGpu, Size, 0, NV_TRUE, AddressSpace,
463                            CpuCacheAttrib,
464                            Flags | MEMDESC_FLAGS_PRE_ALLOCATED | MEMDESC_FLAGS_SKIP_RESOURCE_COMPUTE);
465     NV_ASSERT(status == NV_OK);
466 }
467 
468 
469 /*!
470  * Increment ref count
471  */
memdescAddRef(MEMORY_DESCRIPTOR * pMemDesc)472 void memdescAddRef
473 (
474     MEMORY_DESCRIPTOR *pMemDesc
475 )
476 {
477     NV_ASSERT(pMemDesc != NULL);
478     ++(pMemDesc->RefCount);
479 }
480 
481 /*!
482  * Decrement ref count
483  */
memdescRemoveRef(MEMORY_DESCRIPTOR * pMemDesc)484 void memdescRemoveRef
485 (
486     MEMORY_DESCRIPTOR *pMemDesc
487 )
488 {
489     NV_ASSERT_OR_RETURN_VOID(pMemDesc != NULL);
490     --(pMemDesc->RefCount);
491 }
492 
493 //
494 // Destroy all IOMMU mappings under this memdesc, including child
495 // mappings for root memdescs.
496 //
497 // TODO: merge the new IOMMU paths with the SMMU paths (see bug 1625121).
498 //
499 static void
_memdescFreeIommuMappings(PMEMORY_DESCRIPTOR pMemDesc)500 _memdescFreeIommuMappings(PMEMORY_DESCRIPTOR pMemDesc)
501 {
502 #if (RMCFG_FEATURE_PLATFORM_UNIX || RMCFG_FEATURE_PLATFORM_MODS) && !NVCPU_IS_ARM
503     PIOVAMAPPING pIovaMapping = pMemDesc->_pIommuMappings;
504 
505     if (!pIovaMapping)
506         return;
507 
508     if (memdescIsSubMemoryMemDesc(pMemDesc))
509     {
510         iovaMappingDestroy(pIovaMapping);
511         return;
512     }
513 
514     while (pIovaMapping)
515     {
516         PIOVAMAPPING pTmpIovaMapping = pIovaMapping->pNext;
517         iovaMappingDestroy(pIovaMapping);
518         pIovaMapping = pTmpIovaMapping;
519     }
520 
521     pMemDesc->_pIommuMappings = NULL;
522 #endif
523 }
524 
525 /*!
526  *  Destroy a memory descriptor if last reference is released
527  *
528  *  If the memory descriptor is down to one reference, we need
529  *  to check with the bus code check if that reference needs
530  *  to be reclaimed.
531  *
532  *  @param[in] pMemDesc Memory descriptor to be destroyed
533  *
534  *  @returns None
535  */
536 void
memdescDestroy(MEMORY_DESCRIPTOR * pMemDesc)537 memdescDestroy
538 (
539     MEMORY_DESCRIPTOR *pMemDesc
540 )
541 {
542     // Allow null frees
543     if (!pMemDesc)
544     {
545         return;
546     }
547 
548     memdescRemoveRef(pMemDesc);
549 
550     // if still more references are there for pMemDesc (pMemDesc->RefCount != 0), then bail out.
551 
552     if (pMemDesc->RefCount == 0)
553     {
554         MEM_DESC_DESTROY_CALLBACK *pCb = memdescGetDestroyCallbackList(pMemDesc);
555         MEM_DESC_DESTROY_CALLBACK *pNext;
556 
557         if (pMemDesc->_flags & MEMDESC_FLAGS_RESTORE_PTE_KIND_ON_FREE)
558         {
559             NV_ASSERT_OK(kbusUpdateStaticBar1VAMapping_HAL(pMemDesc->pGpu,
560                              GPU_GET_KERNEL_BUS(pMemDesc->pGpu), pMemDesc,
561                              NV_TRUE));
562         }
563 
564         if (pMemDesc->_flags & MEMDESC_FLAGS_DUMMY_TOPLEVEL)
565         {
566             // When called from RmFreeFrameBuffer() and memdescFree could not do it because it is unallocated.
567             pMemDesc->_pNext = NULL;
568             pMemDesc->_subDeviceAllocCount = 1;
569         }
570 
571         NV_ASSERT(pMemDesc->childDescriptorCnt == 0);
572         NV_ASSERT(pMemDesc->_addressSpace == ADDR_FBMEM || pMemDesc->pHeap == NULL);
573 
574         //
575         // If there is private memdata, use the CB to free
576         //
577         if (pMemDesc->_pMemData && pMemDesc->_pMemDataReleaseCallback)
578         {
579             pMemDesc->_pMemDataReleaseCallback(pMemDesc);
580         }
581 
582         if (pMemDesc->bDeferredFree)
583         {
584             memdescFree(pMemDesc);
585         }
586         else if (pMemDesc->Allocated != 0)
587         {
588             //
589             // The caller forgot to free the actual memory before destroying the memdesc.
590             // Please fix this by calling memdescFree().
591             // To prevent memory leaks, we explicitly free here until its fixed elsewhere.
592             //
593             NV_PRINTF(LEVEL_ERROR, "Destroying unfreed memory %p\n", pMemDesc);
594             NV_PRINTF(LEVEL_ERROR, "Please call memdescFree()\n");
595             memdescFree(pMemDesc);
596             NV_ASSERT(!pMemDesc->Allocated);
597         }
598 
599         if (memdescGetStandbyBuffer(pMemDesc))
600         {
601             memdescFree(memdescGetStandbyBuffer(pMemDesc));
602             memdescDestroy(memdescGetStandbyBuffer(pMemDesc));
603             memdescSetStandbyBuffer(pMemDesc, NULL);
604         }
605 
606         //
607         // Submemory descriptors will be destroyed without going through a free
608         // path, so we need to make sure that we remove the IOMMU submapping
609         // here. For root descriptors, we should already have removed all the
610         // associated IOVA mappings.
611         //
612         // However, for memory descriptors that weren't allocated by the RM,
613         // (e.g., were created from a user allocation), we won't go through a
614         // free path at all. In this case, mappings for other GPUs may still be
615         // attached to this root memory descriptor, so release them now.
616         //
617         _memdescFreeIommuMappings(pMemDesc);
618 
619         // Notify all interested parties of destruction
620         while (pCb)
621         {
622             pNext = pCb->pNext;
623             pCb->destroyCallback(pMemDesc->pGpu, pCb->pObject, pMemDesc);
624             // pCb is now invalid
625             pCb = pNext;
626         }
627 
628         portMemFree(pMemDesc->pPteSpaMappings);
629         pMemDesc->pPteSpaMappings = NULL;
630         portMemFree(pMemDesc->pSubMemDescList);
631         pMemDesc->pSubMemDescList = NULL;
632 
633         if (pMemDesc->pPteEgmMappings != NULL)
634         {
635             portMemFree(pMemDesc->pPteEgmMappings);
636             pMemDesc->pPteEgmMappings = NULL;
637         }
638 
639         if (pMemDesc->_pParentDescriptor)
640         {
641             if ((pMemDesc->_flags & MEMDESC_FLAGS_PRE_ALLOCATED) == 0)
642                 pMemDesc->_pParentDescriptor->childDescriptorCnt--;
643             memdescDestroy(pMemDesc->_pParentDescriptor);
644             pMemDesc->_pParentDescriptor = NULL;
645         }
646 
647         // Verify memdesc is not top
648         NV_ASSERT(memdescHasSubDeviceMemDescs(pMemDesc) == NV_FALSE);
649 
650         if ((pMemDesc->_flags & MEMDESC_FLAGS_PRE_ALLOCATED) == 0)
651         {
652             portMemFree(pMemDesc);
653         }
654     }
655 }
656 
657 /*!
658  *  @brief Function that frees subdevice memory descriptors. If there are no
659  *  subdevice memory descriptors function just simply resets memdesc structure.
660  *  Top level memory descriptor is not destroyed.
661  *
662  *  @param[in,out] pMemDesc  Top level memory descriptor.
663  *
664  *  @returns None
665  */
666 static void
_memSubDeviceFreeAndDestroy(MEMORY_DESCRIPTOR * pMemDesc)667 _memSubDeviceFreeAndDestroy
668 (
669     MEMORY_DESCRIPTOR *pMemDesc
670 )
671 {
672     MEMORY_DESCRIPTOR *pSubDevMemDesc = pMemDesc->_pNext;
673     MEMORY_DESCRIPTOR *pNextMemDesc;
674     OBJGPU            *pGpu           = pMemDesc->pGpu;
675     NvBool             bBcState;
676 
677     // No subdevice memdescs
678     if (pSubDevMemDesc == NULL || pGpu == NULL)
679     {
680         return;
681     }
682 
683     bBcState       = gpumgrGetBcEnabledStatus(pGpu);
684     gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
685 
686     do
687     {
688         pNextMemDesc = pSubDevMemDesc->_pNext;
689         pSubDevMemDesc->_pNext = NULL;
690         memdescFree(pSubDevMemDesc);
691         memdescDestroy(pSubDevMemDesc);
692         pSubDevMemDesc = pNextMemDesc;
693     } while (pSubDevMemDesc != NULL);
694 
695     gpumgrSetBcEnabledStatus(pGpu, bBcState);
696 }
697 
698 /*!
699  *  @brief Lower memdesc allocation layer for the special case of allocation
700            in the VPR region when MODS is managing it.
701  *
702  *  @param[in] pMemDesc  Memory descriptor to allocate
703  *
704  *  @returns NV_OK on successful allocation.
705  *           NV_ERR_NOT_SUPPORTED if not supported
706  */
707 static NV_STATUS
_memdescAllocVprRegion(MEMORY_DESCRIPTOR * pMemDesc)708 _memdescAllocVprRegion
709 (
710     MEMORY_DESCRIPTOR *pMemDesc
711 )
712 {
713     return NV_ERR_NOT_SUPPORTED;
714 }
715 
716 /*!
717  *  @brief Allocate and populate the EGM array based off of the already
718  *         populated _pteArray of the memdesc
719  *
720  *  @param[in] pMemDesc Memory descriptor to allocate EGM array in
721  *
722  *  @returns NV_OK on successful allocation. NV_ERR if not.
723  */
724 static NV_INLINE NV_STATUS
_memdescAllocEgmArray(MEMORY_DESCRIPTOR * pMemDesc)725 _memdescAllocEgmArray
726 (
727     MEMORY_DESCRIPTOR *pMemDesc
728 )
729 {
730     //
731     // Since we allocate an extra PTE, we need to account for that in case we
732     // need it for the EGM array. This is why there is a '+ 1' for pageCount.
733     //
734     NvU64 i;
735     NvU64 pageCount = pMemDesc->PageCount + 1;
736 
737     //
738     // Get the root memory descriptor's memory manager to be able to get the
739     // EGM base of that GPU, instead of the mapping GPU in the case of this
740     // array being used in a submemdesc. The submemdesc should always have the
741     // mapping of the root since it's a submemdesc derived from the root, and
742     // not based on the mapping GPU.
743     //
744     MEMORY_DESCRIPTOR *pRootMemDesc   = memdescGetRootMemDesc(pMemDesc, NULL);
745     MemoryManager     *pMemoryManager = GPU_GET_MEMORY_MANAGER(pRootMemDesc->pGpu);
746 
747     if (pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)
748     {
749         pageCount = 1;
750     }
751 
752     if (pMemDesc->pPteEgmMappings == NULL)
753     {
754         pMemDesc->pPteEgmMappings = portMemAllocNonPaged(sizeof(RmPhysAddr) * pageCount);
755     }
756 
757     NV_ASSERT_OR_RETURN(pMemDesc->pPteEgmMappings != NULL, NV_ERR_NO_MEMORY);
758 
759     for (i = 0; i < pageCount; i++)
760     {
761         pMemDesc->pPteEgmMappings[i] = pMemDesc->_pteArray[i] -
762                                        pMemoryManager->localEgmBasePhysAddr;
763     }
764 
765     return NV_OK;
766 }
767 
768 /*!
769  *  @brief Lower memdesc allocation layer. Provides underlying allocation
770  *  functionality.
771  *
772  *  @param[in,out] pMemDesc  Memory descriptor to allocate
773  *
774  *  @returns NV_OK on successful allocation. Various NV_ERR_GENERIC codes otherwise.
775  */
776 static NV_STATUS
_memdescAllocInternal(MEMORY_DESCRIPTOR * pMemDesc)777 _memdescAllocInternal
778 (
779     MEMORY_DESCRIPTOR *pMemDesc
780 )
781 {
782     OBJGPU                      *pGpu               = pMemDesc->pGpu;
783     NV_STATUS                    status             = NV_OK;
784     FB_ALLOC_INFO               *pFbAllocInfo       = NULL;
785     FB_ALLOC_PAGE_FORMAT        *pFbAllocPageFormat = NULL;
786 
787     if (pMemDesc->Allocated)
788     {
789         NV_ASSERT(!pMemDesc->Allocated);
790         return NV_ERR_INVALID_OBJECT_BUFFER;
791     }
792 
793     // Special case of an allocation request in MODS managed VPR region.
794     status = _memdescAllocVprRegion(pMemDesc);
795     if (status != NV_ERR_NOT_SUPPORTED)
796         goto done;
797 
798     switch (pMemDesc->_addressSpace)
799     {
800         case ADDR_EGM:
801         case ADDR_SYSMEM:
802             // System memory can be obtained from osAllocPages
803             status = osAllocPages(pMemDesc);
804             if (status != NV_OK)
805             {
806                 goto done;
807             }
808 
809             if (memdescIsEgm(pMemDesc))
810             {
811                 NV_ASSERT_OK_OR_GOTO(status,
812                                      _memdescAllocEgmArray(pMemDesc),
813                                      done);
814             }
815 
816             //
817             // The pages have been allocated, so mark the descriptor as
818             // allocated. The IOMMU-mapping code needs the memdesc to be
819             // allocated in order to create the mapping.
820             //
821             pMemDesc->Allocated = 1;
822 
823             //
824             // TODO: merge new IOMMU paths with the SMMU paths below (see bug
825             //       1625121). For now they are parallel, and only one will be
826             //       used.
827             //
828             if (!memdescGetFlag(pMemDesc, MEMDESC_FLAGS_CPU_ONLY) &&
829                 !memdescIsEgm(pMemDesc) &&
830                 !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_SKIP_IOMMU_MAPPING))
831             {
832                 status = memdescMapIommu(pMemDesc, pGpu->busInfo.iovaspaceId);
833                 if (status != NV_OK)
834                 {
835                     pMemDesc->Allocated = 0;
836                     osFreePages(pMemDesc);
837                     goto done;
838                 }
839             }
840 
841             if (pMemDesc->_flags & MEMDESC_FLAGS_PROVIDE_IOMMU_MAP)
842             {
843                 NV_PRINTF(LEVEL_ERROR, "SMMU mapping allocation is not supported for ARMv7.\n");
844                 NV_ASSERT(0);
845                 status = NV_ERR_NOT_SUPPORTED;
846                 goto done;
847             }
848             else if ((pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS) &&
849                      RMCFG_FEATURE_PLATFORM_MODS)
850             {
851                 if (pMemDesc->Alignment > RM_PAGE_SIZE)
852                 {
853                     RmPhysAddr addr = memdescGetPhysAddr(pMemDesc, AT_CPU, 0);
854                     NvU64      offset;
855 
856                     NV_ASSERT((addr & (RM_PAGE_SIZE - 1)) == 0);
857 
858                     NV_ASSERT((pMemDesc->Alignment & (pMemDesc->Alignment - 1)) == 0);
859                     offset = addr & (pMemDesc->Alignment - 1);
860 
861                     if (offset)
862                     {
863                         NV_ASSERT((pMemDesc->PageCount * pMemDesc->pageArrayGranularity - pMemDesc->Size) >= offset);
864                         NV_ASSERT(pMemDesc->PteAdjust == 0);
865                         pMemDesc->PteAdjust += NvU64_LO32(pMemDesc->Alignment - offset);
866                     }
867                 }
868             }
869 
870             break;
871         case ADDR_FBMEM:
872         {
873             Heap *pHeap = pMemDesc->pHeap;
874 
875             if (RMCFG_FEATURE_PMA &&
876                 (pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL))
877             {
878                 CTX_BUF_POOL_INFO *pCtxBufPool = NULL;
879                 pCtxBufPool = memdescGetCtxBufPool(pMemDesc);
880                 NV_ASSERT_TRUE_OR_GOTO(status, pCtxBufPool != NULL, NV_ERR_INVALID_STATE, done);
881 
882                 // If pool is setup then allocate from pool
883                 NV_ASSERT_OK_OR_GOTO(status, ctxBufPoolAllocate(pCtxBufPool, pMemDesc), done);
884             }
885             else
886             {
887                 // XXX Hack!
888                 MEMORY_ALLOCATION_REQUEST allocRequest = {0};
889                 NV_MEMORY_ALLOCATION_PARAMS allocData = {0};
890                 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
891                 NvU64 requestedSize = pMemDesc->Size;
892 
893                 allocRequest.pUserParams = &allocData;
894 
895                 // Don't allow FB allocations if FB is broken unless running in L2 cache only mode
896                 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) &&
897                     !gpuIsCacheOnlyModeEnabled(pGpu))
898                 {
899                     DBG_BREAKPOINT();
900                     status = NV_ERR_BROKEN_FB;
901                     goto done;
902                 }
903 
904                 allocData.owner = HEAP_OWNER_RM_CHANNEL_CTX_BUFFER;
905                 allocData.type = NVOS32_TYPE_IMAGE;
906                 allocData.flags = NVOS32_ALLOC_FLAGS_ALIGNMENT_FORCE;
907 
908                 // remove the "grows_down" flag when bReservedMemAtBottom is set so as to move RM memory to the bottom.
909                 if (!pMemoryManager->bReservedMemAtBottom)
910                 {
911                     allocData.flags |= NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_DOWN;
912                 }
913 
914                 // Allocate in high priority memory?
915                 if (pMemDesc->_flags & MEMDESC_FLAGS_HIGH_PRIORITY)
916                 {
917                     allocData.attr2 |= DRF_DEF(OS32, _ATTR2, _PRIORITY, _HIGH);
918                 }
919                 else if (pMemDesc->_flags & MEMDESC_FLAGS_LOW_PRIORITY)
920                 {
921                     allocData.attr2 |= DRF_DEF(OS32, _ATTR2, _PRIORITY, _LOW);
922                 }
923 
924                 allocData.size = pMemDesc->Size;
925                 allocData.alignment = pMemDesc->Alignment;
926                 allocRequest.pMemDesc = pMemDesc;
927 
928                 if (pMemDesc->_pageSize == RM_PAGE_SIZE)
929                 {
930                     allocData.attr |= DRF_DEF(OS32, _ATTR, _PAGE_SIZE, _4KB);
931                 }
932                 else if (pMemDesc->_pageSize == RM_PAGE_SIZE_64K ||
933                      pMemDesc->_pageSize == RM_PAGE_SIZE_128K)
934                 {
935                     allocData.attr |= DRF_DEF(OS32, _ATTR, _PAGE_SIZE, _BIG);
936                 }
937 
938                 allocData.flags |= pMemDesc->Alignment ?
939                     NVOS32_ALLOC_FLAGS_ALIGNMENT_FORCE :
940                     NVOS32_ALLOC_FLAGS_FORCE_ALIGN_HOST_PAGE;
941 
942                 if (pMemDesc->_flags & MEMDESC_FLAGS_FIXED_ADDRESS_ALLOCATE)
943                 {
944                     allocData.flags |= NVOS32_ALLOC_FLAGS_FIXED_ADDRESS_ALLOCATE;
945                     allocData.offset = pMemDesc->_pteArray[0];
946                 }
947 
948                 if (pMemDesc->_gpuCacheAttrib == NV_MEMORY_CACHED)
949                 {
950                     allocData.attr2 |= DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _YES);
951                 }
952                 else
953                 {
954                     // Force internal allocations to uncached unless explicitly requested.
955                     allocData.attr2 |= DRF_DEF(OS32, _ATTR2, _GPU_CACHEABLE, _NO);
956                 }
957 
958                 allocData.attr2 = FLD_SET_DRF(OS32, _ATTR2, _INTERNAL, _YES, allocData.attr2);
959 
960                 if (pMemDesc->_flags & MEMDESC_ALLOC_FLAGS_PROTECTED)
961                 {
962                     allocData.flags |= NVOS32_ALLOC_FLAGS_PROTECTED;
963                 }
964 
965                 //
966                 // Assume all RM internal allocations to go into protected (CPR)
967                 // video memory unless specified otherwise explicitly
968                 //
969                 if (gpuIsCCFeatureEnabled(pGpu))
970                 {
971                     if (pMemDesc->_flags & MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY)
972                     {
973                         //
974                         // CC-TODO: Remove this check after non-CPR region is
975                         // created. Not sure if RM will ever need to use non-CPR
976                         // region for itself
977                         //
978                         NV_PRINTF(LEVEL_ERROR, "Non-CPR region still not created\n");
979                         NV_ASSERT_OR_RETURN(0, NV_ERR_INVALID_ARGUMENT);
980                     }
981                     else
982                     {
983                         allocData.flags |= NVOS32_ALLOC_FLAGS_PROTECTED;
984                     }
985                 }
986 
987                 allocData.attr |= DRF_DEF(OS32, _ATTR, _PHYSICALITY, _CONTIGUOUS);
988 
989                 pFbAllocInfo = portMemAllocNonPaged(sizeof(FB_ALLOC_INFO));
990                 NV_ASSERT_TRUE_OR_GOTO(status, pFbAllocInfo != NULL, NV_ERR_NO_MEMORY, done);
991 
992                 pFbAllocPageFormat = portMemAllocNonPaged(sizeof(FB_ALLOC_PAGE_FORMAT));
993                 NV_ASSERT_TRUE_OR_GOTO(status, pFbAllocPageFormat != NULL, NV_ERR_NO_MEMORY, done);
994 
995                 portMemSet(pFbAllocInfo, 0, sizeof(FB_ALLOC_INFO));
996                 portMemSet(pFbAllocPageFormat, 0, sizeof(FB_ALLOC_PAGE_FORMAT));
997                 pFbAllocInfo->pageFormat = pFbAllocPageFormat;
998 
999                 memUtilsInitFBAllocInfo(&allocData, pFbAllocInfo, 0, 0); // Client/device N/A
1000 
1001                 status = memmgrAllocResources(pGpu, pMemoryManager, &allocRequest, pFbAllocInfo);
1002                 if (status != NV_OK)
1003                     goto done;
1004 
1005                 status = vidmemAllocResources(pGpu, pMemoryManager, &allocRequest, pFbAllocInfo, pHeap);
1006                 if (status != NV_OK)
1007                     goto done;
1008 
1009                 pMemDesc->Alignment = allocData.alignment;
1010 
1011                 // Update MemDesc GPU cacheability with results of allocation
1012                 if (DRF_VAL(OS32, _ATTR2, _GPU_CACHEABLE, allocData.attr2) == NVOS32_ATTR2_GPU_CACHEABLE_YES)
1013                 {
1014                     pMemDesc->_gpuCacheAttrib = NV_MEMORY_CACHED;
1015                 }
1016                 else
1017                 {
1018                     pMemDesc->_gpuCacheAttrib = NV_MEMORY_UNCACHED;
1019                 }
1020 
1021                 //
1022                 // Adjust size to the requested size, not the heap rounded size.  A number of callers
1023                 // depend on this. In the future we will have the PageCount be accurate.
1024                 //
1025                 pMemDesc->Size = requestedSize;
1026                 pMemDesc->PageCount = ((pMemDesc->Size + pMemDesc->PteAdjust + pMemDesc->pageArrayGranularity - 1) >>
1027                                         BIT_IDX_32(pMemDesc->pageArrayGranularity));
1028             }
1029             // We now have the memory
1030             pMemDesc->Allocated = 1;
1031 
1032             // If the allocation succeeds and if its PhysMemSubAlloc, increment the refCount
1033             if ((status == NV_OK) && (pHeap != NULL) &&
1034                 (pHeap->heapType == HEAP_TYPE_PHYS_MEM_SUBALLOCATOR))
1035             {
1036                 heapAddRef(pHeap);
1037             }
1038             break;
1039         }
1040 
1041         default:
1042             // Don't know how to do any other types of memory yet
1043             DBG_BREAKPOINT();
1044             status = NV_ERR_GENERIC;
1045             goto done;
1046     }
1047 
1048 done:
1049     if (status == NV_OK)
1050     {
1051         memdescPrintMemdesc(pMemDesc, NV_TRUE, MAKE_NV_PRINTF_STR("memdesc allocated"));
1052     }
1053     else if (pMemDesc->pPteEgmMappings != NULL)
1054     {
1055         portMemFree(pMemDesc->pPteEgmMappings);
1056         pMemDesc->pPteEgmMappings = NULL;
1057     }
1058     portMemFree(pFbAllocPageFormat);
1059     portMemFree(pFbAllocInfo);
1060 
1061     return status;
1062 }
1063 
1064 /*!
1065  *  @brief Upper memdesc allocation layer. Provides support for per-subdevice
1066  *  sysmem buffers and lockless sysmem allocation.
1067  *
1068  *  @param[in,out] pMemDesc  Memory descriptor to allocate
1069  *
1070  *  @returns NV_OK on successful allocation. Various NV_ERR_GENERIC codes otherwise.
1071  */
1072 NV_STATUS
memdescAlloc(MEMORY_DESCRIPTOR * pMemDesc)1073 memdescAlloc
1074 (
1075     MEMORY_DESCRIPTOR *pMemDesc
1076 )
1077 {
1078     OBJGPU             *pGpu        = pMemDesc->pGpu;
1079     NV_STATUS           status      = NV_OK;
1080     NvBool              bcState     = NV_FALSE;
1081     OBJSYS             *pSys        = SYS_GET_INSTANCE();
1082     NvBool              reAcquire;
1083     NvU32               gpuMask     = 0;
1084 
1085     NV_ASSERT_OR_RETURN(!pMemDesc->Allocated, NV_ERR_INVALID_OBJECT_BUFFER);
1086 
1087     switch (pMemDesc->_addressSpace)
1088     {
1089         case ADDR_SYSMEM:
1090         case ADDR_EGM:
1091             // Can't alloc sysmem on GSP firmware.
1092             if (RMCFG_FEATURE_PLATFORM_GSP && !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_GUEST_ALLOCATED))
1093             {
1094                 //
1095                 // TO DO: Make this an error once existing allocations are cleaned up.
1096                 // After that pHeap selection can be moved to memdescAllocInternal()
1097                 //
1098                 NV_PRINTF(LEVEL_WARNING,
1099                           "WARNING sysmem alloc on GSP firmware\n");
1100                 pMemDesc->_addressSpace = ADDR_FBMEM;
1101                 pMemDesc->pHeap = GPU_GET_HEAP(pGpu);
1102             }
1103             //
1104             // If AMD SEV is enabled but CC or APM is not enabled on the GPU,
1105             // all RM and client allocations must to to unprotected sysmem.
1106             // So, we override any unprotected/protected flag set by either RM
1107             // or client.
1108             // If APM is enabled and RM is allocating sysmem for its internal use
1109             // use such memory has to be unprotected as protected sysmem is not
1110             // accessible to GPU
1111             //
1112             if ((sysGetStaticConfig(pSys))->bOsCCEnabled)
1113             {
1114                 if (!gpuIsCCorApmFeatureEnabled(pGpu) ||
1115                     (gpuIsApmFeatureEnabled(pGpu) &&
1116                      !memdescGetFlag(pMemDesc, MEMDESC_FLAGS_SYSMEM_OWNED_BY_CLIENT)))
1117                 {
1118                     memdescSetFlag(pMemDesc,
1119                         MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY, NV_TRUE);
1120                 }
1121             }
1122             else
1123             {
1124                 //
1125                 // This flag has no meaning on non-SEV systems. So, unset it. The
1126                 // OS layer currently honours this flag irrespective of whether
1127                 // SEV is enabled or not
1128                 //
1129                 memdescSetFlag(pMemDesc,
1130                         MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY, NV_FALSE);
1131             }
1132 
1133             break;
1134         case ADDR_FBMEM:
1135         {
1136             //
1137             // When APM is enabled, all RM internal vidmem allocations go to
1138             // unprotected memory. There is an underlying assumption that
1139             // memdescAlloc won't be directly called in the client vidmem alloc
1140             // codepath. Note that memdescAlloc still gets called in the client
1141             // sysmem alloc codepath. See CONFCOMP-529
1142             //
1143             if (gpuIsApmFeatureEnabled(pGpu))
1144             {
1145                 memdescSetFlag(pMemDesc,
1146                     MEMDESC_FLAGS_ALLOC_IN_UNPROTECTED_MEMORY, NV_TRUE);
1147             }
1148             // If FB is broken then don't allow the allocation, unless running in L2 cache only mode
1149             if (pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) &&
1150                 !gpuIsCacheOnlyModeEnabled(pGpu))
1151             {
1152                 status = NV_ERR_BROKEN_FB;
1153                 NV_PRINTF(LEVEL_ERROR, "Unsupported FB bound allocation on broken FB(0FB) platform\n");
1154                 DBG_BREAKPOINT();
1155             }
1156 
1157             NV_ASSERT(pMemDesc->pHeap == NULL);
1158             // Set the pHeap based on who owns this allocation
1159             if (pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL)
1160             {
1161                 //
1162                 // pHeap is not required in memdesc for ctx buf pools because each ctx buf
1163                 // pool is tied to PMA and this pools is cached inside memdesc.
1164                 //
1165                 CTX_BUF_POOL_INFO *pCtxBufPool = memdescGetCtxBufPool(pMemDesc);
1166                 NV_ASSERT_OR_RETURN(pCtxBufPool != NULL, NV_ERR_INVALID_STATE);
1167             }
1168             else if (pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE)
1169             {
1170                 NvBool bForceSubheap = NV_FALSE;
1171 
1172                 if (pMemDesc->_flags & MEMDESC_FLAGS_FORCE_ALLOC_FROM_SUBHEAP)
1173                 {
1174                     bForceSubheap = NV_TRUE;
1175                 }
1176 
1177                 pMemDesc->pHeap = memmgrGetDeviceSuballocator(GPU_GET_MEMORY_MANAGER(pGpu), bForceSubheap);
1178             }
1179             else if (GPU_GET_MEMORY_MANAGER(pGpu) != NULL &&
1180                 RMCFG_MODULE_HEAP &&
1181                 pMemDesc->_addressSpace == ADDR_FBMEM)
1182             {
1183                 pMemDesc->pHeap = GPU_GET_HEAP(pGpu);
1184             }
1185 
1186             break;
1187         }
1188         default:
1189             // Don't know how to do any other types of memory yet
1190             DBG_BREAKPOINT();
1191             return NV_ERR_GENERIC;
1192     }
1193 
1194     if (status != NV_OK)
1195     {
1196         return status;
1197     }
1198 
1199     if (gpumgrGetBcEnabledStatus(pGpu))
1200     {
1201         // Broadcast memdescAlloc call with flag set to allocate per subdevice.
1202         if (pMemDesc->_flags & MEMDESC_FLAGS_ALLOC_PER_SUBDEVICE)
1203         {
1204             NvU32               i;
1205             MEMORY_DESCRIPTOR   *pSubDevMemDesc = pMemDesc;
1206             MEMORY_DESCRIPTOR   *pPrev = pMemDesc;
1207             OBJGPU             *pGpuChild;
1208 
1209             pMemDesc->_subDeviceAllocCount = NumSubDevices(pGpu);
1210 
1211             for (i = 0; i < pMemDesc->_subDeviceAllocCount; i++)
1212             {
1213                 // Get pGpu for this subdeviceinst
1214                 pGpuChild = gpumgrGetGpuFromSubDeviceInst(gpuGetDeviceInstance(pGpu), i);
1215                 if (NULL == pGpuChild)
1216                 {
1217                     NV_ASSERT(0);
1218                     status = NV_ERR_OBJECT_NOT_FOUND;
1219                     goto subdeviceAlloc_failed;
1220                 }
1221 
1222                 //
1223                 // We are accessing the fields of the top level desc here directly without using the
1224                 // accessor routines on purpose.
1225                 //
1226                 status = memdescCreate(&pSubDevMemDesc, pGpuChild, pMemDesc->Size, pMemDesc->Alignment,
1227                                        !!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS),
1228                                        pMemDesc->_addressSpace,
1229                                        pMemDesc->_cpuCacheAttrib,
1230                                        pMemDesc->_flags & ~MEMDESC_FLAGS_ALLOC_PER_SUBDEVICE);
1231 
1232                 if (status != NV_OK)
1233                 {
1234                     NV_ASSERT(0);
1235                     goto subdeviceAlloc_failed;
1236                 }
1237 
1238                 pSubDevMemDesc->_gpuCacheAttrib   = pMemDesc->_gpuCacheAttrib;
1239                 pSubDevMemDesc->_pageSize = pMemDesc->_pageSize;
1240 
1241                 // Force broadcast state to false when allocating a subdevice memdesc
1242                 gpumgrSetBcEnabledStatus(pGpuChild, NV_FALSE);
1243 
1244                 status = memdescAlloc(pSubDevMemDesc);
1245 
1246                 if (pMemDesc->_addressSpace == ADDR_FBMEM)
1247                 {
1248                     //
1249                     // The top level memdesc could have flags that don't reflect contiguity which
1250                     // is set after memdescAlloc.
1251                     //
1252                     pMemDesc->Alignment            = pSubDevMemDesc->Alignment;
1253                     pMemDesc->_flags               = pSubDevMemDesc->_flags | MEMDESC_FLAGS_ALLOC_PER_SUBDEVICE;
1254                     pMemDesc->ActualSize           = pSubDevMemDesc->ActualSize;
1255                 }
1256 
1257                 // Restore broadcast state to true after allocating a subdevice memdesc
1258                 gpumgrSetBcEnabledStatus(pGpuChild, NV_TRUE);
1259 
1260                 if (status != NV_OK)
1261                 {
1262                     memdescDestroy(pSubDevMemDesc);
1263                     NV_ASSERT(0);
1264                     goto subdeviceAlloc_failed;
1265                 }
1266 
1267                 // Check for similarity in allocations for previous allocated subdev with current allocated subdev.
1268                 // If subdev0 ~ subdev1 && subdev1~subdev2 then subdev0 ~ subdev2 and so on...Thus can check symmetry across all subdev allocations
1269                 if (i > 0)
1270                 {
1271                     NV_ASSERT(pPrev->Size == pSubDevMemDesc->Size);
1272                     NV_ASSERT(pPrev->PteAdjust == pSubDevMemDesc->PteAdjust);
1273                     NV_ASSERT(pPrev->_addressSpace == pSubDevMemDesc->_addressSpace);
1274                     NV_ASSERT(pPrev->_flags == pSubDevMemDesc->_flags);
1275                     NV_ASSERT(pPrev->_pteKind == pSubDevMemDesc->_pteKind);
1276                     NV_ASSERT(pPrev->_pteKindCompressed == pSubDevMemDesc->_pteKindCompressed);
1277                     NV_ASSERT(pPrev->pHeap != pSubDevMemDesc->pHeap);
1278                 }
1279 
1280                 pPrev->_pNext = pSubDevMemDesc;
1281                 pPrev        = pSubDevMemDesc;
1282             }
1283             pMemDesc->Allocated = 1;
1284             return NV_OK;
1285         }
1286         else if (pMemDesc->_addressSpace == ADDR_FBMEM)
1287         {
1288             // Broadcast memdescAlloc call on vidmem *without* flag set to allocate per subdevice
1289             NV_ASSERT(0);
1290         }
1291     }
1292 
1293     // Unicast memdescAlloc call but with flag set to allocate per subdevice.
1294     NV_ASSERT(!((pMemDesc->_flags & MEMDESC_FLAGS_ALLOC_PER_SUBDEVICE) && !gpumgrGetBcEnabledStatus(pGpu)));
1295 
1296     reAcquire = NV_FALSE;
1297     bcState = NV_FALSE;
1298 
1299     if ((pMemDesc->_flags & MEMDESC_FLAGS_LOCKLESS_SYSMEM_ALLOC) && (pMemDesc->_addressSpace != ADDR_FBMEM))
1300     {
1301         bcState = gpumgrGetBcEnabledStatus(pGpu);
1302         if (RMCFG_FEATURE_RM_BASIC_LOCK_MODEL)
1303         {
1304             //
1305             // There is no equivalent routine for osCondReleaseRmSema in
1306             // the new basic lock model.
1307 
1308             //
1309             // However, we can't drop the RM system semaphore in this
1310             // path because on non-windows platforms (i.e. MODS) it
1311             // has undesirable consequences.  So for now we must
1312             // bracket this section with a reference to the feature
1313             // flag until we can rework this interface.
1314             //
1315             //
1316             // Check to make sure we own the lock and that we are
1317             // not at elevated IRQL; this models the behavior
1318             // of osCondReleaseRmSema.
1319             //
1320             if (!osIsRaisedIRQL() &&
1321                 (rmGpuGroupLockIsOwner(pGpu->gpuInstance, GPU_LOCK_GRP_DEVICE, &gpuMask) ||
1322                  rmGpuGroupLockIsOwner(pGpu->gpuInstance, GPU_LOCK_GRP_SUBDEVICE, &gpuMask)))
1323             {
1324                 //
1325                 // Release all owned gpu locks rather than just the
1326                 // device-related locks because the caller may be holding more
1327                 // than the required device locks. All currently owned
1328                 // locks will be re-acquired before returning.
1329                 //
1330                 // This prevents potential GPU locking violations (e.g., if the
1331                 // caller is holding all the gpu locks but only releases the
1332                 // first of two device locks, then attempting to re-acquire
1333                 // the first device lock will be a locking violation with
1334                 // respect to the second device lock.)
1335                 //
1336                 gpuMask = rmGpuLocksGetOwnedMask();
1337                 rmGpuGroupLockRelease(gpuMask, GPUS_LOCK_FLAGS_NONE);
1338                 reAcquire = NV_TRUE;
1339             }
1340         }
1341         else
1342         {
1343             reAcquire = osCondReleaseRmSema(pSys->pSema);
1344         }
1345     }
1346 
1347     // Actually allocate the memory
1348     NV_CHECK_OK(status, LEVEL_ERROR, _memdescAllocInternal(pMemDesc));
1349 
1350     if (status != NV_OK)
1351     {
1352         pMemDesc->pHeap = NULL;
1353     }
1354 
1355     if (reAcquire)
1356     {
1357         if (osAcquireRmSema(pSys->pSema) != NV_OK)
1358         {
1359             DBG_BREAKPOINT();
1360 
1361         }
1362 
1363         if (rmGpuGroupLockAcquire(pGpu->gpuInstance, GPU_LOCK_GRP_MASK,
1364                                   GPUS_LOCK_FLAGS_NONE, RM_LOCK_MODULES_MEM,
1365                                   &gpuMask) != NV_OK)
1366         {
1367             DBG_BREAKPOINT();
1368         }
1369         // Releasing the semaphore allows another thread to enter RM and
1370         // modify broadcast state. We need to set it back (see bug 368643)
1371         gpumgrSetBcEnabledStatus(pGpu, bcState);
1372     }
1373 
1374     return status;
1375 
1376 subdeviceAlloc_failed:
1377     _memSubDeviceFreeAndDestroy(pMemDesc);
1378     pMemDesc->_subDeviceAllocCount = 1;
1379     pMemDesc->_pNext               = NULL;
1380     return status;
1381 }
1382 
1383 /*!
1384  *  Allocate memory from one of the possible locations specified in pList.
1385  *
1386  *  @param[in,out] pMemDesc      Memory descriptor to allocate
1387  *  @param[in]     pList         List of NV_ADDRESS_SPACE values. Terminated
1388  *                               by an ADDR_UNKNOWN entry.
1389  *
1390  *  @returns NV_OK on successful allocation. Various NV_ERR_GENERIC codes otherwise.
1391  */
1392 NV_STATUS
memdescAllocList(MEMORY_DESCRIPTOR * pMemDesc,const NV_ADDRESS_SPACE * pList)1393 memdescAllocList
1394 (
1395     MEMORY_DESCRIPTOR *pMemDesc,
1396     const NV_ADDRESS_SPACE *pList
1397 )
1398 {
1399     NV_STATUS status = NV_ERR_INVALID_ARGUMENT;
1400     NvU32 i = 0;
1401 
1402     if (!pList)
1403     {
1404         return status;
1405     }
1406 
1407     //
1408     // this memdesc may have gotten forced to sysmem if no carveout,
1409     // but for VPR it needs to be in vidmem, so check and re-direct here
1410     //
1411     if (pMemDesc->_flags & MEMDESC_ALLOC_FLAGS_PROTECTED)
1412     {
1413         OBJGPU *pGpu = pMemDesc->pGpu;
1414 
1415         // Only force to vidmem if not running with zero-FB.
1416         if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) ||
1417             gpuIsCacheOnlyModeEnabled(pGpu))
1418         {
1419             pList = ADDRLIST_FBMEM_ONLY;
1420         }
1421     }
1422 
1423     while (pList[i] != ADDR_UNKNOWN)
1424     {
1425         pMemDesc->_addressSpace = pList[i];
1426         status = memdescAlloc(pMemDesc);
1427 
1428         if (status == NV_OK)
1429         {
1430             return status;
1431         }
1432 
1433         i++;
1434     }
1435 
1436     return status;
1437 }
1438 
1439 /*!
1440  *  @brief Lower memdesc free layer. Provides underlying free
1441  *  functionality.
1442  *
1443  *  @param[in,out] pMemDesc Memory descriptor to free
1444  *
1445  *  @returns None
1446  */
1447 static void
_memdescFreeInternal(MEMORY_DESCRIPTOR * pMemDesc)1448 _memdescFreeInternal
1449 (
1450     MEMORY_DESCRIPTOR *pMemDesc
1451 )
1452 {
1453     MEM_DESC_DESTROY_CALLBACK *pCb, *pNext;
1454     NvU64 oldSize;
1455 
1456     // Allow null frees
1457     if (!pMemDesc)
1458     {
1459         return;
1460     }
1461 
1462     pCb = memdescGetDestroyCallbackList(pMemDesc);
1463 
1464     // Notify all interested parties of destruction
1465     while (pCb)
1466     {
1467         pNext = pCb->pNext;
1468         pCb->destroyCallback(pMemDesc->pGpu, pCb->pObject, pMemDesc);
1469         // pCb is now invalid
1470         pCb = pNext;
1471     }
1472 
1473     if (memdescHasSubDeviceMemDescs(pMemDesc))
1474         return;
1475 
1476     memdescPrintMemdesc(pMemDesc, NV_FALSE, MAKE_NV_PRINTF_STR("memdesc being freed"));
1477 
1478     // Bail our early in case this memdesc describes a MODS managed VPR region.
1479     if (memdescGetFlag(pMemDesc, MEMDESC_FLAGS_VPR_REGION_CLIENT_MANAGED))
1480         return;
1481 
1482     switch (pMemDesc->_addressSpace)
1483     {
1484         case ADDR_SYSMEM:
1485         case ADDR_EGM:
1486             // invalidate if memory is cached in FB L2 cache.
1487             if (pMemDesc->_gpuCacheAttrib == NV_MEMORY_CACHED)
1488             {
1489                 OBJGPU *pGpu = pMemDesc->pGpu;
1490 
1491                 //
1492                 // If this memdesc managed to outlive its pGpu getting detached,
1493                 // we're plenty off the rails already, but avoid using the pGpu
1494                 // and carry on as best we can
1495                 //
1496                 if (gpumgrIsGpuPointerValid(pGpu))
1497                 {
1498                     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY)
1499                     {
1500                         KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
1501                         NV_ASSERT_OK(kmemsysCacheOp_HAL(pGpu, pKernelMemorySystem, pMemDesc,
1502                                                                   FB_CACHE_SYSTEM_MEMORY,
1503                                                                   FB_CACHE_INVALIDATE));
1504                     }
1505                     SLI_LOOP_END
1506                 }
1507                 else
1508                 {
1509                     NV_ASSERT_FAILED("Sysmemdesc outlived its attached pGpu");
1510                 }
1511             }
1512 
1513             oldSize             = pMemDesc->Size;
1514             pMemDesc->Size      = pMemDesc->ActualSize;
1515             pMemDesc->PageCount = ((pMemDesc->ActualSize + pMemDesc->pageArrayGranularity - 1) >> BIT_IDX_64(pMemDesc->pageArrayGranularity));
1516 
1517             osFreePages(pMemDesc);
1518 
1519             pMemDesc->Size      = oldSize;
1520             pMemDesc->PageCount = ((oldSize + pMemDesc->pageArrayGranularity - 1) >> BIT_IDX_64(pMemDesc->pageArrayGranularity));
1521 
1522             break;
1523 
1524         case ADDR_FBMEM:
1525         {
1526             Heap *pHeap = pMemDesc->pHeap;
1527             NV_STATUS status = NV_OK;
1528             OBJGPU *pGpu = pMemDesc->pGpu;
1529 
1530             if (RMCFG_FEATURE_PMA &&
1531                 (pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CTX_BUF_POOL))
1532             {
1533                 CTX_BUF_POOL_INFO *pCtxBufPool = memdescGetCtxBufPool(pMemDesc);
1534                 if (pCtxBufPool == NULL)
1535                 {
1536                     DBG_BREAKPOINT();
1537                     NV_PRINTF(LEVEL_ERROR, "ctx buf pool not found\n");
1538                     return;
1539                 }
1540                 NV_STATUS status = ctxBufPoolFree(pCtxBufPool, pMemDesc);
1541                 if (status != NV_OK)
1542                 {
1543                     DBG_BREAKPOINT();
1544                     NV_PRINTF(LEVEL_ERROR, "Failed to free memdesc from context buffer pool\n");
1545                 }
1546             }
1547             else
1548             {
1549                 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
1550 
1551                 NV_ASSERT(pHeap != NULL);
1552 
1553                 if (!pHeap)
1554                     return;
1555 
1556                 status = memmgrFree(pGpu, pMemoryManager, pHeap, 0x0, 0x0, 0x0,
1557                                     HEAP_OWNER_RM_CHANNEL_CTX_BUFFER,
1558                                     pMemDesc);
1559                 NV_ASSERT(status == NV_OK);
1560             }
1561 
1562             // If this heap is being used to manage PMSA memory, reduce the refcount accordingly
1563             if ((status == NV_OK) && (pHeap != NULL) &&
1564                 (pHeap->heapType == HEAP_TYPE_PHYS_MEM_SUBALLOCATOR))
1565             {
1566                 heapRemoveRef(pHeap);
1567             }
1568             break;
1569         }
1570 
1571         default:
1572             // Don't know how to do any other types of memory yet
1573             DBG_BREAKPOINT();
1574     }
1575 }
1576 
1577 /*!
1578  *  @brief Upper memdesc free layer. Provides support for per-subdevice
1579  *  sysmem buffers and lockless sysmem allocation. Because of SLI and subdevice
1580  *  submem allocations (refer to submem chart) support, if memory has never
1581  *  been allocated function will just unlink subdevice structure and destroy
1582  *  subdevice descriptors.
1583  *
1584  *  @param[in,out] pMemDesc Memory descriptor to free
1585  *
1586  *  @returns None
1587  */
1588 void
memdescFree(MEMORY_DESCRIPTOR * pMemDesc)1589 memdescFree
1590 (
1591     MEMORY_DESCRIPTOR *pMemDesc
1592 )
1593 {
1594     // Allow null frees
1595     if (!pMemDesc)
1596     {
1597         return;
1598     }
1599 
1600 
1601     if (memdescIsSubMemoryMemDesc(pMemDesc))
1602     {
1603         NV_ASSERT(!pMemDesc->_pInternalMapping);
1604 
1605         if (pMemDesc->_addressSpace == ADDR_SYSMEM)
1606         {
1607             // The memdesc is being freed so destroy all of its IOMMU mappings.
1608             _memdescFreeIommuMappings(pMemDesc);
1609         }
1610 
1611         if (pMemDesc->_addressSpace != ADDR_FBMEM &&
1612             pMemDesc->_addressSpace != ADDR_SYSMEM &&
1613             pMemDesc->_addressSpace != ADDR_EGM)
1614         {
1615             return;
1616         }
1617 
1618         _memSubDeviceFreeAndDestroy(pMemDesc);
1619     }
1620     else
1621     {
1622         //
1623         // In case RM attempts to free memory that has more than 1 refcount, the free is deferred until refcount reaches 0
1624         //
1625         // Bug 3307574 RM crashes when client's specify sysmem UserD location.
1626         // RM attempts to peek at the client allocated UserD when waiting for a channel to go idle.
1627         //
1628         if (pMemDesc->RefCount > 1 && pMemDesc->Allocated == 1)
1629         {
1630             pMemDesc->bDeferredFree = NV_TRUE;
1631             return;
1632         }
1633 
1634         if (!pMemDesc->Allocated)
1635         {
1636             return;
1637         }
1638         pMemDesc->Allocated--;
1639         if (0 != pMemDesc->Allocated)
1640         {
1641             return;
1642         }
1643 
1644         // If standbyBuffer memory was allocated then free it
1645         if (pMemDesc->_pStandbyBuffer)
1646         {
1647             memdescFree(pMemDesc->_pStandbyBuffer);
1648             memdescDestroy(pMemDesc->_pStandbyBuffer);
1649             pMemDesc->_pStandbyBuffer = NULL;
1650         }
1651 
1652         NV_ASSERT(!pMemDesc->_pInternalMapping);
1653 
1654         if (pMemDesc->_addressSpace == ADDR_SYSMEM)
1655         {
1656             // The memdesc is being freed so destroy all of its IOMMU mappings.
1657             _memdescFreeIommuMappings(pMemDesc);
1658         }
1659 
1660         if (pMemDesc->_addressSpace != ADDR_FBMEM &&
1661             pMemDesc->_addressSpace != ADDR_EGM &&
1662             pMemDesc->_addressSpace != ADDR_SYSMEM)
1663         {
1664             return;
1665         }
1666 
1667         _memSubDeviceFreeAndDestroy(pMemDesc);
1668 
1669         _memdescFreeInternal(pMemDesc);
1670     }
1671 
1672     // Reset tracking state
1673     pMemDesc->_pNext = NULL;
1674     pMemDesc->_subDeviceAllocCount = 1;
1675 
1676     //
1677     // Reset tracking state of parent
1678     // Why it is needed:
1679     // When a submemory toplevel memdesc with subdevices is freed,
1680     // the subdecice memdescs and their parent are destroyed or their
1681     // refcount decreased.
1682     // When the parent subdevice descriptors are destroyed, their
1683     // top level descriptor is left alone and has a dangling
1684     // _pNext pointer
1685     //
1686     if ((pMemDesc->_pParentDescriptor != NULL) &&
1687         (memdescHasSubDeviceMemDescs(pMemDesc->_pParentDescriptor)) &&
1688         (pMemDesc->_pParentDescriptor->RefCount == 1))
1689     {
1690         pMemDesc->_pParentDescriptor->_pNext = NULL;
1691         pMemDesc->_pParentDescriptor->_subDeviceAllocCount = 1;
1692     }
1693 }
1694 
1695 /*!
1696  *  @brief Lock the paged virtual memory descripted by the memory descriptor
1697  *
1698  *  @param[in] pMemDesc Memory descriptor to lock
1699  *
1700  *  @returns NV_OK on successful allocation. Various NV_ERR_GENERIC codes otherwise.
1701  */
1702 NV_STATUS
memdescLock(MEMORY_DESCRIPTOR * pMemDesc)1703 memdescLock
1704 (
1705     MEMORY_DESCRIPTOR *pMemDesc
1706 )
1707 {
1708 
1709     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
1710     if (!(pMemDesc->_flags & MEMDESC_FLAGS_PAGED_SYSMEM))
1711     {
1712         return NV_ERR_ILLEGAL_ACTION;
1713     }
1714 
1715     return osLockMem(pMemDesc);
1716 }
1717 
1718 /*!
1719  *  @brief Unlock the paged virtual memory descripted by the memory descriptor
1720  *
1721  *  @param[in] pMemDesc Memory descriptor to unlock
1722  *
1723  *  @returns NV_OK on successful allocation. Various NV_ERR_GENERIC codes otherwise.
1724  */
1725 NV_STATUS
memdescUnlock(MEMORY_DESCRIPTOR * pMemDesc)1726 memdescUnlock
1727 (
1728     MEMORY_DESCRIPTOR *pMemDesc
1729 )
1730 {
1731     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
1732     if (!(pMemDesc->_flags & MEMDESC_FLAGS_PAGED_SYSMEM))
1733     {
1734         return NV_ERR_ILLEGAL_ACTION;
1735     }
1736 
1737     return osUnlockMem(pMemDesc);
1738 }
1739 
1740 /*!
1741  *  @brief Get a CPU mapping to the memory described by a memory descriptor
1742  *
1743  *  This is for memory descriptors used by RM clients, not by the RM itself.
1744  *  For internal mappings the busMapRmAperture() hal routines are used.
1745  *
1746  *  @param[in]  pMemDesc    Memory descriptor to map
1747  *  @param[in]  Offset      Offset into memory descriptor to start map
1748  *  @param[in]  Size        Size of mapping
1749  *  @param[in]  Kernel      Kernel or user address space
1750  *  @param[in]  Protect     NV_PROTECT_*
1751  *  @param[out] pAddress    Return address
1752  *  @param[out] pPriv       Return cookie to be passed back to memdescUnmap
1753  *
1754  *  @returns NV_STATUS
1755  */
1756 
1757 NV_STATUS
memdescMapOld(MEMORY_DESCRIPTOR * pMemDesc,NvU64 Offset,NvU64 Size,NvBool Kernel,NvU32 Protect,void ** pAddress,void ** pPriv)1758 memdescMapOld
1759 (
1760     MEMORY_DESCRIPTOR *pMemDesc,
1761     NvU64 Offset,
1762     NvU64 Size,
1763     NvBool Kernel,
1764     NvU32 Protect,
1765     void **pAddress,
1766     void **pPriv
1767 )
1768 {
1769     NvP64 pAddressP64 = NV_PTR_TO_NvP64(*pAddress);
1770     NvP64 pPrivP64 = NV_PTR_TO_NvP64(*pPriv);
1771     NV_STATUS status;
1772 
1773 #if !defined(NV_64_BITS)
1774     NV_ASSERT(Kernel);
1775 #endif
1776 
1777     status = memdescMap(pMemDesc,
1778                         Offset,
1779                         Size,
1780                         Kernel,
1781                         Protect,
1782                         &pAddressP64,
1783                         &pPrivP64);
1784 
1785     *pAddress = NvP64_VALUE(pAddressP64);
1786     *pPriv = NvP64_VALUE(pPrivP64);
1787 
1788     return status;
1789 }
1790 
1791 NV_STATUS
memdescMap(MEMORY_DESCRIPTOR * pMemDesc,NvU64 Offset,NvU64 Size,NvBool Kernel,NvU32 Protect,NvP64 * pAddress,NvP64 * pPriv)1792 memdescMap
1793 (
1794     MEMORY_DESCRIPTOR *pMemDesc,
1795     NvU64 Offset,
1796     NvU64 Size,
1797     NvBool Kernel,
1798     NvU32 Protect,
1799     NvP64 *pAddress,
1800     NvP64 *pPriv
1801 )
1802 {
1803     NV_STATUS status     = NV_OK;
1804     NvU64     rootOffset = 0;
1805 
1806     NV_ASSERT_OR_RETURN(((Offset + Size) <= memdescGetSize(pMemDesc)), NV_ERR_INVALID_ARGUMENT);
1807 
1808     pMemDesc = memdescGetRootMemDesc(pMemDesc, &rootOffset);
1809     Offset  += rootOffset;
1810 
1811     if (pMemDesc->PteAdjust &&
1812         (pMemDesc->Alignment > RM_PAGE_SIZE) &&
1813         (pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS) &&
1814         RMCFG_FEATURE_PLATFORM_MODS)
1815     {
1816         Offset += pMemDesc->PteAdjust;
1817     }
1818 
1819     NV_ASSERT_OR_RETURN(!memdescHasSubDeviceMemDescs(pMemDesc), NV_ERR_INVALID_OBJECT_BUFFER);
1820 
1821     switch (pMemDesc->_addressSpace)
1822     {
1823         case ADDR_SYSMEM:
1824         case ADDR_EGM:
1825         {
1826             status = osMapSystemMemory(pMemDesc, Offset, Size,
1827                                        Kernel, Protect, pAddress, pPriv);
1828             if (status != NV_OK)
1829             {
1830                 return status;
1831             }
1832             break;
1833         }
1834 
1835         case ADDR_FBMEM:
1836         {
1837             OBJGPU          *pGpu                   = pMemDesc->pGpu;
1838             NvU32            mode                   = NV_MEMORY_WRITECOMBINED;
1839             KernelBus       *pKernelBus;
1840             FB_MAPPING_INFO *pMapping;
1841             RmPhysAddr       bar1PhysAddr;
1842             NvBool           bCoherentCpuMapping;
1843 
1844             NV_ASSERT_OR_RETURN(pGpu != NULL, NV_ERR_INVALID_ARGUMENT);
1845 
1846             pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
1847             bCoherentCpuMapping = pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING);
1848 
1849             // Need struct to keep track of the info for this mapping
1850             pMapping = portMemAllocNonPaged(sizeof(FB_MAPPING_INFO));
1851             if (pMapping == NULL)
1852             {
1853                 return NV_ERR_NO_MEMORY;
1854             }
1855 
1856             if (bCoherentCpuMapping)
1857             {
1858                 if (Kernel)
1859                 {
1860                     status = kbusMapCoherentCpuMapping_HAL(pGpu,
1861                                                            pKernelBus,
1862                                                            pMemDesc,
1863                                                            Offset,
1864                                                            Size,
1865                                                            Protect,
1866                                                            pAddress,
1867                                                            &pMapping->pPriv);
1868                 }
1869                 else
1870                 {
1871                     KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
1872                     NvU64              fbOffset             = memdescGetPhysAddr(pMemDesc, AT_CPU, Offset);
1873                     bar1PhysAddr = pKernelMemorySystem->coherentCpuFbBase + fbOffset;
1874 
1875                     // Until we have proper discontig support for NUMA, this assumes that the unix path is a noop
1876                     *pAddress = (NvP64) bar1PhysAddr;
1877                 }
1878 
1879 
1880                 if (status != NV_OK)
1881                 {
1882                     portMemFree(pMapping);
1883                     return status;
1884                 }
1885 
1886                 NV_PRINTF(LEVEL_INFO, "Allocating coherent link mapping. VA: %p PA: 0x%llx size: 0x%llx\n",
1887                           NvP64_VALUE(*pAddress),
1888                           memdescGetPhysAddr(pMemDesc, AT_GPU, Offset), Size);
1889 
1890                 *pPriv = NV_PTR_TO_NvP64(pMapping);
1891                 break;
1892             }
1893 
1894             // Determine where in BAR1 the mapping will go
1895             pMapping->FbApertureLen = Size;
1896             status = kbusMapFbApertureSingle(pGpu, pKernelBus,
1897                                              pMemDesc, Offset,
1898                                              &pMapping->FbAperture,
1899                                              &pMapping->FbApertureLen,
1900                                              BUS_MAP_FB_FLAGS_MAP_UNICAST,
1901                                              NULL);
1902             if (status != NV_OK)
1903             {
1904                 portMemFree(pMapping);
1905                 return status;
1906             }
1907 
1908             bar1PhysAddr = gpumgrGetGpuPhysFbAddr(pGpu) + pMapping->FbAperture;
1909             mode = NV_MEMORY_WRITECOMBINED;
1910 
1911             // Create the mapping
1912             if (Kernel)
1913             {
1914                 status = osMapPciMemoryKernel64(pGpu, bar1PhysAddr,
1915                                                 Size, Protect, pAddress,
1916                                                 mode);
1917             }
1918             else
1919             {
1920                 status = osMapPciMemoryUser(pGpu->pOsGpuInfo, bar1PhysAddr,
1921                                             Size, Protect, pAddress,
1922                                             &pMapping->pPriv,
1923                                             mode);
1924             }
1925 
1926             if (status != NV_OK)
1927             {
1928                 if (!bCoherentCpuMapping)
1929                 {
1930                     kbusUnmapFbApertureSingle(pGpu, pKernelBus, pMemDesc,
1931                                               pMapping->FbAperture,
1932                                               pMapping->FbApertureLen,
1933                                               BUS_MAP_FB_FLAGS_MAP_UNICAST);
1934                 }
1935                 portMemFree(pMapping);
1936                 return status;
1937             }
1938 
1939             *pPriv = NV_PTR_TO_NvP64(pMapping);
1940             break;
1941         }
1942 
1943         default:
1944             // Don't know how to do any other types of memory yet
1945             DBG_BREAKPOINT();
1946             return NV_ERR_GENERIC;
1947     }
1948     return NV_OK;
1949 }
1950 void
memdescUnmapOld(MEMORY_DESCRIPTOR * pMemDesc,NvBool Kernel,NvU32 ProcessId,void * Address,void * Priv)1951 memdescUnmapOld
1952 (
1953     MEMORY_DESCRIPTOR *pMemDesc,
1954     NvBool Kernel,
1955     NvU32 ProcessId,
1956     void *Address,
1957     void *Priv
1958 )
1959 {
1960     memdescUnmap(pMemDesc,
1961                  Kernel,
1962                  ProcessId,
1963                  NV_PTR_TO_NvP64(Address),
1964                  NV_PTR_TO_NvP64(Priv));
1965 }
1966 
1967 /*!
1968  *  @brief Remove a mapping for the memory descriptor, reversing memdescMap
1969  *
1970  *  @param[in]   pMemDesc       Memory descriptor to unmap
1971  *  @param[in]   Kernel         Kernel or user address space
1972  *  @param[in]   ProcessId      Process ID if user space
1973  *  @param[in]   Address        Mapped address
1974  *  @param[in]   Priv           Return priv cookie from memdescMap
1975  *
1976  *  @returns None
1977  */
1978 void
memdescUnmap(MEMORY_DESCRIPTOR * pMemDesc,NvBool Kernel,NvU32 ProcessId,NvP64 Address,NvP64 Priv)1979 memdescUnmap
1980 (
1981     MEMORY_DESCRIPTOR *pMemDesc,
1982     NvBool Kernel,
1983     NvU32 ProcessId,
1984     NvP64 Address,
1985     NvP64 Priv
1986 )
1987 {
1988     // Allow null unmaps
1989     if (!Address)
1990         return;
1991 
1992     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
1993 
1994 
1995     // find first allocated parent descriptor
1996     while (!pMemDesc->Allocated && pMemDesc->_pParentDescriptor)
1997     {
1998         pMemDesc = pMemDesc->_pParentDescriptor;
1999     }
2000 
2001     switch (pMemDesc->_addressSpace)
2002     {
2003         case ADDR_SYSMEM:
2004         case ADDR_EGM:
2005         {
2006             osUnmapSystemMemory(pMemDesc, Kernel, ProcessId, Address, Priv);
2007             break;
2008         }
2009 
2010         case ADDR_FBMEM:
2011         {
2012             OBJGPU          *pGpu                = pMemDesc->pGpu;
2013             KernelBus       *pKernelBus          = GPU_GET_KERNEL_BUS(pGpu);
2014             FB_MAPPING_INFO *pMapping            = (FB_MAPPING_INFO *)NvP64_VALUE(Priv);
2015             NvBool           bCoherentCpuMapping = pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING);
2016             NvU64            Size                = pMapping->FbApertureLen;
2017 
2018             NV_ASSERT(!(pMemDesc->_flags & MEMDESC_FLAGS_CPU_ONLY));
2019 
2020             if (bCoherentCpuMapping)
2021             {
2022                 if (Kernel)
2023                 {
2024                     kbusUnmapCoherentCpuMapping_HAL(pGpu, pKernelBus, pMemDesc, Address, pMapping->pPriv);
2025                 }
2026                 else
2027                 {
2028                     osUnmapPciMemoryUser(pGpu->pOsGpuInfo, Address, Size,
2029                                          pMapping->pPriv);
2030                 }
2031 
2032                 portMemFree(pMapping);
2033                 break;
2034             }
2035 
2036             kbusUnmapFbApertureSingle(pGpu, pKernelBus, pMemDesc,
2037                                       pMapping->FbAperture,
2038                                       Size,
2039                                       BUS_MAP_FB_FLAGS_MAP_UNICAST);
2040             if (Kernel)
2041             {
2042                 osUnmapPciMemoryKernel64(pGpu, Address);
2043             }
2044             else
2045             {
2046                 osUnmapPciMemoryUser(pGpu->pOsGpuInfo, Address, Size,
2047                                      pMapping->pPriv);
2048             }
2049 
2050             portMemFree(pMapping);
2051             break;
2052         }
2053 
2054         default:
2055             // Don't know how to do any other types of memory yet
2056             DBG_BREAKPOINT();
2057     }
2058 }
2059 
2060 typedef enum
2061 {
2062     MEMDESC_MAP_INTERNAL_TYPE_GSP,            // On GSP, use a pre-existing mapping
2063     MEMDESC_MAP_INTERNAL_TYPE_COHERENT_FBMEM, // For NVLINK, use a pre-existing mapping for fbmem
2064     MEMDESC_MAP_INTERNAL_TYPE_BAR2,           // Use BAR2 (fbmem or reflected sysmem)
2065     MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT,  // Use OS to map sysmem
2066 } MEMDESC_MAP_INTERNAL_TYPE;
2067 
2068 static MEMDESC_MAP_INTERNAL_TYPE
memdescGetMapInternalType(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc)2069 memdescGetMapInternalType
2070 (
2071     OBJGPU            *pGpu,
2072     MEMORY_DESCRIPTOR *pMemDesc
2073 )
2074 {
2075     if (RMCFG_FEATURE_PLATFORM_GSP)
2076     {
2077         return MEMDESC_MAP_INTERNAL_TYPE_GSP;
2078     }
2079     else if (pMemDesc->_addressSpace == ADDR_FBMEM &&
2080         pGpu->getProperty(pGpu, PDB_PROP_GPU_COHERENT_CPU_MAPPING))
2081     {
2082         // Temporary hack to keep the same behavior on GV100F (dVOLTA & DFPGA)
2083         if (IsDFPGA(pGpu))
2084             return MEMDESC_MAP_INTERNAL_TYPE_BAR2;
2085 
2086         return MEMDESC_MAP_INTERNAL_TYPE_COHERENT_FBMEM;
2087     }
2088     else
2089     {
2090         KernelBus *pKernelBus      = GPU_GET_KERNEL_BUS(pGpu);
2091         NvBool     bUseDirectMap   = NV_FALSE;
2092         NV_STATUS  status;
2093 
2094         status = kbusUseDirectSysmemMap_HAL(pGpu, pKernelBus, pMemDesc, &bUseDirectMap);
2095         NV_ASSERT_OR_RETURN(status == NV_OK, MEMDESC_MAP_INTERNAL_TYPE_BAR2);
2096 
2097         return bUseDirectMap ? MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT : MEMDESC_MAP_INTERNAL_TYPE_BAR2;
2098     }
2099 
2100     return MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT;
2101 }
2102 
2103 void
memdescFlushGpuCaches(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc)2104 memdescFlushGpuCaches
2105 (
2106     OBJGPU            *pGpu,
2107     MEMORY_DESCRIPTOR *pMemDesc
2108 )
2109 {
2110     KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
2111 
2112     if (memdescGetGpuCacheAttrib(pMemDesc) == NV_MEMORY_CACHED)
2113     {
2114         //
2115         // Only the non-coherent memory path is available, so writeback GPU L2
2116         // invalidate the GPU L2
2117         //
2118         kmemsysCacheOp_HAL(pGpu, pKernelMemorySystem, pMemDesc, FB_CACHE_MEM_UNDEFINED, FB_CACHE_EVICT);
2119     }
2120 }
2121 
2122 void
memdescFlushCpuCaches(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc)2123 memdescFlushCpuCaches
2124 (
2125     OBJGPU            *pGpu,
2126     MEMORY_DESCRIPTOR *pMemDesc
2127 )
2128 {
2129     // Flush WC to get the data written to this mapping out to memory
2130     osFlushCpuWriteCombineBuffer();
2131 
2132     KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
2133 
2134     // Special care is needed on SOC, where the GPU cannot snoop the CPU L2
2135     if ((pKernelBif != NULL)                     &&
2136         !kbifIsSnoopDmaCapable(pGpu, pKernelBif) &&
2137         (memdescGetCpuCacheAttrib(pMemDesc) == NV_MEMORY_CACHED))
2138     {
2139         // Flush CPU L2 so that the GPU will see any changes the CPU made
2140         osFlushCpuCache();
2141     }
2142 }
2143 
2144 /*
2145  * @brief map memory descriptor for internal access
2146  *
2147  * flags - subset of TRANSFER_FLAGS_
2148  */
2149 void*
memdescMapInternal(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,NvU32 flags)2150 memdescMapInternal
2151 (
2152     OBJGPU            *pGpu,
2153     MEMORY_DESCRIPTOR *pMemDesc,
2154     NvU32              flags
2155 )
2156 {
2157     MEMDESC_MAP_INTERNAL_TYPE  mapType;
2158     NV_STATUS                  status;
2159 
2160     NV_ASSERT_OR_RETURN(pMemDesc != NULL, NULL);
2161 
2162     if (pMemDesc->_addressSpace == ADDR_FBMEM)
2163     {
2164         pMemDesc = memdescGetMemDescFromGpu(pMemDesc, pGpu);
2165     }
2166 
2167     mapType = memdescGetMapInternalType(pGpu, pMemDesc);
2168 
2169     // We need to flush & invalidate GPU L2 cache only for directed BAR mappings.
2170     // Reflected BAR mappings will access memory via GPU, and hence go through GPU L2 cache.
2171     if (mapType == MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT)
2172         memdescFlushGpuCaches(pGpu, pMemDesc);
2173 
2174     if (pMemDesc->_pInternalMapping != NULL)
2175     {
2176         NV_ASSERT(pMemDesc->_internalMappingRefCount);
2177 
2178         // Existing BAR2 mapping may be invalid due to GPU reset
2179         if (mapType == MEMDESC_MAP_INTERNAL_TYPE_BAR2)
2180         {
2181             pMemDesc->_pInternalMapping = kbusValidateBar2ApertureMapping_HAL(pGpu, GPU_GET_KERNEL_BUS(pGpu), pMemDesc,
2182                                                                               pMemDesc->_pInternalMapping);
2183             NV_CHECK_OR_RETURN(LEVEL_ERROR, pMemDesc->_pInternalMapping != NULL, NULL);
2184         }
2185 
2186         pMemDesc->_internalMappingRefCount++;
2187         return pMemDesc->_pInternalMapping;
2188     }
2189 
2190     switch (mapType)
2191     {
2192         case MEMDESC_MAP_INTERNAL_TYPE_GSP:
2193             NV_CHECK_OR_RETURN(LEVEL_ERROR, pMemDesc->_pInternalMapping != NULL, NULL);
2194             break;
2195         case MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT:
2196         {
2197             status = memdescMapOld(pMemDesc, 0, pMemDesc->Size, NV_TRUE, NV_PROTECT_READ_WRITE,
2198                                    &pMemDesc->_pInternalMapping, &pMemDesc->_pInternalMappingPriv);
2199             NV_CHECK_OR_RETURN(LEVEL_ERROR, status == NV_OK, NULL);
2200             break;
2201         }
2202         case MEMDESC_MAP_INTERNAL_TYPE_COHERENT_FBMEM:
2203         {
2204             NV_ASSERT(pGpu->getProperty(pGpu, PDB_PROP_GPU_ATS_SUPPORTED));
2205             status = kbusMapCoherentCpuMapping_HAL(pGpu,
2206                                                    GPU_GET_KERNEL_BUS(pGpu),
2207                                                    pMemDesc,
2208                                                    0,
2209                                                    memdescGetSize(pMemDesc),
2210                                                    NV_PROTECT_READ_WRITE,
2211                                                    &pMemDesc->_pInternalMapping,
2212                                                    &pMemDesc->_pInternalMappingPriv);
2213             NV_CHECK_OR_RETURN(LEVEL_ERROR, status == NV_OK, NULL);
2214             break;
2215         }
2216         case MEMDESC_MAP_INTERNAL_TYPE_BAR2:
2217             pMemDesc->_pInternalMapping = kbusMapBar2Aperture_HAL(pGpu, GPU_GET_KERNEL_BUS(pGpu), pMemDesc, flags);
2218             NV_CHECK_OR_RETURN(LEVEL_INFO, pMemDesc->_pInternalMapping != NULL, NULL);
2219             break;
2220 
2221         default:
2222             DBG_BREAKPOINT();
2223     }
2224 
2225     pMemDesc->_internalMappingRefCount = 1;
2226     return pMemDesc->_pInternalMapping;
2227 }
2228 
memdescUnmapInternal(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,NvU32 flags)2229 void memdescUnmapInternal
2230 (
2231     OBJGPU            *pGpu,
2232     MEMORY_DESCRIPTOR *pMemDesc,
2233     NvU32              flags
2234 )
2235 {
2236     MEMDESC_MAP_INTERNAL_TYPE  mapType;
2237 
2238     NV_ASSERT_OR_RETURN_VOID(pMemDesc != NULL);
2239     NV_ASSERT_OR_RETURN_VOID(pMemDesc->_pInternalMapping != NULL && pMemDesc->_internalMappingRefCount != 0);
2240 
2241     if (pMemDesc->_addressSpace == ADDR_FBMEM)
2242     {
2243         pMemDesc = memdescGetMemDescFromGpu(pMemDesc, pGpu);
2244     }
2245 
2246     mapType = memdescGetMapInternalType(pGpu, pMemDesc);
2247 
2248     if (mapType == MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT || mapType == MEMDESC_MAP_INTERNAL_TYPE_BAR2)
2249     {
2250         memdescFlushCpuCaches(pGpu, pMemDesc);
2251     }
2252 
2253     if (--pMemDesc->_internalMappingRefCount == 0)
2254     {
2255         switch (mapType)
2256         {
2257             case MEMDESC_MAP_INTERNAL_TYPE_GSP:
2258                 break;
2259             case MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT:
2260                 memdescUnmapOld(pMemDesc, NV_TRUE, 0,
2261                                 pMemDesc->_pInternalMapping, pMemDesc->_pInternalMappingPriv);
2262                 break;
2263 
2264             case MEMDESC_MAP_INTERNAL_TYPE_COHERENT_FBMEM:
2265             {
2266                 //
2267                 // This flag is set when there is an update in BAR1/FLA PDE/PTE and when mmufill
2268                 // of BAR1 and FLA read on NINB_VC which doesn't probe the cpu cache.
2269                 //
2270                 // TODO: This flag needs to be set when updating PDE/PTE for invisible BAR2 also.
2271                 //
2272                 if (flags & TRANSFER_FLAGS_FLUSH_CPU_CACHE_WAR_BUG4686457)
2273                 {
2274                     osFlushGpuCoherentCpuCacheRange(pGpu->pOsGpuInfo,
2275                                                     (NvUPtr)pMemDesc->_pInternalMapping,
2276                                                     pMemDesc->ActualSize);
2277                 }
2278 
2279                 kbusUnmapCoherentCpuMapping_HAL(pGpu, GPU_GET_KERNEL_BUS(pGpu), pMemDesc,
2280                                                 pMemDesc->_pInternalMapping, pMemDesc->_pInternalMappingPriv);
2281                 break;
2282             }
2283             case MEMDESC_MAP_INTERNAL_TYPE_BAR2:
2284             {
2285                 NvU8 *p = (NvU8 *)pMemDesc->_pInternalMapping;
2286 
2287                 kbusUnmapBar2ApertureWithFlags_HAL(pGpu, GPU_GET_KERNEL_BUS(pGpu), pMemDesc, &p, flags);
2288                 break;
2289             }
2290 
2291             default:
2292                 DBG_BREAKPOINT();
2293         }
2294 
2295         pMemDesc->_pInternalMapping        = NULL;
2296         pMemDesc->_pInternalMappingPriv    = NULL;
2297         pMemDesc->_internalMappingRefCount = 0;
2298     }
2299 
2300     // Flush for direct mappings too to keep the behavior
2301     if (((flags & TRANSFER_FLAGS_DEFER_FLUSH) == 0) &&
2302         (mapType == MEMDESC_MAP_INTERNAL_TYPE_SYSMEM_DIRECT || mapType == MEMDESC_MAP_INTERNAL_TYPE_BAR2))
2303     {
2304         kbusFlush_HAL(pGpu, GPU_GET_KERNEL_BUS(pGpu),
2305                       kbusGetFlushAperture(GPU_GET_KERNEL_BUS(pGpu), memdescGetAddressSpace(pMemDesc)));
2306     }
2307 }
2308 
2309 /*!
2310  *  Describe an existing region of memory in a memory descriptor
2311  *
2312  *  Memory must be physically contiguous.
2313  *
2314  *  The memory descriptor must be initialized with
2315  *  memdescCreate*(), typically memdescCreateExisting()
2316  *  prior to calling memdescDescribe.
2317  *
2318  *  memdescDescribe() now only updates the fields needed in the call.
2319  *
2320  *  @param[out]  pMemDesc       Memory descriptor to fill
2321  *  @param[in]   AddressSpace   Address space of memory
2322  *  @param[in]   Base           Physical address of region
2323  *  @param[in]   Size           Size of region
2324  *
2325  *  @returns None
2326  */
2327 void
memdescDescribe(MEMORY_DESCRIPTOR * pMemDesc,NV_ADDRESS_SPACE AddressSpace,RmPhysAddr Base,NvU64 Size)2328 memdescDescribe
2329 (
2330     MEMORY_DESCRIPTOR *pMemDesc,
2331     NV_ADDRESS_SPACE AddressSpace,
2332     RmPhysAddr Base,
2333     NvU64 Size
2334 )
2335 {
2336     // Some sanity checks to see if we went through MemCreate*() first
2337     NV_ASSERT((pMemDesc->RefCount == 1) &&
2338               (memdescGetDestroyCallbackList(pMemDesc) == NULL) &&
2339               (pMemDesc->PteAdjust == 0));
2340 
2341     NV_ASSERT(pMemDesc->_pIommuMappings == NULL);
2342     NV_ASSERT(pMemDesc->Allocated == 0);
2343     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
2344 
2345     //
2346     // Check if the base address accounts for the DMA window start address
2347     // (always in the high, unaddressable bits of the address) and add it
2348     // if necessary. On most platforms, the DMA window start address will
2349     // simply be 0.
2350     //
2351     // This is most likely to happen in cases where the Base address is
2352     // read directly from a register or MMU entry, which does not already
2353     // account for the DMA window.
2354     //
2355     if (pMemDesc->pGpu == NULL)
2356     {
2357         NV_PRINTF(LEVEL_WARNING,
2358                   "unable to check Base 0x%016llx for DMA window\n", Base);
2359     }
2360     else if (AddressSpace == ADDR_SYSMEM)
2361     {
2362         OBJGPU *pGpu = pMemDesc->pGpu;
2363         if (pGpu)
2364         {
2365             KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
2366             NvU32 physAddrWidth = gpuGetPhysAddrWidth_HAL(pGpu, ADDR_SYSMEM);
2367             if ((Base & ~(NVBIT64(physAddrWidth) - 1)) == 0)
2368             {
2369                 Base += pKernelBif->dmaWindowStartAddress;
2370             }
2371         }
2372     }
2373 
2374     if (pMemDesc->Alignment != 0)
2375     {
2376         NV_ASSERT(NV_FLOOR_TO_QUANTA(Base, pMemDesc->Alignment) == Base);
2377     }
2378 
2379     pMemDesc->Size                 = Size;
2380     pMemDesc->ActualSize           = NV_ROUNDUP(Size, pMemDesc->pageArrayGranularity);
2381     pMemDesc->_flags              |= MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS;
2382     pMemDesc->_addressSpace        = AddressSpace;
2383     pMemDesc->_pteArray[0]         = Base & ~RM_PAGE_MASK;
2384     pMemDesc->_subDeviceAllocCount = 1;
2385     pMemDesc->PteAdjust            = NvU64_LO32(Base) & RM_PAGE_MASK;
2386     pMemDesc->PageCount            = ((Size + pMemDesc->PteAdjust + RM_PAGE_SIZE - 1) >> RM_PAGE_SHIFT);
2387     pMemDesc->_pParentDescriptor   = NULL;
2388     pMemDesc->childDescriptorCnt   = 0;
2389 }
2390 
2391 /*!
2392  * Static helper called from memdescFillPages.
2393  * When dynamic granularity memdescs are enabled. We only need to copy over the pages
2394  * without worrying about converting them to 4K.
2395  *
2396  *  @param[in]   pMemDesc       Memory descriptor to fill
2397  *  @param[in]   pageIndex      Index into memory descriptor to fill from
2398  *  @param[in]   pPages         Array of physical addresses
2399  *  @param[in]   pageCount      Number of entries in pPages
2400  *  @param[in]   pageSize       Size of each page in pPages
2401  *
2402  *  @returns None
2403  */
2404 static void
_memdescFillPagesAtNativeGranularity(MEMORY_DESCRIPTOR * pMemDesc,NvU32 pageIndex,NvU64 * pPages,NvU32 pageCount,NvU64 pageSize)2405 _memdescFillPagesAtNativeGranularity
2406 (
2407     MEMORY_DESCRIPTOR   *pMemDesc,
2408     NvU32                pageIndex,
2409     NvU64               *pPages,
2410     NvU32                pageCount,
2411     NvU64                pageSize
2412 )
2413 {
2414     NV_STATUS status;
2415 
2416     NV_ASSERT(pageIndex + pageCount < pMemDesc->PageCount);
2417 
2418     status = memdescSetPageArrayGranularity(pMemDesc, pageSize);
2419     if (status != NV_OK)
2420     {
2421         return;
2422     }
2423 
2424     for (NvU32 i = 0; i < pageCount; i++)
2425     {
2426         pMemDesc->_pteArray[pageIndex + i] = pPages[i];
2427     }
2428 
2429     pMemDesc->ActualSize = pageCount * pageSize;
2430 }
2431 
2432 /*!
2433  * Fill the PTE array of a memory descriptor with an array of addresses
2434  * returned by pmaAllocatePages().
2435  *
2436  *  Memory must be physically discontiguous. For the contiguous case
2437  *  memdescDescribe() is more apt.
2438  *
2439  *  The memory descriptor must be initialized with memdescCreate*(),
2440  *  typically memdescCreateExisting() prior to calling
2441  *  memdescFillPages().
2442  *
2443  *  @param[in]   pMemDesc       Memory descriptor to fill
2444  *  @param[in]   pageIndex      Index into memory descriptor to fill from
2445  *  @param[in]   pPages         Array of physical addresses
2446  *  @param[in]   pageCount      Number of entries in pPages
2447  *  @param[in]   pageSize       Size of each page in pPages
2448  *
2449  *  @returns None
2450  */
2451 void
memdescFillPages(MEMORY_DESCRIPTOR * pMemDesc,NvU32 pageIndex,NvU64 * pPages,NvU32 pageCount,NvU64 pageSize)2452 memdescFillPages
2453 (
2454     MEMORY_DESCRIPTOR   *pMemDesc,
2455     NvU32                pageIndex,
2456     NvU64               *pPages,
2457     NvU32                pageCount,
2458     NvU64                pageSize
2459 )
2460 {
2461     OBJGPU *pGpu = gpumgrGetSomeGpu();
2462     NvU32 i, j, k;
2463     NvU32 numChunks4k = pageSize / RM_PAGE_SIZE;
2464     NvU32 offset4k = numChunks4k * pageIndex;
2465     NvU32 pageCount4k = numChunks4k * pageCount;
2466     NvU32 result4k, limit4k;
2467     NvU64 addr;
2468 
2469     NV_ASSERT(pMemDesc != NULL);
2470 
2471     if (GPU_GET_MEMORY_MANAGER(pGpu)->bEnableDynamicGranularityPageArrays)
2472     {
2473         _memdescFillPagesAtNativeGranularity(pMemDesc, pageIndex, pPages, pageCount, pageSize);
2474         return;
2475     }
2476 
2477     NV_ASSERT(offset4k < pMemDesc->PageCount);
2478     NV_ASSERT(portSafeAddU32(offset4k, pageCount4k, &result4k));
2479 
2480     //
2481     // There is a possibility that the pMemDesc was created using 4K aligned
2482     // allocSize, but the actual memory allocator could align up the allocation
2483     // size based on its supported pageSize, (e.g. PMA supports 64K pages). In
2484     // that case, pageCount4k would be greater than pMemdesc->pageCount. We
2485     // limit pageCount4k to stay within pMemdesc->pageCount in that case.
2486     //
2487     if (result4k > pMemDesc->PageCount)
2488         pageCount4k = pMemDesc->PageCount - offset4k;
2489 
2490     NV_ASSERT(pageSize > 0);
2491     NV_ASSERT(0 == (pageSize & (RM_PAGE_SIZE - 1)));
2492     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
2493 
2494     // Fill _pteArray array using numChunks4k as a stride
2495     for (i = 0, j = offset4k; i < pageCount; i++, j += numChunks4k)
2496     {
2497         pMemDesc->_pteArray[j] = addr = pPages[i];
2498 
2499         // Fill _pteArray at 4K granularity
2500         limit4k = NV_MIN(j + numChunks4k, pageCount4k);
2501 
2502         addr += RM_PAGE_SIZE;
2503         for (k = j + 1; k < limit4k; k++, addr += RM_PAGE_SIZE)
2504             pMemDesc->_pteArray[k] = addr;
2505     }
2506 }
2507 
2508 /*!
2509  *  @brief Acquire exclusive use for memdesc for RM.
2510  *
2511  *  @param[inout] pMemDesc Memory descriptor
2512  *
2513  *  @returns Boolean indicating whether we successfully acquired the memdesc for exclusive use
2514  */
2515 NvBool
memdescAcquireRmExclusiveUse(MEMORY_DESCRIPTOR * pMemDesc)2516 memdescAcquireRmExclusiveUse
2517 (
2518     MEMORY_DESCRIPTOR *pMemDesc
2519 )
2520 {
2521     NV_CHECK_OR_RETURN(LEVEL_ERROR, pMemDesc->_pParentDescriptor == NULL &&
2522                                     !pMemDesc->bRmExclusiveUse &&
2523                                     pMemDesc->DupCount == 1,
2524                        NV_FALSE);
2525 
2526     pMemDesc->bRmExclusiveUse = NV_TRUE;
2527     return NV_TRUE;
2528 }
2529 
2530 //
2531 // SubMemory per subdevice chart: (MD - Memory Descriptor, SD - subdevice)
2532 //
2533 // If we try to create submemory of descriptor which has subdevices:
2534 //
2535 //   [Top level MD]
2536 //       ^      |
2537 //       |      +--------> [     Subdevice 0 MD    ] --------> [Subdevice 1 MD]
2538 //       |                       ^                               ^
2539 //       |                       |                               |
2540 //  [SubMemory top level MD]     |                               |
2541 //             |                 |                               |
2542 //             +--------> [Subdevice 0 SubMemory MD] --------> [Subdevice 1 SubMemory MD]
2543 //
2544 // Top Level MD             : parent of SubMemoryTopLevelMD; has subdescriptors
2545 //                            for two subdevices
2546 // SubMemory top level MD   : has pointer to parent memory descriptor; has two
2547 //                            subdevice MDs
2548 // Subdevice 0 MD           : subdevice MD of topLevelMD and parent of SD0
2549 //                            submemory descriptor; has pointer to next in the
2550 //                            list of subdevice MDs
2551 // Subdevice 0 SubMemory MD : submemory of subdevice 0 MD; has pointer to
2552 //                            parent, subdevice 0 MD and to next in list of
2553 //                            submemory subdevice memory descriptors
2554 //
2555 
2556 
2557 
2558 /*!
2559  *  @brief Create a new memory descriptor that is a subset of pMemDesc. If
2560  *  pMemDesc has subdevice memory descriptors subMemory will be created for all
2561  *  subdevices and new memory descriptor will be top level for them (ASCII art)
2562  *
2563  *  @param[out]  ppMemDescNew   New memory descriptor
2564  *  @param[in]   pMemDesc       Original memory descriptor
2565  *  @param[in]   pGpu           The GPU that this memory will be mapped to
2566  *  @param[in]   Offset         Sub memory descriptor starts at pMemdesc+Offset
2567  *  @param[in]   Size           For Size bytes
2568  *
2569  *  @returns None
2570  */
2571 NV_STATUS
memdescCreateSubMem(MEMORY_DESCRIPTOR ** ppMemDescNew,MEMORY_DESCRIPTOR * pMemDesc,OBJGPU * pGpu,NvU64 Offset,NvU64 Size)2572 memdescCreateSubMem
2573 (
2574     MEMORY_DESCRIPTOR **ppMemDescNew,
2575     MEMORY_DESCRIPTOR *pMemDesc,
2576     OBJGPU *pGpu,
2577     NvU64 Offset,
2578     NvU64 Size
2579 )
2580 {
2581     NV_STATUS status;
2582     MEMORY_DESCRIPTOR *pMemDescNew;
2583     NvU32 subDevInst;
2584     NvU64 tmpSize = Size;
2585     MEMORY_DESCRIPTOR *pLast;
2586     MEMORY_DESCRIPTOR *pNew;
2587     OBJGPU *pGpuChild;
2588     const NvU64 pageArrayGranularity = pMemDesc->pageArrayGranularity;
2589     const NvU64 pageArrayGranularityMask = pMemDesc->pageArrayGranularity - 1;
2590     const NvU32 pageArrayGranularityShift = BIT_IDX_64(pMemDesc->pageArrayGranularity);
2591 
2592     // Default to the original memdesc's GPU if none is specified
2593     if (pGpu == NULL)
2594     {
2595         pGpu = pMemDesc->pGpu;
2596     }
2597 
2598     // Allocation size should be adjusted for the memory descriptor _pageSize.
2599     // Also note that the first 4k page may not be at _pageSize boundary so at
2600     // the time of the mapping, we maybe overmapping at the beginning or end of
2601     // the descriptor. To fix it in the right way, memory descriptor needs to
2602     // be further cleaned. Do not round to page size if client specifies so.
2603     if (!(pMemDesc->_flags & MEMDESC_FLAGS_PAGE_SIZE_ALIGN_IGNORE) &&
2604           pMemDesc->_pageSize != 0)
2605     {
2606         PMEMORY_DESCRIPTOR pTempMemDesc = pMemDesc;
2607         NvU64              pageOffset;
2608 
2609         if (memdescHasSubDeviceMemDescs(pMemDesc))
2610         {
2611             NV_ASSERT(pGpu);
2612             pTempMemDesc = memdescGetMemDescFromGpu(pMemDesc, pGpu);
2613         }
2614 
2615         pageOffset = memdescGetPhysAddr(pTempMemDesc, AT_CPU, Offset) &
2616                      (pTempMemDesc->_pageSize - 1);
2617 
2618         // Check for integer overflow
2619         if (!portSafeAddU64(pageOffset, Size, &tmpSize))
2620         {
2621             return NV_ERR_INVALID_ARGUMENT;
2622         }
2623 
2624         tmpSize = RM_ALIGN_UP(pageOffset + Size, pTempMemDesc->_pageSize);
2625 
2626         // Check for integer overflow
2627         if (tmpSize < pageOffset + Size)
2628         {
2629             return NV_ERR_INVALID_ARGUMENT;
2630         }
2631     }
2632 
2633     // Allocate the new MEMORY_DESCRIPTOR
2634     status = memdescCreate(&pMemDescNew, pGpu, tmpSize, 0,
2635                            !!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS),
2636                            pMemDesc->_addressSpace,
2637                            pMemDesc->_cpuCacheAttrib,
2638                            ((pMemDesc->_flags & ~MEMDESC_FLAGS_PRE_ALLOCATED) | MEMDESC_FLAGS_SKIP_RESOURCE_COMPUTE));
2639 
2640     if (status != NV_OK)
2641     {
2642         return status;
2643     }
2644 
2645     // Fill in various fields as best we can; XXX this can get sort of sketchy
2646     // in places, which should be all the more motivation to rip some of these
2647     // fields out of the MEMORY_DESCRIPTOR.
2648     if (pMemDesc->_flags & MEMDESC_FLAGS_KERNEL_MODE)
2649         pMemDescNew->_flags |= MEMDESC_FLAGS_KERNEL_MODE;
2650     else
2651         pMemDescNew->_flags &= ~MEMDESC_FLAGS_KERNEL_MODE;
2652 
2653     //
2654     // This flag used to indicate the memdesc needs to restore pte kind
2655     // when it is freed. It should only not be set for any sub memDesc.
2656     //
2657     pMemDescNew->_flags &= ~MEMDESC_FLAGS_RESTORE_PTE_KIND_ON_FREE;
2658 
2659     pMemDescNew->Size = Size;
2660     pMemDescNew->_pteKind = pMemDesc->_pteKind;
2661     pMemDescNew->_hwResId = pMemDesc->_hwResId;
2662     if (pMemDesc->_flags & MEMDESC_FLAGS_ENCRYPTED)
2663         pMemDescNew->_flags |= MEMDESC_FLAGS_ENCRYPTED;
2664     else
2665         pMemDescNew->_flags &= ~MEMDESC_FLAGS_ENCRYPTED;
2666     pMemDescNew->_pageSize   = pMemDesc->_pageSize;
2667     pMemDescNew->pageArrayGranularity = pageArrayGranularity;
2668     pMemDescNew->_gpuCacheAttrib = pMemDesc->_gpuCacheAttrib;
2669     pMemDescNew->_gpuP2PCacheAttrib  = pMemDesc->_gpuP2PCacheAttrib;
2670     pMemDescNew->gfid                = pMemDesc->gfid;
2671     pMemDescNew->bUsingSuballocator  = pMemDesc->bUsingSuballocator;
2672     pMemDescNew->_pParentDescriptor  = pMemDesc;
2673     pMemDesc->childDescriptorCnt++;
2674     pMemDescNew->bRmExclusiveUse = pMemDesc->bRmExclusiveUse;
2675     pMemDescNew->numaNode        = pMemDesc->numaNode;
2676 
2677     pMemDescNew->subMemOffset        = Offset;
2678 
2679     // increase refCount of parent descriptor
2680     memdescAddRef(pMemDesc);
2681 
2682     // Fill in the PteArray and PteAdjust
2683     if ((pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS) ||
2684         (pMemDesc->PageCount == 1))
2685     {
2686         // Compute the base address, then fill it in
2687         RmPhysAddr Base = pMemDesc->_pteArray[0] + pMemDesc->PteAdjust + Offset;
2688         pMemDescNew->_pteArray[0] = Base & ~pageArrayGranularityMask;
2689         pMemDescNew->PteAdjust   = NvU64_LO32(Base) & pageArrayGranularityMask;
2690 
2691         if (memdescIsEgm(pMemDesc))
2692         {
2693             NV_ASSERT_OK_OR_GOTO(status,
2694                                  _memdescAllocEgmArray(pMemDescNew),
2695                                  fail);
2696         }
2697     }
2698     else
2699     {
2700         // More complicated...
2701         RmPhysAddr Adjust;
2702         NvU32 PageIndex, i;
2703 
2704         // We start this many bytes into the memory alloc
2705         Adjust = pMemDesc->PteAdjust + Offset;
2706 
2707         // Break it down into pages (PageIndex) and bytes (PteAdjust)
2708         PageIndex = (NvU32)(Adjust >> pageArrayGranularityShift);
2709         pMemDescNew->PteAdjust = NvU64_LO32(Adjust) & pageArrayGranularityMask;
2710 
2711         // Fill in the PTEs; remember to copy the extra PTE, in case we need it
2712         if (pMemDesc->PageCount)
2713         {
2714             for (i = 0; i < pMemDescNew->PageCount+1; i++)
2715             {
2716                 NvU32 j = i + PageIndex;
2717                 if (j < pMemDesc->PageCount)
2718                 {
2719                     pMemDescNew->_pteArray[i] = pMemDesc->_pteArray[j];
2720                 }
2721                 else
2722                 {
2723                     //
2724                     // This case can happen with page size greater than 4KB.
2725                     // Since pages are always tracked at 4KB granularity the
2726                     // subset description may overflow the parent memdesc.
2727                     //
2728                     // In this case the best we can do is describe the contiguous
2729                     // memory after the last 4KB page in the sub-memdesc.
2730                     //
2731                     // TODO: Tracking memdesc pages at native page size would
2732                     //       remove the need for several hacks, including this one.
2733                     //
2734                     NV_ASSERT(i > 0);
2735                     pMemDescNew->_pteArray[i] = pMemDescNew->_pteArray[i - 1] + pMemDescNew->pageArrayGranularity;
2736                 }
2737             }
2738 
2739             if (memdescIsEgm(pMemDesc))
2740             {
2741                 NV_ASSERT_OK_OR_GOTO(status,
2742                                      _memdescAllocEgmArray(pMemDescNew),
2743                                      fail);
2744             }
2745         }
2746     }
2747 
2748     if ((pMemDesc->_addressSpace == ADDR_SYSMEM) &&
2749         !memdescIsEgm(pMemDesc) &&
2750         !memdescGetFlag(memdescGetMemDescFromGpu(pMemDesc, pGpu), MEMDESC_FLAGS_CPU_ONLY) &&
2751         !memdescGetFlag(memdescGetMemDescFromGpu(pMemDesc, pGpu), MEMDESC_FLAGS_MAP_SYSCOH_OVER_BAR1) &&
2752         !memdescGetFlag(memdescGetMemDescFromGpu(pMemDesc, pGpu), MEMDESC_FLAGS_SKIP_IOMMU_MAPPING))
2753     {
2754         //
2755         // For different IOVA spaces, the IOMMU mapping will often not be a
2756         // subrange of the original mapping.
2757         //
2758         // Request the submapping to be associated with the submemdesc.
2759         //
2760         // TODO: merge the new IOMMU paths with the SMMU path above (see bug
2761         //       1625121).
2762         //
2763         status = memdescMapIommu(pMemDescNew, pGpu->busInfo.iovaspaceId);
2764         if (status != NV_OK)
2765         {
2766             memdescDestroy(pMemDescNew);
2767             return status;
2768         }
2769     }
2770 
2771     // Support for SLI submemory per-subdevice allocations (refer to chart)
2772     if (memdescHasSubDeviceMemDescs(pMemDesc))
2773     {
2774         NvBool bBcState = gpumgrGetBcEnabledStatus(pGpu);
2775 
2776         if (gpumgrGetBcEnabledStatus(pGpu) && (pMemDesc->_addressSpace == ADDR_FBMEM))
2777         {
2778             NV_ASSERT(!!(pMemDesc->_flags & MEMDESC_FLAGS_ALLOC_PER_SUBDEVICE));
2779             gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
2780         }
2781         pLast = pMemDescNew;
2782 
2783         pMemDescNew->_subDeviceAllocCount = pMemDesc->_subDeviceAllocCount;
2784 
2785         for (subDevInst = 0; subDevInst < pMemDesc->_subDeviceAllocCount; subDevInst++)
2786         {
2787             pGpuChild = gpumgrGetGpuFromSubDeviceInst(gpuGetDeviceInstance(pGpu), subDevInst);
2788             status = memdescCreateSubMem(&pNew, memdescGetMemDescFromGpu(pMemDesc, pGpuChild), pGpuChild, Offset, Size);
2789 
2790             if (status != NV_OK)
2791             {
2792                 while (NULL != pMemDescNew)
2793                 {
2794                     pNew = pMemDescNew;
2795                     pMemDescNew = pMemDescNew->_pNext;
2796                     memdescDestroy(pNew);
2797                 }
2798                 return status;
2799             }
2800 
2801             pLast->_pNext = pNew;
2802             pLast = pNew;
2803         }
2804 
2805         gpumgrSetBcEnabledStatus(pGpu, bBcState);
2806     }
2807 
2808     *ppMemDescNew = pMemDescNew;
2809 
2810     return NV_OK;
2811 
2812 fail:
2813     memdescDestroy(pMemDescNew);
2814     return status;
2815 }
2816 
2817 /*!
2818  * Given a memdesc, this checks if the allocated memory falls under subheap or in GPA address space
2819  */
2820 static NvBool
_memIsSriovMappingsEnabled(PMEMORY_DESCRIPTOR pMemDesc)2821 _memIsSriovMappingsEnabled
2822 (
2823     PMEMORY_DESCRIPTOR   pMemDesc
2824 )
2825 {
2826     return gpuIsSriovEnabled(pMemDesc->pGpu) &&
2827            (((pMemDesc->_flags & MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE) && pMemDesc->bUsingSuballocator) ||
2828             (pMemDesc->_flags & MEMDESC_FLAGS_GUEST_ALLOCATED));
2829 }
2830 
2831 /*!
2832  * Fills pGpaEntries with numEntries GPAs from pMemDesc->_pteArray starting at
2833  * the given starting index. For physically contiguous memdescs, fills with
2834  * RM_PAGE_SIZE strides.
2835  */
2836 static void
_memdescFillGpaEntriesForSpaTranslation(PMEMORY_DESCRIPTOR pMemDesc,RmPhysAddr * pGpaEntries,NvU32 start,NvU32 numEntries)2837 _memdescFillGpaEntriesForSpaTranslation
2838 (
2839     PMEMORY_DESCRIPTOR   pMemDesc,
2840     RmPhysAddr          *pGpaEntries,
2841     NvU32                start,
2842     NvU32                numEntries
2843 )
2844 {
2845     if (pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)
2846     {
2847         NvU32 i;
2848 
2849         for (i = 0; i < numEntries; i++)
2850         {
2851             pGpaEntries[i] = pMemDesc->_pteArray[0] + (((RmPhysAddr) (start + i)) * pMemDesc->pageArrayGranularity);
2852         }
2853     }
2854     else
2855     {
2856         portMemCopy(&pGpaEntries[0], numEntries * sizeof(pGpaEntries[0]),
2857                     &pMemDesc->_pteArray[start], numEntries * sizeof(pGpaEntries[0]));
2858     }
2859 }
2860 
2861 /*!
2862  * This function translates GPA -> SPA for a given memdesc and updates pPteSpaMappings with list of SPA addresses.
2863  * If memdesc is contiguous and if the translated SPA count > 1, this function fails for now.
2864  */
2865 NV_STATUS
_memdescUpdateSpaArray(PMEMORY_DESCRIPTOR pMemDesc)2866 _memdescUpdateSpaArray
2867 (
2868     PMEMORY_DESCRIPTOR   pMemDesc
2869 )
2870 {
2871     NV_STATUS   status   = NV_OK;
2872     RM_API     *pRmApi   = GPU_GET_PHYSICAL_RMAPI(pMemDesc->pGpu);
2873     NvU32       allocCnt;
2874     NvU32       i;
2875     NV2080_CTRL_INTERNAL_VMMU_GET_SPA_FOR_GPA_ENTRIES_PARAMS *pParams = NULL;
2876 
2877     if ((pMemDesc->pPteSpaMappings) || (!pMemDesc->PageCount))
2878     {
2879         status = NV_OK;
2880         goto _memUpdateSpArray_exit;
2881     }
2882 
2883     allocCnt = memdescGetPteArraySize(pMemDesc, AT_PA);
2884 
2885     // Allocate the array to hold pages up to PageCount
2886     pMemDesc->pPteSpaMappings = portMemAllocNonPaged(sizeof(RmPhysAddr) * allocCnt);
2887     if (pMemDesc->pPteSpaMappings == NULL)
2888     {
2889         status = NV_ERR_NO_MEMORY;
2890         goto _memUpdateSpArray_exit;
2891     }
2892 
2893     pParams = portMemAllocStackOrHeap(sizeof(*pParams));
2894     if (pParams == NULL)
2895     {
2896         status = NV_ERR_NO_MEMORY;
2897         goto _memUpdateSpArray_exit;
2898     }
2899     portMemSet(pParams, 0, sizeof(*pParams));
2900 
2901     pParams->gfid = pMemDesc->gfid;
2902 
2903     for (i = 0; i < allocCnt; i += NV2080_CTRL_INTERNAL_VMMU_MAX_SPA_FOR_GPA_ENTRIES)
2904     {
2905         NvU32 numEntries = NV_MIN(allocCnt - i, NV2080_CTRL_INTERNAL_VMMU_MAX_SPA_FOR_GPA_ENTRIES);
2906         pParams->numEntries = numEntries;
2907 
2908         _memdescFillGpaEntriesForSpaTranslation(pMemDesc, &pParams->gpaEntries[0],
2909                                                 i, numEntries);
2910 
2911         status = pRmApi->Control(pRmApi,
2912                                  pMemDesc->pGpu->hInternalClient,
2913                                  pMemDesc->pGpu->hInternalSubdevice,
2914                                  NV2080_CTRL_CMD_INTERNAL_VMMU_GET_SPA_FOR_GPA_ENTRIES,
2915                                  pParams,
2916                                  sizeof(*pParams));
2917         if (status != NV_OK)
2918         {
2919             NV_PRINTF(LEVEL_ERROR, "Getting SPA for GPA failed: GFID=%u, GPA=0x%llx\n",
2920                       pMemDesc->gfid, pMemDesc->_pteArray[i]);
2921             goto _memUpdateSpArray_exit;
2922         }
2923 
2924         portMemCopy(&pMemDesc->pPteSpaMappings[i], numEntries * sizeof(pParams->spaEntries[0]),
2925                     &pParams->spaEntries[0], numEntries * sizeof(pParams->spaEntries[0]));
2926     }
2927 
2928 _memUpdateSpArray_exit:
2929     if (status != NV_OK)
2930     {
2931         portMemFree(pMemDesc->pPteSpaMappings);
2932         pMemDesc->pPteSpaMappings = NULL;
2933     }
2934     portMemFreeStackOrHeap(pParams);
2935 
2936     return status;
2937 }
2938 
2939 /*!
2940  *  @brief Return the physical addresses of pMemdesc
2941  *
2942  *  @param[in]  pMemDesc            Memory descriptor used
2943  *  @param[in]  pGpu                GPU to return the addresses for
2944  *  @param[in]  addressTranslation  Address translation identifier
2945  *  @param[in]  offset              Offset into memory descriptor
2946  *  @param[in]  stride              How much to advance the offset for each
2947  *                                  consecutive address
2948  *  @param[in]  count               How many addresses to retrieve
2949  *  @param[out] pAddresses          Returned array of addresses
2950  *
2951  */
memdescGetPhysAddrsForGpu(MEMORY_DESCRIPTOR * pMemDesc,OBJGPU * pGpu,ADDRESS_TRANSLATION addressTranslation,NvU64 offset,NvU64 stride,NvU64 count,RmPhysAddr * pAddresses)2952 void memdescGetPhysAddrsForGpu(MEMORY_DESCRIPTOR *pMemDesc,
2953                                OBJGPU *pGpu,
2954                                ADDRESS_TRANSLATION addressTranslation,
2955                                NvU64 offset,
2956                                NvU64 stride,
2957                                NvU64 count,
2958                                RmPhysAddr *pAddresses)
2959 {
2960     //
2961     // Get the PTE array that we should use for phys addr lookups based on the
2962     // MMU context. (see bug 1625121)
2963     //
2964     NvU64 i;
2965     NvU64 pageIndex;
2966     RmPhysAddr *pteArray = memdescGetPteArrayForGpu(pMemDesc, pGpu, addressTranslation);
2967     const NvBool contiguous = (memdescGetPteArraySize(pMemDesc, addressTranslation) == 1);
2968     const NvU64 pageArrayGranularityMask = pMemDesc->pageArrayGranularity - 1;
2969     const NvU32 pageArrayGranularityShift = BIT_IDX_64(pMemDesc->pageArrayGranularity);
2970 
2971     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
2972     offset += pMemDesc->PteAdjust;
2973 
2974     for (i = 0; i < count; ++i)
2975     {
2976         if (contiguous)
2977         {
2978             pAddresses[i] = pteArray[0] + offset;
2979         }
2980         else
2981         {
2982             pageIndex = offset >> pageArrayGranularityShift;
2983             NV_CHECK_OR_RETURN_VOID(LEVEL_ERROR, pageIndex < pMemDesc->PageCount);
2984             pAddresses[i] = pteArray[pageIndex] + (offset & pageArrayGranularityMask);
2985         }
2986 
2987         offset += stride;
2988     }
2989 }
2990 
2991 
2992 /*!
2993  *  @brief Return the physical addresses of pMemdesc
2994  *
2995  *  @param[in]  pMemDesc           Memory descriptor used
2996  *  @param[in]  addressTranslation Address translation identifier
2997  *  @param[in]  offset             Offset into memory descriptor
2998  *  @param[in]  stride             How much to advance the offset for each
2999  *                                 consecutive address
3000  *  @param[in]  count              How many addresses to retrieve
3001  *  @param[out] pAddresses         Returned array of addresses
3002  *
3003  */
memdescGetPhysAddrs(MEMORY_DESCRIPTOR * pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU64 offset,NvU64 stride,NvU64 count,RmPhysAddr * pAddresses)3004 void memdescGetPhysAddrs(MEMORY_DESCRIPTOR *pMemDesc,
3005                          ADDRESS_TRANSLATION addressTranslation,
3006                          NvU64 offset,
3007                          NvU64 stride,
3008                          NvU64 count,
3009                          RmPhysAddr *pAddresses)
3010 {
3011     memdescGetPhysAddrsForGpu(pMemDesc, pMemDesc->pGpu, addressTranslation, offset, stride, count, pAddresses);
3012 }
3013 
3014 /*!
3015  *  @brief Return the physical address of pMemdesc+Offset
3016  *
3017  *  "long description"
3018  *
3019  *  @param[in]  pMemDesc           Memory descriptor used
3020  *  @param[in]  addressTranslation Address translation identifier
3021  *  @param[in]  offset             Offset into memory descriptor
3022  *
3023  *  @returns A physical address
3024  */
3025 RmPhysAddr
memdescGetPhysAddr(MEMORY_DESCRIPTOR * pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU64 offset)3026 memdescGetPhysAddr
3027 (
3028     MEMORY_DESCRIPTOR *pMemDesc,
3029     ADDRESS_TRANSLATION addressTranslation,
3030     NvU64 offset
3031 )
3032 {
3033     RmPhysAddr addr;
3034     memdescGetPhysAddrs(pMemDesc, addressTranslation, offset, 0, 1, &addr);
3035     return addr;
3036 }
3037 
3038 /*!
3039  *  @brief Return physical address for page specified by PteIndex
3040  *
3041  *  @param[in]  pMemDesc           Memory descriptor to use
3042  *  @param[in]  addressTranslation Address translation identifier
3043  *  @param[in]  PteIndex           Look up this PteIndex
3044  *
3045  *  @returns A physical address
3046  */
3047 RmPhysAddr
memdescGetPte(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU32 PteIndex)3048 memdescGetPte
3049 (
3050     PMEMORY_DESCRIPTOR  pMemDesc,
3051     ADDRESS_TRANSLATION addressTranslation,
3052     NvU32               PteIndex
3053 )
3054 {
3055     //
3056     // Get the PTE array that we should use for phys addr lookups based on the
3057     // MMU context. (see bug 1625121)
3058     //
3059     RmPhysAddr *pteArray = memdescGetPteArray(pMemDesc, addressTranslation);
3060     RmPhysAddr PhysAddr;
3061 
3062     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3063 
3064     if (pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)
3065     {
3066         PhysAddr = pteArray[0] + (PteIndex << RM_PAGE_SHIFT);
3067     }
3068     else
3069     {
3070         PhysAddr = pteArray[PteIndex];
3071     }
3072 
3073     return PhysAddr;
3074 }
3075 
3076 /*!
3077  *  @brief Return physical address for page specified by PteIndex
3078  *
3079  *  @param[in]  pMemDesc           Memory descriptor to use
3080  *  @param[in]  addressTranslation Address translation identifier
3081  *  @param[in]  PteIndex           Look up this PteIndex
3082  *  @param[in]  PhysAddr           PTE address
3083  *
3084  *  @returns None
3085  */
3086 void
memdescSetPte(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU32 PteIndex,RmPhysAddr PhysAddr)3087 memdescSetPte
3088 (
3089     PMEMORY_DESCRIPTOR  pMemDesc,
3090     ADDRESS_TRANSLATION addressTranslation,
3091     NvU32               PteIndex,
3092     RmPhysAddr          PhysAddr
3093 )
3094 {
3095     //
3096     // Get the PTE array that we should use for phys addr lookups based on the
3097     // MMU context. (see bug 1625121)
3098     //
3099     RmPhysAddr *pteArray = memdescGetPteArray(pMemDesc, addressTranslation);
3100     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3101 
3102     if (pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)
3103     {
3104         NV_ASSERT_OR_RETURN_VOID(PteIndex == 0);
3105     }
3106 
3107     pteArray[PteIndex] = PhysAddr;
3108 
3109     // Free pteArraySpa
3110     portMemFree(pMemDesc->pPteSpaMappings);
3111     pMemDesc->pPteSpaMappings = NULL;
3112 }
3113 
3114 /*!
3115  *  @brief Return page array size based on the MMU context
3116  *         For SRIOV, the host context (AT_PA) will
3117  *         have discontiguous view of the GPA in SPA space
3118  *         This is treated similar to discontiguous memdescs
3119  *
3120  *  @param[in]  pMemDesc           Memory descriptor to use
3121  *  @param[in]  addressTranslation Address translation identifier
3122  *
3123  *  @returns PageArray
3124  */
memdescGetPteArraySize(MEMORY_DESCRIPTOR * pMemDesc,ADDRESS_TRANSLATION addressTranslation)3125 NvU32 memdescGetPteArraySize(MEMORY_DESCRIPTOR *pMemDesc, ADDRESS_TRANSLATION addressTranslation)
3126 {
3127     // Contiguous allocations in SPA domain can be non-contiguous at vmmusegment granularity.
3128     // Hence treat SPA domain allocations as non-contiguous by default.
3129     if (!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS) ||
3130          ((addressTranslation == AT_PA) && (pMemDesc->_addressSpace == ADDR_FBMEM) && _memIsSriovMappingsEnabled(pMemDesc)))
3131     {
3132         return NvU64_LO32(pMemDesc->PageCount);
3133     }
3134     return 1;
3135 }
3136 
3137 /*!
3138  *  @brief Return page array
3139  *
3140  *  @param[in]  pMemDesc           Memory descriptor to use
3141  *  @param[in]  pGpu               GPU to get the PTE array for.
3142  *  @param[in]  addressTranslation Address translation identifier
3143  *
3144  *  @returns PageArray
3145  */
3146 RmPhysAddr *
memdescGetPteArrayForGpu(PMEMORY_DESCRIPTOR pMemDesc,OBJGPU * pGpu,ADDRESS_TRANSLATION addressTranslation)3147 memdescGetPteArrayForGpu
3148 (
3149     PMEMORY_DESCRIPTOR  pMemDesc,
3150     OBJGPU             *pGpu,
3151     ADDRESS_TRANSLATION addressTranslation
3152 )
3153 {
3154     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3155 
3156     switch (AT_VALUE(addressTranslation))
3157     {
3158         //
3159         // In SRIOV systems, an access from guest has to go through the following translations
3160         //     GVA -> GPA -> SPA
3161         //
3162         // Given HOST manages channel/memory management for guest, there are certain code paths that
3163         // expects VA -> GPA translations and some may need GPA -> SPA translations. We use addressTranslation
3164         // to differentiate between these cases.
3165         // Since GPA -> SPA is very similar to IOMMU xlation and since existing AT_PA is used only in
3166         // SYSMEM allocations, we decided to reuse AT_PA addressTranslation to fetch GPA -> SPA xlations.
3167         // In case of non-SRIOV systems, using AT_PA will fall back to AT_GPU or default context.
3168         //
3169         // pMemDesc -> _pteArray       tracks GVA -> GPA translations
3170         // pMemDesc -> pPteSpaMappings tracks GPA -> SPA translations
3171         //
3172 
3173         case AT_VALUE(AT_PA):
3174         {
3175             if (pGpu != NULL)
3176             {
3177                 if (pMemDesc->_addressSpace == ADDR_FBMEM)
3178                 {
3179                     if (_memIsSriovMappingsEnabled(pMemDesc))
3180                     {
3181                         if (!pMemDesc->pPteSpaMappings)
3182                             _memdescUpdateSpaArray(pMemDesc);
3183 
3184                         return pMemDesc->pPteSpaMappings;
3185                     }
3186                 }
3187             }
3188         }
3189         case AT_VALUE(AT_GPU):
3190         {
3191             // Imported ADDR_FABRIC_V2 memdescs are device-less.
3192             if (pGpu != NULL)
3193             {
3194                 if (memdescIsEgm(pMemDesc) && (pMemDesc->pPteEgmMappings != NULL))
3195                 {
3196                     return pMemDesc->pPteEgmMappings;
3197                 }
3198 
3199                 PIOVAMAPPING pIovaMap = memdescGetIommuMap(pMemDesc,
3200                                             pGpu->busInfo.iovaspaceId);
3201                 if (pIovaMap != NULL)
3202                 {
3203                     return pIovaMap->iovaArray;
3204                 }
3205             }
3206 
3207             //
3208             // If no IOMMU mapping exists in the default IOVASPACE, fall
3209             // through and use the physical memory descriptor instead.
3210             //
3211         }
3212         default:
3213         {
3214             return pMemDesc->_pteArray;
3215         }
3216     }
3217 }
3218 
3219 
3220 
3221 /*!
3222  *  @brief Convert aperture into a descriptive string.
3223  *
3224  *  @param[in]  addressSpace
3225  *
3226  *  @returns String
3227  *
3228  *  @todo "text"
3229  */
3230 const char *
memdescGetApertureString(NV_ADDRESS_SPACE addressSpace)3231 memdescGetApertureString
3232 (
3233     NV_ADDRESS_SPACE addressSpace
3234 )
3235 {
3236     static NV_PRINTF_STRING_SECTION const char ADDR_FBMEM_STR[]  = "VIDEO MEMORY";
3237     static NV_PRINTF_STRING_SECTION const char ADDR_SYSMEM_STR[] = "SYSTEM MEMORY";
3238 
3239     if (addressSpace == ADDR_FBMEM)
3240     {
3241         return ADDR_FBMEM_STR;
3242     }
3243 
3244     if (addressSpace == ADDR_SYSMEM)
3245     {
3246         return ADDR_SYSMEM_STR;
3247     }
3248 
3249     return NULL;
3250 }
3251 
3252 /*!
3253  *  @brief Compare two memory descriptors to see if the memory described the same
3254  *
3255  *  @param[in]  pMemDescOne
3256  *  @param[in]  pMemDescTwo
3257  *
3258  *  @returns NV_TRUE if the memory descriptors refer to the same memory
3259  */
3260 NvBool
memdescDescIsEqual(MEMORY_DESCRIPTOR * pMemDescOne,MEMORY_DESCRIPTOR * pMemDescTwo)3261 memdescDescIsEqual
3262 (
3263     MEMORY_DESCRIPTOR *pMemDescOne,
3264     MEMORY_DESCRIPTOR *pMemDescTwo
3265 )
3266 {
3267     if ((pMemDescOne == NULL) || (pMemDescTwo == NULL))
3268         return NV_FALSE;
3269 
3270     if (pMemDescOne->_addressSpace != pMemDescTwo->_addressSpace)
3271         return NV_FALSE;
3272 
3273     // All the physical memory views should match.
3274     if ((memdescGetPhysAddr(pMemDescOne, AT_CPU, 0) != memdescGetPhysAddr(pMemDescTwo, AT_CPU, 0)) ||
3275         (memdescGetPhysAddr(pMemDescOne, AT_GPU, 0) != memdescGetPhysAddr(pMemDescTwo, AT_GPU, 0)))
3276         return NV_FALSE;
3277 
3278     if (memdescGetCpuCacheAttrib(pMemDescOne) != memdescGetCpuCacheAttrib(pMemDescTwo))
3279         return NV_FALSE;
3280 
3281     if (pMemDescOne->Size != pMemDescTwo->Size)
3282         return NV_FALSE;
3283 
3284     if (pMemDescOne->Alignment != pMemDescTwo->Alignment)
3285         return NV_FALSE;
3286 
3287     if (pMemDescOne->_pageSize != pMemDescTwo->_pageSize)
3288         return NV_FALSE;
3289 
3290     return NV_TRUE;
3291 }
3292 
3293 /*!
3294  *  @brief Add callback block to the destroy callback queue
3295  *
3296  *  @param[in]  pMemDesc  Memory descriptor to update
3297  *  @param[in]  pCb       Callee allocated block with callback func/arg
3298  *
3299  *  @returns nothing
3300  */
3301 void
memdescAddDestroyCallback(MEMORY_DESCRIPTOR * pMemDesc,MEM_DESC_DESTROY_CALLBACK * pCb)3302 memdescAddDestroyCallback
3303 (
3304     MEMORY_DESCRIPTOR *pMemDesc,
3305     MEM_DESC_DESTROY_CALLBACK *pCb
3306 )
3307 {
3308     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3309     pCb->pNext = memdescGetDestroyCallbackList(pMemDesc);
3310     memdescSetDestroyCallbackList(pMemDesc, pCb);
3311 }
3312 
3313 /*!
3314  *  @brief Remove callback block from the destroy callback queue
3315  *
3316  *  @param[in]  pMemDesc  Memory descriptor to update
3317  *  @param[in]  pRemoveCb Callee allocated block with callback func/arg
3318  *
3319  *  @returns nothing
3320  */
3321 void
memdescRemoveDestroyCallback(MEMORY_DESCRIPTOR * pMemDesc,MEM_DESC_DESTROY_CALLBACK * pRemoveCb)3322 memdescRemoveDestroyCallback
3323 (
3324     MEMORY_DESCRIPTOR *pMemDesc,
3325     MEM_DESC_DESTROY_CALLBACK *pRemoveCb
3326 )
3327 {
3328     MEM_DESC_DESTROY_CALLBACK *pCb = memdescGetDestroyCallbackList(pMemDesc);
3329     MEM_DESC_DESTROY_CALLBACK *pPrev = NULL;
3330 
3331     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3332     while (pCb)
3333     {
3334         if (pCb == pRemoveCb)
3335         {
3336             if (pPrev == NULL)
3337             {
3338                 memdescSetDestroyCallbackList(pMemDesc, pCb->pNext);
3339             }
3340             else
3341             {
3342                 pPrev->pNext = pCb->pNext;
3343             }
3344             break;
3345         }
3346         pPrev = pCb;
3347         pCb = pCb->pNext;
3348     }
3349 }
3350 
3351 /*!
3352  *  @brief Retrieves a subdevice's memory descriptor by subdevice instance
3353  *
3354  *  Subdevice memory descriptors are memory descriptors that describe
3355  *  per-subdevice memory buffers. This functionality is required by our current
3356  *  SLI programming model as our memdescAlloc() calls are primarily broadcast
3357  *  operations. A singular memdesc works for video memory as the
3358  *  heaps are symmetric. However, we run into trouble when dealing with system
3359  *  memory as both GPUs then share the same address space and symmetric
3360  *  addressing is no longer possible.
3361  *
3362  *  N.B. The rational for exposing this routine is that it keeps SLI-isms out of
3363  *  most of the RM -- the alternative approach would've been to pass in the
3364  *  subdevice or a pGpu for all memdesc methods which would require more code
3365  *  changes solely for SLI. Long term hopefully we can transition to a unicast
3366  *  allocation model (SLI loops above memdescAlloc()/memdescCreate()) and the
3367  *  subdevice support in memdesc can (easily) be deleted. This approach also
3368  *  provides a safety net against misuse, e.g., if we added pGpu to
3369  *  memdescGetPhysAddr, current code which utilizes that routine outside an SLI loop
3370  *  would execute cleanly even though it's incorrect.
3371  *
3372  *  @param[in]  pMemDesc        Memory descriptor to query
3373  *  @param[in]  subDeviceInst   SLI subdevice instance (subdevice - 1)
3374  *
3375  *  @returns Memory descriptor if one exist for the subdevice.
3376  *           NULL if none is found.
3377  */
3378 MEMORY_DESCRIPTOR *
memdescGetMemDescFromSubDeviceInst(MEMORY_DESCRIPTOR * pMemDesc,NvU32 subDeviceInst)3379 memdescGetMemDescFromSubDeviceInst(MEMORY_DESCRIPTOR *pMemDesc, NvU32 subDeviceInst)
3380 {
3381     if (!memdescHasSubDeviceMemDescs(pMemDesc))
3382     {
3383         return pMemDesc;
3384     }
3385     else
3386     {
3387         return memdescGetMemDescFromIndex(pMemDesc, subDeviceInst);
3388     }
3389 }
3390 
3391 /*!
3392  *  @brief Retrieves a subdevice's memory descriptor by GPU object
3393  *
3394  *  See memdescGetMemDescFromSubDeviceInst for an explanation of subdevice memory
3395  *  descriptors
3396  *
3397  *  @param[in]  pMemDesc  Memory descriptor to query
3398  *  @param[in]  pGpu
3399  *
3400  *  @returns Memory descriptor if one exist for the GPU.
3401  *           NULL if none is found.
3402  */
3403 MEMORY_DESCRIPTOR *
memdescGetMemDescFromGpu(MEMORY_DESCRIPTOR * pMemDesc,OBJGPU * pGpu)3404 memdescGetMemDescFromGpu(MEMORY_DESCRIPTOR *pMemDesc, OBJGPU *pGpu)
3405 {
3406     NvU32 subDeviceInst = gpumgrGetSubDeviceInstanceFromGpu(pGpu);
3407 
3408     return memdescGetMemDescFromSubDeviceInst(pMemDesc, subDeviceInst);
3409 }
3410 
3411 /*!
3412  *  @brief Retrieves a subdevice's memory descriptor by memdesc index.
3413  *
3414  *  See memdescGetMemDescFromSubDeviceInst for an explanation of subdevice memory
3415  *  descriptors
3416  *
3417  *  @param[in]  pMemDesc  Memory descriptor to query
3418  *  @param[in]  index     Index into array of memdesc
3419  *
3420  *  @returns Memory descriptor if one exist for the GPU.
3421  *           NULL if none is found.
3422  */
3423 MEMORY_DESCRIPTOR *
memdescGetMemDescFromIndex(MEMORY_DESCRIPTOR * pMemDesc,NvU32 index)3424 memdescGetMemDescFromIndex(MEMORY_DESCRIPTOR *pMemDesc, NvU32 index)
3425 {
3426     if (!memdescHasSubDeviceMemDescs(pMemDesc))
3427     {
3428         return pMemDesc;
3429     }
3430     else
3431     {
3432         MEMORY_DESCRIPTOR *pSubDevMemDesc = pMemDesc->_pNext;
3433 
3434         NV_ASSERT(pSubDevMemDesc);
3435 
3436         while (index--)
3437         {
3438             pSubDevMemDesc = pSubDevMemDesc->_pNext;
3439 
3440             if (!pSubDevMemDesc)
3441             {
3442                 NV_ASSERT(0);
3443                 return NULL;
3444             }
3445         }
3446 
3447         return pSubDevMemDesc;
3448     }
3449 }
3450 
3451 /*!
3452  *  @brief Set address for a fixed heap allocation.
3453  *
3454  *  Offset must refer to the heap.  A later memdescAlloc() will
3455  *  force this offset.
3456  *
3457  *  @param[in]  pMemDesc  Memory descriptor to update
3458  *  @param[in]  fbOffset  Offset to refer to
3459  *
3460  *  @returns nothing
3461  */
3462 void
memdescSetHeapOffset(MEMORY_DESCRIPTOR * pMemDesc,RmPhysAddr fbOffset)3463 memdescSetHeapOffset
3464 (
3465     MEMORY_DESCRIPTOR *pMemDesc,
3466     RmPhysAddr fbOffset
3467 )
3468 {
3469     NV_ASSERT(pMemDesc->_addressSpace == ADDR_FBMEM);
3470     NV_ASSERT(pMemDesc->Allocated == NV_FALSE);
3471 
3472     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3473     pMemDesc->_flags      |= MEMDESC_FLAGS_FIXED_ADDRESS_ALLOCATE;
3474     pMemDesc->_pteArray[0] = fbOffset;
3475 }
3476 
3477 /*!
3478  *  @brief Set GPU cacheability
3479  *
3480  *  A later memdescAlloc() will use this setting.
3481  *
3482  *  @param[in]  pMemDesc    Memory descriptor to update
3483  *  @param[in]  cacheAttrib Set memory to GPU cacheable
3484  *
3485  *  @returns nothing
3486  */
memdescSetGpuCacheAttrib(MEMORY_DESCRIPTOR * pMemDesc,NvU32 cacheAttrib)3487 void memdescSetGpuCacheAttrib
3488 (
3489     MEMORY_DESCRIPTOR *pMemDesc,
3490     NvU32 cacheAttrib
3491 )
3492 {
3493     NV_ASSERT(pMemDesc->Allocated == NV_FALSE);
3494 
3495     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3496     pMemDesc->_gpuCacheAttrib = cacheAttrib;
3497 }
3498 
3499 /*!
3500  *  @brief Get GPU P2P cache attributes
3501  *
3502  *  @param[in]  pMemDesc    Memory descriptor pointer
3503  *
3504  *  @returns Current GPU P2P cache attributes
3505  */
memdescGetGpuP2PCacheAttrib(MEMORY_DESCRIPTOR * pMemDesc)3506 NvU32 memdescGetGpuP2PCacheAttrib
3507 (
3508     MEMORY_DESCRIPTOR *pMemDesc
3509 )
3510 {
3511     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3512     return pMemDesc->_gpuP2PCacheAttrib;
3513 }
3514 
3515 /*!
3516  *  @brief Set GPU P2P cacheability
3517  *
3518  *  A later memdescAlloc() will use this setting.
3519  *
3520  *  @param[in]  pMemDesc    Memory descriptor to update
3521  *  @param[in]  cacheAttrib Set memory to GPU P2P cacheable
3522  *
3523  *  @returns nothing
3524  */
memdescSetGpuP2PCacheAttrib(MEMORY_DESCRIPTOR * pMemDesc,NvU32 cacheAttrib)3525 void memdescSetGpuP2PCacheAttrib
3526 (
3527     MEMORY_DESCRIPTOR *pMemDesc,
3528     NvU32 cacheAttrib
3529 )
3530 {
3531     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3532     pMemDesc->_gpuP2PCacheAttrib = cacheAttrib;
3533 }
3534 
3535 /*!
3536  *  @brief Set CPU cacheability
3537  *
3538  *  A later memdescAlloc() will use this setting.
3539  *
3540  *  @param[in]  pMemDesc    Memory descriptor to update
3541  *  @param[in]  cacheAttrib Set memory to CPU cacheable
3542  *
3543  *  @returns nothing
3544  */
memdescSetCpuCacheAttrib(MEMORY_DESCRIPTOR * pMemDesc,NvU32 cpuCacheAttrib)3545 void memdescSetCpuCacheAttrib
3546 (
3547     MEMORY_DESCRIPTOR *pMemDesc,
3548     NvU32 cpuCacheAttrib
3549 )
3550 {
3551     //
3552     // When running 64-bit MODS on ARM v8, we need to force all CPU mappings as WC.
3553     // This seems to be an issue with glibc. See bug 1556221.
3554     //
3555     // Ideally, this should have been set based on a Core Logic (CL) property.
3556     // But chipset initialization will only happen during bifStateInit().
3557     // RM can makes sysmem CPU mappings before bifStateInit().
3558     //
3559     if (RMCFG_FEATURE_PLATFORM_MODS && NVCPU_IS_AARCH64)
3560     {
3561         if (cpuCacheAttrib == NV_MEMORY_UNCACHED)
3562         {
3563             cpuCacheAttrib = NV_MEMORY_WRITECOMBINED;
3564         }
3565     }
3566 
3567     pMemDesc->_cpuCacheAttrib = cpuCacheAttrib;
3568 }
3569 
3570 /*!
3571  *  @brief Print contents of a MEMORY_DESCRIPTOR in a human readable format.
3572  *
3573  *  @param[in]  pMemDesc                Memory Descriptor to print
3574  *  @param[in]  bPrintIndividualPages   Individual pages will also be printed
3575  *                                      iff they are discontiguous
3576  *  @param[in]  pPrefixMessage          Message that will be printed before the contents
3577  *                                      of the Memory Descriptor are printed.
3578  *
3579  *  @returns nothing
3580  */
memdescPrintMemdesc(MEMORY_DESCRIPTOR * pMemDesc,NvBool bPrintIndividualPages,const char * pPrefixMessage)3581 void memdescPrintMemdesc
3582 (
3583     MEMORY_DESCRIPTOR *pMemDesc,
3584     NvBool             bPrintIndividualPages,
3585     const char        *pPrefixMessage
3586 )
3587 {
3588 #if 0
3589     NvU32 i;
3590 
3591     if ((DBG_RMMSG_CHECK(DBG_LEVEL_INFO) == 0) || (pPrefixMessage == NULL) || (pMemDesc == NULL))
3592     {
3593         return;
3594     }
3595 
3596     NV_PRINTF(LEVEL_INFO,
3597                 "%s Aperture %s starting at 0x%llx and of size 0x%llx\n",
3598                 pPrefixMessage,
3599                 memdescGetApertureString(pMemDesc->_addressSpace),
3600                 memdescGetPhysAddr(pMemDesc, AT_CPU, 0),
3601                 pMemDesc->Size);
3602 
3603     if ((bPrintIndividualPages == NV_TRUE) &&
3604         (pMemDesc->PageCount > 1) &&
3605         (!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS)))
3606     {
3607         for (i = 0; i < pMemDesc->PageCount; i++)
3608         {
3609             NV_PRINTF(LEVEL_INFO,
3610                         "     contains page starting @0x%llx\n",
3611                         pMemDesc->_pteArray[i]);
3612         }
3613     }
3614 
3615     // TODO: merge with SMMU path above (see bug 1625121).
3616     if (pMemDesc->_pIommuMappings != NULL)
3617     {
3618         if (!memdescIsSubMemoryMemDesc(pMemDesc))
3619         {
3620             PIOVAMAPPING pIovaMap = pMemDesc->_pIommuMappings;
3621             while (pIovaMap != NULL)
3622             {
3623                 NV_PRINTF(LEVEL_INFO,
3624                     "Has additional IOMMU mapping for IOVA space 0x%x starting @ 0x%llx\n",
3625                     pIovaMap->iovaspaceId,
3626                     pIovaMap->iovaArray[0]);
3627                 pIovaMap = pIovaMap->pNext;
3628             }
3629         }
3630         else
3631         {
3632             NV_PRINTF(LEVEL_INFO,
3633                 "Has additional IOMMU mapping starting @ 0x%llx\n",
3634                 memdescGetPhysAddr(pMemDesc, AT_PA, 0));
3635         }
3636     }
3637 #endif // NV_PRINTF_ENABLED
3638 }
3639 
3640 /*!
3641  *  @brief Return page offset from a MEMORY_DESCRIPTOR for an arbitrary power of two page size
3642  *
3643  *  PageAdjust covers the 4KB alignment, but must include bits from the address for big pages.
3644  *
3645  *  @param[in]  pMemDesc                Memory Descriptor to print
3646  *  @param[in]  pageSize                Page size (4096, 64K, 128K, etc)
3647  *
3648  *  @returns nothing
3649  */
memdescGetPageOffset(MEMORY_DESCRIPTOR * pMemDesc,NvU64 pageSize)3650 NvU64 memdescGetPageOffset
3651 (
3652     MEMORY_DESCRIPTOR *pMemDesc,
3653     NvU64 pageSize
3654 )
3655 {
3656     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3657     return  (pMemDesc->PteAdjust + pMemDesc->_pteArray[0]) & (pageSize-1);
3658 }
3659 
3660 /*!
3661  *  @brief Get PTE kind using GPU
3662  *
3663  *  @param[in]  pMemDesc           Memory descriptor pointer
3664  *  @param[in]  pGpu               GPU to be used get supported kind
3665  *  @param[in]  addressTranslation Address translation identifier
3666  *
3667  *  @returns Current PTE kind value.
3668  */
memdescGetPteKindForGpu(PMEMORY_DESCRIPTOR pMemDesc,OBJGPU * pGpu)3669 NvU32 memdescGetPteKindForGpu
3670 (
3671     PMEMORY_DESCRIPTOR  pMemDesc,
3672     OBJGPU             *pGpu
3673 )
3674 {
3675     return memmgrGetHwPteKindFromSwPteKind_HAL(pGpu, GPU_GET_MEMORY_MANAGER(pGpu), pMemDesc->_pteKind);
3676 }
3677 
3678 /*!
3679  *  @brief Set PTE kind using GPU.
3680  *
3681  *  @param[in]  pMemDesc           Memory descriptor pointer
3682  *  @param[in]  pGpu               GPU to be used set supported kind
3683  *  @param[in]  addressTranslation Address translation identifier
3684  *  @param[in]  pteKind            New PTE kind
3685  *
3686  *  @returns nothing
3687  */
memdescSetPteKindForGpu(PMEMORY_DESCRIPTOR pMemDesc,OBJGPU * pGpu,NvU32 pteKind)3688 void memdescSetPteKindForGpu
3689 (
3690     PMEMORY_DESCRIPTOR  pMemDesc,
3691     OBJGPU             *pGpu,
3692     NvU32               pteKind
3693 )
3694 {
3695     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3696     pMemDesc->_pteKind = memmgrGetSwPteKindFromHwPteKind_HAL(pGpu, GPU_GET_MEMORY_MANAGER(pGpu), pteKind);
3697     memdescSetFlag(pMemDesc, MEMDESC_FLAGS_SET_KIND, NV_TRUE);
3698 }
3699 
3700 /*!
3701  *  @brief Set PTE kind compressed value.
3702  *
3703  *  @param[in]  pMemDesc           Memory descriptor pointer
3704  *  @param[in]  pteKind            New PTE kind compressed value
3705  *
3706  *  @returns nothing
3707  */
memdescSetPteKindCompressed(PMEMORY_DESCRIPTOR pMemDesc,NvU32 pteKindCmpr)3708 void memdescSetPteKindCompressed
3709 (
3710     PMEMORY_DESCRIPTOR  pMemDesc,
3711     NvU32               pteKindCmpr
3712 )
3713 {
3714     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3715     pMemDesc->_pteKindCompressed = pteKindCmpr;
3716 }
3717 
3718 /*!
3719  *  @brief Get PTE kind compressed value.
3720  *
3721  *  @param[in]  pMemDesc           Memory descriptor pointer
3722  *  @param[in]  addressTranslation Address translation identifier
3723  *
3724  *  @returns Current PTE kind compressed value.
3725  */
memdescGetPteKindCompressed(PMEMORY_DESCRIPTOR pMemDesc)3726 NvU32 memdescGetPteKindCompressed
3727 (
3728     PMEMORY_DESCRIPTOR  pMemDesc
3729 )
3730 {
3731     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3732     return pMemDesc->_pteKindCompressed;
3733 }
3734 
3735 /*!
3736  *  @brief Get kernel mapping
3737  *
3738  *  @param[in]  pMemDesc    Memory descriptor pointer
3739  *
3740  *  @returns Current kernel mapping
3741  */
memdescGetKernelMapping(MEMORY_DESCRIPTOR * pMemDesc)3742 NvP64 memdescGetKernelMapping
3743 (
3744     MEMORY_DESCRIPTOR *pMemDesc
3745 )
3746 {
3747     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3748     return pMemDesc->_kernelMapping;
3749 }
3750 
3751 /*!
3752  *  @brief Set kernel mapping
3753  *
3754  *  @param[in]  pMemDesc        Memory descriptor pointer
3755  *  @param[in]  kernelMapping   New kernel mapping
3756  *
3757  *  @returns nothing
3758  */
memdescSetKernelMapping(MEMORY_DESCRIPTOR * pMemDesc,NvP64 kernelMapping)3759 void memdescSetKernelMapping
3760 (
3761     MEMORY_DESCRIPTOR *pMemDesc,
3762     NvP64 kernelMapping
3763 )
3764 {
3765     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3766     pMemDesc->_kernelMapping = kernelMapping;
3767 }
3768 
3769 /*!
3770  *  @brief Get privileged kernel mapping
3771  *
3772  *  @param[in]  pMemDesc    Memory descriptor pointer
3773  *
3774  *  @returns Current privileged kernel mapping
3775  */
memdescGetKernelMappingPriv(MEMORY_DESCRIPTOR * pMemDesc)3776 NvP64 memdescGetKernelMappingPriv
3777 (
3778     MEMORY_DESCRIPTOR *pMemDesc
3779 )
3780 {
3781     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3782     return pMemDesc->_kernelMappingPriv;
3783 }
3784 
3785 /*!
3786  *  @brief Set HW resource identifier (HwResId)
3787  *
3788  *  @param[in]  pMemDesc            Memory descriptor pointer
3789  *  @param[in]  kernelMappingPriv   New privileged kernel mapping
3790  *
3791  *  @returns nothing
3792  */
memdescSetKernelMappingPriv(MEMORY_DESCRIPTOR * pMemDesc,NvP64 kernelMappingPriv)3793 void memdescSetKernelMappingPriv
3794 (
3795     MEMORY_DESCRIPTOR *pMemDesc,
3796     NvP64 kernelMappingPriv
3797 )
3798 {
3799     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3800     pMemDesc->_kernelMappingPriv = kernelMappingPriv;
3801 }
3802 
3803 
3804 /*!
3805  *  @brief Set standby buffer memory descriptor
3806  *
3807  *  @param[in]  pMemDesc    Memory descriptor pointer
3808  *
3809  *  @returns Pointer to standby buffer memory descriptor
3810  */
memdescGetStandbyBuffer(MEMORY_DESCRIPTOR * pMemDesc)3811 MEMORY_DESCRIPTOR *memdescGetStandbyBuffer
3812 (
3813     MEMORY_DESCRIPTOR *pMemDesc
3814 )
3815 {
3816     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3817     return pMemDesc->_pStandbyBuffer;
3818 }
3819 
3820 /*!
3821  *  @brief Set standby buffer memory descriptor
3822  *
3823  *  @param[in]  pMemDesc        Memory descriptor pointer
3824  *  @param[in]  pStandbyBuffer  Standby buffer memory descriptor pointer
3825  *
3826  *  @returns nothing
3827  */
memdescSetStandbyBuffer(MEMORY_DESCRIPTOR * pMemDesc,MEMORY_DESCRIPTOR * pStandbyBuffer)3828 void memdescSetStandbyBuffer
3829 (
3830     MEMORY_DESCRIPTOR *pMemDesc,
3831     MEMORY_DESCRIPTOR *pStandbyBuffer
3832 )
3833 {
3834     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3835     pMemDesc->_pStandbyBuffer = pStandbyBuffer;
3836 }
3837 
3838 /*!
3839  *  @brief Set mem destroy callback list pointer
3840  *
3841  *  @param[in]  pMemDesc                Memory descriptor pointer
3842  *  @param[in]  pMemDestroyCallbackList Memory destroy callback list pointer
3843  *
3844  *  @returns nothing
3845  */
memdescSetDestroyCallbackList(MEMORY_DESCRIPTOR * pMemDesc,MEM_DESC_DESTROY_CALLBACK * pCb)3846 void memdescSetDestroyCallbackList
3847 (
3848     MEMORY_DESCRIPTOR *pMemDesc,
3849     MEM_DESC_DESTROY_CALLBACK *pCb
3850 )
3851 {
3852     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3853     pMemDesc->_pMemDestroyCallbackList = pCb;
3854 }
3855 
3856 /*!
3857  *  @brief Get guest ID for specified memory descriptor
3858  *
3859  *  @param[in]  pMemDesc    Memory descriptor pointer
3860  *
3861  *  @returns Guest ID value
3862  */
memdescGetGuestId(MEMORY_DESCRIPTOR * pMemDesc)3863 NvU64 memdescGetGuestId
3864 (
3865     MEMORY_DESCRIPTOR *pMemDesc
3866 )
3867 {
3868     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3869     return pMemDesc->_guestId;
3870 }
3871 
3872 /*!
3873  *  @brief Set guest ID for memory descriptor
3874  *
3875  *  @param[in]  pMemDesc    Memory descriptor pointer
3876  *  @param[in]  guestId     New guest ID
3877  *
3878  *  @returns nothing
3879  */
memdescSetGuestId(MEMORY_DESCRIPTOR * pMemDesc,NvU64 guestId)3880 void memdescSetGuestId
3881 (
3882     MEMORY_DESCRIPTOR *pMemDesc,
3883     NvU64 guestId
3884 )
3885 {
3886     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3887     pMemDesc->_guestId = guestId;
3888 }
3889 
3890 /*!
3891  *  @brief Get value of specified flag
3892  *
3893  *  @param[in]  pMemDesc    Memory descriptor pointer
3894  *  @param[in]  flag        MEMDESC_FLAGS_* value
3895  *
3896  *  @returns Boolean value of specified flag
3897  */
memdescGetFlag(MEMORY_DESCRIPTOR * pMemDesc,NvU64 flag)3898 NvBool memdescGetFlag
3899 (
3900     MEMORY_DESCRIPTOR *pMemDesc,
3901     NvU64 flag
3902 )
3903 {
3904     // For checking contiguity, use the memdescGetContiguity() api
3905     NV_ASSERT(flag != MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS);
3906     // GPU_IN_RESET is set/got from top level memdesc always.
3907     if (flag != MEMDESC_FLAGS_GPU_IN_RESET)
3908     {
3909         NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3910     }
3911     return !!(pMemDesc->_flags & flag);
3912 }
3913 
3914 /*!
3915  *  @brief Set value of specified flag
3916  *
3917  *  @param[in]  pMemDesc    Memory descriptor pointer
3918  *  @param[in]  flag        MEMDESC_FLAGS_* value
3919  *  @param[in]  bValue      Boolean value of flag
3920  *
3921  *  @returns nothing
3922  */
memdescSetFlag(MEMORY_DESCRIPTOR * pMemDesc,NvU64 flag,NvBool bValue)3923 void memdescSetFlag
3924 (
3925     MEMORY_DESCRIPTOR *pMemDesc,
3926     NvU64 flag,
3927     NvBool bValue
3928 )
3929 {
3930     // For setting contiguity, use the memdescSetContiguity() api
3931     NV_ASSERT(flag != MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS);
3932 
3933     // GPU_IN_RESET is set/got from top level memdesc always.
3934     if (flag != MEMDESC_FLAGS_GPU_IN_RESET)
3935     {
3936         NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3937     }
3938 
3939     if (flag == MEMDESC_FLAGS_OWNED_BY_CURRENT_DEVICE)
3940     {
3941         NV_ASSERT_OK(_memdescSetSubAllocatorFlag(pMemDesc->pGpu, pMemDesc, bValue));
3942         return;
3943     }
3944     else if (flag == MEMDESC_FLAGS_GUEST_ALLOCATED)
3945     {
3946         NV_ASSERT_OK(_memdescSetGuestAllocatedFlag(pMemDesc->pGpu, pMemDesc, bValue));
3947         return;
3948     }
3949 
3950     if (bValue)
3951         pMemDesc->_flags |= flag;
3952     else
3953         pMemDesc->_flags &= ~flag;
3954 }
3955 
3956 /*!
3957  *  @brief Return memory descriptor address pointer
3958  *
3959  *  The address value is returned by osAllocPages
3960  *
3961  *  @param[in]  pMemDesc    Memory descriptor pointer
3962  *
3963  *  @returns Memory descriptor address pointer
3964  */
memdescGetAddress(MEMORY_DESCRIPTOR * pMemDesc)3965 NvP64 memdescGetAddress
3966 (
3967     MEMORY_DESCRIPTOR *pMemDesc
3968 )
3969 {
3970     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3971     return pMemDesc->_address;
3972 }
3973 
3974 /*!
3975  *  @brief Set memory descriptor address pointer
3976  *
3977  *  The address value is returned by osAllocPages
3978  *
3979  *  @param[in]  pMemDesc    Memory descriptor pointer
3980  *  @param[in]  pAddress    Pointer to address information
3981  *
3982  *  @returns nothing
3983  */
memdescSetAddress(MEMORY_DESCRIPTOR * pMemDesc,NvP64 pAddress)3984 void memdescSetAddress
3985 (
3986     MEMORY_DESCRIPTOR *pMemDesc,
3987     NvP64 pAddress
3988 )
3989 {
3990     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
3991     pMemDesc->_address = pAddress;
3992 }
3993 
3994 /*!
3995  *  @brief Get memory descriptor os-specific memory data pointer
3996  *
3997  *  The pMemData value is returned by osAllocPages
3998  *
3999  *  @param[in]  pMemDesc    Memory descriptor pointer
4000  *
4001  *  @returns Memory data pointer
4002  */
memdescGetMemData(MEMORY_DESCRIPTOR * pMemDesc)4003 void *memdescGetMemData
4004 (
4005     MEMORY_DESCRIPTOR *pMemDesc
4006 )
4007 {
4008     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
4009     return pMemDesc->_pMemData;
4010 }
4011 
4012 /*!
4013  *  @brief Set memory descriptor os-specific memory data pointer
4014  *
4015  *  The pMemData value is returned by osAllocPages
4016  *
4017  *  @param[in]  pMemDesc    Memory descriptor pointer
4018  *  @param[in]  pMemData    Pointer to new os-specific memory data
4019  *  @param[in]  pMemDataReleaseCallback Pointer to CB to be called when memdesc
4020  *                                      is freed.
4021  *
4022  *  @returns nothing
4023  */
memdescSetMemData(MEMORY_DESCRIPTOR * pMemDesc,void * pMemData,MEM_DATA_RELEASE_CALL_BACK * pMemDataReleaseCallback)4024 void memdescSetMemData
4025 (
4026     MEMORY_DESCRIPTOR          *pMemDesc,
4027     void                       *pMemData,
4028     MEM_DATA_RELEASE_CALL_BACK *pMemDataReleaseCallback
4029 )
4030 {
4031     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
4032     pMemDesc->_pMemData = pMemData;
4033     pMemDesc->_pMemDataReleaseCallback = pMemDataReleaseCallback;
4034 }
4035 
4036 /*!
4037  *  @brief Return memory descriptor volatile attribute
4038  *
4039  *  @param[in]  pMemDesc    Memory descriptor pointer
4040  *
4041  *  @returns Volatile or not
4042  */
memdescGetVolatility(PMEMORY_DESCRIPTOR pMemDesc)4043 NvBool memdescGetVolatility
4044 (
4045     PMEMORY_DESCRIPTOR pMemDesc
4046 )
4047 {
4048     NvBool bVolatile = NV_FALSE;
4049 
4050     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
4051     if (pMemDesc->_addressSpace == ADDR_SYSMEM)
4052     {
4053         bVolatile = (memdescGetGpuCacheAttrib(pMemDesc) == NV_MEMORY_UNCACHED);
4054     }
4055     else
4056     {
4057         NV_ASSERT(pMemDesc->_addressSpace == ADDR_FBMEM);
4058     }
4059 
4060     return bVolatile;
4061 }
4062 
4063 /*!
4064  *  @brief Quick check whether the memory is contiguous or not
4065  *
4066  *  @param[in]  pMemDesc           Memory descriptor used
4067  *  @param[in]  addressTranslation Address translation identifier
4068  *
4069  *  @returns NV_TRUE if contiguous
4070  */
memdescGetContiguity(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation)4071 NvBool memdescGetContiguity(PMEMORY_DESCRIPTOR pMemDesc, ADDRESS_TRANSLATION addressTranslation)
4072 {
4073     return !!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS);
4074 }
4075 
4076 /*!
4077  *  @brief Detailed Check whether the memory is contiguous or not
4078  *
4079  *  @param[in]  pMemDesc           Memory descriptor used
4080  *  @param[in]  addressTranslation Address translation identifier
4081  *
4082  *  @returns NV_TRUE if contiguous
4083  */
memdescCheckContiguity(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation)4084 NvBool memdescCheckContiguity(PMEMORY_DESCRIPTOR pMemDesc, ADDRESS_TRANSLATION addressTranslation)
4085 {
4086     NvU32 i;
4087 
4088     if (!(pMemDesc->_flags & MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS))
4089     {
4090         for (i = 0; i < (pMemDesc->PageCount - 1); i++)
4091         {
4092             if ((memdescGetPte(pMemDesc, addressTranslation, i) + pMemDesc->pageArrayGranularity) !=
4093                     memdescGetPte(pMemDesc, addressTranslation, i + 1))
4094                 return NV_FALSE;
4095         }
4096     }
4097 
4098     return NV_TRUE;
4099 }
4100 
4101 /*!
4102  *  @brief Set the contiguity of the memory descriptor
4103  *
4104  *  @param[in]  pMemDesc           Memory descriptor used
4105  *  @param[in]  addressTranslation Address translation identifier
4106  *  @param[in]  isContiguous       Contiguity value
4107  *
4108  *  @returns nothing
4109  */
memdescSetContiguity(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvBool isContiguous)4110 void memdescSetContiguity(PMEMORY_DESCRIPTOR pMemDesc, ADDRESS_TRANSLATION addressTranslation, NvBool isContiguous)
4111 {
4112     NV_ASSERT_OR_RETURN_VOID(pMemDesc);
4113 
4114     if (isContiguous)
4115         pMemDesc->_flags |= MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS;
4116     else
4117         pMemDesc->_flags &= ~MEMDESC_FLAGS_PHYSICALLY_CONTIGUOUS;
4118 }
4119 
4120 /*!
4121  *  @brief Get the address space of the memory descriptor
4122  *
4123  *  @param[in]  pMemDesc           Memory descriptor used
4124  *  @param[in]  addressTranslation Address translation identifier
4125  *
4126  *  @returns addresspace
4127  */
memdescGetAddressSpace(PMEMORY_DESCRIPTOR pMemDesc)4128 NV_ADDRESS_SPACE memdescGetAddressSpace(PMEMORY_DESCRIPTOR pMemDesc)
4129 {
4130     NV_ASSERT_OR_RETURN(pMemDesc != NULL, 0);
4131     return pMemDesc->_addressSpace;
4132 }
4133 
4134 /*!
4135  *  @brief Get page size
4136  *
4137  *  @param[in]  pMemDesc           Memory descriptor pointer
4138  *  @param[in]  addressTranslation Address translation identifier
4139  *
4140  *  @returns Current page size.
4141  */
memdescGetPageSize(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation)4142 NvU64 memdescGetPageSize
4143 (
4144     PMEMORY_DESCRIPTOR  pMemDesc,
4145     ADDRESS_TRANSLATION addressTranslation
4146 )
4147 {
4148     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
4149     return pMemDesc->_pageSize;
4150 }
4151 
4152 /*!
4153  *  @brief Set page size
4154  *
4155  *  @param[in]  pMemDesc           Memory descriptor pointer
4156  *  @param[in]  addressTranslation Address translation identifier
4157  *  @param[in]  pteKind            New PTE kind
4158  *
4159  *  @returns nothing
4160  */
memdescSetPageSize(PMEMORY_DESCRIPTOR pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU64 pageSize)4161 void memdescSetPageSize
4162 (
4163     PMEMORY_DESCRIPTOR  pMemDesc,
4164     ADDRESS_TRANSLATION addressTranslation,
4165     NvU64               pageSize
4166 )
4167 {
4168     NV_ASSERT(!memdescHasSubDeviceMemDescs(pMemDesc));
4169     pMemDesc->_pageSize = pageSize;
4170 }
4171 
4172 /*!
4173  *  @brief Get the Root memory descriptor.
4174  *
4175  *  This can also be used to get the root offset as well.
4176  *
4177  *  Root memory descriptor is the top level memory descriptor with no parent,
4178  *  from which this memory descriptor was derived
4179  *
4180  *  @param[in]  pMemDesc     Pointer to memory descriptor.
4181  *  @param[out] pRootOffset  Pointer to the root offset parameter.
4182  *
4183  *  @returns the Root memory descriptor.
4184  */
memdescGetRootMemDesc(PMEMORY_DESCRIPTOR pMemDesc,NvU64 * pRootOffset)4185 PMEMORY_DESCRIPTOR memdescGetRootMemDesc
4186 (
4187     PMEMORY_DESCRIPTOR  pMemDesc,
4188     NvU64              *pRootOffset
4189 )
4190 {
4191     NvU64 offset = 0;
4192 
4193     // Find the top-level parent descriptor
4194     while (pMemDesc->_pParentDescriptor)
4195     {
4196         // Sanity check, None of the child descriptors should be allocated
4197         NV_ASSERT(!pMemDesc->Allocated);
4198         offset += pMemDesc->subMemOffset;
4199         pMemDesc = pMemDesc->_pParentDescriptor;
4200     }
4201 
4202     if (pRootOffset)
4203     {
4204         *pRootOffset = offset;
4205     }
4206 
4207     return pMemDesc;
4208 }
4209 /*!
4210  *  @brief Sets the CUSTOM_HEAP flag of MEMDESC.
4211  *
4212  *  Since we have ACR region, Memory descriptor can be allocated in ACR region
4213  *  in that case, we need to set this flag since we are using the custom ACR HEAP
4214  *
4215  *  @param[in]  pMemDesc     Pointer to memory descriptor.
4216  *
4217  *  @returns void.
4218  */
4219 void
memdescSetCustomHeap(PMEMORY_DESCRIPTOR pMemDesc,MEMDESC_CUSTOM_HEAP heap)4220 memdescSetCustomHeap
4221 (
4222     PMEMORY_DESCRIPTOR  pMemDesc,
4223     MEMDESC_CUSTOM_HEAP heap
4224 )
4225 {
4226     NV_ASSERT(0);
4227 }
4228 
4229 /*!
4230  *  @brief Returns the ACR CUSTOM_HEAP flag.
4231  *
4232  *
4233  *  @param[in]  pMemDesc     Pointer to memory descriptor.
4234  *
4235  *  @returns NV_TRUE if flag MEMDESC_FLAGS_CUSTOM_HEAP_ACR is SET.
4236  */
4237 MEMDESC_CUSTOM_HEAP
memdescGetCustomHeap(PMEMORY_DESCRIPTOR pMemDesc)4238 memdescGetCustomHeap
4239 (
4240     PMEMORY_DESCRIPTOR pMemDesc
4241 )
4242 {
4243 
4244     return MEMDESC_CUSTOM_HEAP_NONE;
4245 }
4246 
memdescGetIommuMap(PMEMORY_DESCRIPTOR pMemDesc,NvU32 iovaspaceId)4247 PIOVAMAPPING memdescGetIommuMap
4248 (
4249     PMEMORY_DESCRIPTOR pMemDesc,
4250     NvU32 iovaspaceId
4251 )
4252 {
4253     PIOVAMAPPING pIommuMap = pMemDesc->_pIommuMappings;
4254     while (pIommuMap != NULL)
4255     {
4256         if (pIommuMap->iovaspaceId == iovaspaceId)
4257         {
4258             break;
4259         }
4260 
4261         pIommuMap = pIommuMap->pNext;
4262     }
4263 
4264     return pIommuMap;
4265 }
4266 
memdescAddIommuMap(PMEMORY_DESCRIPTOR pMemDesc,PIOVAMAPPING pIommuMap)4267 NV_STATUS memdescAddIommuMap
4268 (
4269     PMEMORY_DESCRIPTOR pMemDesc,
4270     PIOVAMAPPING pIommuMap
4271 )
4272 {
4273     NV_ASSERT_OR_RETURN((pMemDesc->_pIommuMappings == NULL) ||
4274         (!memdescIsSubMemoryMemDesc(pMemDesc)), NV_ERR_INVALID_ARGUMENT);
4275 
4276     //
4277     // Only root physical memdescs can have multiple IOMMU mappings.
4278     // Submemdescs can only have one, and the list linkage is used
4279     // instead to link it as a child of the root IOMMU mapping, so we
4280     // don't want to overwrite that here.
4281     //
4282     if (!memdescIsSubMemoryMemDesc(pMemDesc))
4283     {
4284         pIommuMap->pNext = pMemDesc->_pIommuMappings;
4285     }
4286 
4287     pMemDesc->_pIommuMappings = pIommuMap;
4288 
4289     return NV_OK;
4290 }
4291 
memdescRemoveIommuMap(PMEMORY_DESCRIPTOR pMemDesc,PIOVAMAPPING pIommuMap)4292 void memdescRemoveIommuMap
4293 (
4294     PMEMORY_DESCRIPTOR pMemDesc,
4295     PIOVAMAPPING pIommuMap
4296 )
4297 {
4298     //
4299     // Only root physical memdescs can have multiple IOMMU mappings.
4300     // Submemdescs can only have one, and the list linkage is used
4301     // instead to link it as a child of the root IOMMU mapping, so we
4302     // don't want to overwrite that here.
4303     //
4304     if (!memdescIsSubMemoryMemDesc(pMemDesc))
4305     {
4306         PIOVAMAPPING *ppTmpIommuMap = &pMemDesc->_pIommuMappings;
4307         while ((*ppTmpIommuMap != NULL) && (*ppTmpIommuMap != pIommuMap))
4308         {
4309             ppTmpIommuMap = &(*ppTmpIommuMap)->pNext;
4310         }
4311 
4312         if (*ppTmpIommuMap != NULL)
4313         {
4314             *ppTmpIommuMap = pIommuMap->pNext;
4315 
4316         }
4317         else
4318         {
4319             NV_ASSERT(*ppTmpIommuMap != NULL);
4320         }
4321     }
4322     else if (pMemDesc->_pIommuMappings == pIommuMap)
4323     {
4324         pMemDesc->_pIommuMappings = NULL;
4325     }
4326     else
4327     {
4328         //
4329         // Trying to remove a submemory mapping that doesn't belong to this
4330         // descriptor?
4331         //
4332         NV_ASSERT(pMemDesc->_pIommuMappings == pIommuMap);
4333     }
4334 }
4335 
memdescMapIommu(PMEMORY_DESCRIPTOR pMemDesc,NvU32 iovaspaceId)4336 NV_STATUS memdescMapIommu
4337 (
4338     PMEMORY_DESCRIPTOR pMemDesc,
4339     NvU32 iovaspaceId
4340 )
4341 {
4342 #if (RMCFG_FEATURE_PLATFORM_UNIX || RMCFG_FEATURE_PLATFORM_MODS) && !NVCPU_IS_ARM
4343     if (iovaspaceId != NV_IOVA_DOMAIN_NONE)
4344     {
4345         NV_ADDRESS_SPACE addrSpace = memdescGetAddressSpace(pMemDesc);
4346         OBJGPU *pMappingGpu = gpumgrGetGpuFromId(iovaspaceId);
4347         PMEMORY_DESCRIPTOR pRootMemDesc = memdescGetRootMemDesc(pMemDesc, NULL);
4348         if ((addrSpace == ADDR_SYSMEM) || gpumgrCheckIndirectPeer(pMappingGpu, pRootMemDesc->pGpu))
4349         {
4350             NV_STATUS status;
4351             OBJIOVASPACE *pIOVAS = iovaspaceFromId(iovaspaceId);
4352             NV_ASSERT_OR_RETURN(pIOVAS, NV_ERR_OBJECT_NOT_FOUND);
4353 
4354             status = iovaspaceAcquireMapping(pIOVAS, pMemDesc);
4355             NV_ASSERT_OR_RETURN(status == NV_OK, status);
4356         }
4357     }
4358 #endif
4359 
4360     //
4361     // Verify that the final physical addresses are indeed addressable by the
4362     // GPU. We only need to do this for internally allocated sysmem (RM owned)
4363     // as well as externally allocated/mapped sysmem. Note, addresses for peer
4364     // (P2P mailbox registers) BARs are actually not handled by the GMMU and
4365     // support a full 64-bit address width, hence validation is not needed.
4366     //
4367     if ((pMemDesc->Allocated ||
4368          memdescGetFlag(pMemDesc, MEMDESC_FLAGS_EXT_PAGE_ARRAY_MEM) ||
4369          memdescGetFlag(pMemDesc, MEMDESC_FLAGS_PEER_IO_MEM)) &&
4370         memdescGetAddressSpace(pMemDesc) == ADDR_SYSMEM)
4371     {
4372         // TODO This should look up the GPU corresponding to the IOVAS instead.
4373         OBJGPU *pGpu = pMemDesc->pGpu;
4374         RmPhysAddr dmaWindowStartAddr = gpuGetDmaStartAddress(pGpu);
4375         RmPhysAddr dmaWindowEndAddr = gpuGetDmaEndAddress_HAL(pGpu);
4376         RmPhysAddr physAddr;
4377 
4378         if (memdescGetContiguity(pMemDesc, AT_GPU))
4379         {
4380             physAddr = memdescGetPhysAddr(pMemDesc, AT_GPU, 0);
4381             if ((physAddr < dmaWindowStartAddr) ||
4382                 (physAddr + pMemDesc->Size - 1 > dmaWindowEndAddr))
4383             {
4384                 NV_PRINTF(LEVEL_ERROR,
4385                           "0x%llx-0x%llx is not addressable by GPU 0x%x [0x%llx-0x%llx]\n",
4386                           physAddr, physAddr + pMemDesc->Size - 1,
4387                           pGpu->gpuId, dmaWindowStartAddr, dmaWindowEndAddr);
4388                 memdescUnmapIommu(pMemDesc, iovaspaceId);
4389                 return NV_ERR_INVALID_ADDRESS;
4390             }
4391         }
4392         else
4393         {
4394             NvU32 i;
4395             for (i = 0; i < pMemDesc->PageCount; i++)
4396             {
4397                 physAddr = memdescGetPte(pMemDesc, AT_GPU, i);
4398                 if ((physAddr < dmaWindowStartAddr) ||
4399                     (physAddr + (pMemDesc->pageArrayGranularity - 1) > dmaWindowEndAddr))
4400                 {
4401                     NV_PRINTF(LEVEL_ERROR,
4402                               "0x%llx is not addressable by GPU 0x%x [0x%llx-0x%llx]\n",
4403                               physAddr, pGpu->gpuId, dmaWindowStartAddr,
4404                               dmaWindowEndAddr);
4405                     memdescUnmapIommu(pMemDesc, iovaspaceId);
4406                     return NV_ERR_INVALID_ADDRESS;
4407                 }
4408             }
4409         }
4410     }
4411 
4412     return NV_OK;
4413 }
4414 
memdescUnmapIommu(PMEMORY_DESCRIPTOR pMemDesc,NvU32 iovaspaceId)4415 void memdescUnmapIommu
4416 (
4417     PMEMORY_DESCRIPTOR pMemDesc,
4418     NvU32 iovaspaceId
4419 )
4420 {
4421 #if (RMCFG_FEATURE_PLATFORM_UNIX || RMCFG_FEATURE_PLATFORM_MODS) && !NVCPU_IS_ARM
4422     PIOVAMAPPING pIovaMapping;
4423     OBJIOVASPACE *pIOVAS;
4424 
4425     if (iovaspaceId == NV_IOVA_DOMAIN_NONE)
4426         return;
4427 
4428     pIovaMapping = memdescGetIommuMap(pMemDesc, iovaspaceId);
4429     NV_ASSERT(pIovaMapping);
4430 
4431     pIOVAS = iovaspaceFromMapping(pIovaMapping);
4432     iovaspaceReleaseMapping(pIOVAS, pIovaMapping);
4433 #endif
4434 }
4435 
memdescCheckSubDevicePageSizeConsistency(OBJGPU * pGpu,PMEMORY_DESCRIPTOR pMemDesc,OBJVASPACE * pVAS,NvU64 pageSize,NvU64 pageOffset)4436 void memdescCheckSubDevicePageSizeConsistency
4437 (
4438     OBJGPU              *pGpu,
4439     PMEMORY_DESCRIPTOR   pMemDesc,
4440     OBJVASPACE          *pVAS,
4441     NvU64                pageSize,
4442     NvU64                pageOffset
4443 )
4444 {
4445     NvU64 tempPageSize, tempPageOffset;
4446     PMEMORY_DESCRIPTOR pTempMemDesc = NULL;
4447 
4448     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY)
4449        pTempMemDesc   = memdescGetMemDescFromGpu(pMemDesc, pGpu);
4450        tempPageSize   = memdescGetPageSize(pTempMemDesc, VAS_ADDRESS_TRANSLATION(pVAS));
4451        tempPageOffset = memdescGetPhysAddr(pTempMemDesc, VAS_ADDRESS_TRANSLATION(pVAS), 0) & (tempPageSize - 1);
4452 
4453        // Assert if inconsistent
4454        NV_ASSERT(pageSize == tempPageSize);
4455        NV_ASSERT(pageOffset == tempPageOffset);
4456     SLI_LOOP_END
4457 }
4458 
memdescCheckSubDeviceMemContiguityConsistency(OBJGPU * pGpu,PMEMORY_DESCRIPTOR pMemDesc,OBJVASPACE * pVAS,NvBool bIsMemContiguous)4459 void memdescCheckSubDeviceMemContiguityConsistency
4460 (
4461     OBJGPU              *pGpu,
4462     PMEMORY_DESCRIPTOR   pMemDesc,
4463     OBJVASPACE          *pVAS,
4464     NvBool               bIsMemContiguous
4465 )
4466 {
4467     NvBool bTempIsMemContiguous = NV_FALSE;
4468 
4469     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY)
4470        bTempIsMemContiguous = memdescGetContiguity(memdescGetMemDescFromGpu(pMemDesc, pGpu), VAS_ADDRESS_TRANSLATION(pVAS));
4471        // Assert if inconsistent
4472        NV_ASSERT(bIsMemContiguous == bTempIsMemContiguous);
4473     SLI_LOOP_END
4474 }
4475 
memdescCheckSubDeviceKindComprConsistency(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,OBJVASPACE * pVAS,NvU32 kind,COMPR_INFO * pComprInfo)4476 NV_STATUS memdescCheckSubDeviceKindComprConsistency
4477 (
4478     OBJGPU             *pGpu,
4479     MEMORY_DESCRIPTOR  *pMemDesc,
4480     OBJVASPACE         *pVAS,
4481     NvU32               kind,
4482     COMPR_INFO         *pComprInfo
4483 )
4484 {
4485     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY)
4486     {
4487         MemoryManager    *MemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
4488         NvU32             tempKind;
4489         COMPR_INFO        tempComprInfo = {0};
4490         NV_STATUS         status;
4491 
4492         status = memmgrGetKindComprFromMemDesc(MemoryManager,
4493                                                memdescGetMemDescFromGpu(pMemDesc, pGpu),
4494                                                0,
4495                                                &tempKind, &tempComprInfo);
4496 
4497         if (NV_OK != status)
4498             SLI_LOOP_RETURN(status);
4499 
4500         // Assert if inconsistent
4501         NV_ASSERT(kind == tempKind);
4502         NV_ASSERT(tempComprInfo.compPageShift         == pComprInfo->compPageShift &&
4503                   tempComprInfo.kind                  == pComprInfo->kind &&
4504                   tempComprInfo.compPageIndexLo       == pComprInfo->compPageIndexLo &&
4505                   tempComprInfo.compPageIndexHi       == pComprInfo->compPageIndexHi &&
4506                   tempComprInfo.compTagLineMin        == pComprInfo->compTagLineMin &&
4507                   tempComprInfo.compTagLineMultiplier == pComprInfo->compTagLineMultiplier);
4508     }
4509     SLI_LOOP_END
4510 
4511     return NV_OK;
4512 }
4513 
4514 /*  @brief Get GPA(guest physical addresses) for given GPU physical addresses.
4515  *
4516  *  @param[in]  pGpu         GPU for which GPAs are needed
4517  *  @param[in]  pageCount    Size of array. Should be 1 for contiguous mappings
4518  *  @param[in/out] pGpa      Array of GPU PAs to be converted to guest PAs
4519  *
4520  *  @returns NV_STATUS
4521  */
memdescGetNvLinkGpa(OBJGPU * pGpu,NvU64 pageCount,RmPhysAddr * pGpa)4522 NV_STATUS memdescGetNvLinkGpa
4523 (
4524     OBJGPU            *pGpu,
4525     NvU64              pageCount,
4526     RmPhysAddr        *pGpa
4527 )
4528 {
4529     KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
4530 
4531     NV_ASSERT_OR_RETURN(pGpa, NV_ERR_INVALID_ARGUMENT);
4532 
4533     NvU32  pageIndex;
4534     // For each page, do the GPU PA to GPA conversion
4535     for (pageIndex = 0; pageIndex < pageCount; pageIndex++)
4536     {
4537         RmPhysAddr gpa;
4538         gpa = pGpa[pageIndex] + pKernelMemorySystem->coherentCpuFbBase;
4539 
4540         NV_ASSERT_OR_RETURN((gpa >= pKernelMemorySystem->coherentCpuFbBase) &&
4541                             (gpa <= pKernelMemorySystem->coherentCpuFbEnd),
4542                             NV_ERR_INVALID_ARGUMENT);
4543 
4544         pGpa[pageIndex] = gpa;
4545     }
4546 
4547     return NV_OK;
4548 }
4549 
4550 NV_STATUS
memdescSetCtxBufPool(PMEMORY_DESCRIPTOR pMemDesc,CTX_BUF_POOL_INFO * pCtxBufPool)4551 memdescSetCtxBufPool
4552 (
4553     PMEMORY_DESCRIPTOR pMemDesc,
4554     CTX_BUF_POOL_INFO *pCtxBufPool
4555 )
4556 {
4557 
4558     NV_ASSERT_OR_RETURN(!pMemDesc->Allocated, NV_ERR_INVALID_STATE);
4559     NV_ASSERT_OR_RETURN(!memdescHasSubDeviceMemDescs(pMemDesc), NV_ERR_INVALID_ARGUMENT);
4560 
4561     pMemDesc->pCtxBufPool = pCtxBufPool;
4562     return NV_OK;
4563 }
4564 
4565 CTX_BUF_POOL_INFO*
memdescGetCtxBufPool(PMEMORY_DESCRIPTOR pMemDesc)4566 memdescGetCtxBufPool
4567 (
4568     PMEMORY_DESCRIPTOR pMemDesc
4569 )
4570 {
4571     NV_ASSERT_OR_RETURN(!memdescHasSubDeviceMemDescs(pMemDesc), NULL);
4572     return pMemDesc->pCtxBufPool;
4573 }
4574 
4575 /*!
4576  * @brief Override the registry INST_LOC two-bit enum to an aperture (list) + cpu attr.
4577  *
4578  * Caller must set initial default values.
4579  */
4580 void
memdescOverrideInstLocList(NvU32 instLoc,const char * name,const NV_ADDRESS_SPACE ** ppAllocList,NvU32 * pCpuMappingAttr)4581 memdescOverrideInstLocList
4582 (
4583     NvU32                    instLoc,       // NV_REG_STR_RM_INST_LOC
4584     const char              *name,
4585     const NV_ADDRESS_SPACE **ppAllocList,
4586     NvU32                   *pCpuMappingAttr
4587 )
4588 {
4589     switch (instLoc)
4590     {
4591         case NV_REG_STR_RM_INST_LOC_COH:
4592             NV_PRINTF(LEVEL_INFO, "using coh system memory for %s\n", name);
4593             *ppAllocList = ADDRLIST_SYSMEM_ONLY;
4594             *pCpuMappingAttr = NV_MEMORY_CACHED;
4595             break;
4596         case NV_REG_STR_RM_INST_LOC_NCOH:
4597             NV_PRINTF(LEVEL_INFO, "using ncoh system memory for %s\n", name);
4598             *ppAllocList = ADDRLIST_SYSMEM_ONLY;
4599             *pCpuMappingAttr = NV_MEMORY_UNCACHED;
4600             break;
4601         case NV_REG_STR_RM_INST_LOC_VID:
4602             NV_PRINTF(LEVEL_INFO, "using video memory for %s\n", name);
4603             *ppAllocList = ADDRLIST_FBMEM_ONLY;
4604             *pCpuMappingAttr = NV_MEMORY_WRITECOMBINED;
4605             break;
4606         case NV_REG_STR_RM_INST_LOC_DEFAULT:
4607         default:
4608             // Do not update parameters
4609             break;
4610     }
4611 }
4612 
4613 /*!
4614  * @brief Override wrapper for callers needed an aperture
4615  */
4616 void
memdescOverrideInstLoc(NvU32 instLoc,const char * name,NV_ADDRESS_SPACE * pAddrSpace,NvU32 * pCpuMappingAttr)4617 memdescOverrideInstLoc
4618 (
4619     NvU32             instLoc,
4620     const char       *name,
4621     NV_ADDRESS_SPACE *pAddrSpace,
4622     NvU32            *pCpuMappingAttr
4623 )
4624 {
4625     const NV_ADDRESS_SPACE *pAllocList = NULL;
4626 
4627     memdescOverrideInstLocList(instLoc, name, &pAllocList, pCpuMappingAttr);
4628     if (pAllocList != NULL)
4629         *pAddrSpace = pAllocList[0];
4630 }
4631 /*!
4632 *  @brief override physical address width
4633 *
4634 *  address width to be override in bits.
4635 *  @param[in]  pGpu
4636 *  @param[in]  pMemDesc  Memory descriptor to update
4637 *  @param[in]  addresswidth  Offset to refer to
4638 *
4639 *  @returns nothing
4640 */
4641 void
memdescOverridePhysicalAddressWidthWindowsWAR(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,NvU32 addressWidth)4642 memdescOverridePhysicalAddressWidthWindowsWAR
4643 (
4644     OBJGPU *pGpu,
4645     MEMORY_DESCRIPTOR *pMemDesc,
4646     NvU32 addressWidth
4647 )
4648 {
4649     if (RMCFG_FEATURE_PLATFORM_WINDOWS)
4650     {
4651         if (addressWidth < gpuGetPhysAddrWidth_HAL(pGpu, ADDR_SYSMEM))
4652         {
4653             pMemDesc->_flags |= MEMDESC_FLAGS_OVERRIDE_SYSTEM_ADDRESS_LIMIT;
4654             pMemDesc->_overridenAddressWidth = addressWidth;
4655         }
4656     }
4657 }
4658 
4659 void
memdescSetName(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,const char * name,const char * suffix)4660 memdescSetName(OBJGPU *pGpu, MEMORY_DESCRIPTOR *pMemDesc, const char *name, const char* suffix)
4661 {
4662     return;
4663 }
4664 
4665 NV_STATUS
memdescSendMemDescToGSP(OBJGPU * pGpu,MEMORY_DESCRIPTOR * pMemDesc,NvHandle * pHandle)4666 memdescSendMemDescToGSP(OBJGPU *pGpu, MEMORY_DESCRIPTOR *pMemDesc, NvHandle *pHandle)
4667 {
4668     NV_STATUS                         status          = NV_OK;
4669     RsClient                         *pClient;
4670     MemoryManager                    *pMemoryManager  = GPU_GET_MEMORY_MANAGER(pGpu);
4671     NvU32                             flags           = 0;
4672     NvU32                             index           = 0;
4673     NvU32                             hClass;
4674     NvU64                            *pageNumberList  = NULL;
4675     RM_API                           *pRmApi          = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
4676     NV_MEMORY_LIST_ALLOCATION_PARAMS  listAllocParams = {0};
4677 
4678     // Nothing to do without GSP
4679     if (!IS_GSP_CLIENT(pGpu))
4680     {
4681         return NV_OK;
4682     }
4683 
4684     switch (memdescGetAddressSpace(pMemDesc))
4685     {
4686 
4687         case ADDR_FBMEM:
4688             hClass = NV01_MEMORY_LIST_FBMEM;
4689             break;
4690 
4691         case ADDR_SYSMEM:
4692             hClass = NV01_MEMORY_LIST_SYSTEM;
4693             break;
4694 
4695         default:
4696             return NV_ERR_NOT_SUPPORTED;
4697     }
4698 
4699     // Initialize parameters with pMemDesc information
4700     listAllocParams.pteAdjust = pMemDesc->PteAdjust;
4701     listAllocParams.format    = memdescGetPteKind(pMemDesc);
4702     listAllocParams.size      = pMemDesc->Size;
4703     listAllocParams.hClient   = NV01_NULL_OBJECT;
4704     listAllocParams.hParent   = NV01_NULL_OBJECT;
4705     listAllocParams.hObject   = NV01_NULL_OBJECT;
4706     listAllocParams.limit     = pMemDesc->Size - 1;
4707     listAllocParams.flagsOs02 = (DRF_DEF(OS02,_FLAGS,_MAPPING,_NO_MAP) |
4708                                 (flags & DRF_SHIFTMASK(NVOS02_FLAGS_COHERENCY)));
4709 
4710     // Handle pageCount based on pMemDesc contiguity
4711     if (!memdescGetContiguity(pMemDesc, AT_GPU))
4712     {
4713         listAllocParams.flagsOs02 |=  DRF_DEF(OS02,_FLAGS,_PHYSICALITY,_NONCONTIGUOUS);
4714         listAllocParams.pageCount = pMemDesc->PageCount;
4715     }
4716     else
4717     {
4718         listAllocParams.pageCount = 1;
4719     }
4720 
4721 
4722     // Initialize pageNumberList
4723     pageNumberList = portMemAllocNonPaged(sizeof(NvU64) * listAllocParams.pageCount);
4724     for (index = 0; index < listAllocParams.pageCount; index++)
4725         pageNumberList[index] = memdescGetPte(pMemDesc, AT_GPU, index) >> RM_PAGE_SHIFT;
4726     listAllocParams.pageNumberList = pageNumberList;
4727 
4728     // Create MemoryList object
4729     NV_ASSERT_OK_OR_GOTO(status,
4730                          pRmApi->Alloc(pRmApi,
4731                                        pMemoryManager->hClient,
4732                                        pMemoryManager->hSubdevice,
4733                                        pHandle,
4734                                        hClass,
4735                                        &listAllocParams,
4736                                        sizeof(listAllocParams)),
4737                          end);
4738 
4739     NV_ASSERT_OK_OR_GOTO(status,
4740         serverGetClientUnderLock(&g_resServ, pMemoryManager->hClient, &pClient),
4741         end);
4742 
4743     // Register MemoryList object to GSP
4744     NV_ASSERT_OK_OR_GOTO(status,
4745                          memRegisterWithGsp(pGpu,
4746                                             pClient,
4747                                             pMemoryManager->hSubdevice,
4748                                             *pHandle),
4749                          end);
4750 
4751 end:
4752     if ((status != NV_OK) && (*pHandle != NV01_NULL_OBJECT))
4753         pRmApi->Free(pRmApi, pMemoryManager->hClient, *pHandle);
4754 
4755     if (pageNumberList != NULL)
4756         portMemFree(pageNumberList);
4757 
4758     return status;
4759 }
4760 
4761 NV_STATUS
memdescSetPageArrayGranularity(MEMORY_DESCRIPTOR * pMemDesc,NvU64 pageArrayGranularity)4762 memdescSetPageArrayGranularity
4763 (
4764     MEMORY_DESCRIPTOR *pMemDesc,
4765     NvU64 pageArrayGranularity
4766 )
4767 {
4768     // Make sure pageArrayGranularity is a power of 2 value.
4769     NV_ASSERT_OR_RETURN((pageArrayGranularity & (pageArrayGranularity - 1)) == 0, NV_ERR_INVALID_ARGUMENT);
4770 
4771     // Allow setting the same granularity.
4772     if (pMemDesc->pageArrayGranularity == pageArrayGranularity)
4773     {
4774         return NV_OK;
4775     }
4776 
4777     // Make sure setting the page array happens before the pteArray is populated.
4778     NV_ASSERT_OR_RETURN(pMemDesc->_pteArray[0] == 0, NV_ERR_INVALID_STATE);
4779 
4780     pMemDesc->pageArrayGranularity = pageArrayGranularity;
4781 
4782     return NV_OK;
4783 }
4784 
4785 NV_STATUS
memdescFillMemdescForPhysAttr(MEMORY_DESCRIPTOR * pMemDesc,ADDRESS_TRANSLATION addressTranslation,NvU64 * pOffset,NvU32 * pMemAperture,NvU32 * pMemKind,NvU32 * pZCullId,NvU32 * pGpuCacheAttr,NvU32 * pGpuP2PCacheAttr,NvU64 * contigSegmentSize)4786 memdescFillMemdescForPhysAttr
4787 (
4788     MEMORY_DESCRIPTOR *pMemDesc,
4789     ADDRESS_TRANSLATION addressTranslation,
4790     NvU64 *pOffset,
4791     NvU32 *pMemAperture,
4792     NvU32 *pMemKind,
4793     NvU32 *pZCullId,
4794     NvU32 *pGpuCacheAttr,
4795     NvU32 *pGpuP2PCacheAttr,
4796     NvU64 *contigSegmentSize
4797 )
4798 {
4799     NvU64 surfOffset = *pOffset, surfBase, surfLimit;
4800     NvU32 zcbitmap;
4801 
4802     surfBase  = memdescGetPhysAddr(pMemDesc, addressTranslation, 0);
4803     surfLimit = surfBase + pMemDesc->Size - 1;
4804     *pMemKind = memdescGetPteKind(pMemDesc);
4805 
4806     *pOffset  = memdescGetPhysAddr(pMemDesc, addressTranslation, surfOffset);
4807 
4808     if (memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM )
4809         *pMemAperture = NV0041_CTRL_CMD_GET_SURFACE_PHYS_ATTR_APERTURE_VIDMEM;
4810     else if (memdescGetAddressSpace(pMemDesc) == ADDR_SYSMEM)
4811         *pMemAperture = NV0041_CTRL_CMD_GET_SURFACE_PHYS_ATTR_APERTURE_SYSMEM;
4812     else if (memdescGetAddressSpace(pMemDesc) == ADDR_EGM)
4813         *pMemAperture = NV0041_CTRL_CMD_GET_SURFACE_PHYS_ATTR_APERTURE_SYSMEM;
4814     else if (memdescGetAddressSpace(pMemDesc) == ADDR_VIRTUAL )
4815     {
4816         //
4817         // XXX we could theoretically find whatever phys mem object is plugged
4818         // in at surfOffset w/in the virt object... that'd mean scanning
4819         // pMemory->DmaMappingList
4820         //
4821         return NV_ERR_NOT_SUPPORTED;
4822     }
4823     else
4824         return NV_ERR_GENERIC;
4825 
4826     if (memdescGetGpuCacheAttrib(pMemDesc) == NV_MEMORY_CACHED)
4827     {
4828         *pGpuCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_CACHED;
4829     }
4830     else if (memdescGetGpuCacheAttrib(pMemDesc) == NV_MEMORY_UNCACHED)
4831     {
4832         *pGpuCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_UNCACHED;
4833     }
4834     else
4835     {
4836         *pGpuCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_CACHED_UNKNOWN;
4837     }
4838 
4839     if (memdescGetGpuP2PCacheAttrib(pMemDesc) == NV_MEMORY_CACHED)
4840     {
4841         *pGpuP2PCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_CACHED;
4842     }
4843     else if (memdescGetGpuP2PCacheAttrib(pMemDesc) == NV_MEMORY_UNCACHED)
4844     {
4845         *pGpuP2PCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_UNCACHED;
4846     }
4847     else
4848     {
4849         *pGpuP2PCacheAttr = NV0041_CTRL_GET_SURFACE_PHYS_ATTR_GPU_CACHED_UNKNOWN;
4850     }
4851 
4852     zcbitmap = FB_HWRESID_ZCULL_VAL_FERMI(memdescGetHwResId(pMemDesc)); //bitmap form... need a scalar
4853     for ( *pZCullId = 0;  zcbitmap; zcbitmap >>= 1, *pZCullId += 1) {;;;}
4854     *pZCullId -= 1; // side effect if there is no zcull id of setting ~0
4855 
4856     *contigSegmentSize = surfLimit - (surfBase + surfOffset) + 1;
4857 
4858     if ( !memdescGetContiguity(pMemDesc, addressTranslation))
4859     {
4860         // XXX overly conservative.  we could scan the PTEs to find out if more pages are contig.
4861         NvU64 surfOffsetLimitSame4KBPage = (4*1024)*((surfBase + surfOffset)/(4*1024)) + (4*1024) - 1;
4862         if ( surfLimit >= surfOffsetLimitSame4KBPage )
4863             *contigSegmentSize = surfOffsetLimitSame4KBPage - (surfBase + surfOffset) + 1;
4864     }
4865 
4866     return NV_OK;
4867 }
4868 
4869 NvBool
memdescIsEgm(MEMORY_DESCRIPTOR * pMemDesc)4870 memdescIsEgm
4871 (
4872     MEMORY_DESCRIPTOR *pMemDesc
4873 )
4874 {
4875     NV_ADDRESS_SPACE   addrSpace;
4876     MEMORY_DESCRIPTOR *pRootMemDesc;
4877     MemoryManager     *pMemoryManager;
4878 
4879     //
4880     // If memdesc is not device owned, we can't tell if local EGM is enabled
4881     // due to lack of memory manager.
4882     //
4883     if (pMemDesc->pGpu == NULL)
4884     {
4885         return NV_FALSE;
4886     }
4887 
4888     addrSpace = memdescGetAddressSpace(pMemDesc);
4889     pRootMemDesc = memdescGetRootMemDesc(pMemDesc, NULL);
4890 
4891     if ((pRootMemDesc == NULL) || (pRootMemDesc->pGpu == NULL))
4892     {
4893         return NV_FALSE;
4894     }
4895 
4896     pMemoryManager = GPU_GET_MEMORY_MANAGER(pRootMemDesc->pGpu);
4897     if (pMemoryManager == NULL)
4898     {
4899         return NV_FALSE;
4900     }
4901 
4902     if ((addrSpace == ADDR_EGM) ||
4903         (memmgrIsLocalEgmEnabled(pMemoryManager) &&
4904          (addrSpace == ADDR_SYSMEM) &&
4905          (memdescGetNumaNode(pMemDesc) == pMemoryManager->localEgmNodeId)))
4906     {
4907         return NV_TRUE;
4908     }
4909 
4910     return NV_FALSE;
4911 }
4912