1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-2022 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/heap.h"
29 #include "gpu/bus/kern_bus.h"
30 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
31 #include "gpu/mem_mgr/mem_desc.h"
32 #include "gpu/mem_mgr/virt_mem_allocator.h"
33 #include "gpu/gpu_resource_desc.h"
34 #include "gpu/subdevice/subdevice.h"
35 #include "platform/chipset/chipset.h"
36 #include "ctrl/ctrl0080/ctrl0080fb.h"
37 #include "ctrl/ctrl2080/ctrl2080fb.h"
38 #include "core/locks.h"
39 #include "vgpu/rpc.h"
40 #include "rmapi/client.h"
41 
42 
43 static NV_STATUS
44 _fbGetFbInfos(OBJGPU *pGpu, NvHandle hClient, NvHandle hObject, NV2080_CTRL_FB_INFO *pFbInfos, NvU32 fbInfoListSize)
45 {
46     KernelMemorySystem *pKernelMemorySystem  = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
47     MemoryManager      *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
48     Heap               *pHeap = GPU_GET_HEAP(pGpu);
49     Heap               *pMemoryPartitionHeap = NULL;
50     KernelMIGManager   *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
51     NV_STATUS           status = NV_OK;
52     NvU32               data = 0;
53     NvU32               i = 0;
54     NvBool              bIsPmaEnabled = memmgrIsPmaInitialized(pMemoryManager);
55     NvBool              bIsMIGInUse = IS_MIG_IN_USE(pGpu);
56     NvU64               bytesTotal;
57     NvU64               bytesFree;
58     NvU64               heapBase;
59     NvU64               largestOffset;
60     NvU64               largestFree;
61     NvU64               val;
62     NvU64               routeToPhysicalIdxMask = 0;
63     NvBool              bIsClientMIGMonitor = NV_FALSE;
64     NvBool              bIsClientMIGProfiler = NV_FALSE;
65 
66     ct_assert(NV2080_CTRL_FB_INFO_INDEX_MAX < NV_NBITS_IN_TYPE(routeToPhysicalIdxMask));
67 
68     if (!RMCFG_FEATURE_PMA)
69         return NV_ERR_NOT_SUPPORTED;
70 
71     if (bIsMIGInUse)
72     {
73         bIsClientMIGMonitor = !RMCFG_FEATURE_PLATFORM_GSP && rmclientIsCapableByHandle(hClient, NV_RM_CAP_SYS_SMC_MONITOR);
74         bIsClientMIGProfiler = kmigmgrIsClientUsingDeviceProfiling(pGpu, pKernelMIGManager, hClient);
75     }
76 
77     //
78     // Most MIG queries require GPU instance info that is only kept in the Physical RM. Flag
79     // the indices that will need to be fulfilled by the GSP when in offload mode, and
80     // also load the per-GPU instance heap for others.
81     //
82     for (i = 0; i < fbInfoListSize; i++)
83     {
84         switch (pFbInfos[i].index)
85         {
86             // The cases which aren't affected by MIG
87             case NV2080_CTRL_FB_INFO_INDEX_TILE_REGION_COUNT:
88             case NV2080_CTRL_FB_INFO_INDEX_TILE_REGION_FREE_COUNT:
89             case NV2080_CTRL_FB_INFO_INDEX_BANK_SWIZZLE_ALIGNMENT:
90             case NV2080_CTRL_FB_INFO_INDEX_BANK_COUNT:
91             case NV2080_CTRL_FB_INFO_INDEX_OVERLAY_OFFSET_ADJUSTMENT:
92             case NV2080_CTRL_FB_INFO_INDEX_FB_TAX_SIZE_KB:
93             case NV2080_CTRL_FB_INFO_INDEX_RAM_LOCATION:
94             case NV2080_CTRL_FB_INFO_INDEX_FB_IS_BROKEN:
95             case NV2080_CTRL_FB_INFO_INDEX_L2CACHE_ONLY_MODE:
96             case NV2080_CTRL_FB_INFO_INDEX_SMOOTHDISP_RSVD_BAR1_SIZE:
97             case NV2080_CTRL_FB_INFO_INDEX_HEAP_OFFLINE_SIZE:
98             case NV2080_CTRL_FB_INFO_INDEX_SUSPEND_RESUME_RSVD_SIZE:
99             case NV2080_CTRL_FB_INFO_INDEX_ALLOW_PAGE_RETIREMENT:
100             case NV2080_CTRL_FB_INFO_POISON_FUSE_ENABLED:
101             case NV2080_CTRL_FB_INFO_FBPA_ECC_ENABLED:
102             case NV2080_CTRL_FB_INFO_DYNAMIC_PAGE_OFFLINING_ENABLED:
103             case NV2080_CTRL_FB_INFO_INDEX_FORCED_BAR1_64KB_MAPPING_ENABLED:
104             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_SIZE:
105             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_ALIGNMENT:
106             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_BAR1_MAX_OFFSET_64KB:
107             {
108                 continue;
109             }
110             case NV2080_CTRL_FB_INFO_INDEX_BUS_WIDTH:
111             case NV2080_CTRL_FB_INFO_INDEX_PARTITION_COUNT:
112             case NV2080_CTRL_FB_INFO_INDEX_PARTITION_MASK:
113             case NV2080_CTRL_FB_INFO_INDEX_FBP_MASK:
114             case NV2080_CTRL_FB_INFO_INDEX_FBP_COUNT:
115             case NV2080_CTRL_FB_INFO_INDEX_L2CACHE_SIZE:
116             case NV2080_CTRL_FB_INFO_INDEX_LTC_COUNT:
117             case NV2080_CTRL_FB_INFO_INDEX_LTS_COUNT:
118             case NV2080_CTRL_FB_INFO_INDEX_LTC_MASK:
119             case NV2080_CTRL_FB_INFO_INDEX_MEMORYINFO_VENDOR_ID:
120             case NV2080_CTRL_FB_INFO_INDEX_TRAINIG_2T:
121             case NV2080_CTRL_FB_INFO_INDEX_PSEUDO_CHANNEL_MODE:
122             case NV2080_CTRL_FB_INFO_INDEX_COMPRESSION_SIZE:
123             case NV2080_CTRL_FB_INFO_INDEX_DRAM_PAGE_STRIDE:
124             case NV2080_CTRL_FB_INFO_INDEX_RAM_CFG:
125             case NV2080_CTRL_FB_INFO_INDEX_RAM_TYPE:
126             case NV2080_CTRL_FB_INFO_INDEX_ECC_STATUS_SIZE:
127             {
128                 // This info is only known by the Physical RM. Redirect it there.
129                 if (IS_GSP_CLIENT(pGpu))
130                 {
131                     routeToPhysicalIdxMask |= BIT64(i);
132                 }
133 
134                 break;
135             }
136             case NV2080_CTRL_FB_INFO_INDEX_TOTAL_RAM_SIZE:
137             case NV2080_CTRL_FB_INFO_INDEX_RAM_SIZE:
138             {
139                 //
140                 // If MIG is enabled and device profiling/monitoring
141                 // is not in use we check for GPU instance subscription
142                 // and provide GPU instance local info. Unsubscribed + unprivileged
143                 // clients may still query global info for the above list of
144                 // indices.
145                 //
146                 if (bIsMIGInUse &&
147                     !bIsClientMIGProfiler && !bIsClientMIGMonitor)
148                 {
149                     MIG_INSTANCE_REF ref;
150                     status = kmigmgrGetInstanceRefFromClient(pGpu, pKernelMIGManager,
151                                                              hClient, &ref);
152 
153                     if ((status != NV_OK) && !kmigmgrIsMIGReferenceValid(&ref))
154                     {
155                         status = NV_OK;
156                         break;
157                     }
158                 }
159 
160                 // Fall through to the default case to get the memory partition heap
161             }
162             default:
163             {
164                 //
165                 // If MIG is enabled and device profiling/monitoring
166                 // is not in use we check for GPU instance subscription
167                 // and provide GPU instance local info
168                 //
169                 if (bIsMIGInUse &&
170                     !bIsClientMIGProfiler && !bIsClientMIGMonitor)
171                 {
172                     NV_CHECK_OR_RETURN(LEVEL_INFO, (kmigmgrGetMemoryPartitionHeapFromClient(pGpu,
173                                        pKernelMIGManager, hClient, &pMemoryPartitionHeap) == NV_OK),
174                                        NV_ERR_INSUFFICIENT_PERMISSIONS);
175 
176                     //
177                     // If client is associated with a GPU instance then point pHeap
178                     // to client's memory partition heap
179                     //
180                     if (pMemoryPartitionHeap != NULL)
181                         pHeap = pMemoryPartitionHeap;
182                 }
183                 break;
184             }
185         }
186     }
187 
188     // If we have any infos that need to be populated by Physical RM, query now
189     if (routeToPhysicalIdxMask != 0)
190     {
191         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
192         NV2080_CTRL_FB_GET_INFO_V2_PARAMS *pParams =
193             portMemAllocNonPaged(sizeof(NV2080_CTRL_FB_GET_INFO_V2_PARAMS));
194         NvU32 physIdx = 0;
195 
196         portMemSet(pParams, 0, sizeof(*pParams));
197         FOR_EACH_INDEX_IN_MASK(64, i, routeToPhysicalIdxMask)
198         {
199             pParams->fbInfoList[physIdx++].index = pFbInfos[i].index;
200         }
201         FOR_EACH_INDEX_IN_MASK_END;
202 
203         pParams->fbInfoListSize = physIdx;
204 
205         NV_CHECK_OK_OR_ELSE(status, LEVEL_ERROR,
206             pRmApi->Control(pRmApi, hClient, hObject,
207                             NV2080_CTRL_CMD_FB_GET_INFO_V2,
208                             pParams, sizeof(*pParams)),
209             portMemFree(pParams);
210             return status;
211         );
212 
213         physIdx = 0;
214         FOR_EACH_INDEX_IN_MASK(64, i, routeToPhysicalIdxMask)
215         {
216             NV_ASSERT(pFbInfos[i].index == pParams->fbInfoList[physIdx].index);
217             pFbInfos[i].data = pParams->fbInfoList[physIdx++].data;
218         }
219         FOR_EACH_INDEX_IN_MASK_END;
220 
221         portMemFree(pParams);
222     }
223 
224     for (i = 0; i < fbInfoListSize; i++)
225     {
226         // Skip info already populated by Physical RM
227         if ((routeToPhysicalIdxMask & BIT64(i)) != 0)
228             continue;
229 
230         switch (pFbInfos[i].index)
231         {
232             case NV2080_CTRL_FB_INFO_INDEX_TILE_REGION_COUNT:
233             {
234                 data = 0;
235                 break;
236             }
237             case NV2080_CTRL_FB_INFO_INDEX_TILE_REGION_FREE_COUNT:
238             {
239                 // Obsolete
240                 data = 0;
241                 break;
242             }
243             case NV2080_CTRL_FB_INFO_INDEX_BAR1_SIZE:
244             {
245                 GETBAR1INFO bar1Info = {0};
246                 status = memmgrGetBAR1InfoForClient_HAL(pGpu, pMemoryManager, hClient, &bar1Info);
247                 if (status != NV_OK)
248                     data = 0;
249                 else
250                     data = bar1Info.bar1Size;
251 
252                 break;
253             }
254             case NV2080_CTRL_FB_INFO_INDEX_BAR1_AVAIL_SIZE:
255             {
256                 GETBAR1INFO bar1Info = {0};
257                 status = memmgrGetBAR1InfoForClient_HAL(pGpu, pMemoryManager, hClient, &bar1Info);
258                 if (status != NV_OK)
259                     data = 0;
260                 else
261                     data = bar1Info.bar1AvailSize;
262 
263                 break;
264             }
265             case NV2080_CTRL_FB_INFO_INDEX_BAR1_MAX_CONTIGUOUS_AVAIL_SIZE:
266             {
267                 GETBAR1INFO bar1Info = {0};
268                 status = memmgrGetBAR1InfoForClient_HAL(pGpu, pMemoryManager, hClient, &bar1Info);
269                 if (status != NV_OK)
270                     data = 0;
271                 else
272                     data = bar1Info.bar1MaxContigAvailSize;
273 
274                 break;
275             }
276             case NV2080_CTRL_FB_INFO_INDEX_BANK_SWIZZLE_ALIGNMENT:
277             {
278                 GETBAR1INFO bar1Info = {0};
279                 status = memmgrGetBAR1InfoForClient_HAL(pGpu, pMemoryManager, hClient, &bar1Info);
280                 if (status != NV_OK)
281                     data = 0;
282                 else
283                     data = bar1Info.bankSwizzleAlignment;
284 
285                 break;
286             }
287             case NV2080_CTRL_FB_INFO_INDEX_TOTAL_RAM_SIZE:
288             {
289                 if (pMemoryPartitionHeap != NULL)
290                 {
291                     NvU32 heapSizeKb;
292                     if (bIsPmaEnabled)
293                     {
294                         pmaGetTotalMemory(&pHeap->pmaObject, &bytesTotal);
295                         NV_ASSERT(NvU64_HI32(bytesTotal >> 10) == 0);
296                         heapSizeKb = NvU64_LO32(bytesTotal >> 10);
297                     }
298                     else
299                     {
300                         NvU64 size;
301 
302                         heapGetSize(pHeap, &size);
303                         NV_ASSERT(NvU64_HI32(size >> 10) == 0);
304                         heapSizeKb = NvU64_LO32(size >> 10);
305                     }
306                     data = heapSizeKb;
307                     break;
308                 }
309                 else
310                 {
311                     const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
312                             kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
313                     NV_ASSERT(0 == NvU64_HI32(pMemoryManager->Ram.fbTotalMemSizeMb << 10));
314                     data = NvU64_LO32(NV_MIN((pMemoryManager->Ram.fbTotalMemSizeMb << 10),
315                                              (pMemoryManager->Ram.fbOverrideSizeMb << 10))
316                                              - pMemsysConfig->fbOverrideStartKb);
317                     break;
318                 }
319             }
320             case NV2080_CTRL_FB_INFO_INDEX_RAM_SIZE:
321             {
322                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
323                         kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
324                 if (pMemoryPartitionHeap != NULL)
325                 {
326                     NvU32 heapSizeKb;
327                     if (bIsPmaEnabled)
328                     {
329                         pmaGetTotalMemory(&pHeap->pmaObject, &bytesTotal);
330                         NV_ASSERT(NvU64_HI32(bytesTotal >> 10) == 0);
331                         heapSizeKb = NvU64_LO32(bytesTotal >> 10);
332                     }
333                     else
334                     {
335                         NvU64 size;
336 
337                         heapGetSize(pHeap, &size);
338                         NV_ASSERT(NvU64_HI32(size >> 10) == 0);
339                         heapSizeKb = NvU64_LO32(size >> 10);
340                     }
341                     data = heapSizeKb;
342                     break;
343                 }
344                 NV_ASSERT(0 == NvU64_HI32(pMemoryManager->Ram.fbTotalMemSizeMb << 10));
345                 data = NvU64_LO32(NV_MIN((pMemoryManager->Ram.fbTotalMemSizeMb << 10),
346                                          (pMemoryManager->Ram.fbOverrideSizeMb << 10))
347                                          - pMemsysConfig->fbOverrideStartKb);
348                 break;
349             }
350             case NV2080_CTRL_FB_INFO_INDEX_USABLE_RAM_SIZE:
351             {
352                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
353                         kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
354                 if (pMemoryPartitionHeap != NULL)
355                 {
356                     NvU32 heapSizeKb;
357                     if (bIsPmaEnabled)
358                     {
359                         pmaGetTotalMemory(&pHeap->pmaObject, &bytesTotal);
360                         NV_ASSERT(NvU64_HI32(bytesTotal >> 10) == 0);
361                         heapSizeKb = NvU64_LO32(bytesTotal >> 10);
362                     }
363                     else
364                     {
365                         NvU64 size;
366 
367                         heapGetSize(pHeap, &size);
368                         NV_ASSERT(NvU64_HI32(size >> 10) == 0);
369                         heapSizeKb = NvU64_LO32(size >> 10);
370                     }
371                     data = heapSizeKb;
372                     break;
373                 }
374                 NV_ASSERT(0 == NvU64_HI32(pMemoryManager->Ram.fbUsableMemSize >> 10));
375                 data = NvU64_LO32(NV_MIN((pMemoryManager->Ram.fbUsableMemSize >> 10 ),
376                                          (pMemoryManager->Ram.fbOverrideSizeMb << 10))
377                                          - pMemsysConfig->fbOverrideStartKb);
378                 break;
379             }
380             case NV2080_CTRL_FB_INFO_INDEX_HEAP_SIZE:
381             {
382                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
383                         kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
384                 if (bIsPmaEnabled)
385                 {
386                     pmaGetTotalMemory(&pHeap->pmaObject, &bytesTotal);
387                     NV_ASSERT(NvU64_HI32(bytesTotal >> 10) == 0);
388                     data = NvU64_LO32(bytesTotal >> 10);
389                 }
390                 else
391                 {
392                     NvU64 size;
393 
394                     heapGetUsableSize(pHeap, &size);
395                     NV_ASSERT(NvU64_HI32(size >> 10) == 0);
396                     data = NvU64_LO32(size >> 10);
397                 }
398                 data -= pMemsysConfig->fbOverrideStartKb;
399                 break;
400             }
401             case NV2080_CTRL_FB_INFO_INDEX_HEAP_START:
402             {
403                 if (pMemoryPartitionHeap != NULL)
404                 {
405                     if (bIsPmaEnabled)
406                     {
407                         pmaGetLargestFree(&pHeap->pmaObject, &largestFree, &heapBase, &largestOffset);
408                     }
409                     else
410                     {
411                         status = heapInfo(pHeap, &bytesFree, &bytesTotal, &heapBase,
412                                           &largestOffset, &largestFree);
413                     }
414                     data = NvU64_LO32(heapBase >> 10);
415                 }
416                 else
417                 {
418                     const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
419                             kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
420                     if (pMemsysConfig->fbOverrideStartKb != 0)
421                     {
422                         data = NvU64_LO32(pMemsysConfig->fbOverrideStartKb);
423                         NV_ASSERT(((NvU64) data << 10ULL) == pMemsysConfig->fbOverrideStartKb);
424                     }
425 					else
426 					{
427                         //
428                         // Returns start of heap in kbytes. This is zero unless
429                         // VGA display memory is reserved.
430                         //
431                         heapGetBase(pHeap, &heapBase);
432                         data = NvU64_LO32(heapBase >> 10);
433                         NV_ASSERT(((NvU64) data << 10ULL) == heapBase);
434                     }
435                 }
436                 break;
437             }
438             case NV2080_CTRL_FB_INFO_INDEX_HEAP_FREE:
439             {
440                 if (bIsClientMIGMonitor || bIsClientMIGProfiler)
441                 {
442                     bytesFree = 0;
443 
444                     //
445                     // Add free memory across the all valid MIG GPU instances and
446                     // the global heap.
447                     //
448                     // As MIG uses the global heap when memory is not
449                     // partitioned, skip getting information from it.
450                     //
451                     if (kmigmgrIsMIGMemPartitioningEnabled(pGpu, pKernelMIGManager))
452                     {
453                         memmgrGetFreeMemoryForAllMIGGPUInstances(pGpu, pMemoryManager, &val);
454                         bytesFree = val;
455                     }
456 
457                     if (bIsPmaEnabled)
458                         pmaGetFreeMemory(&pHeap->pmaObject, &val);
459                     else
460                         heapGetFree(pHeap, &val);
461 
462                     bytesFree += val;
463 
464                     NV_ASSERT(NvU64_HI32(bytesFree >> 10) == 0);
465                     data = NvU64_LO32(bytesFree >> 10);
466                 }
467                 else if (bIsPmaEnabled)
468                 {
469                     pmaGetFreeMemory(&pHeap->pmaObject, &bytesFree);
470 
471                     NV_ASSERT(NvU64_HI32(bytesFree >> 10) == 0);
472                     data = NvU64_LO32(bytesFree >> 10);
473                 }
474                 else
475                 {
476                     NvU64 size;
477 
478                     heapGetFree(pHeap, &size);
479                     NV_ASSERT(NvU64_HI32(size >> 10) == 0);
480                     data = NvU64_LO32(size >> 10);
481                 }
482                 break;
483             }
484 
485             case NV2080_CTRL_FB_INFO_INDEX_VISTA_RESERVED_HEAP_SIZE:
486             {
487                 //
488                 // If PMA is enabled, ideally we wouldn't have any reserved heap but UVM vidheapctrl
489                 // allocations are not accounted for by KMD. RM will reserve it.
490                 //
491                 if (bIsPmaEnabled)
492                 {
493                     if (pMemoryPartitionHeap != NULL)
494                     {
495                         data = 0;
496                         break;
497                     }
498 
499                     NvU64 uvmReserveMem = 0;
500                     memmgrCalcReservedFbSpaceForUVM_HAL(pGpu, pMemoryManager, &uvmReserveMem);
501                     // Ceil bytes and return the # of KB
502                     data = NvU64_LO32(NV_CEIL(uvmReserveMem, 1024));
503                 }
504                 else
505                 {
506                     memmgrCalcReservedFbSpace(pGpu, pMemoryManager);
507                     // heap size in kbytes
508                     data = memmgrGetReservedHeapSizeMb_HAL(pGpu, pMemoryManager) << 10;
509                 }
510                 break;
511             }
512 
513             case NV2080_CTRL_FB_INFO_INDEX_MAPPABLE_HEAP_SIZE:
514             {
515                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemsysConfig =
516                             kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
517                 if (bIsPmaEnabled)
518                 {
519                     NvU32 heapSizeKb;
520 
521                     pmaGetTotalMemory(&pHeap->pmaObject, &bytesTotal);
522                     NV_ASSERT(NvU64_HI32(bytesTotal >> 10) == 0);
523                     heapSizeKb = NvU64_LO32(bytesTotal >> 10);
524 
525                     data = memmgrGetMappableRamSizeMb(pMemoryManager) << 10;
526                     if (data > heapSizeKb)
527                         data = heapSizeKb;
528                 }
529                 else
530                 {
531                     NvU64 size;
532                     NvU32 heapSizeKb;
533 
534                     heapGetSize(pHeap, &size);
535                     NV_ASSERT(NvU64_HI32(size >> 10) == 0);
536                     heapSizeKb = NvU64_LO32(size >> 10);
537 
538                     data = memmgrGetMappableRamSizeMb(pMemoryManager) << 10;
539                     if (data > heapSizeKb)
540                         data = heapSizeKb;
541                 }
542                 data -= pMemsysConfig->fbOverrideStartKb;
543                 break;
544             }
545             case NV2080_CTRL_FB_INFO_INDEX_BANK_COUNT:
546             {
547                 data = 1;
548                 break;
549             }
550             case NV2080_CTRL_FB_INFO_INDEX_OVERLAY_OFFSET_ADJUSTMENT:
551             {
552                 data = 0;
553                 break;
554             }
555             case NV2080_CTRL_FB_INFO_INDEX_FB_TAX_SIZE_KB:
556             {
557                 bytesTotal = memmgrGetFbTaxSize_HAL(pGpu, pMemoryManager);
558                 data = NvU64_LO32(bytesTotal >> 10);
559                 break;
560             }
561             case NV2080_CTRL_FB_INFO_INDEX_HEAP_BASE_KB:
562             {
563                 if (bIsPmaEnabled)
564                 {
565                     pmaGetLargestFree(&pHeap->pmaObject, &largestFree, &heapBase, &largestOffset);
566                 }
567                 else
568                 {
569                     status = heapInfo(pHeap, &bytesFree, &bytesTotal, &heapBase,
570                                       &largestOffset, &largestFree);
571                 }
572 
573                 data = NvU64_LO32(heapBase >> 10);
574                 break;
575             }
576             case NV2080_CTRL_FB_INFO_INDEX_LARGEST_FREE_REGION_SIZE_KB:
577             {
578                 if (bIsPmaEnabled)
579                 {
580                     pmaGetLargestFree(&pHeap->pmaObject, &largestFree, &heapBase, &largestOffset);
581                 }
582                 else
583                 {
584                     status = heapInfo(pHeap, &bytesFree, &bytesTotal, &heapBase,
585                                       &largestOffset, &largestFree);
586                 }
587 
588                 data = NvU64_LO32(largestFree >> 10);
589                 break;
590             }
591             case NV2080_CTRL_FB_INFO_INDEX_LARGEST_FREE_REGION_BASE_KB:
592             {
593                 if (bIsPmaEnabled)
594                 {
595                     pmaGetLargestFree(&pHeap->pmaObject, &largestFree, &heapBase, &largestOffset);
596                 }
597                 else
598                 {
599                     status = heapInfo(pHeap, &bytesFree, &bytesTotal, &heapBase,
600                                       &largestOffset, &largestFree);
601                 }
602 
603                 data = NvU64_LO32(largestOffset >> 10);
604                 break;
605             }
606             case NV2080_CTRL_FB_INFO_INDEX_RAM_LOCATION:
607             {
608                 data = NV2080_CTRL_FB_INFO_RAM_LOCATION_GPU_DEDICATED;
609                 break;
610             }
611             case NV2080_CTRL_FB_INFO_INDEX_FB_IS_BROKEN:
612             {
613                 data = (pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) &&
614                         !pGpu->getProperty(pGpu, PDB_PROP_GPU_ZERO_FB)) ? 1 : 0;
615                 break;
616             }
617             case NV2080_CTRL_FB_INFO_INDEX_L2CACHE_ONLY_MODE:
618             {
619                 data = gpuIsCacheOnlyModeEnabled(pGpu) ? 1 : 0;
620                 break;
621             }
622 
623             case NV2080_CTRL_FB_INFO_INDEX_SMOOTHDISP_RSVD_BAR1_SIZE:
624             {
625                 data = pGpu->uefiScanoutSurfaceSizeInMB;
626                 break;
627             }
628 
629             case NV2080_CTRL_FB_INFO_INDEX_HEAP_OFFLINE_SIZE:
630             {
631                 data = pHeap->dynamicBlacklistSize;
632                 break;
633             }
634             case NV2080_CTRL_FB_INFO_INDEX_1TO1_COMPTAG_ENABLED:
635             {
636                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemorySystemConfig = kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
637                 data = (pMemorySystemConfig->bOneToOneComptagLineAllocation) ? 1 : 0;
638                 break;
639             }
640 
641             case NV2080_CTRL_FB_INFO_INDEX_SUSPEND_RESUME_RSVD_SIZE:
642             {
643                 NvU64 rsvdSize = memmgrGetRsvdSizeForSr_HAL(pGpu, pMemoryManager);
644                 NV_ASSERT(NvU64_HI32(rsvdSize) == 0);
645                 data = NvU64_LO32(rsvdSize);
646                 break;
647             }
648             case NV2080_CTRL_FB_INFO_INDEX_ALLOW_PAGE_RETIREMENT:
649             {
650                 data = pGpu->getProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT) ? 1 : 0;
651                 break;
652             }
653             case NV2080_CTRL_FB_INFO_POISON_FUSE_ENABLED:
654             {
655                 data = gpuIsGlobalPoisonFuseEnabled(pGpu) ? 1 : 0;
656                 break;
657             }
658             case NV2080_CTRL_FB_INFO_FBPA_ECC_ENABLED:
659             {
660                 const MEMORY_SYSTEM_STATIC_CONFIG *pMemorySystemConfig =
661                     kmemsysGetStaticConfig(pGpu, GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu));
662                 data = (pMemorySystemConfig->bEnabledEccFBPA) ? 1: 0;
663                 break;
664             }
665             case NV2080_CTRL_FB_INFO_DYNAMIC_PAGE_OFFLINING_ENABLED:
666             {
667                 data = pMemoryManager->bEnableDynamicPageOfflining ? 1 : 0;
668                 break;
669             }
670             case NV2080_CTRL_FB_INFO_INDEX_FORCED_BAR1_64KB_MAPPING_ENABLED:
671             {
672                 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
673                 data = kbusIsBar1Force64KBMappingEnabled(pKernelBus);
674                 break;
675             }
676             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_SIZE:
677             {
678                 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
679                 data = 0;
680                 if (kbusIsP2pMailboxClientAllocated(pKernelBus))
681                     kbusGetP2PMailboxAttributes_HAL(pGpu, pKernelBus, &data, NULL, NULL);
682                 break;
683             }
684             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_ALIGNMENT:
685             {
686                 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
687                 data = 0;
688                 if (kbusIsP2pMailboxClientAllocated(pKernelBus))
689                     kbusGetP2PMailboxAttributes_HAL(pGpu, pKernelBus, NULL, &data, NULL);
690                 break;
691             }
692             case NV2080_CTRL_FB_INFO_INDEX_P2P_MAILBOX_BAR1_MAX_OFFSET_64KB:
693             {
694                 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
695                 data = 0;
696                 if (kbusIsP2pMailboxClientAllocated(pKernelBus))
697                     kbusGetP2PMailboxAttributes_HAL(pGpu, pKernelBus, NULL, NULL, &data);
698                 break;
699             }
700             default:
701             {
702                 data = 0;
703                 status = NV_ERR_INVALID_ARGUMENT;
704                 break;
705             }
706         }
707 
708         if (status != NV_OK)
709             break;
710         // save off data value
711         pFbInfos[i].data = data;
712     }
713 
714     return status;
715 }
716 
717 //
718 // subdeviceCtrlCmdFbGetInfo
719 //
720 // Lock Requirements:
721 //      Assert that API and Gpus lock held on entry
722 //
723 NV_STATUS
724 subdeviceCtrlCmdFbGetInfo_IMPL
725 (
726     Subdevice *pSubdevice,
727     NV2080_CTRL_FB_GET_INFO_PARAMS *pFbInfoParams
728 )
729 {
730     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
731     NvHandle hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
732     NvHandle hObject = RES_GET_HANDLE(pSubdevice);
733 
734     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
735 
736     if ((pFbInfoParams->fbInfoListSize == 0) ||
737         (NvP64_VALUE(pFbInfoParams->fbInfoList) == NULL))
738     {
739         return NV_ERR_INVALID_ARGUMENT;
740     }
741 
742     return _fbGetFbInfos(pGpu, hClient, hObject, NvP64_VALUE(pFbInfoParams->fbInfoList), pFbInfoParams->fbInfoListSize);
743 }
744 
745 //
746 // subdeviceCtrlCmdFbGetInfoV2
747 //
748 // Lock Requirements:
749 //      Assert that API and Gpus lock held on entry
750 //
751 NV_STATUS
752 subdeviceCtrlCmdFbGetInfoV2_IMPL
753 (
754     Subdevice *pSubdevice,
755     NV2080_CTRL_FB_GET_INFO_V2_PARAMS *pFbInfoParams
756 )
757 {
758     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
759     NvHandle hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
760     NvHandle hObject = RES_GET_HANDLE(pSubdevice);
761 
762     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
763 
764     if ((pFbInfoParams->fbInfoListSize > NV2080_CTRL_FB_INFO_MAX_LIST_SIZE) ||
765         (pFbInfoParams->fbInfoListSize == 0))
766     {
767        return NV_ERR_INVALID_ARGUMENT;
768     }
769 
770     return _fbGetFbInfos(pGpu, hClient, hObject, pFbInfoParams->fbInfoList, pFbInfoParams->fbInfoListSize);
771 }
772 
773 //
774 // subdeviceCtrlCmdFbGetCarveoutAddressInfo
775 //
776 // Lock Requirements:
777 //      Assert that API and GPUs lock held on entry
778 //
779 NV_STATUS
780 subdeviceCtrlCmdFbGetCarveoutAddressInfo_IMPL
781 (
782     Subdevice *pSubdevice,
783     NV2080_CTRL_FB_GET_SYSTEM_CARVEOUT_ADDRESS_SPACE_INFO *pParams
784 )
785 {
786 
787     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
788 
789     pParams->StartAddr = 0x0;
790     pParams->SpaceSize = 0x0;
791 
792     return NV_ERR_GENERIC;
793 }
794 
795 //
796 // subdeviceCtrlCmdFbSetGpuCacheAllocPolicy
797 //
798 // Lock Requirements:
799 //      Assert that GPUs lock held on entry
800 //      Called from SW method w/o API lock
801 //
802 NV_STATUS
803 subdeviceCtrlCmdFbSetGpuCacheAllocPolicy_IMPL
804 (
805     Subdevice *pSubdevice,
806     NV2080_CTRL_FB_GPU_CACHE_ALLOC_POLICY_PARAMS *pParams
807 )
808 {
809     LOCK_ASSERT_AND_RETURN(rmGpuLockIsOwner());
810 
811     // Map engine to FBBA client
812     return NV_ERR_NOT_SUPPORTED;
813 }
814 
815 //
816 // subdeviceCtrlCmdFbGetGpuCacheAllocPolicy
817 //
818 // Lock Requirements:
819 //      Assert that API and GPUs lock held on entry
820 //
821 NV_STATUS
822 subdeviceCtrlCmdFbGetGpuCacheAllocPolicy_IMPL
823 (
824     Subdevice *pSubdevice,
825     NV2080_CTRL_FB_GPU_CACHE_ALLOC_POLICY_PARAMS *pGpuCacheAllocPolicyParams
826 )
827 {
828 
829     NV_STATUS status = NV_ERR_NOT_SUPPORTED;
830     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
831 
832     pGpuCacheAllocPolicyParams->allocPolicy = 0;
833 
834     NV_PRINTF(LEVEL_ERROR, "Failed to read Client reads ALLOC policy\n");
835     return status;
836 }
837 
838 //
839 // subdeviceCtrlCmdFbSetGpuCacheAllocPolicyV2
840 //
841 // Lock Requirements:
842 //      Assert that GPUs lock held on entry
843 //      Called from SW method w/o API lock
844 //
845 NV_STATUS
846 subdeviceCtrlCmdFbSetGpuCacheAllocPolicyV2_IMPL
847 (
848     Subdevice *pSubdevice,
849     NV2080_CTRL_FB_GPU_CACHE_ALLOC_POLICY_V2_PARAMS *pParams
850 )
851 {
852     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
853     RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
854     NV_STATUS status = NV_ERR_NOT_SUPPORTED;
855 
856     // Bug 724186 -- Skip this check for deferred API
857     LOCK_ASSERT_AND_RETURN(pRmCtrlParams->bDeferredApi || rmGpuLockIsOwner());
858 
859     NV_PRINTF(LEVEL_ERROR, "Failed to set alloc policy\n");
860     return status;
861 }
862 
863 //
864 // subdeviceCtrlCmdFbGetGpuCacheAllocPolicyV2
865 //
866 // Lock Requirements:
867 //      Assert that API and GPUs lock held on entry
868 //
869 NV_STATUS
870 subdeviceCtrlCmdFbGetGpuCacheAllocPolicyV2_IMPL
871 (
872     Subdevice *pSubdevice,
873     NV2080_CTRL_FB_GPU_CACHE_ALLOC_POLICY_V2_PARAMS *pParams
874 )
875 {
876     NV_STATUS status = NV_ERR_NOT_SUPPORTED;
877 
878     NV_ASSERT_OR_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner(), NV_ERR_INVALID_LOCK_STATE);
879 
880     NV_PRINTF(LEVEL_ERROR, "Failed to get alloc policy.\n");
881     return status;
882 }
883 
884 //
885 // subdeviceCtrlCmdFbGetCliManagedOfflinedPages
886 //
887 // Lock Requirements:
888 //      Assert that API and Gpus lock held on entry
889 //
890 
891 NV_STATUS
892 subdeviceCtrlCmdFbGetCliManagedOfflinedPages_IMPL
893 (
894     Subdevice *pSubdevice,
895     NV2080_CTRL_FB_GET_CLI_MANAGED_OFFLINED_PAGES_PARAMS *pOsOfflinedParams
896 )
897 {
898     OBJGPU             *pGpu                = GPU_RES_GET_GPU(pSubdevice);
899     Heap               *pHeap               = GPU_GET_HEAP(pGpu);
900     MemoryManager      *pMemoryManager      = GPU_GET_MEMORY_MANAGER(pGpu);
901     BLACKLIST_CHUNK    *pBlacklistChunks    = pHeap->blackList.pBlacklistChunks;
902     NvU64               pageAddress;
903     NvU32               i;
904     NvU32               osBlackListCount    = 0;
905     NvU32               chunk;
906     NvU64               chunks[NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES];
907     NvU32               pageSize;
908     NvU32               numChunks           = 0;
909 
910     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
911     if (!IsSLIEnabled(pGpu))
912     {
913         if (memmgrIsPmaInitialized(pMemoryManager))
914         {
915             // If PMA is enabled Client pages are located here.
916             pmaGetClientBlacklistedPages(&pHeap->pmaObject, chunks, &pageSize, &numChunks);
917 
918             NV_ASSERT(numChunks <= NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES);
919 
920             for (chunk = 0; chunk < numChunks; chunk++)
921             {
922                 pOsOfflinedParams->offlinedPages[chunk] = (NvU32)(chunks[chunk] >> RM_PAGE_SHIFT);
923             }
924             pOsOfflinedParams->validEntries = numChunks;
925             pOsOfflinedParams->pageSize     = pageSize;
926         }
927         else
928         {
929             // Iterate over the heap blacklist array to get the OS blacklisted regions
930             for (i = 0; i < pHeap->blackList.count; i++)
931             {
932                 // Extract only the globally excluded page offsets
933                 if (!pBlacklistChunks[i].bIsValid)
934                 {
935                     pageAddress = pBlacklistChunks[i].physOffset;
936                     pOsOfflinedParams->offlinedPages[osBlackListCount] = (NvU32) (pageAddress >> RM_PAGE_SHIFT);
937                     osBlackListCount++;
938                 }
939             }
940             pOsOfflinedParams->validEntries = osBlackListCount;
941             pOsOfflinedParams->pageSize = RM_PAGE_SIZE;
942         }
943         return NV_OK;
944     }
945     else
946         return NV_ERR_NOT_SUPPORTED;
947 }
948 
949 /*!
950  * @brief This call can be used to update the NUMA status.
951  *
952  * Lock Requirements:
953  *      Assert that API and GPUs lock held on entry
954  *
955  * @param[in] pSubdevice Subdevice
956  * @param[in] pParams    pointer to control parameters
957  *
958  * @return NV_OK When successful
959  *         NV_ERR_INVALID_STATE Otherwise
960  */
961 NV_STATUS
962 subdeviceCtrlCmdFbUpdateNumaStatus_IMPL
963 (
964     Subdevice *pSubdevice,
965     NV2080_CTRL_FB_UPDATE_NUMA_STATUS_PARAMS *pParams
966 )
967 {
968     OBJGPU             *pGpu                = GPU_RES_GET_GPU(pSubdevice);
969     KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
970     Heap               *pHeap               = GPU_GET_HEAP(pGpu);
971     PMA                *pPma                = &pHeap->pmaObject;
972     NV_STATUS          status               = NV_OK;
973 
974     if (!RMCFG_FEATURE_PMA)
975         return NV_ERR_NOT_SUPPORTED;
976 
977     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
978 
979     if (pParams->bOnline)
980     {
981         status = pmaNumaOnlined(pPma, pGpu->numaNodeId,
982                                 pKernelMemorySystem->coherentCpuFbBase,
983                                 pKernelMemorySystem->numaOnlineSize);
984     }
985     else
986     {
987         pmaNumaOfflined(pPma);
988     }
989 
990     return status;
991 }
992 
993 /*
994  * @brief This call can be used to get NUMA related information.
995  *
996  * Lock Requirements:
997  *      Assert that API and GPUs lock held on entry
998  *
999  * @param[in] pSubdevice Subdevice
1000  * @param[in] pParams    pointer to control parameters
1001  *
1002  * @return NV_OK When successful
1003  *         NV_ERR_INVALID_STATE Otherwise
1004  */
1005 NV_STATUS
1006 subdeviceCtrlCmdFbGetNumaInfo_IMPL
1007 (
1008     Subdevice *pSubdevice,
1009     NV2080_CTRL_FB_GET_NUMA_INFO_PARAMS *pParams
1010 )
1011 {
1012     OBJGPU              *pGpu                 = GPU_RES_GET_GPU(pSubdevice);
1013     KernelMemorySystem  *pKernelMemorySystem  = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
1014     MemoryManager       *pMemoryManager       = GPU_GET_MEMORY_MANAGER(pGpu);
1015     BLACKLIST_ADDRESS   *pBlAddrs;
1016     NvU32                numaOfflineIdx       = 0;
1017     NvU32                idx;
1018     NV_STATUS            status;
1019     NvU32                count;
1020     const MEMORY_SYSTEM_STATIC_CONFIG *pMemorySystemConfig =
1021         kmemsysGetStaticConfig(pGpu, pKernelMemorySystem);
1022 
1023     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1024 
1025     if (pParams->numaOfflineAddressesCount >
1026         NV_ARRAY_ELEMENTS(pParams->numaOfflineAddresses))
1027     {
1028         return NV_ERR_INVALID_ARGUMENT;
1029     }
1030 
1031     pParams->numaNodeId = pGpu->numaNodeId;
1032     pParams->numaMemAddr = pKernelMemorySystem->coherentCpuFbBase + pKernelMemorySystem->numaOnlineBase;
1033     pParams->numaMemSize = pKernelMemorySystem->numaOnlineSize;
1034 
1035     if (pParams->numaOfflineAddressesCount == 0)
1036     {
1037         return NV_OK;
1038     }
1039 
1040     if (!(pGpu->getProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT) &&
1041           gpuCheckPageRetirementSupport_HAL(pGpu)))
1042     {
1043         pParams->numaOfflineAddressesCount = 0;
1044         return NV_OK;
1045     }
1046 
1047     count = pMemorySystemConfig->maximumBlacklistPages;
1048     pBlAddrs = portMemAllocNonPaged(sizeof(BLACKLIST_ADDRESS) * count);
1049     if (pBlAddrs == NULL)
1050     {
1051         return NV_ERR_NO_MEMORY;
1052     }
1053 
1054     status = memmgrGetBlackListPages_HAL(pGpu, pMemoryManager, pBlAddrs, &count);
1055     NV_ASSERT(status != NV_ERR_BUFFER_TOO_SMALL);
1056 
1057     if(status == NV_OK)
1058     {
1059         for (idx = 0; idx < count; idx++)
1060         {
1061             NvU64 offset = pBlAddrs[idx].address;
1062 
1063             if (numaOfflineIdx >= pParams->numaOfflineAddressesCount)
1064             {
1065                 status = NV_ERR_BUFFER_TOO_SMALL;
1066                 break;
1067             }
1068 
1069             // Only tell the caller about Offline pages in the NUMA region.
1070             if (offset < pParams->numaMemSize)
1071             {
1072                 pParams->numaOfflineAddresses[numaOfflineIdx++] = pParams->numaMemAddr + offset;
1073             }
1074             else
1075             {
1076                 NV_PRINTF(LEVEL_INFO, "retired page address 0x%llx not in NUMA region\n",
1077                           offset);
1078             }
1079         }
1080     }
1081     else
1082     {
1083         // No offlined pages or failure to read offlined addresses.
1084         status = NV_OK;
1085     }
1086 
1087     pParams->numaOfflineAddressesCount = numaOfflineIdx;
1088 
1089     portMemFree(pBlAddrs);
1090 
1091     return status;
1092 }
1093 
1094 NV_STATUS
1095 subdeviceCtrlCmdFbSetZbcReferenced_IMPL
1096 (
1097     Subdevice *pSubdevice,
1098     NV2080_CTRL_INTERNAL_MEMSYS_SET_ZBC_REFERENCED_PARAMS *pParams
1099 )
1100 {
1101     OBJGPU       *pGpu = GPU_RES_GET_GPU(pSubdevice);
1102     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
1103     NvU32         gfid;
1104     NV_STATUS     status = NV_OK;
1105 
1106     NV_ASSERT_OK_OR_RETURN(vgpuGetCallingContextGfid(pGpu, &gfid));
1107 
1108     NV_CHECK_OR_RETURN(LEVEL_ERROR, IS_GFID_VF(gfid) || pCallContext->secInfo.privLevel >= RS_PRIV_LEVEL_KERNEL, NV_ERR_INSUFFICIENT_PERMISSIONS);
1109 
1110     if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
1111     {
1112         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
1113 
1114         NV_RM_RPC_CONTROL(pGpu,
1115                           pRmCtrlParams->hClient,
1116                           pRmCtrlParams->hObject,
1117                           pRmCtrlParams->cmd,
1118                           pRmCtrlParams->pParams,
1119                           pRmCtrlParams->paramsSize,
1120                           status);
1121 
1122         return status;
1123     }
1124 
1125     return status;
1126 }
1127 
1128 /*!
1129  * @brief This call can be used to flush L2 followed by FB or
1130  * just the FB.
1131  *
1132  * If L2 ops are needed, either _INVALIDATE or _WRITE_BACK
1133  * or both flags set to _YES is required. Specifying both
1134  * to _YES implies EVICT.
1135  *
1136  * If only the FB flush is needed, only the
1137  * _APERTURE and _FB_FLUSH_YES are needed.
1138  *
1139  * If only L2 ops are needed (i.e. no FB flush following
1140  * it), _FB_FLUSH_NO is needed in addition to the other
1141  * L2 ops flags.
1142  *
1143  * Lock Requirements:
1144  *      Assert that API and GPUs lock held on entry
1145  *
1146  * @param[in] pSubdevice Subdevice
1147  * @param[in] pCacheFlushParams Various flush flags
1148  *
1149  */
1150 NV_STATUS
1151 subdeviceCtrlCmdFbFlushGpuCache_IMPL
1152 (
1153     Subdevice *pSubdevice,
1154     NV2080_CTRL_FB_FLUSH_GPU_CACHE_PARAMS *pCacheFlushParams
1155 )
1156 {
1157     OBJGPU             *pGpu = GPU_RES_GET_GPU(pSubdevice);
1158     KernelMemorySystem *pKernelMemorySystem = GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu);
1159     NV_STATUS           status = NV_OK;
1160     FB_CACHE_MEMTYPE    memType = FB_CACHE_MEM_UNDEFINED;
1161     FB_CACHE_OP         cacheOp = FB_CACHE_OP_UNDEFINED;
1162     KernelBus          *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
1163     NvBool              bWriteback = NV_FALSE;
1164     NvBool              bInvalidate = NV_FALSE;
1165 
1166     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1167 
1168     // Either WriteBack or Invalidate are required for Cache Ops
1169     if (FLD_TEST_DRF(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _WRITE_BACK,
1170                      _YES, pCacheFlushParams->flags))
1171     {
1172         bWriteback = NV_TRUE;
1173     }
1174     if (FLD_TEST_DRF(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _INVALIDATE,
1175                 _YES, pCacheFlushParams->flags))
1176     {
1177         bInvalidate = NV_TRUE;
1178     }
1179 
1180     if (bWriteback || bInvalidate )
1181     {
1182         // Cache Ops Path
1183 
1184         switch (DRF_VAL(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _APERTURE,
1185                     pCacheFlushParams->flags))
1186         {
1187             case NV2080_CTRL_FB_FLUSH_GPU_CACHE_FLAGS_APERTURE_VIDEO_MEMORY:
1188                 memType = FB_CACHE_VIDEO_MEMORY;
1189                 break;
1190             case NV2080_CTRL_FB_FLUSH_GPU_CACHE_FLAGS_APERTURE_SYSTEM_MEMORY:
1191                 memType = FB_CACHE_SYSTEM_MEMORY;
1192                 break;
1193             case NV2080_CTRL_FB_FLUSH_GPU_CACHE_FLAGS_APERTURE_PEER_MEMORY:
1194                 memType = FB_CACHE_PEER_MEMORY;
1195                 break;
1196             default:
1197                 NV_PRINTF(LEVEL_ERROR, "Invalid aperture.\n");
1198                 return NV_ERR_INVALID_ARGUMENT;
1199         }
1200 
1201         if (bWriteback && bInvalidate)
1202         {
1203             cacheOp = FB_CACHE_EVICT;
1204         }
1205         else if (!bWriteback && bInvalidate)
1206         {
1207             cacheOp = FB_CACHE_INVALIDATE;
1208         }
1209         else if (bWriteback && !bInvalidate)
1210         {
1211             cacheOp = FB_CACHE_WRITEBACK;
1212         }
1213         else
1214         {
1215             NV_PRINTF(LEVEL_ERROR,
1216                       "Must specify at least one of WRITE_BACK or INVALIDATE\n");
1217             return NV_ERR_INVALID_ARGUMENT;
1218         }
1219 
1220         switch (DRF_VAL(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _FLUSH_MODE,
1221                     pCacheFlushParams->flags))
1222         {
1223             case NV2080_CTRL_FB_FLUSH_GPU_CACHE_FLAGS_FLUSH_MODE_ADDRESS_ARRAY:
1224                 if ((pCacheFlushParams->addressArraySize == 0) ||
1225                         (pCacheFlushParams->addressArraySize >
1226                         NV2080_CTRL_FB_FLUSH_GPU_CACHE_MAX_ADDRESSES))
1227                 {
1228                     NV_PRINTF(LEVEL_ERROR, "Invalid array size (0x%x)\n",
1229                               pCacheFlushParams->addressArraySize);
1230                     status = NV_ERR_INVALID_ARGUMENT;
1231                     break;
1232                 }
1233 
1234                 if(pCacheFlushParams->memBlockSizeBytes == 0)
1235                 {
1236                     NV_PRINTF(LEVEL_ERROR, "Invalid memBlock size (0x%llx)\n",
1237                               pCacheFlushParams->memBlockSizeBytes);
1238                     status = NV_ERR_INVALID_ARGUMENT;
1239                     break;
1240                 }
1241 
1242                 status = NV_ERR_GENERIC;
1243                 break;
1244             case NV2080_CTRL_FB_FLUSH_GPU_CACHE_FLAGS_FLUSH_MODE_FULL_CACHE:
1245                 status = kmemsysCacheOp_HAL(pGpu, pKernelMemorySystem, NULL, memType, cacheOp);
1246                 break;
1247             default:
1248                 NV_PRINTF(LEVEL_ERROR, "Invalid FLUSH_MODE 0x%x\n",
1249                           DRF_VAL(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _FLUSH_MODE, pCacheFlushParams->flags));
1250                 return NV_ERR_INVALID_ARGUMENT;
1251         }
1252     }
1253 
1254     // FB Flush
1255     if (FLD_TEST_DRF(2080, _CTRL_FB_FLUSH_GPU_CACHE_FLAGS, _FB_FLUSH,
1256                      _YES, pCacheFlushParams->flags))
1257     {
1258         NV_CHECK_OK_OR_CAPTURE_FIRST_ERROR(status, LEVEL_ERROR,
1259                         kbusFlush_HAL(pGpu, pKernelBus, BUS_FLUSH_VIDEO_MEMORY));
1260     }
1261 
1262     return status;
1263 }
1264