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