1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-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 #include "core/core.h"
25 #include "gpu/gpu.h"
26 #include "gpu/mem_mgr/mem_mgr.h"
27 #include "gpu/mem_sys/kern_mem_sys.h"
28 #include "gpu/mem_mgr/mem_desc.h"
29 #include "platform/sli/sli.h"
30 
31 #include "nvRmReg.h"
32 
33 #include "kernel/gpu/intr/intr.h"
34 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
35 #include "vgpu/vgpu_events.h"
36 #include "nvdevid.h"
37 
38 #include "published/ampere/ga100/dev_mmu.h"
39 #include "published/ampere/ga100/dev_fb.h"
40 
41 #define NV_CBC_MAX_SIZE_BUG_2509894_WAR   ((3 * NVBIT64(30)) / 2) // 1.5GBs
42 
43 /*!
44  * @brief This function will return the Kind that should be used by surfaces which
45  *        maps the FLA object
46  *
47  * @param[in/out] pPteKind
48  *
49  * @returns NV_OK
50  */
51 NV_STATUS
memmgrGetFlaKind_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,NvU32 * pPteKind)52 memmgrGetFlaKind_GA100
53 (
54     OBJGPU        *pGpu,
55     MemoryManager *pMemoryManager,
56     NvU32         *pPteKind
57 )
58 {
59     *pPteKind = NV_MMU_PTE_KIND_SMSKED_MESSAGE;
60     return NV_OK;
61 }
62 
63 /*!
64  * @brief Determine Alignment for a surface, if the surface is compressible with
65  * the reg key enabled, set the hwAlignment to 256KB
66  * else fall back to pre-Ampere way
67  *
68  * returns NV_STATUS
69  */
70 NV_STATUS
memmgrAllocDetermineAlignment_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,NvU64 * pMemSize,NvU64 * pAlign,NvU64 alignPad,NvU32 allocFlags,NvU32 retAttr,NvU32 retAttr2,NvU64 hwAlignment)71 memmgrAllocDetermineAlignment_GA100
72 (
73     OBJGPU        *pGpu,
74     MemoryManager *pMemoryManager,
75     NvU64         *pMemSize,
76     NvU64         *pAlign,
77     NvU64          alignPad,
78     NvU32          allocFlags,
79     NvU32          retAttr,
80     NvU32          retAttr2,
81     NvU64          hwAlignment
82 )
83 {
84     const MEMORY_SYSTEM_STATIC_CONFIG    *pMemorySystemConfig =
85         kmemsysGetStaticConfig(pGpu, GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu));
86 
87     // set the alignment to 256K if property is enabled and its a compressed surface
88     if (pMemorySystemConfig->bUseOneToFourComptagLineAllocation &&
89         !FLD_TEST_DRF(OS32, _ATTR, _COMPR, _NONE, retAttr))
90     {
91         hwAlignment = pMemorySystemConfig->comprPageSize - 1;
92     }
93 
94     return memmgrAllocDetermineAlignment_GM107(pGpu, pMemoryManager, pMemSize, pAlign, alignPad,
95                                                allocFlags, retAttr, retAttr2, hwAlignment);
96 }
97 
98 /**
99  * @brief Override Scrubber related PDB properties based on regkeys and platform configs
100  */
101 void
memmgrScrubRegistryOverrides_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager)102 memmgrScrubRegistryOverrides_GA100
103 (
104     OBJGPU        *pGpu,
105     MemoryManager *pMemoryManager
106 )
107 {
108     //Fix me: Fork the same function for GA10x.
109 
110     //
111     // Disabling the SCRUB_ON_FREE property for all the platforms except Windows TCC Mode.
112     // Disabling in Non-TCC windows because the OS manages FB
113     // Disabling for Simulation Platforms, since slower in simulation
114     // Disabling in DFPGA, since they skip the Host Load
115     // Disabling for vGPU (host), since the plugin has scrubbing support
116     // Disabling for legacy VGPU (guest), blocked on bug #1929798
117     // Disabling for SLI for now, until the bug # 1790190 is fixed.
118     // Disabling for GSP-RM ucode, since scrubbing is done from CPU-side kernel RM.
119     // Enabling virtual scrubbing mode for SRIOV-HEAVY mode.
120     //
121 
122     if ((RMCFG_FEATURE_PLATFORM_WINDOWS && !pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_TCC_MODE)) ||
123          IS_SIMULATION(pGpu) || IsDFPGA(pGpu) ||
124          pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_VIRTUALIZATION_MODE_HOST_VGPU) ||
125          IS_VIRTUAL_WITHOUT_SRIOV(pGpu) ||
126          RMCFG_FEATURE_PLATFORM_GSP ||
127          pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) ||
128          IsSLIEnabled(pGpu))
129     {
130         pMemoryManager->bScrubOnFreeEnabled = NV_FALSE;
131     }
132 
133     //
134     // CE virtual writes are used in the following cases
135     // 1. When SR-IOV heavy is in use on GA100
136     // 2. When APM is enabled on GA100.
137     //
138     if (pMemoryManager->bScrubOnFreeEnabled &&
139         ((IS_VIRTUAL_WITH_SRIOV(pGpu) && gpuIsWarBug200577889SriovHeavyEnabled(pGpu)) ||
140         gpuIsApmFeatureEnabled(pGpu)))
141     {
142         pMemoryManager->bUseVasForCeMemoryOps = NV_TRUE;
143     }
144 }
145 
146 /*!
147  * Read and validate MMU Lock registers.
148  */
149 NV_STATUS
memmgrReadMmuLock_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,NvBool * pbIsValid,NvU64 * pMmuLockLo,NvU64 * pMmuLockHi)150 memmgrReadMmuLock_GA100
151 (
152     OBJGPU   *pGpu,
153     MemoryManager *pMemoryManager,
154     NvBool    *pbIsValid,
155     NvU64     *pMmuLockLo,
156     NvU64     *pMmuLockHi
157 )
158 {
159     NvU32 plm = 0;
160     NvU32 tmp = 0;
161 
162 
163     *pbIsValid = NV_FALSE;
164     *pMmuLockLo = 0;
165     *pMmuLockHi = 0;
166 
167     // Ensure RM can read MMU_LOCKED region
168     plm = GPU_REG_RD32(pGpu, NV_PFB_PRI_MMU_LOCK_ADDR_LO__PRIV_LEVEL_MASK);
169 
170     if (!FLD_TEST_DRF(_PFB_PRI, _MMU_LOCK_CFG_PRIV_LEVEL_MASK, _READ_PROTECTION_LEVEL0, _ENABLE, plm))
171     {
172         NV_PRINTF(LEVEL_ERROR, "MMU_LOCK read permission disabled, PLM val 0x%0x\n",
173                          plm);
174         NV_ASSERT(0);
175         return NV_ERR_INSUFFICIENT_RESOURCES;
176     }
177 
178     // Read MEM lock values
179     tmp  = DRF_VAL(_PFB, _PRI_MMU_LOCK_ADDR_LO, _VAL, GPU_REG_RD32(pGpu, NV_PFB_PRI_MMU_LOCK_ADDR_LO));
180     *pMmuLockLo  = ((NvU64)tmp) << NV_PFB_PRI_MMU_LOCK_ADDR_LO_ALIGNMENT;
181 
182     tmp  = DRF_VAL(_PFB, _PRI_MMU_LOCK_ADDR_HI, _VAL, GPU_REG_RD32(pGpu, NV_PFB_PRI_MMU_LOCK_ADDR_HI));
183     *pMmuLockHi  = ((NvU64)tmp) << NV_PFB_PRI_MMU_LOCK_ADDR_HI_ALIGNMENT;
184 
185     // Check for validity
186     if (*pMmuLockHi >= *pMmuLockLo)
187         *pbIsValid = NV_TRUE;
188 
189     return NV_OK;
190 }
191 
192 /*
193  * Bug 2974274
194  * As stated in the bug, row remapper takes up few MBs at end of FB but LOCAL_MEMORY_RANGE register
195  * rounds it down by nearest 1GB boundary. Since RM uses LOCAL_MEMORY_RANGE to figure out the total
196  * FB size, this results in almost 1GB of loss in usable FB size and this function along with WARs
197  * in VBIOS & ACR solves the issue.
198  * VBIOS rounds up the size to nearest 1GB boundary and locks down (MMU_LOCK) the difference between the usable
199  * and rounded up size. This function ensures the difference is blocked from RM allocation.
200  *
201  */
202 NV_STATUS
memmgrBlockMemLockedMemory_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager)203 memmgrBlockMemLockedMemory_GA100
204 (
205     OBJGPU        *pGpu,
206     MemoryManager *pMemoryManager
207 )
208 {
209     FB_REGION_DESCRIPTOR blockedFbRegion;
210     NvU64                memLockLo            = 0;
211     NvU64                memLockHi            = 0;
212     NvU64                size                 = 0;
213     NvBool               bIsMmuLockValid      = NV_FALSE;
214 
215     NV_ASSERT_OK_OR_RETURN(memmgrReadMmuLock_HAL(pGpu, pMemoryManager, &bIsMmuLockValid, &memLockLo, &memLockHi));
216 
217     // MMU_LOCK is not set in OLD Vbios that programs 1GB less in LOCAL_MEMORY_RANGE
218     if (!bIsMmuLockValid)
219     {
220         return NV_OK;
221     }
222 
223     memLockHi  = NV_ALIGN_UP(memLockHi, 0x10000) - 1; // Align up to cover till the last byte
224 
225     // Check if memLockHi equals FB_TOP, if not MMU_LOCK is set in unexpected range
226     if (((memLockHi + 1) >> 20) != pMemoryManager->Ram.fbTotalMemSizeMb)
227     {
228         return NV_ERR_INVALID_STATE;
229     }
230 
231     // Add a new region that will be blocked for any usage.
232     portMemSet(&blockedFbRegion, 0, sizeof(blockedFbRegion));
233     size = RM_PAGE_ALIGN_UP(((memLockHi - memLockLo) + 1));
234 
235     blockedFbRegion.base = memLockLo;
236     blockedFbRegion.limit = memLockHi;
237     blockedFbRegion.rsvdSize = 0;
238     blockedFbRegion.bRsvdRegion = NV_TRUE;
239     blockedFbRegion.performance = 0;
240     blockedFbRegion.bSupportCompressed = NV_FALSE;
241     blockedFbRegion.bSupportISO = NV_FALSE;
242     blockedFbRegion.bProtected = NV_FALSE;
243     blockedFbRegion.bInternalHeap = NV_FALSE;
244     blockedFbRegion.bLostOnSuspend = NV_TRUE;
245 
246     memmgrInsertFbRegion(pGpu, pMemoryManager, &blockedFbRegion);
247 
248     pMemoryManager->Ram.fbUsableMemSize -= size;
249 
250     NV_PRINTF(LEVEL_INFO, "Blocked  Start: 0x%0llx End: 0x%0llx Size: 0x%0llx\n",
251                        memLockLo, memLockHi, size);
252     return NV_OK;
253 }
254 
255 /*!
256  *  Returns the max context size
257  *
258  *  @returns NvU64
259  */
260 NvU64
memmgrGetMaxContextSize_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager)261 memmgrGetMaxContextSize_GA100
262 (
263     OBJGPU        *pGpu,
264     MemoryManager *pMemoryManager
265 )
266 {
267     NvU64  size = memmgrGetMaxContextSize_TU102(pGpu, pMemoryManager);
268 
269     if (RMCFG_FEATURE_PLATFORM_GSP)
270     {
271         if (!gpuIsClientRmAllocatedCtxBufferEnabled(pGpu))
272         {
273             //
274             // When ctx buffer management is in GSP-RM, GSP-RM needs extra
275             // 100 MBs to meet max CUDA context allocation requirement
276             //
277             size += 100 * 1024 * 1024;
278         }
279     }
280 
281     //
282     // See bug 200619860. We are running out of memory during allocation
283     // of GR buffers. Since GR buffers are not allocated inside guest RM
284     // we are skipping reservation there
285     //
286     if (RMCFG_FEATURE_PLATFORM_WINDOWS &&
287         pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_TCC_MODE))
288     {
289         size += 32 * 1024 * 1024;
290     }
291 
292     return size;
293 }
294 
295 void
memmgrGetDisablePlcKind_GA100(MemoryManager * pMemoryManager,NvU32 * pKind)296 memmgrGetDisablePlcKind_GA100
297 (
298     MemoryManager *pMemoryManager,
299     NvU32          *pKind
300 )
301 {
302     if (pKind != NULL)
303     {
304         *pKind = NV_MMU_PTE_KIND_GENERIC_MEMORY_COMPRESSIBLE_DISABLE_PLC;
305     }
306 }
307 
308 /*!
309  * @brief This function sets the PDB property to enable/disable dynamic page offlining
310  */
311 void
memmgrEnableDynamicPageOfflining_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager)312 memmgrEnableDynamicPageOfflining_GA100
313 (
314     OBJGPU        *pGpu,
315     MemoryManager *pMemoryManager
316 )
317 {
318     if (gpuIsGlobalPoisonFuseEnabled(pGpu))
319     {
320        pMemoryManager->bEnableDynamicPageOfflining = NV_TRUE;
321     }
322 
323     return;
324 }
325 
326 /*!
327  *  @brief Get blacklist page details.
328  *
329  *  @param[in]      pGpu            OBJGPU
330  *  @param[in]      pMemoryManager  MemoryManager
331  *  @param[out]     pBlAddrs        BLACKLIST_ADDRESSES where count is taken
332  *                                  as input and the addressed and count is
333  *                                  returned.
334  *  @param[in/out]  pCount          Takes size of pBlAddrs as input and returns
335  *                                  the number of populated addresses in
336  *                                  pBlAddrs.
337    @returns NV_STATUS
338  *
339  */
340 NV_STATUS
memmgrGetBlackListPages_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,BLACKLIST_ADDRESS * pBlAddrs,NvU32 * pCount)341 memmgrGetBlackListPages_GA100
342 (
343     OBJGPU              *pGpu,
344     MemoryManager       *pMemoryManager,
345     BLACKLIST_ADDRESS   *pBlAddrs,
346     NvU32               *pCount
347 )
348 {
349     NvU32               baseIndex        = 0;
350     NV_STATUS           status           = NV_OK;
351     NvU32               idx              = 0;
352     NvU32               entryIdx         = 0;
353 
354     if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT) ||
355              !gpuCheckPageRetirementSupport_HAL(pGpu))
356     {
357         return NV_ERR_NOT_SUPPORTED;
358     }
359 
360     //
361     // Read the inforom for a list of pages to blacklist.
362     // SLI support requires investigation to ensure
363     // identical heaps on both devices (bug 756971).
364     //
365     if (IsSLIEnabled(pGpu) && !gpuIsEccPageRetirementWithSliAllowed(pGpu))
366     {
367         return NV_ERR_NOT_SUPPORTED;
368     }
369 
370     NV2080_CTRL_FB_GET_DYNAMIC_OFFLINED_PAGES_PARAMS *pBlParams =
371         portMemAllocNonPaged(sizeof(*pBlParams));
372     if (pBlParams == NULL)
373     {
374         return NV_ERR_NO_MEMORY;
375     }
376 
377     while (baseIndex < NV2080_CTRL_FB_DYNAMIC_BLACKLIST_MAX_PAGES)
378     {
379         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
380 
381         portMemSet(pBlParams, 0, sizeof(*pBlParams));
382 
383         pBlParams->baseIndex = baseIndex;
384 
385         status = pRmApi->Control(pRmApi,
386                                  pGpu->hInternalClient,
387                                  pGpu->hInternalSubdevice,
388                                  NV2080_CTRL_CMD_FB_GET_DYNAMIC_OFFLINED_PAGES,
389                                  pBlParams,
390                                  sizeof(*pBlParams));
391         if(NV_OK != status)
392         {
393             if (NV_ERR_NOT_SUPPORTED == status ||
394                 NV_ERR_OBJECT_NOT_FOUND == status)
395             {
396                 NV_PRINTF(LEVEL_ERROR,
397                           "No blacklisted pages\n");
398             }
399             else
400             {
401                 NV_ASSERT(0);
402                 NV_PRINTF(LEVEL_ERROR,
403                           "Failed to read black list addresses\n");
404             }
405             break;
406         }
407 
408         for (idx = 0; idx < pBlParams->validEntries; idx++)
409         {
410 
411             if (entryIdx >= *pCount)
412             {
413                 status = NV_ERR_BUFFER_TOO_SMALL;
414                 goto done;
415             }
416             pBlAddrs[entryIdx].address = pBlParams->offlined[idx].pageNumber << RM_PAGE_SHIFT;
417             pBlAddrs[entryIdx].type = pBlParams->offlined[idx].source;
418             entryIdx++;
419          }
420 
421         if (!pBlParams->bMore) {
422             break;
423         }
424 
425         baseIndex += NV2080_CTRL_FB_DYNAMIC_BLACKLIST_MAX_ENTRIES;
426     }
427 
428 done:
429     portMemFree(pBlParams);
430     *pCount = entryIdx;
431 
432     return status;
433 }
434 
435 /*!
436  *  @brief Inserts an unprotected segment at the start of FB on GA100
437            to prevent VPR from getting allocated here
438  *
439  *  @returns NV_STATUS
440  */
441 NV_STATUS
memmgrInsertUnprotectedRegionAtBottomOfFb_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,NvU64 * pSize)442 memmgrInsertUnprotectedRegionAtBottomOfFb_GA100
443 (
444     OBJGPU        *pGpu,
445     MemoryManager *pMemoryManager,
446     NvU64         *pSize
447 )
448 {
449     FB_REGION_DESCRIPTOR fbRegion        = {0};
450     NvU64                memLockLo       = 0;
451     NvU64                memLockHi       = 0;
452     NvBool               bIsMmuLockValid = NV_FALSE;
453     NvU64                size;
454 
455     NV_ASSERT_OK_OR_RETURN(memmgrReadMmuLock_HAL(pGpu, pMemoryManager,
456                                                  &bIsMmuLockValid, &memLockLo,
457                                                  &memLockHi));
458 
459     // MMU_LOCK is not set in OLD Vbios that programs 1GB less in LOCAL_MEMORY_RANGE
460     if (!bIsMmuLockValid)
461     {
462         *pSize = 0;
463         return NV_OK;
464     }
465 
466     memLockHi  = NV_ALIGN_UP(memLockHi, 0x10000) - 1; // Align up to cover till the last byte
467 
468     size = RM_PAGE_ALIGN_UP(memLockHi - memLockLo + 1);
469 
470     //
471     // Bug 2509894: In order to prevent CBC wrap around and clobbering of
472     // VPR contents, we move VPR out of the bottom 1.5GB of video memory.
473     // For raw mode, HW assumes a max of 384 MBs (for 96GB FB) of CBC. However,
474     // on GA100 due to a HW bug this figure comes around ~1GB. By experimentation,
475     // we found that 1.5GBs works fine for us.
476     //
477     size = NV_MAX(size, NV_CBC_MAX_SIZE_BUG_2509894_WAR);
478 
479     // SEC2 ucode expects VPR start address to be 1MB aligned
480     size = NV_ALIGN_UP(size, 1 * 1024 * 1024);
481 
482     fbRegion.base = 0;
483     fbRegion.limit = size - 1;
484     fbRegion.rsvdSize = 0;
485     fbRegion.bRsvdRegion = NV_FALSE;
486     fbRegion.performance = 0;
487     fbRegion.bSupportCompressed = NV_TRUE;
488     fbRegion.bSupportISO = NV_FALSE;
489     fbRegion.bProtected = NV_FALSE;
490     fbRegion.bInternalHeap = NV_FALSE;
491 
492     memmgrInsertFbRegion(pGpu, pMemoryManager, &fbRegion);
493 
494     NV_PRINTF(LEVEL_INFO, "Unprotected Block Start: 0x%0llx End: 0x%0llx Size: 0x%0llx\n",
495                        memLockLo, memLockHi, size);
496 
497     // Return the size
498     *pSize = size;
499 
500     return NV_OK;
501 }
502 
503 NvBool
memmgrIsMemDescSupportedByFla_GA100(OBJGPU * pGpu,MemoryManager * pMemoryManager,MEMORY_DESCRIPTOR * pMemDesc)504 memmgrIsMemDescSupportedByFla_GA100
505 (
506     OBJGPU *pGpu,
507     MemoryManager *pMemoryManager,
508     MEMORY_DESCRIPTOR *pMemDesc
509 )
510 {
511     if ((memdescGetAddressSpace(pMemDesc) == ADDR_FBMEM)
512          || memdescIsEgm(pMemDesc)
513        )
514     {
515         return NV_TRUE;
516     }
517     return NV_FALSE;
518 }
519