1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2004-2023 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 This module contains the gpu control interfaces for the
27  *        subdevice (NV20_SUBDEVICE_0) class. Subdevice-level control calls
28  *        are directed unicast to the associated GPU.
29  *        File contains ctrls related to general GPU
30  */
31 
32 #include "core/core.h"
33 #include "core/locks.h"
34 #include "gpu/subdevice/subdevice.h"
35 #include "gpu/gpu.h"
36 #include "gpu_mgr/gpu_db.h"
37 #include "nvrm_registry.h"
38 #include "nvVer.h"
39 #include "gpu/bif/kernel_bif.h"
40 #include "gpu/bus/kern_bus.h"
41 #include "gpu/disp/kern_disp.h"
42 #include "disp/nvfbc_session.h"
43 #include "gpu/mmu/kern_gmmu.h"
44 #include "kernel/gpu/intr/intr.h"
45 #include "kernel/gpu/mc/kernel_mc.h"
46 #include "kernel/gpu/nvlink/kernel_nvlink.h"
47 #include "gpu/gpu_fabric_probe.h"
48 #include "objtmr.h"
49 #include "platform/chipset/chipset.h"
50 #include "kernel/gpu/gr/kernel_graphics.h"
51 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
52 #include "kernel/gpu/gr/kernel_graphics_manager.h"
53 #include "vgpu/rpc.h"
54 #include "gpu/mem_mgr/mem_mgr.h"
55 
56 #include "gpu/mem_sys/kern_mem_sys.h"
57 #include "gpu/nvenc/nvencsession.h"
58 
59 #include "kernel/gpu/fifo/kernel_fifo.h"
60 #include "rmapi/resource_fwd_decls.h"
61 #include "rmapi/client.h"
62 
63 #include "class/cl900e.h"
64 
65 
66 
67 // bit to set when telling physical to fill in an info entry
68 #define INDEX_FORWARD_TO_PHYSICAL 0x80000000
69 
70 static NV_STATUS
71 getGpuInfos(Subdevice *pSubdevice, NV2080_CTRL_GPU_GET_INFO_V2_PARAMS *pParams, NvBool bCanAccessHw)
72 {
73     OBJGPU *pGpu            = GPU_RES_GET_GPU(pSubdevice);
74     NV_STATUS status        = NV_OK;
75     NvU32 i                 = 0;
76     NvU32 data              = 0;
77     NvBool bPhysicalForward = NV_FALSE;
78 
79     if ((pParams->gpuInfoListSize > NV2080_CTRL_GPU_INFO_MAX_LIST_SIZE) ||
80         (pParams->gpuInfoListSize == 0))
81     {
82        return NV_ERR_INVALID_ARGUMENT;
83     }
84 
85     for (i = 0; i < pParams->gpuInfoListSize; i++)
86     {
87         if (pParams->gpuInfoList[i].index >= NV2080_CTRL_GPU_INFO_MAX_LIST_SIZE)
88         {
89             return NV_ERR_INVALID_ARGUMENT;
90         }
91 
92         switch (pParams->gpuInfoList[i].index)
93         {
94             case NV2080_CTRL_GPU_INFO_INDEX_GPU_FLA_CAPABILITY:
95             {
96                 KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
97 
98                 if (kbusIsFlaSupported(pKernelBus))
99                 {
100                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_FLA_CAPABILITY_YES;
101                 }
102                 else
103                 {
104                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_FLA_CAPABILITY_NO;
105                 }
106                 break;
107             }
108             case NV2080_CTRL_GPU_INFO_INDEX_MINOR_REVISION_EXT:
109             {
110                 data = gpuGetChipMinExtRev(pGpu);
111                 break;
112             }
113             case NV2080_CTRL_GPU_INFO_INDEX_NETLIST_REV0:
114             {
115                 data = 0;
116                 break;
117             }
118             case NV2080_CTRL_GPU_INFO_INDEX_NETLIST_REV1:
119             {
120                 data = 0;
121                 break;
122             }
123             case NV2080_CTRL_GPU_INFO_INDEX_SYSMEM_ACCESS:
124             {
125                 data = NV2080_CTRL_GPU_INFO_SYSMEM_ACCESS_YES;
126                 break;
127             }
128             case NV2080_CTRL_GPU_INFO_INDEX_GEMINI_BOARD:
129             {
130                 data = !!pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_GEMINI);
131                 break;
132             }
133             case NV2080_CTRL_GPU_INFO_INDEX_SURPRISE_REMOVAL_POSSIBLE:
134             {
135                 OBJSYS *pSys = SYS_GET_INSTANCE();
136                 OBJCL  *pCl  = SYS_GET_CL(pSys);
137                 data = !!pCl->getProperty(pCl, PDB_PROP_CL_IS_EXTERNAL_GPU);
138                 break;
139             }
140             case NV2080_CTRL_GPU_INFO_INDEX_IBMNPU_RELAXED_ORDERING:
141             {
142                 NvBool mode = NV_FALSE;
143                 data = NV2080_CTRL_GPU_INFO_IBMNPU_RELAXED_ORDERING_UNSUPPORTED;
144 
145                 if (osGetIbmnpuRelaxedOrderingMode(pGpu->pOsGpuInfo, &mode) == NV_OK)
146                 {
147                     data = NV2080_CTRL_GPU_INFO_IBMNPU_RELAXED_ORDERING_DISABLED;
148 
149                     if (mode)
150                     {
151                         data = NV2080_CTRL_GPU_INFO_IBMNPU_RELAXED_ORDERING_ENABLED;
152                     }
153                 }
154                 break;
155             }
156             case NV2080_CTRL_GPU_INFO_INDEX_GLOBAL_POISON_FUSE_ENABLED:
157             {
158                 if (gpuIsGlobalPoisonFuseEnabled(pGpu))
159                 {
160                     data = NV2080_CTRL_GPU_INFO_INDEX_GLOBAL_POISON_FUSE_ENABLED_YES;
161                 }
162                 else
163                 {
164                     data = NV2080_CTRL_GPU_INFO_INDEX_GLOBAL_POISON_FUSE_ENABLED_NO;
165                 }
166                 break;
167             }
168             case NV2080_CTRL_GPU_INFO_INDEX_NVSWITCH_PROXY_DETECTED:
169             {
170                 NV_CHECK_OR_ELSE(LEVEL_WARNING, bCanAccessHw,
171                     { data = 0; status = NV_ERR_INVALID_ARGUMENT; break; });
172 
173                 KernelNvlink *pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu);
174 
175                 data = NV2080_CTRL_GPU_INFO_NVSWITCH_PROXY_DETECTED_NO;
176 
177                 if (pKernelNvlink != NULL &&
178                     knvlinkIsNvswitchProxyPresent(pGpu, pKernelNvlink))
179                 {
180                     data = NV2080_CTRL_GPU_INFO_NVSWITCH_PROXY_DETECTED_YES;
181                 }
182                 break;
183             }
184             case NV2080_CTRL_GPU_INFO_INDEX_GPU_SMC_MODE:
185             {
186                 NV_CHECK_OR_ELSE(LEVEL_WARNING, bCanAccessHw,
187                     { data = 0; status = NV_ERR_INVALID_ARGUMENT; break; });
188 
189                 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
190                 NV2080_CTRL_INTERNAL_GPU_GET_SMC_MODE_PARAMS params;
191 
192                 if (IS_VIRTUAL(pGpu))
193                 {
194                     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
195 
196                     if ((pKernelMIGManager == NULL) || !kmigmgrIsMIGSupported(pGpu, pKernelMIGManager))
197                     {
198                         data = NV2080_CTRL_GPU_INFO_GPU_SMC_MODE_UNSUPPORTED;
199                         break;
200                     }
201 
202                     data = IS_MIG_ENABLED(pGpu) ?
203                         NV2080_CTRL_GPU_INFO_GPU_SMC_MODE_ENABLED :
204                         NV2080_CTRL_GPU_INFO_GPU_SMC_MODE_DISABLED;
205 
206                     break;
207                 }
208 
209                 portMemSet(&params, 0x0, sizeof(params));
210                 status = pRmApi->Control(pRmApi,
211                                          pGpu->hInternalClient,
212                                          pGpu->hInternalSubdevice,
213                                          NV2080_CTRL_CMD_INTERNAL_GPU_GET_SMC_MODE,
214                                          &params,
215                                          sizeof(params));
216                 data = params.smcMode;
217                 break;
218             }
219             case NV2080_CTRL_GPU_INFO_INDEX_SPLIT_VAS_MGMT_SERVER_CLIENT_RM:
220             {
221                 if (gpuIsSplitVasManagementServerClientRmEnabled(pGpu))
222                 {
223                     data = NV2080_CTRL_GPU_INFO_SPLIT_VAS_MGMT_SERVER_CLIENT_RM_YES;
224                 }
225                 else
226                 {
227                     data = NV2080_CTRL_GPU_INFO_SPLIT_VAS_MGMT_SERVER_CLIENT_RM_NO;
228                 }
229                 break;
230             }
231             case NV2080_CTRL_GPU_INFO_INDEX_GPU_SM_VERSION:
232             {
233                 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
234 
235                 if ((pKernelGraphicsManager == NULL) ||
236                     !kgrmgrGetLegacyKGraphicsStaticInfo(pGpu, pKernelGraphicsManager)->bInitialized ||
237                     (kgrmgrGetLegacyKGraphicsStaticInfo(pGpu, pKernelGraphicsManager)->pGrInfo == NULL))
238                 {
239                     NV_PRINTF(LEVEL_ERROR, "Unable to retrieve SM version!\n");
240                     data = NV2080_CTRL_GR_INFO_SM_VERSION_NONE;
241                     status = NV_ERR_INVALID_STATE;
242                 }
243                 else
244                 {
245                     data = kgrmgrGetLegacyKGraphicsStaticInfo(pGpu, pKernelGraphicsManager)->pGrInfo->infoList[NV2080_CTRL_GR_INFO_INDEX_SM_VERSION].data;
246                 }
247                 break;
248             }
249             case NV2080_CTRL_GPU_INFO_INDEX_PER_RUNLIST_CHANNEL_RAM:
250             {
251                 KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
252 
253                 if (kfifoIsPerRunlistChramEnabled(pKernelFifo))
254                 {
255                     data = NV2080_CTRL_GPU_INFO_INDEX_PER_RUNLIST_CHANNEL_RAM_ENABLED;
256                 }
257                 else
258                 {
259                     data = NV2080_CTRL_GPU_INFO_INDEX_PER_RUNLIST_CHANNEL_RAM_DISABLED;
260                 }
261                 break;
262             }
263             case NV2080_CTRL_GPU_INFO_INDEX_GPU_ATS_CAPABILITY:
264             {
265                 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_ATS_SUPPORTED))
266                 {
267                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_ATS_CAPABILITY_YES;
268                 }
269                 else
270                 {
271                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_ATS_CAPABILITY_NO;
272                 }
273                 break;
274             }
275             case NV2080_CTRL_GPU_INFO_INDEX_NVENC_STATS_REPORTING_STATE:
276             {
277                 if (IS_VIRTUAL(pGpu))
278                 {
279                     // On vGPU, if encoding is supported then we need to keep the NvEnc stats reporting state enabled
280                     // all the time so that NvEnc UMD keeps pushing the raw timestamp data.
281                     // This is to handle the migration case where on source host the NvEnc stats reporting was disabled,
282                     // but on target host the NvEnc stats reporting is enabled. If UMD doesn't keep pushing raw data
283                     // even if stats reporting was disabled on source host, we won't be able to report NvEnc stats on
284                     // target host data reporting is enabled.
285                     if (pGpu->encSessionStatsReportingState == NV2080_CTRL_GPU_INFO_NVENC_STATS_REPORTING_STATE_NOT_SUPPORTED)
286                     {
287                         data = NV2080_CTRL_GPU_INFO_NVENC_STATS_REPORTING_STATE_NOT_SUPPORTED;
288                     }
289                     else
290                     {
291                         data = NV2080_CTRL_GPU_INFO_NVENC_STATS_REPORTING_STATE_ENABLED;
292                     }
293                 }
294                 else
295                 {
296                     data = pGpu->encSessionStatsReportingState;
297                 }
298                 break;
299             }
300             case NV2080_CTRL_GPU_INFO_INDEX_4K_PAGE_ISOLATION_REQUIRED:
301             {
302                 if (pGpu->bNeed4kPageIsolation)
303                 {
304                     data = NV2080_CTRL_GPU_INFO_INDEX_4K_PAGE_ISOLATION_REQUIRED_YES;
305                 }
306                 else
307                 {
308                     data = NV2080_CTRL_GPU_INFO_INDEX_4K_PAGE_ISOLATION_REQUIRED_NO;
309                 }
310                 break;
311             }
312             case NV2080_CTRL_GPU_INFO_INDEX_DISPLAY_ENABLED:
313             {
314                 if (GPU_GET_KERNEL_DISPLAY(pGpu) != NULL)
315                 {
316                     data = NV2080_CTRL_GPU_INFO_DISPLAY_ENABLED_YES;
317                 }
318                 else
319                 {
320                     data = NV2080_CTRL_GPU_INFO_DISPLAY_ENABLED_NO;
321                 }
322                 break;
323             }
324             case NV2080_CTRL_GPU_INFO_INDEX_MOBILE_CONFIG_ENABLED:
325             {
326                 if (IsMobile(pGpu))
327                 {
328                     data = NV2080_CTRL_GPU_INFO_INDEX_MOBILE_CONFIG_ENABLED_YES;
329                 }
330                 else
331                 {
332                     data = NV2080_CTRL_GPU_INFO_INDEX_MOBILE_CONFIG_ENABLED_NO;
333                 }
334                 break;
335             }
336             case NV2080_CTRL_GPU_INFO_INDEX_GPU_PROFILING_CAPABILITY:
337             {
338                 if (IS_VIRTUAL(pGpu))
339                 {
340                     VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
341                     if (pVSI)
342                     {
343                         data = pVSI->vgpuStaticProperties.bProfilingTracingEnabled ?
344                                NV2080_CTRL_GPU_INFO_INDEX_GPU_PROFILING_CAPABILITY_ENABLED :
345                                NV2080_CTRL_GPU_INFO_INDEX_GPU_PROFILING_CAPABILITY_DISABLED;
346                     }
347                     else
348                     {
349                         data = NV2080_CTRL_GPU_INFO_INDEX_GPU_PROFILING_CAPABILITY_DISABLED;
350                     }
351                 }
352                 else
353                 {
354                     // Always return ENABLED for Baremetal/Host
355                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_PROFILING_CAPABILITY_ENABLED;
356                 }
357                 break;
358             }
359             case NV2080_CTRL_GPU_INFO_INDEX_GPU_DEBUGGING_CAPABILITY:
360             {
361                 if (IS_VIRTUAL(pGpu))
362                 {
363                     VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
364                     if (pVSI)
365                     {
366                         data = pVSI->vgpuStaticProperties.bDebuggingEnabled ?
367                                NV2080_CTRL_GPU_INFO_INDEX_GPU_DEBUGGING_CAPABILITY_ENABLED :
368                                NV2080_CTRL_GPU_INFO_INDEX_GPU_DEBUGGING_CAPABILITY_DISABLED;
369                     }
370                     else
371                     {
372                         data = NV2080_CTRL_GPU_INFO_INDEX_GPU_DEBUGGING_CAPABILITY_DISABLED;
373                     }
374                 }
375                 else
376                 {
377                     // Always return ENABLED for Baremetal/Host
378                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_DEBUGGING_CAPABILITY_ENABLED;
379                 }
380                 break;
381             }
382             case NV2080_CTRL_GPU_INFO_INDEX_GPU_LOCAL_EGM_CAPABILITY:
383             {
384                 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
385                 if (memmgrIsLocalEgmEnabled(pMemoryManager))
386                 {
387                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_LOCAL_EGM_CAPABILITY_YES;
388                     data = FLD_SET_DRF_NUM(2080_CTRL_GPU_INFO, _INDEX_GPU_LOCAL_EGM, _PEERID, pMemoryManager->localEgmPeerId, data);
389                 }
390                 else
391                 {
392                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_LOCAL_EGM_CAPABILITY_NO;
393                 }
394                 break;
395             }
396             case NV2080_CTRL_GPU_INFO_INDEX_GPU_SELF_HOSTED_CAPABILITY:
397             {
398                 KernelBif *pKernelBif = GPU_GET_KERNEL_BIF(pGpu);
399 
400                 if (gpuIsSelfHosted(pGpu) &&
401                     pKernelBif->getProperty(pKernelBif, PDB_PROP_KBIF_IS_C2C_LINK_UP))
402                 {
403                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_SELF_HOSTED_CAPABILITY_YES;
404                 }
405                 else
406                 {
407                     data = NV2080_CTRL_GPU_INFO_INDEX_GPU_SELF_HOSTED_CAPABILITY_NO;
408                 }
409                 break;
410             }
411             case NV2080_CTRL_GPU_INFO_INDEX_CMP_SKU:
412             {
413                 if (gpuGetChipInfo(pGpu) && gpuGetChipInfo(pGpu)->isCmpSku)
414                 {
415                     data = NV2080_CTRL_GPU_INFO_INDEX_CMP_SKU_YES;
416                 }
417                 else
418                 {
419                     data = NV2080_CTRL_GPU_INFO_INDEX_CMP_SKU_NO;
420                 }
421                 break;
422             }
423             case NV2080_CTRL_GPU_INFO_INDEX_DMABUF_CAPABILITY:
424             {
425                 data = NV2080_CTRL_GPU_INFO_INDEX_DMABUF_CAPABILITY_NO;
426 
427                 if (osDmabufIsSupported() &&
428                     (!IS_VIRTUAL(pGpu)) &&
429                     (!gpuIsApmFeatureEnabled(pGpu)) &&
430                     (!NVCPU_IS_PPC64LE))
431                 {
432                     data = NV2080_CTRL_GPU_INFO_INDEX_DMABUF_CAPABILITY_YES;
433                 }
434                 break;
435             }
436             case NV2080_CTRL_GPU_INFO_INDEX_IS_RESETLESS_MIG_SUPPORTED:
437             {
438                 data = NV2080_CTRL_GPU_INFO_INDEX_IS_RESETLESS_MIG_SUPPORTED_NO;
439 
440                 if (pGpu->getProperty(pGpu, PDB_PROP_GPU_RESETLESS_MIG_SUPPORTED))
441                 {
442                     data = NV2080_CTRL_GPU_INFO_INDEX_IS_RESETLESS_MIG_SUPPORTED_YES;
443                 }
444                 break;
445             }
446             default:
447             {
448                 // Only forward to physical if we're in the HW-access-enabled control
449                 if ((IS_GSP_CLIENT(pGpu) || IS_VIRTUAL(pGpu)) && bCanAccessHw)
450                 {
451                     pParams->gpuInfoList[i].index |= INDEX_FORWARD_TO_PHYSICAL;
452                     bPhysicalForward = NV_TRUE;
453                 }
454                 else
455                 {
456                     data = 0;
457                     status = NV_ERR_INVALID_ARGUMENT;
458                 }
459                 break;
460             }
461         }
462 
463         if (status != NV_OK)
464         {
465             break;
466         }
467 
468         // save off data value
469         pParams->gpuInfoList[i].data = data;
470     }
471 
472     if ((IS_GSP_CLIENT(pGpu) || IS_VIRTUAL(pGpu)) && bPhysicalForward && (status == NV_OK))
473     {
474         NV_RM_RPC_CONTROL(pGpu,
475                           RES_GET_CLIENT_HANDLE(pSubdevice),
476                           RES_GET_HANDLE(pSubdevice),
477                           NV2080_CTRL_CMD_GPU_GET_INFO_V2,
478                           pParams, sizeof(*pParams), status);
479     }
480 
481     return status;
482 }
483 
484 #undef INDEX_FORWARD_TO_PHYSICAL
485 
486 NV_STATUS
487 subdeviceCtrlCmdGpuGetInfoV2_IMPL
488 (
489     Subdevice *pSubdevice,
490     NV2080_CTRL_GPU_GET_INFO_V2_PARAMS *pGpuInfoParams
491 )
492 {
493     return getGpuInfos(pSubdevice, pGpuInfoParams, NV_TRUE);
494 }
495 
496 //
497 // subdeviceCtrlCmdGpuGetCachedInfo: As subdeviceCtrlCmdGpuGetInfoV2, except
498 // does not perform any HW access (NO_GPUS_ACCESS and NO_GPUS_LOCK flags)
499 //
500 NV_STATUS
501 subdeviceCtrlCmdGpuGetCachedInfo_IMPL
502 (
503     Subdevice *pSubdevice,
504     NV2080_CTRL_GPU_GET_INFO_V2_PARAMS *pGpuInfoParams
505 )
506 {
507     return getGpuInfos(pSubdevice, pGpuInfoParams, NV_FALSE);
508 }
509 
510 static POBJHWBC
511 getBridgeObject(OBJHWBC *pHWBC, NvU32 hwbcId)
512 {
513     OBJHWBC *pBridgeObject = NULL;
514     if (NULL != pHWBC)
515     {
516         if (hwbcId == pHWBC->hwbcId)
517         {
518             pBridgeObject = pHWBC;
519         }
520         else
521         {
522             pBridgeObject = getBridgeObject(pHWBC->pSibling, hwbcId);
523             if (NULL == pBridgeObject)
524             {
525                 pBridgeObject = getBridgeObject(pHWBC->pFirstChild, hwbcId);
526             }
527         }
528     }
529     return pBridgeObject;
530 }
531 
532 static NV_STATUS
533 getPlxFirmwareAndBusInfo
534 (
535     OBJHWBC *pHWBC,
536     NvU32 *domainId,
537     NvU8  *busId,
538     NvU8  *deviceId,
539     NvU8  *funcId,
540     NvU32 *fwVersion,
541     NvU8  *oemVersion,
542     NvU8  *siliconRevision,
543     NvU8  *bcRes
544 )
545 {
546     if (NULL == pHWBC)
547     {
548         return NV_ERR_INVALID_ARGUMENT;
549     }
550 
551     if (domainId)
552         *domainId           = pHWBC->ctrlDev.domain;
553     if (busId)
554         *busId              = pHWBC->ctrlDev.bus;
555     if (deviceId)
556         *deviceId           = pHWBC->ctrlDev.device;
557     if (funcId)
558         *funcId             = pHWBC->ctrlDev.func;
559     if (fwVersion)
560         *fwVersion          = pHWBC->fwVersion;
561     if (oemVersion)
562         *oemVersion         = pHWBC->fwOemVersion;
563     if (siliconRevision)
564         *siliconRevision    = pHWBC->plxRevision;
565     if (bcRes)
566         *bcRes              = (NvU8)pHWBC->bcRes;
567     return NV_OK;
568 }
569 
570 static NV_STATUS
571 getPlxFirmwareVersion
572 (
573     NvU32 hwbcId,
574     NvU32 *fwVersion,
575     NvU8  *oemVersion,
576     NvU8  *siliconRevision,
577     NvU8  *bcRes
578 )
579 {
580     OBJSYS *pSys = SYS_GET_INSTANCE();
581     OBJCL *pCl  = SYS_GET_CL(pSys);
582     OBJHWBC *pHWBC = getBridgeObject(pCl->pHWBC, hwbcId);
583 
584     return getPlxFirmwareAndBusInfo(pHWBC, NULL, NULL, NULL, NULL, fwVersion,
585                                     oemVersion, siliconRevision, bcRes);
586 }
587 
588 static NvU8
589 getBridgeCountAndId(OBJHWBC *pHWBC, NvU32 pBridgeId[], NvU32 *bridgeIndex)
590 {
591     NvU8 count = 0;
592     if ((NULL == bridgeIndex) ||
593         (*bridgeIndex >= NV2080_CTRL_MAX_PHYSICAL_BRIDGE))
594     {
595         return count;
596     }
597     if (NULL != pHWBC)
598     {
599         if ((HWBC_PLX_PEX8747 == pHWBC->bcRes) || (HWBC_NVIDIA_BR04 == pHWBC->bcRes))
600         {
601             pBridgeId[*bridgeIndex] = pHWBC->hwbcId;
602             (*bridgeIndex)++;
603             count++;
604         }
605         count += getBridgeCountAndId(pHWBC->pSibling, pBridgeId, bridgeIndex);
606         count += getBridgeCountAndId(pHWBC->pFirstChild, pBridgeId, bridgeIndex);
607     }
608     return count;
609 }
610 
611 static NV_STATUS
612 getBridgeData
613 (
614     NvU8 *pPlxCount,
615     NvU32 pBridgeId[]
616 )
617 {
618     OBJSYS *pSys = SYS_GET_INSTANCE();
619     OBJCL *pCl  = SYS_GET_CL(pSys);
620     NvU32 bridgeIndex = 0;
621 
622     if (NULL == pPlxCount)
623     {
624         return NV_ERR_INVALID_ARGUMENT;
625     }
626 
627     *pPlxCount = getBridgeCountAndId(pCl->pHWBC, pBridgeId, &bridgeIndex);
628     NV_ASSERT_OR_RETURN(*pPlxCount < NV2080_CTRL_MAX_PHYSICAL_BRIDGE,
629                         NV_ERR_OUT_OF_RANGE);
630     return NV_OK;
631 }
632 
633 static NV_STATUS
634 getUpstreamBridgeIds
635 (
636     OBJGPU *pGpu,
637     NvU8 *pPlxCount,
638     NvU32 pBridgeId[]
639 )
640 {
641     HWBC_LIST *pGpuHWBCList;
642     NvU8 bridgeIndex = 0;
643 
644     if (NULL == pPlxCount)
645     {
646         return NV_ERR_INVALID_ARGUMENT;
647     }
648 
649     pGpuHWBCList = pGpu->pHWBCList;
650     while(pGpuHWBCList)
651     {
652         NV_ASSERT_OR_RETURN(pGpuHWBCList->pHWBC != NULL, NV_ERR_INVALID_POINTER);
653         pBridgeId[bridgeIndex] = pGpuHWBCList->pHWBC->hwbcId;
654         pGpuHWBCList = pGpuHWBCList->pNext;
655         bridgeIndex++;
656         NV_ASSERT_OR_RETURN(bridgeIndex < NV2080_CTRL_MAX_PHYSICAL_BRIDGE,
657                             NV_ERR_OUT_OF_RANGE);
658     }
659     *pPlxCount = bridgeIndex;
660 
661     return NV_OK;
662 }
663 
664 NV_STATUS
665 subdeviceCtrlCmdGpuGetPhysicalBridgeVersionInfo_IMPL
666 (
667     Subdevice *pSubdevice,
668     NV2080_CTRL_GPU_GET_PHYSICAL_BRIDGE_VERSION_INFO_PARAMS *pBridgeInfoParams
669 )
670 {
671     NV_STATUS status = NV_OK;
672     NvU8      bridgeIndex;
673     status = getBridgeData(&pBridgeInfoParams->bridgeCount,
674                             pBridgeInfoParams->hPhysicalBridges);
675     if (status == NV_OK)
676     {
677         NV2080_CTRL_GPU_PHYSICAL_BRIDGE_VERSION_PARAMS *pBridgeVersionParams =
678                                                     pBridgeInfoParams->bridgeList;
679         for (bridgeIndex = 0;
680              bridgeIndex < pBridgeInfoParams->bridgeCount;
681              bridgeIndex++)
682         {
683             status = getPlxFirmwareVersion(pBridgeInfoParams->hPhysicalBridges[bridgeIndex],
684                                             &pBridgeVersionParams->fwVersion,
685                                             &pBridgeVersionParams->oemVersion,
686                                             &pBridgeVersionParams->siliconRevision,
687                                             &pBridgeVersionParams->hwbcResourceType);
688             if (status != NV_OK)
689             {
690                 break;
691             }
692             pBridgeVersionParams++;
693         }
694     }
695     return status;
696 }
697 
698 NV_STATUS
699 subdeviceCtrlCmdGpuGetAllBridgesUpstreamOfGpu_IMPL
700 (
701     Subdevice *pSubdevice,
702     NV2080_CTRL_GPU_GET_ALL_BRIDGES_UPSTREAM_OF_GPU_PARAMS *pBridgeInfoParams
703 )
704 {
705     OBJGPU    *pGpu = GPU_RES_GET_GPU(pSubdevice);
706     NV_STATUS  status = NV_OK;
707     NvU8       bridgeIndex;
708     HWBC_LIST *pGpuHWBCList;
709     status = getUpstreamBridgeIds(pGpu,
710                                   &pBridgeInfoParams->bridgeCount,
711                                   pBridgeInfoParams->physicalBridgeIds);
712     if (status == NV_OK)
713     {
714         NV2080_CTRL_GPU_BRIDGE_VERSION_PARAMS *pBridgeVersionParams =
715                                                 pBridgeInfoParams->bridgeList;
716         pGpuHWBCList = pGpu->pHWBCList;
717         for (bridgeIndex = 0;
718              bridgeIndex < pBridgeInfoParams->bridgeCount && pGpuHWBCList;
719              bridgeIndex++)
720         {
721             status = getPlxFirmwareAndBusInfo(pGpuHWBCList->pHWBC,
722                                               &pBridgeVersionParams->domain,
723                                               &pBridgeVersionParams->bus,
724                                               &pBridgeVersionParams->device,
725                                               &pBridgeVersionParams->func,
726                                               &pBridgeVersionParams->fwVersion,
727                                               &pBridgeVersionParams->oemVersion,
728                                               &pBridgeVersionParams->siliconRevision,
729                                               &pBridgeVersionParams->hwbcResourceType);
730             if (status != NV_OK)
731             {
732                 break;
733             }
734             pGpuHWBCList = pGpuHWBCList->pNext;
735             pBridgeVersionParams++;
736         }
737     }
738     return status;
739 }
740 
741 /*!
742  * @brief This command can be used for Optimus enabled system.
743  *
744  * @return :
745  *    NV_OK
746  */
747 NV_STATUS
748 subdeviceCtrlCmdGpuSetOptimusInfo_IMPL
749 (
750     Subdevice *pSubdevice,
751     NV2080_CTRL_GPU_OPTIMUS_INFO_PARAMS *pGpuOptimusInfoParams
752 )
753 {
754     NvU32   status  =   NV_OK;
755     OBJGPU *pGpu    =   GPU_RES_GET_GPU(pSubdevice);
756 
757     if (pGpuOptimusInfoParams->isOptimusEnabled)
758     {
759         //
760         // Setting pMemoryManager->bPersistentStandbyBuffer for Optimus system.
761         // It is used for sys_mem allocation which is pinned across
762         // S3 transitions.Sys_mem allocations are done at first S3 cycle
763         // and release during driver unload, which reduces system
764         // VM fragmentation, which was a problem in optimus system.
765         // For more details refer bug 754122.
766         //
767         GPU_GET_MEMORY_MANAGER(pGpu)->bPersistentStandbyBuffer = NV_TRUE;
768     }
769     return status;
770 }
771 
772 // RM reports dynamic encoder capacity as a percentage (0-100) of the encoders fixed
773 // capacity. Fixed capacity is readable via NvEncode API and is defined in
774 // drivers/video/encode/src/CNVVAEncoder.cpp#200
775 //
776 // Dynamic capacity of 0x0 indicates that encoder performance may be minimal for this
777 // GPU and software should fall back to CPU-based encode.
778 //
779 
780 #define NV_ENC_CAPACITY_MAX_VALUE          100
781 //
782 // subdeviceCtrlCmdGpuGetEncoderCapacity
783 //
784 // Lock Requirements:
785 //      Assert that API lock and GPUs lock held on entry
786 //
787 NV_STATUS
788 subdeviceCtrlCmdGpuGetEncoderCapacity_IMPL
789 (
790     Subdevice *pSubdevice,
791     NV2080_CTRL_GPU_GET_ENCODER_CAPACITY_PARAMS *pEncoderCapacityParams
792 )
793 {
794     NV_STATUS rmStatus = NV_OK;
795     OBJGPU *pGpu    =   GPU_RES_GET_GPU(pSubdevice);
796     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
797     NvHandle  hObject = RES_GET_HANDLE(pSubdevice);
798 
799     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
800 
801     if (pEncoderCapacityParams->queryType == NV2080_CTRL_GPU_GET_ENCODER_CAPACITY_AV1)
802     {
803         if (pGpu->bGpuNvEncAv1Supported == NV_FALSE)
804         {
805             return NV_ERR_NOT_SUPPORTED;
806         }
807     }
808     else if ((pEncoderCapacityParams->queryType != NV2080_CTRL_GPU_GET_ENCODER_CAPACITY_H264) &&
809              (pEncoderCapacityParams->queryType != NV2080_CTRL_GPU_GET_ENCODER_CAPACITY_HEVC))
810     {
811         return NV_ERR_INVALID_ARGUMENT;
812     }
813 
814     pEncoderCapacityParams->encoderCapacity = NV_ENC_CAPACITY_MAX_VALUE;
815 
816     //
817     // vGPU: Since vGPU does all real hardware management
818     // in the host, there is nothing to do at this point in
819     // the guest OS (where IS_VIRTUAL(pGpu) is true).
820     //
821     if (IS_VIRTUAL(pGpu)) // Otherwise default for vGPU host/baremetal/NMOS/GSP_CLIENT
822     {
823         NV_RM_RPC_GET_ENCODER_CAPACITY(pGpu,
824                                        hClient,
825                                        hObject,
826                                        &pEncoderCapacityParams->encoderCapacity,
827                                        rmStatus);
828     }
829     return rmStatus;
830 }
831 
832 //
833 // subdeviceCtrlCmdGpuGetNvencSwSessionStats
834 //
835 // Lock Requirements:
836 //      Assert that API lock and GPUs lock held on entry
837 //
838 NV_STATUS
839 subdeviceCtrlCmdGpuGetNvencSwSessionStats_IMPL
840 (
841     Subdevice *pSubdevice,
842     NV2080_CTRL_GPU_GET_NVENC_SW_SESSION_STATS_PARAMS *pParams
843 )
844 {
845 
846     NvU32                     averageEncodeFps = 0, averageEncodeLatency = 0;
847     OBJGPU                   *pGpu = GPU_RES_GET_GPU(pSubdevice);
848     NvencSession             *pNvencSession = NULL;
849     PNVENC_SESSION_LIST_ITEM  pNvencSessionListItem = NULL;
850 
851     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
852 
853     //
854     // For GSP vGPU host, get the data from GSP RM for CPU RM and it's client
855     //
856     if (IS_GSP_CLIENT(pGpu) && IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu))
857     {
858         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
859         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
860         RM_API       *pRmApi        = GPU_GET_PHYSICAL_RMAPI(pGpu);
861 
862         return pRmApi->Control(pRmApi,
863                                pRmCtrlParams->hClient,
864                                pRmCtrlParams->hObject,
865                                pRmCtrlParams->cmd,
866                                pRmCtrlParams->pParams,
867                                pRmCtrlParams->paramsSize);
868     }
869 
870     if (listCount(&(pGpu->nvencSessionList)) == 0)
871     {
872         pParams->encoderSessionCount = 0;
873         pParams->averageEncodeFps = 0;
874         pParams->averageEncodeLatency = 0;
875         return NV_OK;
876     }
877 
878     pParams->encoderSessionCount = listCount(&(pGpu->nvencSessionList));
879 
880     for (pNvencSessionListItem = listHead(&(pGpu->nvencSessionList));
881          pNvencSessionListItem != NULL;
882          pNvencSessionListItem = listNext(&(pGpu->nvencSessionList), pNvencSessionListItem))
883     {
884         if (pNvencSessionListItem->sessionPtr)
885         {
886             pNvencSession = pNvencSessionListItem->sessionPtr;
887 
888             averageEncodeFps      += pNvencSession->nvencSessionEntry.averageEncodeFps;
889             averageEncodeLatency  += pNvencSession->nvencSessionEntry.averageEncodeLatency;
890         }
891     }
892 
893     // average FPS and latency over all active sessions on this GPU.
894     pParams->averageEncodeFps = averageEncodeFps / listCount(&(pGpu->nvencSessionList));
895     pParams->averageEncodeLatency = averageEncodeLatency / listCount(&(pGpu->nvencSessionList));
896 
897     return NV_OK;
898 }
899 
900 NV_STATUS
901 _subdeviceCtrlCmdGpuGetNvencSwSessionInfo
902 (
903     OBJGPU                              *pGpu,
904     NvU32                               sessionInfoTblEntry,
905     NV2080_CTRL_NVENC_SW_SESSION_INFO   *pSessionInfo,
906     NvU32                               *entryCount
907 )
908 {
909 
910     NvencSession                *pNvencSession = NULL;
911     PNVENC_SESSION_LIST_ITEM    pNvencSessionListItem = NULL;
912     NvU32                       i = 0;
913     NV2080_CTRL_NVENC_SW_SESSION_INFO   *pSession;
914 
915     NV_ASSERT_OR_RETURN(sessionInfoTblEntry ==
916                         NV2080_CTRL_GPU_NVENC_SESSION_INFO_MAX_COPYOUT_ENTRIES,
917                         NV_ERR_INVALID_ARGUMENT);
918 
919     portMemSet(pSessionInfo, 0, sizeof(NV2080_CTRL_NVENC_SW_SESSION_INFO) * sessionInfoTblEntry);
920 
921     for (pNvencSessionListItem = listHead(&(pGpu->nvencSessionList));
922          pNvencSessionListItem != NULL;
923          pNvencSessionListItem = listNext(&(pGpu->nvencSessionList), pNvencSessionListItem))
924     {
925         if (pNvencSessionListItem->sessionPtr)
926         {
927             pNvencSession = pNvencSessionListItem->sessionPtr;
928             pSession = &pSessionInfo[i];
929 
930             pSession->sessionId              = pNvencSession->nvencSessionEntry.sessionId;
931             pSession->processId              = pNvencSession->nvencSessionEntry.processId;
932             pSession->subProcessId           = pNvencSession->nvencSessionEntry.subProcessId;
933             pSession->codecType              = pNvencSession->nvencSessionEntry.codecType;
934             pSession->hResolution            = pNvencSession->nvencSessionEntry.hResolution;
935             pSession->vResolution            = pNvencSession->nvencSessionEntry.vResolution;
936             pSession->averageEncodeFps       = pNvencSession->nvencSessionEntry.averageEncodeFps;
937             pSession->averageEncodeLatency   = pNvencSession->nvencSessionEntry.averageEncodeLatency;
938 
939             i++;
940 
941             if (i == NV2080_CTRL_GPU_NVENC_SESSION_INFO_MAX_COPYOUT_ENTRIES)
942             {
943                 // Stop copying beyond max size otherwise we might corrupt other kernel data
944                 break;
945             }
946         }
947     }
948 
949     //
950     // Copy the data only if sessionInfoTbl entry is equals or greater
951     // than current active sessions i.e. listCount(&(pGpu->nvencSessionList))
952     //
953     *entryCount = i;
954 
955     return NV_OK;
956 }
957 
958 //
959 // subdeviceCtrlCmdGpuGetNvencSwSessionInfo
960 //
961 // Lock Requirements:
962 //      Assert that API lock and GPUs lock held on entry
963 //
964 
965 NV_STATUS
966 subdeviceCtrlCmdGpuGetNvencSwSessionInfo_IMPL
967 (
968     Subdevice *pSubdevice,
969     NV2080_CTRL_GPU_GET_NVENC_SW_SESSION_INFO_PARAMS *pParams
970 )
971 {
972     NV_STATUS               status = NV_OK;
973     NV2080_CTRL_NVENC_SW_SESSION_INFO  *pSessionInfo = NvP64_VALUE(pParams->sessionInfoTbl);
974     OBJGPU                  *pGpu = GPU_RES_GET_GPU(pSubdevice);
975     NvU32                   entryCount = 0;
976 
977     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
978 
979     if ((!IS_VIRTUAL(pGpu)) && (pGpu->encSessionStatsReportingState != NV2080_CTRL_GPU_INFO_NVENC_STATS_REPORTING_STATE_ENABLED))
980     {
981         pParams->sessionInfoTblEntry = 0;
982         return status;
983     }
984 
985     if (pParams->sessionInfoTbl == NvP64_NULL || listCount(&(pGpu->nvencSessionList)) == 0)
986     {
987         pParams->sessionInfoTblEntry = listCount(&(pGpu->nvencSessionList));
988         return status;
989     }
990 
991     status = _subdeviceCtrlCmdGpuGetNvencSwSessionInfo(pGpu, pParams->sessionInfoTblEntry, pSessionInfo, &entryCount);
992     if (status != NV_OK)
993         return status;
994 
995     pParams->sessionInfoTblEntry = entryCount;
996 
997     return status;
998 }
999 
1000 NV_STATUS
1001 subdeviceCtrlCmdGpuGetNvencSwSessionInfoV2_IMPL
1002 (
1003     Subdevice *pSubdevice,
1004     NV2080_CTRL_GPU_GET_NVENC_SW_SESSION_INFO_V2_PARAMS *pParams
1005 )
1006 {
1007     NV_STATUS               status = NV_OK;
1008     NV2080_CTRL_NVENC_SW_SESSION_INFO  *pSessionInfo = pParams->sessionInfoTbl;
1009     OBJGPU                  *pGpu = GPU_RES_GET_GPU(pSubdevice);
1010     NvU32                   entryCount = 0;
1011 
1012     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1013 
1014     if ((!IS_VIRTUAL(pGpu)) && (pGpu->encSessionStatsReportingState != NV2080_CTRL_GPU_INFO_NVENC_STATS_REPORTING_STATE_ENABLED))
1015     {
1016         pParams->sessionInfoTblEntry = 0;
1017         return status;
1018     }
1019 
1020     if (pParams->sessionInfoTblEntry == 0 || listCount(&(pGpu->nvencSessionList)) == 0)
1021     {
1022         pParams->sessionInfoTblEntry = listCount(&(pGpu->nvencSessionList));
1023         return status;
1024     }
1025 
1026     status = _subdeviceCtrlCmdGpuGetNvencSwSessionInfo(pGpu, pParams->sessionInfoTblEntry, pSessionInfo, &entryCount);
1027     if (status != NV_OK)
1028         return status;
1029 
1030     pParams->sessionInfoTblEntry = entryCount;
1031 
1032     return status;
1033 }
1034 
1035 //
1036 // subdeviceCtrlCmdGpuGetNvfbcSwSessionStats
1037 //
1038 // Lock Requirements:
1039 //      Assert that API lock and GPUs lock held on entry
1040 //
1041 NV_STATUS
1042 subdeviceCtrlCmdGpuGetNvfbcSwSessionStats_IMPL
1043 (
1044     Subdevice *pSubdevice,
1045     NV2080_CTRL_GPU_GET_NVFBC_SW_SESSION_STATS_PARAMS *pParams
1046 )
1047 {
1048 
1049     NvU32                    averageFPS = 0, averageLatency = 0, localSessionCount = 0;
1050     OBJGPU                  *pGpu = GPU_RES_GET_GPU(pSubdevice);
1051     NvfbcSession            *pNvfbcSession = NULL;
1052     PNVFBC_SESSION_LIST_ITEM pNvfbcSessionListItem = NULL;
1053 
1054     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1055 
1056     if (listCount(&(pGpu->nvfbcSessionList)) == 0)
1057     {
1058         pParams->sessionCount   = 0;
1059         pParams->averageFPS     = 0;
1060         pParams->averageLatency = 0;
1061         return NV_OK;
1062     }
1063 
1064     for (pNvfbcSessionListItem = listHead(&(pGpu->nvfbcSessionList));
1065          pNvfbcSessionListItem != NULL;
1066          pNvfbcSessionListItem = listNext(&(pGpu->nvfbcSessionList), pNvfbcSessionListItem))
1067     {
1068         if (pNvfbcSessionListItem->sessionPtr)
1069         {
1070             pNvfbcSession  = pNvfbcSessionListItem->sessionPtr;
1071 
1072             averageFPS     += pNvfbcSession->nvfbcSessionEntry.averageFPS;
1073             averageLatency += pNvfbcSession->nvfbcSessionEntry.averageLatency;
1074 
1075             localSessionCount++;
1076         }
1077     }
1078 
1079     // average FPS and latency over all active sessions on this GPU.
1080     pParams->averageFPS     = localSessionCount == 0 ? 0 : (averageFPS     / localSessionCount);
1081     pParams->averageLatency = localSessionCount == 0 ? 0 : (averageLatency / localSessionCount);
1082 
1083     pParams->sessionCount   = localSessionCount;
1084 
1085     return NV_OK;
1086 }
1087 
1088 //
1089 // subdeviceCtrlCmdGpuGetNvfbcSwSessionInfo
1090 //
1091 // Lock Requirements:
1092 //      Assert that API lock and GPUs lock held on entry
1093 //
1094 
1095 NV_STATUS
1096 subdeviceCtrlCmdGpuGetNvfbcSwSessionInfo_IMPL
1097 (
1098     Subdevice *pSubdevice,
1099     NV2080_CTRL_GPU_GET_NVFBC_SW_SESSION_INFO_PARAMS *pParams
1100 )
1101 {
1102 
1103     NV2080_CTRL_NVFBC_SW_SESSION_INFO *pSession, *pSessionInfo = pParams->sessionInfoTbl;
1104     OBJGPU                  *pGpu = GPU_RES_GET_GPU(pSubdevice);
1105     NvU32                    i = 0;
1106     NvfbcSession            *pNvfbcSession = NULL;
1107     PNVFBC_SESSION_LIST_ITEM pNvfbcSessionListItem = NULL;
1108 
1109     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1110 
1111     portMemSet(pParams, 0, sizeof(NV2080_CTRL_GPU_GET_NVFBC_SW_SESSION_INFO_PARAMS));
1112 
1113     for (pNvfbcSessionListItem = listHead(&(pGpu->nvfbcSessionList));
1114          pNvfbcSessionListItem != NULL;
1115          pNvfbcSessionListItem = listNext(&(pGpu->nvfbcSessionList), pNvfbcSessionListItem))
1116     {
1117         if (pNvfbcSessionListItem->sessionPtr)
1118         {
1119             pNvfbcSession = pNvfbcSessionListItem->sessionPtr;
1120             pSession = &pSessionInfo[i];
1121 
1122             pSession->processId      = pNvfbcSession->nvfbcSessionEntry.processId;
1123             pSession->vgpuInstanceId = pNvfbcSession->nvfbcSessionEntry.vgpuInstanceId;
1124             pSession->sessionId      = pNvfbcSession->nvfbcSessionEntry.sessionId;
1125             pSession->displayOrdinal = pNvfbcSession->nvfbcSessionEntry.displayOrdinal;
1126             pSession->sessionType    = pNvfbcSession->nvfbcSessionEntry.sessionType;
1127             pSession->sessionFlags   = pNvfbcSession->nvfbcSessionEntry.sessionFlags;
1128             pSession->hMaxResolution = pNvfbcSession->nvfbcSessionEntry.hMaxResolution;
1129             pSession->vMaxResolution = pNvfbcSession->nvfbcSessionEntry.vMaxResolution;
1130 
1131             // All the following fields are dynamic fields.
1132             // We will return these as 0 if these are stale values.
1133             if (nvfbcIsSessionDataStale(pNvfbcSession->nvfbcSessionEntry.lastUpdateTimeStamp))
1134             {
1135                 pSession->hResolution    = 0;
1136                 pSession->vResolution    = 0;
1137                 pSession->averageFPS     = 0;
1138                 pSession->averageLatency = 0;
1139             }
1140             else
1141             {
1142                 pSession->hResolution    = pNvfbcSession->nvfbcSessionEntry.hResolution;
1143                 pSession->vResolution    = pNvfbcSession->nvfbcSessionEntry.vResolution;
1144                 pSession->averageFPS     = pNvfbcSession->nvfbcSessionEntry.averageFPS;
1145                 pSession->averageLatency = pNvfbcSession->nvfbcSessionEntry.averageLatency;
1146             }
1147 
1148             i++;
1149 
1150             if (i == NV2080_GPU_NVFBC_MAX_SESSION_COUNT)
1151             {
1152                 NV_ASSERT(0);
1153                 NV_PRINTF(LEVEL_ERROR,
1154                           "more entries in pGpu->nvencSessionList than "
1155                           "NV2080_CTRL_GPU_NVENC_SESSION_INFO_MAX_COPYOUT_ENTRIES\n");
1156 
1157                 // Stop copying beyond max size otherwise we might corrupt other kernel data.
1158                 break;
1159             }
1160         }
1161     }
1162 
1163     pParams->sessionInfoCount = i;
1164 
1165     return NV_OK;
1166 }
1167 
1168 //
1169 // subdeviceCtrlCmdGpuGetSdm
1170 //
1171 // Lock Requirements:
1172 //      Assert that API lock held on entry
1173 //
1174 NV_STATUS
1175 subdeviceCtrlCmdGpuGetSdm_IMPL
1176 (
1177     Subdevice *pSubdevice,
1178     NV2080_CTRL_GPU_GET_SDM_PARAMS *pSdmParams
1179 )
1180 {
1181     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
1182 
1183     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1184 
1185     pSdmParams->subdeviceMask = gpuGetSubdeviceMask(pGpu);
1186 
1187     return NV_OK;
1188 }
1189 
1190 //
1191 // subdeviceCtrlCmdGpuSetSdm
1192 //
1193 // Lock Requirements:
1194 //      Assert that API lock held on entry
1195 //
1196 NV_STATUS
1197 subdeviceCtrlCmdGpuSetSdm_IMPL
1198 (
1199     Subdevice* pSubdevice,
1200     NV2080_CTRL_GPU_SET_SDM_PARAMS* pSdmParams
1201 )
1202 {
1203     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
1204     NvU32   subdeviceInstance;
1205 
1206     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1207 
1208     if (!ONEBITSET(pSdmParams->subdeviceMask))
1209     {
1210         NV_PRINTF(LEVEL_ERROR, "Subdevice mask has none or more than one bit set");
1211         return NV_ERR_INVALID_DATA;
1212     }
1213 
1214     if (gpuIsStateLoaded(pGpu))
1215     {
1216         NV_PRINTF(LEVEL_ERROR, "NV2080_CTRL_CMD_GPU_SET_SDM cannot be called after the GPU is loaded");
1217         return NV_ERR_INVALID_STATE;
1218     }
1219     subdeviceInstance = BIT_IDX_32(pSdmParams->subdeviceMask);
1220 
1221     if (subdeviceInstance >= NV_MAX_SUBDEVICES)
1222     {
1223         NV_PRINTF(LEVEL_ERROR, "Subdevice mask exceeds the max count of subdevices");
1224         return NV_ERR_INVALID_DATA;
1225     }
1226     pGpu->subdeviceInstance = subdeviceInstance;
1227 
1228     return NV_OK;
1229 }
1230 
1231 //
1232 // subdeviceCtrlCmdGpuGetSimulationInfo
1233 //
1234 // Lock Requirements:
1235 //      Assert that API lock held on entry
1236 //
1237 NV_STATUS
1238 subdeviceCtrlCmdGpuGetSimulationInfo_IMPL
1239 (
1240     Subdevice *pSubdevice,
1241     NV2080_CTRL_GPU_GET_SIMULATION_INFO_PARAMS *pGpuSimulationInfoParams
1242 )
1243 {
1244     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
1245 
1246     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1247 
1248     if (IS_SILICON(pGpu))
1249     {
1250         pGpuSimulationInfoParams->type = NV2080_CTRL_GPU_GET_SIMULATION_INFO_TYPE_NONE;
1251     }
1252     else
1253     {
1254         pGpuSimulationInfoParams->type = NV2080_CTRL_GPU_GET_SIMULATION_INFO_TYPE_UNKNOWN;
1255     }
1256 
1257     return NV_OK;
1258 }
1259 
1260 //
1261 // subdeviceCtrlCmdGpuGetEngines
1262 //
1263 // Lock Requirements:
1264 //      Assert that API lock held on entry
1265 //
1266 NV_STATUS
1267 subdeviceCtrlCmdGpuGetEngines_IMPL
1268 (
1269     Subdevice *pSubdevice,
1270     NV2080_CTRL_GPU_GET_ENGINES_PARAMS *pParams
1271 )
1272 {
1273     NV2080_CTRL_GPU_GET_ENGINES_V2_PARAMS getEngineParamsV2;
1274     NvU32    *pKernelEngineList = NvP64_VALUE(pParams->engineList);
1275     NV_STATUS status = NV_OK;
1276 
1277     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1278 
1279     portMemSet(&getEngineParamsV2, 0, sizeof(getEngineParamsV2));
1280 
1281     status = subdeviceCtrlCmdGpuGetEnginesV2(pSubdevice, &getEngineParamsV2);
1282     NV_CHECK_OR_RETURN(LEVEL_INFO, NV_OK == status, status);
1283 
1284     // NULL clients just want an engine count
1285     if (NULL != pKernelEngineList)
1286     {
1287         NV_CHECK_OR_RETURN(LEVEL_INFO, pParams->engineCount >= getEngineParamsV2.engineCount,
1288                          NV_ERR_BUFFER_TOO_SMALL);
1289         portMemCopy(pKernelEngineList,
1290                     getEngineParamsV2.engineCount * sizeof(*getEngineParamsV2.engineList), getEngineParamsV2.engineList,
1291                     getEngineParamsV2.engineCount * sizeof(*getEngineParamsV2.engineList));
1292     }
1293 
1294     pParams->engineCount = getEngineParamsV2.engineCount;
1295 
1296     return status;
1297 }
1298 
1299 //
1300 // subdeviceCtrlCmdGpuGetEnginesV2
1301 //
1302 // Lock Requirements:
1303 //      Assert that API lock held on entry
1304 //
1305 NV_STATUS
1306 subdeviceCtrlCmdGpuGetEnginesV2_IMPL
1307 (
1308     Subdevice *pSubdevice,
1309     NV2080_CTRL_GPU_GET_ENGINES_V2_PARAMS *pEngineParams
1310 )
1311 {
1312     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
1313     NV_STATUS status = NV_OK;
1314 
1315     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1316 
1317     // Update the engine Database
1318     NV_ASSERT_OK_OR_RETURN(gpuUpdateEngineTable(pGpu));
1319 
1320     // Validate engine count
1321     if (pGpu->engineDB.size > NV2080_GPU_MAX_ENGINES_LIST_SIZE)
1322     {
1323         NV_PRINTF(LEVEL_ERROR, "The engine database's size (0x%x) exceeds "
1324                   "NV2080_GPU_MAX_ENGINES_LIST_SIZE (0x%x)!\n",
1325                   pGpu->engineDB.size, NV2080_GPU_MAX_ENGINES_LIST_SIZE);
1326         DBG_BREAKPOINT();
1327         return NV_ERR_INVALID_STATE;
1328     }
1329 
1330     {
1331         // Need this null check in case object doesn't exist when using Orin trimmed profile
1332         KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1333         if (pKernelMIGManager != NULL)
1334         {
1335             RM_ENGINE_TYPE rmEngineTypeList[NV2080_GPU_MAX_ENGINES_LIST_SIZE];
1336 
1337             // Filter engines based on current partitioning scheme
1338             status = kmigmgrFilterEngineList(pGpu,
1339                                              pKernelMIGManager,
1340                                              pSubdevice,
1341                                              rmEngineTypeList,
1342                                              &pEngineParams->engineCount);
1343 
1344             if (status == NV_OK)
1345             {
1346                 // Convert the RM_ENGINE_TYPE list to NV2080_ENGINE_TYPE list
1347                 gpuGetNv2080EngineTypeList(rmEngineTypeList,
1348                                            pEngineParams->engineCount,
1349                                            pEngineParams->engineList);
1350             }
1351         }
1352     }
1353 
1354     return status;
1355 }
1356 
1357 //
1358 // subdeviceCtrlCmdGpuGetEngineClasslist
1359 //
1360 // Lock Requirements:
1361 //      Assert that API lock held on entry
1362 //
1363 NV_STATUS
1364 subdeviceCtrlCmdGpuGetEngineClasslist_IMPL
1365 (
1366     Subdevice *pSubdevice,
1367     NV2080_CTRL_GPU_GET_ENGINE_CLASSLIST_PARAMS *pClassParams
1368 )
1369 {
1370     OBJGPU       *pGpu = GPU_RES_GET_GPU(pSubdevice);
1371     ENGDESCRIPTOR engDesc;
1372     NV_STATUS     status = NV_OK;
1373     RM_ENGINE_TYPE rmEngineType = gpuGetRmEngineType(pClassParams->engineType);
1374 
1375     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1376 
1377     {
1378         if (IS_MIG_IN_USE(pGpu))
1379         {
1380             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1381             MIG_INSTANCE_REF ref;
1382 
1383             NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
1384                 kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager, GPU_RES_GET_DEVICE(pSubdevice), &ref));
1385 
1386             NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
1387                 kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
1388                                                     rmEngineType,
1389                                                     &rmEngineType));
1390         }
1391     }
1392 
1393     status = gpuXlateClientEngineIdToEngDesc(pGpu, rmEngineType, &engDesc);
1394 
1395     NV_ASSERT(status == NV_OK);
1396 
1397     if (status != NV_OK)
1398     {
1399         NV_PRINTF(LEVEL_ERROR,
1400                   "NV2080_CTRL_CMD_GPU_GET_ENGINE_CLASSLIST Invalid engine ID 0x%x\n",
1401                   pClassParams->engineType);
1402         DBG_BREAKPOINT();
1403         return status;
1404     }
1405 
1406     status = gpuGetClassList(pGpu, &pClassParams->numClasses, NvP64_VALUE(pClassParams->classList), engDesc);
1407 
1408     if (status != NV_OK)
1409     {
1410         NV_PRINTF(LEVEL_ERROR,
1411                   "NV2080_CTRL_CMD_GPU_GET_ENGINE_CLASSLIST Class List query failed\n");
1412     }
1413 
1414     return status;
1415 }
1416 
1417 //
1418 // subdeviceCtrlCmdGpuGetEnginePartnerList
1419 //
1420 // Lock Requirements:
1421 //      Assert that API lock held on entry
1422 //
1423 NV_STATUS
1424 subdeviceCtrlCmdGpuGetEnginePartnerList_IMPL
1425 (
1426     Subdevice *pSubdevice,
1427     NV2080_CTRL_GPU_GET_ENGINE_PARTNERLIST_PARAMS *pPartnerListParams
1428 )
1429 {
1430     OBJGPU          *pGpu = GPU_RES_GET_GPU(pSubdevice);
1431     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1432     ENGDESCRIPTOR    engDesc;
1433     NvU32            localNv2080EngineType;
1434     RM_ENGINE_TYPE   rmEngineType;
1435     NvU32            i;
1436     PCLASSDESCRIPTOR pClass;
1437     NV_STATUS        status = NV_OK;
1438 
1439     pPartnerListParams->numPartners = 0;
1440 
1441     rmEngineType = gpuGetRmEngineType(pPartnerListParams->engineType);
1442 
1443     status = gpuXlateClientEngineIdToEngDesc(pGpu, rmEngineType, &engDesc);
1444     if (NV_OK != status)
1445     {
1446         NV_PRINTF(LEVEL_ERROR, "Invalid engine ID 0x%x (0x%x)\n",
1447                   pPartnerListParams->engineType, rmEngineType);
1448         return status;
1449     }
1450 
1451     // find class in class db
1452     status = gpuGetClassByClassId(pGpu, pPartnerListParams->partnershipClassId, &pClass);
1453     if (NV_OK != status)
1454     {
1455         NV_PRINTF(LEVEL_ERROR, "Invalid class ID 0x%x\n",
1456                   pPartnerListParams->partnershipClassId);
1457         return status;
1458     }
1459 
1460     // Make sure that the engine related to this class is FIFO...
1461     if (pClass->engDesc != ENG_KERNEL_FIFO)
1462     {
1463         NV_PRINTF(LEVEL_ERROR,
1464                   "Class 0x%x is not considered a partnership class.\n",
1465                   pPartnerListParams->partnershipClassId);
1466         return NV_ERR_NOT_SUPPORTED;
1467     }
1468 
1469     localNv2080EngineType = pPartnerListParams->engineType;
1470 
1471     // Translate the instance-local engine type to the global engine type in MIG mode
1472     if (IS_MIG_IN_USE(pGpu))
1473     {
1474         Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
1475         MIG_INSTANCE_REF ref;
1476 
1477         NV_CHECK_OK_OR_RETURN(
1478             LEVEL_ERROR,
1479             kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager, pDevice, &ref));
1480 
1481         NV_CHECK_OK_OR_RETURN(
1482             LEVEL_ERROR,
1483             kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
1484                                               rmEngineType,
1485                                               &rmEngineType));
1486 
1487         pPartnerListParams->engineType = gpuGetNv2080EngineType(rmEngineType);
1488     }
1489 
1490     // See if the hal wants to handle this
1491     KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
1492     status = kfifoGetEnginePartnerList_HAL(pGpu, pKernelFifo, pPartnerListParams);
1493 
1494     // Restore the client's passed engineType
1495     pPartnerListParams->engineType = localNv2080EngineType;
1496 
1497     if (NV_OK == status)
1498     {
1499         goto subdeviceCtrlCmdGpuGetEnginePartnerList_filter;
1500     }
1501 
1502     //
1503     // For channels that the hal didn't handle, we should just return
1504     // all of the supported engines except for the target engine.
1505     //
1506 
1507     // Update the engine Database
1508     NV_ASSERT_OK_OR_RETURN(gpuUpdateEngineTable(pGpu));
1509 
1510     // Make sure it all will fit
1511     if (pGpu->engineDB.size > NV2080_CTRL_GPU_MAX_ENGINE_PARTNERS)
1512     {
1513         NV_PRINTF(LEVEL_ERROR,
1514                   "partnerList space is too small, time to increase. This is fatal\n");
1515         DBG_BREAKPOINT();
1516         return status;
1517     }
1518 
1519     // Copy over all of the engines except the target
1520     for (i = 0; i < pGpu->engineDB.size; i++)
1521     {
1522         localNv2080EngineType = gpuGetNv2080EngineType(pGpu->engineDB.pType[i]);
1523 
1524         // Skip the engine handed in
1525         if (localNv2080EngineType != pPartnerListParams->engineType )
1526         {
1527             pPartnerListParams->partnerList[pPartnerListParams->numPartners++] = localNv2080EngineType;
1528         }
1529     }
1530 
1531 subdeviceCtrlCmdGpuGetEnginePartnerList_filter:
1532     if (IS_MIG_IN_USE(pGpu))
1533     {
1534         // Remove entries which don't exist in this client's GPU instance
1535         status = kmigmgrFilterEnginePartnerList(pGpu, pKernelMIGManager,
1536                                                 pSubdevice,
1537                                                 pPartnerListParams);
1538     }
1539 
1540     return status;
1541 }
1542 
1543 //
1544 // subdeviceCtrlCmdGpuGetEngineFaultInfo
1545 //
1546 // Lock Requirements:
1547 //      Assert that API lock held on entry
1548 //
1549 NV_STATUS
1550 subdeviceCtrlCmdGpuGetEngineFaultInfo_IMPL
1551 (
1552     Subdevice *pSubdevice,
1553     NV2080_CTRL_GPU_GET_ENGINE_FAULT_INFO_PARAMS *pParams
1554 )
1555 {
1556     OBJGPU     *pGpu        = GPU_RES_GET_GPU(pSubdevice);
1557     KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
1558     NV_STATUS   status      = NV_OK;
1559     RM_ENGINE_TYPE rmEngineType = gpuGetRmEngineType(pParams->engineType);
1560 
1561     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1562 
1563     //
1564     // When MIG is enabled, clients pass in their instance-specific engineId
1565     // rather than physical engineId since each client only sees engines available in
1566     // its own instance. So we need to convert this local engineId to physical engineId
1567     //
1568     if (IS_MIG_IN_USE(pGpu))
1569     {
1570         KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1571         Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
1572         MIG_INSTANCE_REF ref;
1573 
1574         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
1575             kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager, pDevice, &ref));
1576 
1577         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
1578             kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
1579                                               rmEngineType,
1580                                               &rmEngineType));
1581     }
1582 
1583     // Populate HW info for SW engine entry
1584     status = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, ENGINE_INFO_TYPE_RM_ENGINE_TYPE,
1585                                       (NvU32)rmEngineType, ENGINE_INFO_TYPE_MMU_FAULT_ID,
1586                                       &pParams->mmuFaultId);
1587     if (status != NV_OK)
1588     {
1589         NV_PRINTF(LEVEL_ERROR,
1590                   "NV2080_CTRL_CMD_GPU_GET_ENGINE_INFO failed\n");
1591         return status;
1592     }
1593 
1594     // Only GR engine supports subcontext faulting on Volta+ chips
1595     pParams->bSubcontextSupported = (RM_ENGINE_TYPE_IS_GR(rmEngineType) &&
1596         kfifoIsSubcontextSupported(pKernelFifo));
1597 
1598     return status;
1599 }
1600 
1601 ct_assert(NV2080_CTRL_INTERNAL_MAX_TPC_PER_GPC_COUNT ==
1602           NV2080_CTRL_CMD_GPU_GET_PES_INFO_MAX_TPC_PER_GPC_COUNT);
1603 
1604 //
1605 // subdeviceCtrlCmdGpuGetFermiGpcInfo
1606 //
1607 // Lock Requirements:
1608 //      Assert that API lock and GPUs lock held on entry
1609 //
1610 NV_STATUS
1611 subdeviceCtrlCmdGpuGetFermiGpcInfo_IMPL
1612 (
1613     Subdevice *pSubdevice,
1614     NV2080_CTRL_GPU_GET_FERMI_GPC_INFO_PARAMS *pParams
1615 )
1616 {
1617     NV2080_CTRL_GR_GET_GPC_MASK_PARAMS gpcMaskParams;
1618     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
1619     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
1620     NvHandle  hSubdevice = RES_GET_HANDLE(pSubdevice);
1621 
1622     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(GPU_RES_GET_GPU(pSubdevice)->gpuInstance));
1623 
1624     portMemSet(&gpcMaskParams, 0, sizeof(gpcMaskParams));
1625 
1626     NV_CHECK_OK_OR_RETURN(
1627         LEVEL_ERROR,
1628         pRmApi->Control(pRmApi,
1629                         hClient,
1630                         hSubdevice,
1631                         NV2080_CTRL_CMD_GR_GET_GPC_MASK,
1632                         &gpcMaskParams,
1633                         sizeof(gpcMaskParams)));
1634 
1635     pParams->gpcMask = gpcMaskParams.gpcMask;
1636     return NV_OK;
1637 }
1638 
1639 //
1640 // subdeviceCtrlCmdGpuGetFermiTpcInfo
1641 //
1642 // Lock Requirements:
1643 //      Assert that API lock and GPUs lock held on entry
1644 //
1645 NV_STATUS
1646 subdeviceCtrlCmdGpuGetFermiTpcInfo_IMPL
1647 (
1648     Subdevice *pSubdevice,
1649     NV2080_CTRL_GPU_GET_FERMI_TPC_INFO_PARAMS *pParams
1650 )
1651 {
1652     NV2080_CTRL_GR_GET_TPC_MASK_PARAMS tpcMaskParams;
1653     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
1654     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
1655     NvHandle  hSubdevice = RES_GET_HANDLE(pSubdevice);
1656 
1657     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(GPU_RES_GET_GPU(pSubdevice)->gpuInstance));
1658 
1659     portMemSet(&tpcMaskParams, 0, sizeof(tpcMaskParams));
1660     tpcMaskParams.gpcId = pParams->gpcId;
1661 
1662     NV_CHECK_OK_OR_RETURN(
1663         LEVEL_ERROR,
1664         pRmApi->Control(pRmApi,
1665                         hClient,
1666                         hSubdevice,
1667                         NV2080_CTRL_CMD_GR_GET_TPC_MASK,
1668                         &tpcMaskParams,
1669                         sizeof(tpcMaskParams)));
1670 
1671     pParams->tpcMask = tpcMaskParams.tpcMask;
1672     return NV_OK;
1673 }
1674 
1675 //
1676 // subdeviceCtrlCmdGpuGetFermiZcullInfo
1677 //
1678 // Lock Requirements:
1679 //      Assert that API lock and GPUs lock held on entry
1680 //
1681 // WARNING: This control call is deprecated.
1682 //
1683 NV_STATUS
1684 subdeviceCtrlCmdGpuGetFermiZcullInfo_IMPL
1685 (
1686     Subdevice *pSubdevice,
1687     NV2080_CTRL_GPU_GET_FERMI_ZCULL_INFO_PARAMS *pParams
1688 )
1689 {
1690     NV2080_CTRL_GR_GET_ZCULL_MASK_PARAMS zcullMaskParams;
1691     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
1692     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
1693     NvHandle  hSubdevice = RES_GET_HANDLE(pSubdevice);
1694 
1695     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(GPU_RES_GET_GPU(pSubdevice)->gpuInstance));
1696 
1697     portMemSet(&zcullMaskParams, 0, sizeof(zcullMaskParams));
1698     zcullMaskParams.gpcId = pParams->gpcId;
1699 
1700     NV_CHECK_OK_OR_RETURN(
1701         LEVEL_ERROR,
1702         pRmApi->Control(pRmApi,
1703                         hClient,
1704                         hSubdevice,
1705                         NV2080_CTRL_CMD_GR_GET_ZCULL_MASK,
1706                         &zcullMaskParams,
1707                         sizeof(zcullMaskParams)));
1708 
1709     pParams->zcullMask = zcullMaskParams.zcullMask;
1710 
1711     return NV_OK;
1712 }
1713 
1714 /*!
1715  * @brief Get graphics engine PES configuration
1716  *
1717  * This can be called before floor sweeping is determined, so we cannot use cached
1718  * values.
1719  */
1720 NV_STATUS
1721 subdeviceCtrlCmdGpuGetPesInfo_IMPL
1722 (
1723     Subdevice *pSubdevice,
1724     NV2080_CTRL_GPU_GET_PES_INFO_PARAMS *pParams
1725 )
1726 {
1727     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
1728     NvHandle hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
1729     KernelGraphics *pKernelGraphics;
1730     const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo;
1731     RsClient *pRsClient;
1732     NvU32 gpcId = pParams->gpcId;
1733     NvU32 maxGpcCount;
1734 
1735     //
1736     // XXX Bug 2681931 - GET_PES_INFO overloads interpretation of gpcId parameter
1737     // This ctrl call is due for deprecation and should not be used.
1738     //
1739 
1740     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1741 
1742     NV_ASSERT_OK_OR_RETURN(
1743         serverGetClientUnderLock(&g_resServ, hClient, &pRsClient));
1744 
1745     NV_CHECK_OR_RETURN(LEVEL_INFO, !IS_MIG_IN_USE(pGpu), NV_ERR_NOT_SUPPORTED);
1746     pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, 0);
1747     pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
1748     NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo != NULL, NV_ERR_INVALID_STATE);
1749 
1750     maxGpcCount = gpuGetLitterValues_HAL(pGpu, NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_GPCS);
1751     if (gpcId >= maxGpcCount)
1752     {
1753         return NV_ERR_INVALID_ARGUMENT;
1754     }
1755 
1756     pParams->numPesInGpc = pKernelGraphicsStaticInfo->floorsweepingMasks.numPesPerGpc[gpcId];
1757 
1758     NV_CHECK_OR_RETURN(LEVEL_SILENT, pKernelGraphicsStaticInfo->pPpcMasks != NULL, NV_ERR_NOT_SUPPORTED);
1759     pParams->activePesMask = pKernelGraphicsStaticInfo->pPpcMasks->mask[gpcId];
1760 
1761     pParams->maxTpcPerGpcCount = pKernelGraphicsStaticInfo->pGrInfo->infoList[NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_TPC_PER_GPC].data;
1762     portMemCopy(pParams->tpcToPesMap, sizeof(pParams->tpcToPesMap),
1763                 pKernelGraphicsStaticInfo->floorsweepingMasks.tpcToPesMap, sizeof(pKernelGraphicsStaticInfo->floorsweepingMasks.tpcToPesMap));
1764 
1765     return NV_OK;
1766 }
1767 
1768 //
1769 // subdeviceCtrlCmdGpuQueryMode_IMPL
1770 //
1771 // Lock Requirements:
1772 //      Assert that API and GPUs lock held on entry
1773 //
1774 NV_STATUS
1775 subdeviceCtrlCmdGpuQueryMode_IMPL
1776 (
1777     Subdevice *pSubdevice,
1778     NV2080_CTRL_GPU_QUERY_MODE_PARAMS *pQueryMode
1779 )
1780 {
1781     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
1782 
1783     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
1784 
1785     switch (gpuGetMode(pGpu))
1786     {
1787         case NV_GPU_MODE_GRAPHICS_MODE:
1788         {
1789             pQueryMode->mode = NV2080_CTRL_GPU_QUERY_MODE_GRAPHICS_MODE;
1790             break;
1791         }
1792         case NV_GPU_MODE_COMPUTE_MODE:
1793         {
1794             pQueryMode->mode = NV2080_CTRL_GPU_QUERY_MODE_COMPUTE_MODE;
1795             break;
1796         }
1797         default:
1798         {
1799             pQueryMode->mode = NV2080_CTRL_GPU_QUERY_MODE_UNKNOWN_MODE;
1800             break;
1801         }
1802     }
1803 
1804     return NV_OK;
1805 }
1806 
1807 //
1808 // subdeviceCtrlCmdGpuHandleGpuSR
1809 //
1810 // Lock Requirements:
1811 //      Assert that API lock held on entry
1812 //
1813 NV_STATUS
1814 subdeviceCtrlCmdGpuHandleGpuSR_IMPL
1815 (
1816     Subdevice *pSubdevice
1817 )
1818 {
1819     return NV_OK;
1820 }
1821 
1822 //
1823 // subdeviceCtrlCmdGpuSetComputeModeRules
1824 //
1825 // Lock Requirements:
1826 //      Assert that API lock held on entry
1827 //
1828 NV_STATUS
1829 subdeviceCtrlCmdGpuSetComputeModeRules_IMPL
1830 (
1831     Subdevice *pSubdevice,
1832     NV2080_CTRL_GPU_SET_COMPUTE_MODE_RULES_PARAMS *pSetRulesParams
1833 )
1834 {
1835     OBJGPU           *pGpu = GPU_RES_GET_GPU(pSubdevice);
1836 
1837     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1838 
1839     if (IS_GSP_CLIENT(pGpu))
1840     {
1841         CALL_CONTEXT *pCallContext  = resservGetTlsCallContext();
1842         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
1843         RM_API       *pRmApi        = GPU_GET_PHYSICAL_RMAPI(pGpu);
1844 
1845         //
1846         // Client RM still needs to set its value and update the registry,
1847         // so don't return unless there was an error.
1848         //
1849         NV_ASSERT_OK_OR_RETURN(pRmApi->Control(pRmApi,
1850                                                pRmCtrlParams->hClient,
1851                                                pRmCtrlParams->hObject,
1852                                                pRmCtrlParams->cmd,
1853                                                pRmCtrlParams->pParams,
1854                                                pRmCtrlParams->paramsSize));
1855     }
1856 
1857     //TODO Bug 2718406  will extend compute mode support for MIG
1858     if (IS_MIG_ENABLED(pGpu))
1859     {
1860         return NV_ERR_NOT_SUPPORTED;
1861     }
1862 
1863     // Setting compute mode for cuda non supported vGPU profiles
1864     // is not supported.
1865     // Exclude GSP environment for that rule.
1866     VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
1867     if (pVSI && !IS_GSP_CLIENT(pGpu) && pVSI->vgpuConfig.cudaEnabled == 0)
1868     {
1869         return NV_ERR_NOT_SUPPORTED;
1870     }
1871 
1872     switch(pSetRulesParams->rules)
1873     {
1874         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_NONE:
1875         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_EXCLUSIVE_COMPUTE:
1876         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_COMPUTE_PROHIBITED:
1877         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_EXCLUSIVE_COMPUTE_PROCESS:
1878             pGpu->computeModeRules = pSetRulesParams->rules;
1879 
1880             //
1881             // Store this setting in the registry so that it persists even
1882             // after the last client disconnects.
1883             // Client RM handles this so skip on GSP.
1884             //
1885             if (NV_OK !=
1886                 osWriteRegistryDword(pGpu,
1887                                      NV_REG_STR_RM_COMPUTE_MODE_RULES,
1888                                      pGpu->computeModeRules))
1889             {
1890                 // Non-fatal but worth reporting
1891                 NV_PRINTF(LEVEL_ERROR,
1892                           "Could not store compute mode rule in the registry, current setting may not persist if all clients disconnect!\n");
1893             }
1894             break;
1895 
1896         default:
1897             return NV_ERR_INVALID_ARGUMENT;
1898     }
1899 
1900     return NV_OK;
1901 }
1902 
1903 //
1904 // subdeviceCtrlCmdGpuQueryComputeModeRules
1905 //
1906 // Lock Requirements:
1907 //      Assert that API lock held on entry
1908 //
1909 // TODO Bug 2718406  will extend compute mode support for MIG
1910 //
1911 NV_STATUS
1912 subdeviceCtrlCmdGpuQueryComputeModeRules_IMPL
1913 (
1914     Subdevice *pSubdevice,
1915     NV2080_CTRL_GPU_QUERY_COMPUTE_MODE_RULES_PARAMS *pQueryRulesParams
1916 )
1917 {
1918     OBJGPU           *pGpu = GPU_RES_GET_GPU(pSubdevice);
1919 
1920     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1921 
1922     //
1923     // vGPU specific check to assign compute mode as 'Prohibited'
1924     // for cuda non supported vGPU profiles.
1925     // Exclude GSP environment for that rule.
1926     //
1927     VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
1928     if ((pVSI != NULL) && !IS_GSP_CLIENT(pGpu) && (pVSI->vgpuConfig.cudaEnabled == 0))
1929     {
1930         pQueryRulesParams->rules = NV2080_CTRL_GPU_COMPUTE_MODE_RULES_COMPUTE_PROHIBITED;
1931     }
1932     else
1933     {
1934         pQueryRulesParams->rules = pGpu->computeModeRules;
1935     }
1936 
1937     return NV_OK;
1938 }
1939 
1940 NV_STATUS
1941 subdeviceCtrlCmdGpuAcquireComputeModeReservation_IMPL
1942 (
1943     Subdevice *pSubdevice
1944 )
1945 {
1946     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
1947     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
1948 
1949     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
1950 
1951     //TODO Bug 2718406  will extend compute mode support for MIG
1952     if (IS_MIG_ENABLED(pGpu))
1953     {
1954         return NV_ERR_NOT_SUPPORTED;
1955     }
1956 
1957     switch (pGpu->computeModeRules)
1958     {
1959         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_NONE:
1960             {
1961                 // If a GPU is in "normal" mode, then the caller can always get the reservation:
1962                 pGpu->hComputeModeReservation = hClient;
1963             }
1964             return NV_OK;
1965             break; // For the Coverity code checker.
1966 
1967         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_EXCLUSIVE_COMPUTE:
1968         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_EXCLUSIVE_COMPUTE_PROCESS:
1969             {
1970                 //
1971                 // If a GPU is in "cuda exclusive" mode, then the caller can only get the
1972                 // reservation if no other client holds the reservation:
1973                 //
1974                 if (NV01_NULL_OBJECT == pGpu->hComputeModeReservation)
1975                 {
1976                     pGpu->hComputeModeReservation = hClient;
1977                     return NV_OK;
1978                 }
1979                 else
1980                 {
1981                     // Someone else holds the reservation:
1982                     return NV_ERR_STATE_IN_USE;
1983                 }
1984             }
1985             break;
1986 
1987         case NV2080_CTRL_GPU_COMPUTE_MODE_RULES_COMPUTE_PROHIBITED:
1988             //
1989             // If a GPU is in "cuda prohibited" mode, then the caller can never get the
1990             // reservation:
1991             //
1992             return NV_ERR_STATE_IN_USE;
1993             break;
1994 
1995         default:
1996             NV_ASSERT(0); // This *should* be unreachable code.
1997             break;
1998     }
1999 
2000     return NV_OK;
2001 }
2002 
2003 NV_STATUS
2004 subdeviceCtrlCmdGpuReleaseComputeModeReservation_IMPL
2005 (
2006     Subdevice *pSubdevice
2007 )
2008 {
2009     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
2010     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
2011 
2012     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
2013 
2014     //TODO Bug 2718406  will extend compute mode support for MIG
2015     if (IS_MIG_ENABLED(pGpu))
2016     {
2017         return NV_ERR_NOT_SUPPORTED;
2018     }
2019 
2020     // Release the reservation ONLY IF we had the reservation to begin with. Otherwise,
2021     // leave it alone, because someone else has acquired it:
2022     if (pGpu->hComputeModeReservation == hClient)
2023     {
2024         pGpu->hComputeModeReservation = NV01_NULL_OBJECT;
2025     }
2026     else
2027     {
2028         return NV_ERR_STATE_IN_USE;
2029     }
2030 
2031     return NV_OK;
2032 }
2033 
2034 //
2035 // subdeviceCtrlCmdGpuGetId
2036 //
2037 // Lock Requirements:
2038 //      Assert that API lock held on entry
2039 //
2040 NV_STATUS
2041 subdeviceCtrlCmdGpuGetId_IMPL
2042 (
2043     Subdevice *pSubdevice,
2044     NV2080_CTRL_GPU_GET_ID_PARAMS *pIdParams
2045 )
2046 {
2047     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
2048 
2049     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
2050 
2051     pIdParams->gpuId = pGpu->gpuId;
2052 
2053     return NV_OK;
2054 }
2055 
2056 //
2057 // nv2080CtrlCmdGpuGetPids
2058 //
2059 // Lock Requirements:
2060 //      Assert that API and GPUs lock held on entry
2061 //
2062 NV_STATUS
2063 subdeviceCtrlCmdGpuGetPids_IMPL
2064 (
2065     Subdevice *pSubdevice,
2066     NV2080_CTRL_GPU_GET_PIDS_PARAMS *pGetPidsParams
2067 )
2068 {
2069     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
2070     NvU32 internalClassId;
2071     NV_STATUS status;
2072     MIG_INSTANCE_REF *pRef = NULL;
2073 
2074     NV_ASSERT_OR_RETURN(RMCFG_FEATURE_KERNEL_RM, NV_ERR_NOT_SUPPORTED);
2075 
2076     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2077 
2078     switch (pGetPidsParams->idType)
2079     {
2080         case (NV2080_CTRL_GPU_GET_PIDS_ID_TYPE_CLASS):
2081         {
2082             if (pGetPidsParams->id == NV20_SUBDEVICE_0)
2083             {
2084                 internalClassId = classId(Subdevice);
2085             }
2086             else if (pGetPidsParams->id == MPS_COMPUTE)
2087             {
2088                 internalClassId = classId(MpsApi);
2089             }
2090             else
2091             {
2092                 internalClassId = classId(ChannelDescendant);
2093             }
2094             break;
2095         }
2096         case (NV2080_CTRL_GPU_GET_PIDS_ID_TYPE_VGPU_GUEST):
2097         {
2098             internalClassId = classId(KernelHostVgpuDeviceApi);
2099             break;
2100         }
2101 
2102         default:
2103             return NV_ERR_INVALID_ARGUMENT;
2104     }
2105 
2106     //
2107     // With MIG GPU instancing enabled, get associated instance ref
2108     // Clients with MIG_MONITOR capability are allowed to get full device
2109     // info
2110     //
2111     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
2112     NvHandle hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
2113     MIG_INSTANCE_REF partitionRef = kmigmgrMakeNoMIGReference();
2114     pRef = &partitionRef;
2115     if (IS_MIG_IN_USE(pGpu) &&
2116         !rmclientIsCapableByHandle(hClient, NV_RM_CAP_SYS_SMC_MONITOR))
2117     {
2118         Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
2119         //
2120         // Check instanceSubscription to limit the scope of the call
2121         // Clients with mig-monitor capability are allowed to get full device
2122         // info
2123         //
2124         NV_CHECK_OR_RETURN(LEVEL_INFO, (kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
2125                                                                         pDevice, pRef) == NV_OK),
2126                          NV_ERR_INSUFFICIENT_PERMISSIONS);
2127     }
2128 
2129     //
2130     // Search over all clients to see if any contain objects of type = id.
2131     // If they do, then add their PID to the PIDArray param and also
2132     // return the amount of valid entries in the Array through pidTblCount.
2133     //
2134     status = gpuGetProcWithObject(pGpu, pGetPidsParams->id, internalClassId,
2135                                   pGetPidsParams->pidTbl, &pGetPidsParams->pidTblCount,
2136                                   pRef);
2137     return status;
2138 }
2139 
2140 //
2141 // subdeviceCtrlCmdGpuGetPidInfo
2142 //
2143 // Lock Requirements:
2144 //      Assert that API and GPUs lock held on entry
2145 //
2146 NV_STATUS
2147 subdeviceCtrlCmdGpuGetPidInfo_IMPL
2148 (
2149     Subdevice *pSubdevice,
2150     NV2080_CTRL_GPU_GET_PID_INFO_PARAMS *pGetPidInfoParams
2151 )
2152 {
2153     NV2080_CTRL_GPU_PID_INFO_DATA *pPidInfoData;
2154     NV2080_CTRL_SMC_SUBSCRIPTION_INFO *pSmcInfo;
2155     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
2156     NV2080_CTRL_GPU_PID_INFO *pPidInfo;
2157     NvU32 internalClassId;
2158     NvU32 i;
2159     MIG_INSTANCE_REF *pRef = NULL;
2160     NvBool bGlobalInfo = NV_TRUE;
2161 
2162     NV_ASSERT_OR_RETURN(RMCFG_FEATURE_KERNEL_RM, NV_ERR_NOT_SUPPORTED);
2163 
2164     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2165 
2166     if ((pGetPidInfoParams->pidInfoListCount <= 0) ||
2167         (pGetPidInfoParams->pidInfoListCount >
2168          NV2080_CTRL_GPU_GET_PID_INFO_MAX_COUNT))
2169     {
2170         return NV_ERR_INVALID_ARGUMENT;
2171     }
2172 
2173     //
2174     // With MIG GPU instancing enabled, get associated instance ref
2175     // Clients with MIG_MONITOR capability are allowed to get full device
2176     // info
2177     //
2178     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
2179     NvHandle hClient = RES_GET_CLIENT_HANDLE(pSubdevice);
2180     MIG_INSTANCE_REF ref = kmigmgrMakeNoMIGReference();
2181     pRef = &ref;
2182     if (IS_MIG_IN_USE(pGpu) &&
2183         !rmclientIsCapableByHandle(hClient, NV_RM_CAP_SYS_SMC_MONITOR))
2184     {
2185         Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
2186         //
2187         // Check instanceSubscription to limit the scope of the call
2188         // Clients with mig-monitor capability are allowed to get full device
2189         // info
2190         //
2191         NV_CHECK_OR_RETURN(LEVEL_INFO, (kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
2192                                                                         pDevice, pRef) == NV_OK),
2193                          NV_ERR_INSUFFICIENT_PERMISSIONS);
2194         bGlobalInfo = NV_FALSE;
2195     }
2196 
2197     for (i = 0; i < pGetPidInfoParams->pidInfoListCount; ++i)
2198     {
2199         pPidInfo = &pGetPidInfoParams->pidInfoList[i];
2200 
2201         pSmcInfo = &pPidInfo->smcSubscription;
2202         pSmcInfo->computeInstanceId = PARTITIONID_INVALID;
2203         pSmcInfo->gpuInstanceId = PARTITIONID_INVALID;
2204 
2205         switch (pPidInfo->index)
2206         {
2207             case (NV2080_CTRL_GPU_PID_INFO_INDEX_VIDEO_MEMORY_USAGE):
2208             {
2209                 internalClassId = classId(Memory);
2210 
2211                 pPidInfoData = &pPidInfo->data;
2212                 portMemSet(pPidInfoData, 0, sizeof(NV2080_CTRL_GPU_PID_INFO_DATA));
2213                 pPidInfo->result = gpuFindClientInfoWithPidIterator(pGpu, pPidInfo->pid, 0,
2214                                                                     internalClassId,
2215                                                                     pPidInfoData,
2216                                                                     pSmcInfo,
2217                                                                     pRef,
2218                                                                     bGlobalInfo);
2219                 break;
2220             }
2221             default:
2222             {
2223                 pPidInfo->result = NV_ERR_INVALID_ARGUMENT;
2224                 break;
2225             }
2226         }
2227     }
2228 
2229     return NV_OK;
2230 }
2231 
2232 // Control call to fetch the Runlist pri base for the engine(s) specified
2233 NV_STATUS
2234 subdeviceCtrlCmdGpuGetEngineRunlistPriBase_IMPL
2235 (
2236     Subdevice *pSubdevice,
2237     NV2080_CTRL_GPU_GET_ENGINE_RUNLIST_PRI_BASE_PARAMS *pParams
2238 )
2239 {
2240     NV_STATUS   status      = NV_OK;
2241     NV_STATUS   tmpStatus   = NV_OK;
2242     NvU32       i;
2243     OBJGPU     *pGpu        = GPU_RES_GET_GPU(pSubdevice);
2244     KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
2245 
2246     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2247 
2248     if (!kfifoIsHostEngineExpansionSupported(pKernelFifo))
2249     {
2250        status = NV_ERR_NOT_SUPPORTED;
2251        return status;
2252     }
2253 
2254     for (i = 0; i < NV2080_GPU_MAX_ENGINES_LIST_SIZE; i++)
2255     {
2256         RM_ENGINE_TYPE rmEngineType;
2257 
2258         // Check if input is NULL or a SW engine; return a NULL value since SW engine does not have a runlist pri base
2259         // and this should not be returned as an error
2260         if ((pParams->engineList[i] == NV2080_ENGINE_TYPE_NULL) || (pParams->engineList[i] == NV2080_ENGINE_TYPE_SW))
2261         {
2262             pParams->runlistPriBase[i] = NV2080_CTRL_GPU_GET_ENGINE_RUNLIST_PRI_BASE_NULL;
2263             continue;
2264         }
2265 
2266         rmEngineType = gpuGetRmEngineType(pParams->engineList[i]);
2267 
2268         //
2269         // See if MIG is enabled. If yes, then we have to convert instanceLocal
2270         // engine to global engine before moving ahead
2271         //
2272         if (IS_MIG_IN_USE(pGpu))
2273         {
2274             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
2275             Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
2276             MIG_INSTANCE_REF ref;
2277 
2278             NV_CHECK_OK_OR_RETURN(
2279                 LEVEL_ERROR,
2280                 kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
2281                                                 pDevice, &ref));
2282 
2283             NV_CHECK_OK_OR_RETURN(
2284                 LEVEL_ERROR,
2285                 kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
2286                                                   rmEngineType,
2287                                                   &rmEngineType));
2288         }
2289 
2290         tmpStatus = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, ENGINE_INFO_TYPE_RM_ENGINE_TYPE,
2291                                              rmEngineType, ENGINE_INFO_TYPE_RUNLIST_PRI_BASE,
2292                                              &pParams->runlistPriBase[i]);
2293 
2294         if (tmpStatus != NV_OK)
2295         {
2296             pParams->runlistPriBase[i] = NV2080_CTRL_GPU_GET_ENGINE_RUNLIST_PRI_BASE_ERROR;
2297             status = tmpStatus;
2298         }
2299     }
2300     return status;
2301 }
2302 
2303 // Control call to fetch the HW engine ID for the engine(s) specified
2304 NV_STATUS
2305 subdeviceCtrlCmdGpuGetHwEngineId_IMPL
2306 (
2307     Subdevice *pSubdevice,
2308     NV2080_CTRL_GPU_GET_HW_ENGINE_ID_PARAMS *pParams
2309 )
2310 {
2311     NV_STATUS   status      = NV_OK;
2312     NV_STATUS   tmpStatus   = NV_OK;
2313     NvU32       i;
2314     OBJGPU     *pGpu        = GPU_RES_GET_GPU(pSubdevice);
2315     KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
2316 
2317     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2318 
2319     if (!kfifoIsHostEngineExpansionSupported(pKernelFifo))
2320     {
2321        status = NV_ERR_NOT_SUPPORTED;
2322        return status;
2323     }
2324 
2325     for (i = 0; i < NV2080_GPU_MAX_ENGINES_LIST_SIZE; i++)
2326     {
2327         RM_ENGINE_TYPE rmEngineType;
2328 
2329         // Check if input is NULL or a SW engine; return a NULL value since SW engine does not have a runlist pri base
2330         // and this should not be returned as an error
2331         if (pParams->engineList[i] == NV2080_ENGINE_TYPE_NULL || (pParams->engineList[i] == NV2080_ENGINE_TYPE_SW))
2332         {
2333             pParams->hwEngineID[i] = NV2080_CTRL_GPU_GET_HW_ENGINE_ID_NULL;
2334             continue;
2335         }
2336 
2337         rmEngineType = gpuGetRmEngineType(pParams->engineList[i]);
2338 
2339         //
2340         // See if MIG is enabled. If yes, then we have to convert instanceLocal
2341         // engine to global engine before moving ahead
2342         //
2343         if (IS_MIG_IN_USE(pGpu))
2344         {
2345             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
2346             Device *pDevice = GPU_RES_GET_DEVICE(pSubdevice);
2347             MIG_INSTANCE_REF ref;
2348 
2349             NV_CHECK_OK_OR_RETURN(
2350                 LEVEL_ERROR,
2351                 kmigmgrGetInstanceRefFromDevice(pGpu, pKernelMIGManager,
2352                                                 pDevice, &ref));
2353 
2354             NV_CHECK_OK_OR_RETURN(
2355                 LEVEL_ERROR,
2356                 kmigmgrGetLocalToGlobalEngineType(pGpu, pKernelMIGManager, ref,
2357                                                   rmEngineType,
2358                                                   &rmEngineType));
2359         }
2360 
2361         tmpStatus = kfifoEngineInfoXlate_HAL(pGpu, pKernelFifo, ENGINE_INFO_TYPE_RM_ENGINE_TYPE,
2362                                              (NvU32)rmEngineType,
2363                                              ENGINE_INFO_TYPE_FIFO_TAG,
2364                                              &pParams->hwEngineID[i]);
2365 
2366         if (tmpStatus != NV_OK)
2367         {
2368             pParams->hwEngineID[i] = NV2080_CTRL_GPU_GET_HW_ENGINE_ID_ERROR;
2369             status = tmpStatus;
2370         }
2371     }
2372     return status;
2373 }
2374 
2375 NV_STATUS
2376 subdeviceCtrlCmdGpuGetMaxSupportedPageSize_IMPL
2377 (
2378     Subdevice *pSubdevice,
2379     NV2080_CTRL_GPU_GET_MAX_SUPPORTED_PAGE_SIZE_PARAMS *pParams
2380 )
2381 {
2382     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
2383     NV_STATUS status  = NV_OK;
2384 
2385     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
2386 
2387     // Default to minimal page size (4k)
2388     pParams->maxSupportedPageSize = RM_PAGE_SIZE;
2389 
2390     if (IS_VIRTUAL(pGpu))
2391     {
2392         VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
2393 
2394         pParams->maxSupportedPageSize = pVSI->maxSupportedPageSize;
2395 
2396         return status;
2397     }
2398 
2399     KernelGmmu *pKernelGmmu = GPU_GET_KERNEL_GMMU(pGpu);
2400 
2401     if (kgmmuIsPageSize512mbSupported(pKernelGmmu))
2402     {
2403         pParams->maxSupportedPageSize = RM_PAGE_SIZE_512M;
2404     }
2405     else if (kgmmuIsHugePageSupported(pKernelGmmu))
2406     {
2407         pParams->maxSupportedPageSize = RM_PAGE_SIZE_HUGE;
2408     }
2409     else
2410     {
2411         pParams->maxSupportedPageSize = (NvU32)kgmmuGetMaxBigPageSize_HAL(pKernelGmmu);
2412     }
2413 
2414     if (gpuIsSriovEnabled(pGpu)
2415         || gpuIsCCFeatureEnabled(pGpu)
2416        )
2417     {
2418         NvU64 vmmuSegmentSize = gpuGetVmmuSegmentSize(pGpu);
2419         if (vmmuSegmentSize > 0 &&
2420             vmmuSegmentSize < NV2080_CTRL_GPU_VMMU_SEGMENT_SIZE_512MB)
2421         {
2422             pParams->maxSupportedPageSize = RM_PAGE_SIZE_HUGE;
2423         }
2424     }
2425 
2426     return status;
2427 }
2428 
2429 #if (defined(DEBUG) || defined(DEVELOP) || RMCFG_FEATURE_MODS_FEATURES) && RMCFG_MODULE_KERNEL_GRAPHICS
2430 NV_STATUS
2431 subdeviceCtrlCmdGpuGetNumMmusPerGpc_IMPL
2432 (
2433     Subdevice *pSubdevice,
2434     NV2080_CTRL_GPU_GET_NUM_MMUS_PER_GPC_PARAMS *pParams
2435 )
2436 {
2437     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
2438     KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
2439     KernelGraphics *pKernelGraphics;
2440     const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo;
2441     NvU32 count;
2442     NvU32 maxGpcCount;
2443 
2444     // Ensure that the gpcId is within range
2445     maxGpcCount = gpuGetLitterValues_HAL(pGpu, NV2080_CTRL_GR_INFO_INDEX_LITTER_NUM_GPCS);
2446     if (pParams->gpcId >= maxGpcCount)
2447     {
2448         return NV_ERR_INVALID_ARGUMENT;
2449     }
2450 
2451     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2452         kgrmgrCtrlRouteKGRWithDevice(pGpu, pKernelGraphicsManager,
2453                                      GPU_RES_GET_DEVICE(pSubdevice),
2454                                      &pParams->grRouteInfo, &pKernelGraphics));
2455 
2456     pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
2457     NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo != NULL, NV_ERR_INVALID_STATE);
2458 
2459     count = pKernelGraphicsStaticInfo->floorsweepingMasks.mmuPerGpc[pParams->gpcId];
2460 
2461     // If the litter value doesn't exist (pre Ampere) than default to 1 gpcmmu
2462     pParams->count = ((count != 0) ? count : 1);
2463 
2464     return NV_OK;
2465 }
2466 #endif
2467 
2468 // Stubbed for Orin
2469 
2470 /*
2471  * @brief Update/Set the compute policy config for a GPU
2472  *
2473  * @param[in] pSubdevice
2474  * @param[in] pParams    pointer to control parameters
2475  *
2476  * @return
2477  *  NV_OK                           Success
2478  *  NV_ERR_NOT_SUPPORTED            Setting policy is not supported on requested GPU
2479  *  NV_ERR_INVALID_ARGUMENT         Invalid config type/value specified
2480  *  else appropriate error code.
2481  */
2482 NV_STATUS
2483 subdeviceCtrlCmdGpuSetComputePolicyConfig_IMPL
2484 (
2485     Subdevice                                        *pSubdevice,
2486     NV2080_CTRL_GPU_SET_COMPUTE_POLICY_CONFIG_PARAMS *pParams
2487 )
2488 {
2489     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
2490     GPU_COMPUTE_POLICY_INFO policyInfo;
2491     NvU32 gidFlags;
2492     NV_STATUS status = NV_OK;
2493 
2494     switch(pParams->config.type)
2495     {
2496         case NV2080_CTRL_GPU_COMPUTE_POLICY_TIMESLICE:
2497             if (!gpuIsComputePolicyTimesliceSupported(pGpu))
2498             {
2499                 NV_PRINTF(LEVEL_ERROR, "Setting the timeslice policy is not supported for gpu with pci id 0x%llx\n",
2500                           gpuGetDBDF(pGpu));
2501                 return NV_ERR_NOT_SUPPORTED;
2502 
2503             }
2504 
2505             if (pParams->config.data.timeslice >= NV2080_CTRL_CMD_GPU_COMPUTE_TIMESLICE_MAX)
2506             {
2507                 NV_PRINTF(LEVEL_ERROR, "Unsupported timeslice value %u specified for gpu with pci id 0x%llx\n",
2508                           pParams->config.data.timeslice,  gpuGetDBDF(pGpu));
2509                 return NV_ERR_INVALID_ARGUMENT;
2510             }
2511 
2512             policyInfo.timeslice = pParams->config.data.timeslice;
2513             break;
2514         default:
2515             NV_PRINTF(LEVEL_ERROR, "Unsupported compute policy %u specified for gpu id 0x%llx\n",
2516                       pParams->config.type, gpuGetDBDF(pGpu));
2517             return NV_ERR_INVALID_ARGUMENT;
2518     }
2519 
2520     gidFlags = DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1) |
2521                DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _BINARY);
2522     status = gpuGetGidInfo(pGpu, NULL, NULL, gidFlags);
2523     if (status != NV_OK)
2524     {
2525         return status;
2526     }
2527 
2528     NV_ASSERT(pGpu->gpuUuid.isInitialized);
2529     status = gpudbSetGpuComputePolicyConfig(pGpu->gpuUuid.uuid, pParams->config.type,
2530                                             &policyInfo);
2531 
2532     return status;
2533 }
2534 
2535 //
2536 // Make sure number of compute policies per GPU is always less than or equal
2537 // to the number of policy configs that can be handled by the
2538 // NV2080_CTRL_CMD_GPU_GET_COMPUTE_POLICY_CONFIG command.
2539 //
2540 ct_assert(NV2080_CTRL_GPU_COMPUTE_POLICY_MAX <= NV2080_CTRL_GPU_COMPUTE_POLICY_CONFIG_LIST_MAX);
2541 
2542 /*
2543  * @brief Get all compute policy configs for a GPU
2544  *
2545  * @param[in] pSubdevice
2546  * @param[in] pParams    pointer to control parameters
2547  *
2548  * @return
2549  *  NV_OK on success
2550  *  else appropriate error code.
2551  */
2552 NV_STATUS
2553 subdeviceCtrlCmdGpuGetComputePolicyConfig_IMPL
2554 (
2555     Subdevice                                         *pSubdevice,
2556     NV2080_CTRL_GPU_GET_COMPUTE_POLICY_CONFIG_PARAMS  *pParams
2557 )
2558 {
2559     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
2560     GPU_COMPUTE_POLICY_INFO policyInfo;
2561     NvU32 policyId;
2562     NvU32 gidFlags;
2563     NV_STATUS status = NV_OK;
2564 
2565     gidFlags = DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1) |
2566                DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _BINARY);
2567     status = gpuGetGidInfo(pGpu, NULL, NULL, gidFlags);
2568     if (status != NV_OK)
2569     {
2570         return status;
2571     }
2572 
2573     NV_ASSERT(pGpu->gpuUuid.isInitialized);
2574     status = gpudbGetGpuComputePolicyConfigs(pGpu->gpuUuid.uuid, &policyInfo);
2575     if (status != NV_OK)
2576     {
2577         return status;
2578     }
2579 
2580     pParams->numConfigs = 0;
2581     // Loop through all compute policies and retrieve the configured settings
2582     for (policyId = NV2080_CTRL_GPU_COMPUTE_POLICY_TIMESLICE;
2583          policyId < NV2080_CTRL_GPU_COMPUTE_POLICY_MAX;
2584          policyId++)
2585     {
2586         switch (policyId)
2587         {
2588             case NV2080_CTRL_GPU_COMPUTE_POLICY_TIMESLICE:
2589                 pParams->configList[policyId].type = NV2080_CTRL_GPU_COMPUTE_POLICY_TIMESLICE;
2590                 pParams->configList[policyId].data.timeslice = policyInfo.timeslice;
2591                 pParams->numConfigs++;
2592                 break;
2593             default:
2594                 NV_ASSERT(0);
2595                 break;
2596         }
2597     }
2598 
2599     return status;
2600 }
2601 
2602 /*!
2603  * @brief Check if address range is within the provided limits
2604  *
2605  * @param[in]  addrStart       Staring address of address range
2606  * @param[in]  addrLength      Size of address range
2607  * @param[in]  limitStart      Staring address of limit
2608  * @param[in]  limitLength     Size of limit
2609  *
2610  * @return
2611  *     NV_TRUE, if address range is within the provided limits
2612  *     NV_FALSE, if address range is outside the provided limits
2613  *
2614  */
2615 static NvBool isAddressWithinLimits
2616 (
2617     NvU64 addrStart,
2618     NvU64 addrLength,
2619     NvU64 limitStart,
2620     NvU64 limitLength
2621 )
2622 {
2623     NvU64 addrEnd  = 0;
2624     NvU64 limitEnd = 0;
2625 
2626     //
2627     // Calculate End address of address range and limit,
2628     // Return NV_FALSE in case of 64-bit addition overflow
2629     //
2630     if (!portSafeAddU64(addrStart, addrLength - 1, &addrEnd) ||
2631         !portSafeAddU64(limitStart, limitLength - 1, &limitEnd))
2632     {
2633         return NV_FALSE;
2634     }
2635 
2636     return ((addrStart >= limitStart) && (addrEnd <= limitEnd));
2637 }
2638 
2639 /*!
2640  * @brief Validate the address range for Memory Map request by comparing the
2641  *        user supplied address range with GPU BAR0/BAR1 range.
2642  *
2643  * Lock Requirements:
2644  *      Assert that API and GPUs lock held on entry
2645  *
2646  * @param[in] pSubdevice
2647  * @param[in] pParams    pointer to control parameters
2648  *
2649  * Possible status values returned are:
2650  *     NV_OK
2651  *     NV_ERR_PROTECTION_FAULT
2652  *
2653  */
2654 NV_STATUS subdeviceCtrlCmdValidateMemMapRequest_IMPL
2655 (
2656     Subdevice                                       *pSubdevice,
2657     NV2080_CTRL_GPU_VALIDATE_MEM_MAP_REQUEST_PARAMS *pParams
2658 )
2659 {
2660     OBJGPU       *pGpu     = GPU_RES_GET_GPU(pSubdevice);
2661     NvU64         start    = pParams->addressStart;
2662     NvU64         length   = pParams->addressLength;
2663     NV_STATUS     rmStatus;
2664     NvU32         bar0MapSize;
2665     NvU64         bar0MapOffset;
2666 
2667     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(GPU_RES_GET_GPU(pSubdevice)->gpuInstance));
2668 
2669     pParams->protection = NV_PROTECT_READ_WRITE;
2670 
2671     if (isAddressWithinLimits(start, length, pGpu->busInfo.gpuPhysAddr,
2672                         pGpu->deviceMappings[0].gpuNvLength))
2673     {
2674         start -= pGpu->busInfo.gpuPhysAddr;
2675 
2676         OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
2677         rmStatus = tmrGetTimerBar0MapInfo_HAL(pGpu, pTmr,
2678                                               &bar0MapOffset, &bar0MapSize);
2679         if ((rmStatus == NV_OK) &&
2680             isAddressWithinLimits(start, length, bar0MapOffset, bar0MapSize))
2681         {
2682             pParams->protection = NV_PROTECT_READABLE;
2683             return NV_OK;
2684         }
2685 
2686         KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
2687         rmStatus = kfifoGetUsermodeMapInfo_HAL(pGpu, pKernelFifo,
2688                                                &bar0MapOffset, &bar0MapSize);
2689         if ((rmStatus == NV_OK) &&
2690             isAddressWithinLimits(start, length, bar0MapOffset, bar0MapSize))
2691         {
2692             return NV_OK;
2693         }
2694 
2695         KernelMc *pKernelMc = GPU_GET_KERNEL_MC(pGpu);
2696         rmStatus = kmcGetMcBar0MapInfo_HAL(pGpu, pKernelMc,
2697                 &bar0MapOffset, &bar0MapSize);
2698         if ((rmStatus == NV_OK) &&
2699             isAddressWithinLimits(start, length, bar0MapOffset, bar0MapSize))
2700         {
2701             pParams->protection = NV_PROTECT_READABLE;
2702             return NV_OK;
2703         }
2704 
2705         //
2706         // If the kernel side does not know about the object being mapped,
2707         // fall-through to GSP and see if it knows anything.
2708         //
2709         if (IS_GSP_CLIENT(pGpu))
2710         {
2711             RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2712 
2713             return pRmApi->Control(pRmApi,
2714                                    pGpu->hInternalClient,
2715                                    pGpu->hInternalSubdevice,
2716                                    NV2080_CTRL_CMD_GPU_VALIDATE_MEM_MAP_REQUEST,
2717                                    pParams, sizeof(*pParams));
2718         }
2719 
2720         return NV_ERR_PROTECTION_FAULT;
2721     }
2722     // See bug 1784955
2723     else if (isAddressWithinLimits(start, length, pGpu->busInfo.gpuPhysFbAddr, pGpu->fbLength)
2724             || GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu)->coherentCpuFbBase)
2725     {
2726         return NV_OK;
2727     }
2728 
2729     return NV_ERR_PROTECTION_FAULT;
2730 }
2731 
2732 /*!
2733  * @brief Computes the GFID (GPU Function ID) for a given SR-IOV
2734  *        Virtual Function (VF) of the physical GPU based on the
2735  *        BDF parameters provided by the caller.
2736  *
2737  * Lock Requirements:
2738  *      Assert that API and GPUs lock held on entry
2739  *
2740  * @param[in] pSubdevice
2741  * @param[in] pParams    pointer to control parameters
2742  *
2743  * Possible status values returned are:
2744  *     NV_OK                on successful computation of a valid GFID
2745  *     NV_ERR_NOT_SUPPORTED if ctrl call is made when
2746  *                          SRIOV is not enabled OR
2747  *                          caller is not FM from Host RM
2748  *     NV_ERR_INVALID_STATE if computed GFID is greater than
2749  *                          max GFID that is expected/allowed
2750  */
2751 NV_STATUS
2752 subdeviceCtrlCmdGpuGetGfid_IMPL
2753 (
2754     Subdevice                           *pSubdevice,
2755     NV2080_CTRL_GPU_GET_GFID_PARAMS     *pParams
2756 )
2757 {
2758     OBJSYS *pSys = SYS_GET_INSTANCE();
2759     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
2760     NvU32  pciFunction, gfid;
2761 
2762     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2763 
2764     if (!gpuIsSriovEnabled(pGpu))
2765         return NV_ERR_NOT_SUPPORTED;
2766 
2767     // Host RM && FM
2768     if ((!IS_VIRTUAL(pGpu)) &&
2769         (pSys->getProperty(pSys, PDB_PROP_SYS_FABRIC_IS_EXTERNALLY_MANAGED)))
2770     {
2771         //
2772         // In unix based systems, OS uses lspci format which is "ssss:bb:dd.f",
2773         // so device is 5 bits and function 3 bits.
2774         // for SR-IOV when ARI is enabled, device and function gets combined and
2775         // we need to consider 8 bits function.
2776         //
2777         pciFunction = (pParams->device << 3) | pParams->func;
2778         gfid = (pciFunction - pGpu->sriovState.firstVFOffset) + 1;
2779 
2780         if (gfid > pGpu->sriovState.maxGfid)
2781         {
2782             NV_PRINTF(LEVEL_ERROR, "Computed GFID %d greater than max supported GFID\n", gfid);
2783             return NV_ERR_INVALID_STATE;
2784         }
2785 
2786         pParams->gfid = gfid;
2787         // Also set the mask for max gfid supported currently in the driver
2788         pParams->gfidMask = (pGpu->sriovState.maxGfid - 1);
2789     }
2790     else
2791     {
2792         return NV_ERR_NOT_SUPPORTED;
2793     }
2794 
2795     return NV_OK;
2796 }
2797 
2798 /*!
2799  * @brief Sets or unsets the SW state to inform the GPU driver that the GPU instance
2800  *        associated with input GFID has been activated or de-activated respectively.
2801  *
2802  * Lock Requirements:
2803  *      Assert that API and GPUs lock held on entry
2804  *
2805  * @param[in] pSubdevice
2806  * @param[in] pParams    pointer to control parameters
2807  *
2808  * Possible status values returned are:
2809  *     NV_OK                    on success
2810  *     NV_ERR_INVALID_STATE     if SRIOV state for P2P in driver is not setup
2811  *     NV_ERR_INVALID_ARGUMENT  if input GFID is greater than the max GFID allowed
2812  *     NV_ERR_NOT_SUPPORTED     if ctrl call is made when
2813  *                              SRIOV is not enabled OR
2814  *                              caller is not FM from Host RM
2815  *     NV_ERR_IN_USE            If MAX_NUM_P2P_GFIDS have already been enabled for P2P
2816  */
2817 NV_STATUS
2818 gpuUpdateGfidP2pCapability
2819 (
2820     OBJGPU                                                  *pGpu,
2821     NV2080_CTRL_CMD_GPU_UPDATE_GFID_P2P_CAPABILITY_PARAMS   *pParams
2822 )
2823 {
2824     OBJSYS *pSys = SYS_GET_INSTANCE();
2825     PSRIOV_P2P_INFO pP2PInfo = pGpu->sriovState.pP2PInfo;
2826     NvBool  bSetP2PAccess = NV_FALSE;
2827     NvU32   idx;
2828 
2829     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2830 
2831     if (!gpuIsSriovEnabled(pGpu))
2832         return NV_ERR_NOT_SUPPORTED;
2833 
2834     NV_ASSERT_OR_RETURN(pP2PInfo != NULL, NV_ERR_INVALID_STATE);
2835 
2836     // Ctrl call should only be called by the FM from Host RM
2837     if ((!IS_VIRTUAL(pGpu)) &&
2838         (pSys->getProperty(pSys, PDB_PROP_SYS_FABRIC_IS_EXTERNALLY_MANAGED)))
2839     {
2840         if (pParams->gfid > pGpu->sriovState.maxGfid)
2841         {
2842             NV_PRINTF(LEVEL_ERROR, "Input GFID %d greater than max allowed GFID\n", pParams->gfid);
2843             return NV_ERR_INVALID_ARGUMENT;
2844         }
2845 
2846         for (idx = 0; idx < pGpu->sriovState.maxP2pGfid; idx++)
2847         {
2848             //
2849             // Check if Host RM is already using a GFID for P2P,
2850             // Since only "MAX_NUM_P2P_GFIDS" GFID(s) is(are) allowed to do P2P at any time,
2851             // we should fail here if a GFID greater than supported number is being enabled
2852             //
2853             if (pParams->bEnable)
2854             {
2855                 if (pP2PInfo[idx].gfid == INVALID_P2P_GFID)
2856                 {
2857                     pP2PInfo[idx].gfid = pParams->gfid;
2858                     pGpu->sriovState.p2pFabricPartitionId = pParams->fabricPartitionId;
2859                     bSetP2PAccess = NV_TRUE;
2860                     break;
2861                 }
2862             }
2863             else
2864             {
2865                 if (pP2PInfo[idx].gfid == pParams->gfid)
2866                 {
2867                     pP2PInfo[idx].gfid = INVALID_P2P_GFID;
2868                     pGpu->sriovState.p2pFabricPartitionId = INVALID_FABRIC_PARTITION_ID;
2869                     bSetP2PAccess = NV_TRUE;
2870                     break;
2871                 }
2872             }
2873         }
2874 
2875         if (bSetP2PAccess == NV_TRUE)
2876         {
2877             pP2PInfo[idx].bAllowP2pAccess = pParams->bEnable;
2878         }
2879         else
2880         {
2881             // Some other GFID(s) has already been enabled to do P2P
2882             // Fail the call
2883             return NV_ERR_IN_USE;
2884         }
2885     }
2886     else
2887     {
2888         return NV_ERR_NOT_SUPPORTED;
2889     }
2890 
2891     return NV_OK;
2892 }
2893 
2894 NV_STATUS
2895 subdeviceCtrlCmdUpdateGfidP2pCapability_IMPL
2896 (
2897     Subdevice                                               *pSubdevice,
2898     NV2080_CTRL_CMD_GPU_UPDATE_GFID_P2P_CAPABILITY_PARAMS   *pParams
2899 )
2900 {
2901     return gpuUpdateGfidP2pCapability(GPU_RES_GET_GPU(pSubdevice), pParams);
2902 }
2903 /*
2904  * Set the EGM fabric base address
2905  */
2906 NV_STATUS
2907 subdeviceCtrlCmdGpuSetEgmGpaFabricAddr_IMPL
2908 (
2909     Subdevice *pSubdevice,
2910     NV2080_CTRL_GPU_SET_EGM_GPA_FABRIC_BASE_ADDR_PARAMS *pParams
2911 )
2912 {
2913     return NV_OK;
2914 }
2915 
2916 /*!
2917  * @brief: This command returns the load time (latency) of each engine,
2918  *         implementing NV2080_CTRL_CMD_GPU_GET_ENGINE_LOAD_TIMES control call.
2919  *
2920  * @param[in]   pSubdevice
2921  * @param[in]   pParams
2922  *
2923  * @return
2924  *  NV_OK       Success
2925  */
2926 NV_STATUS
2927 subdeviceCtrlCmdGpuGetEngineLoadTimes_IMPL
2928 (
2929     Subdevice *pSubdevice,
2930     NV2080_CTRL_GPU_GET_ENGINE_LOAD_TIMES_PARAMS *pParams
2931 )
2932 {
2933     OBJGPU        *pGpu              = GPU_RES_GET_GPU(pSubdevice);
2934     PENGDESCRIPTOR engDescriptorList = gpuGetInitEngineDescriptors(pGpu);
2935     NvU32          numEngDescriptors = gpuGetNumEngDescriptors(pGpu);
2936     NvU32          curEngDescIdx;
2937 
2938     NV_ASSERT_OR_RETURN(numEngDescriptors < NV2080_CTRL_GPU_MAX_ENGINE_OBJECTS, NV_ERR_BUFFER_TOO_SMALL);
2939 
2940     pParams->engineCount = numEngDescriptors;
2941     for (curEngDescIdx = 0; curEngDescIdx < numEngDescriptors; curEngDescIdx++)
2942     {
2943         ENGDESCRIPTOR   curEngDescriptor = engDescriptorList[curEngDescIdx];
2944         OBJENGSTATE    *pEngstate        = gpuGetEngstate(pGpu, curEngDescriptor);
2945 
2946         if (pEngstate == NULL)
2947         {
2948             pParams->engineIsInit[curEngDescIdx] = NV_FALSE;
2949             continue;
2950         }
2951 
2952         pParams->engineList[curEngDescIdx]          = pEngstate->engDesc;
2953         pParams->engineStateLoadTime[curEngDescIdx] = pEngstate->stats[ENGSTATE_STATE_LOAD].transitionTimeUs * 1000;
2954         pParams->engineIsInit[curEngDescIdx]        = NV_TRUE;
2955     }
2956 
2957     return NV_OK;
2958 }
2959 
2960 //
2961 // subdeviceCtrlCmdGpuSetFabricAddr
2962 //
2963 // Lock Requirements:
2964 //      Assert that API lock and GPUs lock held on entry
2965 //
2966 NV_STATUS
2967 subdeviceCtrlCmdGpuSetFabricAddr_IMPL
2968 (
2969     Subdevice *pSubdevice,
2970     NV2080_CTRL_GPU_SET_FABRIC_BASE_ADDR_PARAMS *pParams
2971 )
2972 {
2973     OBJGPU       *pGpu         = GPU_RES_GET_GPU(pSubdevice);
2974     NvHandle      hClient      = RES_GET_CLIENT_HANDLE(pSubdevice);
2975     CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
2976 
2977     NV_ASSERT_OR_RETURN(RMCFG_FEATURE_KERNEL_RM, NV_ERR_NOT_SUPPORTED);
2978     NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
2979 
2980     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
2981 
2982     if (!rmclientIsCapableOrAdminByHandle(hClient,
2983                                           NV_RM_CAP_EXT_FABRIC_MGMT,
2984                                           pCallContext->secInfo.privLevel))
2985     {
2986         NV_PRINTF(LEVEL_ERROR, "Non-privileged context issued privileged cmd\n");
2987         return NV_ERR_INSUFFICIENT_PERMISSIONS;
2988     }
2989 
2990     KernelNvlink *pKernelNvlink = GPU_GET_KERNEL_NVLINK(pGpu);
2991 
2992     if (pKernelNvlink == NULL)
2993         return NV_ERR_NOT_SUPPORTED;
2994 
2995     return knvlinkSetUniqueFabricBaseAddress(pGpu, pKernelNvlink, pParams->fabricBaseAddr);
2996 }
2997 
2998 static NvU64
2999 _convertGpuFabricProbeInfoCaps
3000 (
3001     NvU64 fmCaps
3002 )
3003 {
3004     NvU64 fabricCaps = 0;
3005     NvU32 i = 0;
3006 
3007     FOR_EACH_INDEX_IN_MASK(64, i, fmCaps)
3008     {
3009         switch (NVBIT64(i))
3010         {
3011             case NVLINK_INBAND_FM_CAPS_MC_TEAM_SETUP_V1:
3012             case NVLINK_INBAND_FM_CAPS_MC_TEAM_RELEASE_V1:
3013             {
3014                 fabricCaps |= NV2080_CTRL_GPU_FABRIC_PROBE_CAP_MC_SUPPORTED;
3015                 break;
3016             }
3017             case NVLINK_INBAND_FM_CAPS_MC_TEAM_SETUP_V2:
3018             {
3019                 fabricCaps |= NV2080_CTRL_GPU_FABRIC_PROBE_CAP_MC_SUPPORTED;
3020 #ifdef NV2080_CTRL_GPU_FABRIC_PROBE_CAP_MC_MUTLINODE_SUPPORTED
3021                 fabricCaps |=
3022                     NV2080_CTRL_GPU_FABRIC_PROBE_CAP_MC_MUTLINODE_SUPPORTED;
3023 #endif
3024                 break;
3025             }
3026             default:
3027             {
3028                 break;
3029             }
3030         }
3031     }
3032     FOR_EACH_INDEX_IN_MASK_END;
3033 
3034     return fabricCaps;
3035 }
3036 
3037 NV_STATUS
3038 subdeviceCtrlCmdGetGpuFabricProbeInfo_IMPL
3039 (
3040     Subdevice *pSubdevice,
3041     NV2080_CTRL_CMD_GET_GPU_FABRIC_PROBE_INFO_PARAMS *pParams
3042 )
3043 {
3044     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
3045     NV_STATUS status;
3046     NvU64 numProbeReqs = 0;
3047     NvU64 fmCaps = 0;
3048     NvUuid *pClusterUuid = (NvUuid*) pParams->clusterUuid;
3049     NvU32 mask = 0, healthMask = 0;
3050 
3051     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() &&
3052                            rmDeviceGpuLockIsOwner(gpuGetInstance(pGpu)));
3053 
3054     // Probe is not supported - Ex - Direct connected etc.
3055     if (!gpuFabricProbeIsSupported(pGpu))
3056     {
3057         pParams->state = NV2080_CTRL_GPU_FABRIC_PROBE_STATE_UNSUPPORTED;
3058         return NV_OK;
3059     }
3060 
3061     // Probe is not supported - Ex - GPU is degraded etc.
3062     if (pGpu->pGpuFabricProbeInfoKernel == NULL)
3063     {
3064         pParams->state = NV2080_CTRL_GPU_FABRIC_PROBE_STATE_COMPLETE;
3065         pParams->status = NV_ERR_NOT_SUPPORTED; // Due to degradation etc.
3066         return NV_OK;
3067     }
3068 
3069     status = gpuFabricProbeGetNumProbeReqs(pGpu->pGpuFabricProbeInfoKernel,
3070                                            &numProbeReqs);
3071     if (status != NV_OK)
3072     {
3073         NV_PRINTF(LEVEL_ERROR, "Error while retrieving numProbeReqs\n");
3074         return status;
3075     }
3076 
3077     pParams->state = (numProbeReqs == 0) ?
3078                      NV2080_CTRL_GPU_FABRIC_PROBE_STATE_NOT_STARTED :
3079                      NV2080_CTRL_GPU_FABRIC_PROBE_STATE_IN_PROGRESS;
3080 
3081     if (!gpuFabricProbeIsReceived(pGpu->pGpuFabricProbeInfoKernel))
3082     {
3083         return NV_OK;
3084     }
3085 
3086     pParams->state  = NV2080_CTRL_GPU_FABRIC_PROBE_STATE_COMPLETE;
3087     pParams->status = gpuFabricProbeGetFmStatus(pGpu->pGpuFabricProbeInfoKernel);
3088     if (pParams->status != NV_OK)
3089     {
3090         // Nothing needs to be done as probe response status is not success
3091         return NV_OK;
3092     }
3093 
3094     ct_assert(NV2080_GPU_FABRIC_CLUSTER_UUID_LEN == NV_UUID_LEN);
3095 
3096     status = gpuFabricProbeGetClusterUuid(pGpu->pGpuFabricProbeInfoKernel, pClusterUuid);
3097     NV_ASSERT_OK_OR_RETURN(status);
3098 
3099     status = gpuFabricProbeGetFabricPartitionId(pGpu->pGpuFabricProbeInfoKernel,
3100                                                 &pParams->fabricPartitionId);
3101     NV_ASSERT_OK_OR_RETURN(status);
3102 
3103     status = gpuFabricProbeGetfmCaps(pGpu->pGpuFabricProbeInfoKernel, &fmCaps);
3104     NV_ASSERT_OK_OR_RETURN(status);
3105 
3106     pParams->fabricCaps = _convertGpuFabricProbeInfoCaps(fmCaps);
3107 
3108     status = gpuFabricProbeGetFabricCliqueId(pGpu->pGpuFabricProbeInfoKernel,
3109                                              &pParams->fabricCliqueId);
3110     NV_ASSERT_OK_OR_RETURN(status);
3111 
3112     status = gpuFabricProbeGetFabricHealthStatus(pGpu->pGpuFabricProbeInfoKernel,
3113                                                  &mask);
3114     NV_ASSERT_OK_OR_RETURN(status);
3115 
3116     if (FLD_TEST_DRF(LINK, _INBAND_FABRIC_HEALTH_MASK, _DEGRADED_BW, _TRUE, mask))
3117     {
3118         healthMask |= FLD_SET_DRF(2080, _CTRL_GPU_FABRIC_HEALTH_MASK,
3119                                   _DEGRADED_BW, _TRUE, healthMask);
3120     }
3121     else if (FLD_TEST_DRF(LINK, _INBAND_FABRIC_HEALTH_MASK, _DEGRADED_BW,
3122                           _FALSE, mask))
3123     {
3124         healthMask |= FLD_SET_DRF(2080, _CTRL_GPU_FABRIC_HEALTH_MASK,
3125                                   _DEGRADED_BW, _FALSE, healthMask);
3126     }
3127     else if (FLD_TEST_DRF(LINK, _INBAND_FABRIC_HEALTH_MASK, _DEGRADED_BW,
3128                           _NOT_SUPPORTED, mask))
3129     {
3130         healthMask |= FLD_SET_DRF(2080, _CTRL_GPU_FABRIC_HEALTH_MASK,
3131                                   _DEGRADED_BW, _NOT_SUPPORTED, healthMask);
3132     }
3133 
3134     pParams->fabricHealthMask = healthMask;
3135 
3136     return NV_OK;
3137 }
3138 
3139 /*!
3140  * @brief   This command is used to determine which GSP features are
3141  *          supported on this GPU.
3142  *
3143  * @param[in]     pSubdevice
3144  * @param[in,out] pGspFeaturesParams
3145  *
3146  * @return  Returns NV_STATUS
3147  *          NV_OK                     Success
3148  */
3149 NV_STATUS
3150 subdeviceCtrlCmdGspGetFeatures_KERNEL
3151 (
3152     Subdevice *pSubdevice,
3153     NV2080_CTRL_GSP_GET_FEATURES_PARAMS *pGspFeaturesParams
3154 )
3155 {
3156     pGspFeaturesParams->bValid = NV_FALSE;
3157     return NV_OK;
3158 }
3159 
3160 //
3161 // Lock Requirements:
3162 //      Assert that API lock and GPUs lock held on entry
3163 //
3164 NV_STATUS
3165 subdeviceCtrlCmdGpuGetNameString_IMPL
3166 (
3167     Subdevice *pSubdevice,
3168     NV2080_CTRL_GPU_GET_NAME_STRING_PARAMS *pNameStringParams
3169 )
3170 {
3171     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
3172 
3173     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
3174 
3175     return gpuGetNameString(pGpu,
3176                             pNameStringParams->gpuNameStringFlags,
3177                             (void *)&pNameStringParams->gpuNameString);
3178 }
3179 
3180 //
3181 // subdeviceCtrlCmdGpuGetShortNameString
3182 //
3183 // Lock Requirements:
3184 //      Assert that API lock and GPUs lock held on entry
3185 //
3186 NV_STATUS
3187 subdeviceCtrlCmdGpuGetShortNameString_IMPL
3188 (
3189     Subdevice *pSubdevice,
3190     NV2080_CTRL_GPU_GET_SHORT_NAME_STRING_PARAMS *pShortNameStringParams
3191 )
3192 {
3193     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
3194 
3195     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
3196 
3197     return gpuGetShortNameString(pGpu, (void *)&pShortNameStringParams->gpuShortNameString);
3198 }
3199 
3200 //
3201 // subdeviceCtrlCmdGpuGetGidInfo
3202 //
3203 // Lock Requirements:
3204 //      Assert that API lock held on entry
3205 //
3206 NV_STATUS
3207 subdeviceCtrlCmdGpuGetGidInfo_IMPL
3208 (
3209     Subdevice *pSubdevice,
3210     NV2080_CTRL_GPU_GET_GID_INFO_PARAMS *pGidInfoParams
3211 )
3212 {
3213     NV_STATUS rmStatus = NV_OK;
3214     OBJGPU   *pGpu = GPU_RES_GET_GPU(pSubdevice);
3215     NvU8     *pGidString;
3216     NvU32     flags = pGidInfoParams->flags;
3217     NvU32     gidStrlen;
3218 
3219     rmStatus = gpuGetGidInfo(pGpu, &pGidString, &gidStrlen, flags);
3220     if (rmStatus == NV_OK)
3221     {
3222         if (sizeof(pGidInfoParams->data) >= gidStrlen)
3223         {
3224             portMemCopy(pGidInfoParams->data, gidStrlen, pGidString, gidStrlen);
3225             pGidInfoParams->length = gidStrlen;
3226         }
3227         else
3228         {
3229             rmStatus = NV_ERR_INSUFFICIENT_RESOURCES;
3230         }
3231 
3232         portMemFree(pGidString);
3233     }
3234 
3235     return rmStatus;
3236 }
3237 
3238 // Control call to report a nonreplayable fault from UVM
3239 NV_STATUS
3240 subdeviceCtrlCmdGpuReportNonReplayableFault_IMPL
3241 (
3242     Subdevice *pSubdevice,
3243     NV2080_CTRL_GPU_REPORT_NON_REPLAYABLE_FAULT_PARAMS *pParams
3244 )
3245 {
3246     NV_STATUS          status       = NV_OK;
3247     OBJGPU            *pGpu         = GPU_RES_GET_GPU(pSubdevice);
3248     KernelGmmu        *pKernelGmmu  = GPU_GET_KERNEL_GMMU(pGpu);
3249     GMMU_FAULT_PACKET *pFaultPacket = (GMMU_FAULT_PACKET *)(NvUPtr)&pParams->faultPacket.data;
3250 
3251     ct_assert(sizeof(GMMU_FAULT_PACKET) == NV2080_CTRL_GPU_FAULT_PACKET_SIZE);
3252 
3253     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmGpuLockIsOwner());
3254 
3255     status = kgmmuHandleNonReplayableFaultPacket_HAL(pGpu, pKernelGmmu, pFaultPacket);
3256 
3257     return status;
3258 }
3259 
3260 NV_STATUS
3261 subdeviceCtrlCmdGpuGetChipDetails_IMPL
3262 (
3263     Subdevice *pSubdevice,
3264     NV2080_CTRL_GPU_GET_CHIP_DETAILS_PARAMS *pParams
3265 )
3266 {
3267     OBJGPU *pGpu = GPU_RES_GET_GPU(pSubdevice);
3268 
3269     return gpuGetChipDetails(pGpu, pParams);
3270 }
3271 
3272 /*!
3273  * @brief   This Command is used to report if the specified logo illumination attribute
3274  *          is supported
3275  *
3276  * @param[in,out]   pConfigParams
3277  *                  attribute:  The attribute whose support is to be determined.
3278  *                  bSupported: indicator if the specified attribute is supported.
3279  *
3280  * @return  Returns NV_STATUS
3281  *          NV_OK                     Success
3282  *
3283  */
3284 NV_STATUS
3285 subdeviceCtrlCmdGpuQueryIllumSupport_VF
3286 (
3287     Subdevice *pSubdevice,
3288     NV2080_CTRL_CMD_GPU_QUERY_ILLUM_SUPPORT_PARAMS *pConfigParams
3289 )
3290 {
3291     pConfigParams->bSupported = NV_FALSE;
3292 
3293     return NV_OK;
3294 }
3295