1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2012-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "ctrl/ctrla081.h"
25 #include "class/clc637.h" // for AMPERE_SMC_PARTITION_REF
26 #include "virtualization/kernel_hostvgpudeviceapi.h"
27 
28 #include "core/system.h"
29 #include "os/os.h"
30 #include "rmapi/control.h"
31 #include "virtualization/hypervisor/hypervisor.h"
32 #include "virtualization/kernel_vgpu_mgr.h"
33 #include "gpu/device/device.h"
34 #include "vgpu/vgpu_version.h"
35 #include "rmapi/rmapi_utils.h"
36 #include "rmapi/rs_utils.h"
37 #include "gpu/gpu.h"
38 #include "gpu/mem_sys/kern_mem_sys.h"
39 #include "gpu/mem_mgr/mem_mgr.h"
40 #include "gpu/mem_mgr/heap.h"
41 #include "containers/eheap_old.h"
42 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
43 #include "nvdevid.h"
44 #include "nvmisc.h"
45 
46 #define __VGPU_ALIAS_PGPU_LIST__
47 #include "g_vgpu_resman_specific.h" // _get_chip_id_for_alias_pgpu
48 #undef __VGPU_ALIAS_PGPU_LIST__
49 
50 #define MAX_NVU32_TO_CONVERTED_STR_LEN   0x8
51 
52 #define DEVID_ENCODED_VALUE_SIZE          0x4
53 #define SUBDEVID_ENCODED_VALUE_SIZE       0x4
54 #define PGPU_CAP_ENCODED_VALUE_SIZE       0x8
55 
56 #define PGPU_CAP_ECC_ON                  (1 << 0)
57 #define PGPU_CAP_SRIOV_ON                (1 << 1)
58 
59 #define VGPU_LOWER_FB_PROFILE_SIZE_1_GB (1024 * 1024 * 1024)
60 
61 // Mapping of vGPU MIG profiles types to corresponding RM partiotionFlag
62 #define GENERATE_vgpuSmcTypeIdMappings
63 #include "g_vgpu_resman_specific.h"
64 #undef GENERATE_vgpuSmcTypeIdMappings
65 //
66 // ODB functions
67 //
68 
69 NV_STATUS
kvgpumgrConstruct_IMPL(KernelVgpuMgr * pKernelVgpuMgr)70 kvgpumgrConstruct_IMPL(KernelVgpuMgr *pKernelVgpuMgr)
71 {
72     NV_PRINTF(LEVEL_INFO, "Enter function\n");
73 
74     pKernelVgpuMgr->pHeap = NULL;
75 
76     /* Default vGPU version is set to the host supported vGPU version range */
77     pKernelVgpuMgr->user_min_supported_version
78         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
79                                   NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
80     pKernelVgpuMgr->user_max_supported_version
81         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
82                                   NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
83 
84     listInit(&(pKernelVgpuMgr->listVgpuTypeHead), portMemAllocatorGetGlobalNonPaged());
85     listInit(&(pKernelVgpuMgr->listVgpuGuestHead), portMemAllocatorGetGlobalNonPaged());
86     listInit(&(pKernelVgpuMgr->listRequestVgpuHead), portMemAllocatorGetGlobalNonPaged());
87 
88     return NV_OK;
89 }
90 
91 void
kvgpumgrDestruct_IMPL(KernelVgpuMgr * pKernelVgpuMgr)92 kvgpumgrDestruct_IMPL(KernelVgpuMgr *pKernelVgpuMgr)
93 {
94     if (pKernelVgpuMgr->pHeap != NULL)
95     {
96         pKernelVgpuMgr->pHeap->eheapDestruct(pKernelVgpuMgr->pHeap);
97         portMemFree(pKernelVgpuMgr->pHeap);
98     }
99 
100     listDestroy(&(pKernelVgpuMgr->listRequestVgpuHead));
101     listDestroy(&(pKernelVgpuMgr->listVgpuTypeHead));
102     listDestroy(&(pKernelVgpuMgr->listVgpuGuestHead));
103 }
104 
105 //
106 // Get max instance for a vgpu profile.
107 //
108 NV_STATUS
kvgpumgrGetMaxInstanceOfVgpu(NvU32 vgpuTypeId,NvU32 * maxInstanceVgpu)109 kvgpumgrGetMaxInstanceOfVgpu(NvU32 vgpuTypeId, NvU32 *maxInstanceVgpu)
110 {
111     VGPU_TYPE  *vgpuTypeInfo;
112     NV_STATUS   status;
113 
114     if (maxInstanceVgpu == NULL)
115     {
116         return NV_ERR_INVALID_ARGUMENT;
117     }
118 
119     status = kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &vgpuTypeInfo);
120     if (status == NV_OK)
121     {
122         *maxInstanceVgpu = vgpuTypeInfo->maxInstance;
123     }
124 
125     return status;
126 }
127 
128 //
129 // vGPU Manager functions
130 //
131 
132 static NV_STATUS
133 _kvgpumgrGetVgpuTypeIdFromPartitionFlag(NvU32 devId, NvU32 partitionFlag, NvU32 *vgpuTypeId);
134 
135 static NV_STATUS
136 _kvgpumgrClearAssignedSwizzIdMask(OBJGPU *pGpu,
137                                   NvU32 swizzId);
138 
139 static NV_STATUS
140 _kvgpumgrUpdateCreatablePlacementIds(OBJGPU *pGpu, NvU16 placementId,
141                                      NvU32 vgpuTypeId, NvBool isVmBoot);
142 
143 NV_STATUS
kvgpumgrGetPgpuIndex(KernelVgpuMgr * pKernelVgpuMgr,NvU32 gpuPciId,NvU32 * index)144 kvgpumgrGetPgpuIndex(KernelVgpuMgr *pKernelVgpuMgr, NvU32 gpuPciId, NvU32* index)
145 {
146     NvU32 i;
147     for (i = 0; i < NV_ARRAY_ELEMENTS(pKernelVgpuMgr->pgpuInfo); i++)
148     {
149         if ((pKernelVgpuMgr->pgpuInfo[i].gpuPciId == gpuPciId) &&
150             (pKernelVgpuMgr->pgpuInfo[i].isAttached == NV_TRUE))
151         {
152             *index = i;
153             return NV_OK;
154         }
155     }
156     return NV_ERR_OBJECT_NOT_FOUND;
157 }
158 
159 NvBool
kvgpumgrIsHeterogeneousVgpuSupported(void)160 kvgpumgrIsHeterogeneousVgpuSupported(void)
161 {
162     /*This support is currently limited to VMware and KVM*/
163     return (osIsVgpuVfioPresent() == NV_OK);
164 }
165 
166 NvBool
kvgpumgrIsVgpuWarmUpdateSupported(void)167 kvgpumgrIsVgpuWarmUpdateSupported(void)
168 {
169     /*This support is currently limited to VMware and KVM*/
170     return (osIsVgpuVfioPresent() == NV_OK);
171 }
172 
173 NV_STATUS
kvgpumgrSetVgpuType(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPhysGpuInfo,NvU32 vgpuTypeId)174 kvgpumgrSetVgpuType(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPhysGpuInfo, NvU32 vgpuTypeId)
175 {
176     NvU32 i;
177 
178     /*
179      * If heterogeneous timesliced mode is enabled, supportedTypeIds is already
180      * prepared when creatable placementIds array is updated in
181      * _kvgpumgrUpdateCreatablePlacementIds() function
182      */
183     if (pGpu && pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_VGPU_HETEROGENEOUS_MODE))
184         return NV_OK;
185 
186     for (i = 0; i < MAX_VGPU_TYPES_PER_PGPU; i++)
187         pPhysGpuInfo->supportedTypeIds[i] = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
188 
189     if (vgpuTypeId == NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE)
190     {
191         for (i = 0; i < pPhysGpuInfo->numVgpuTypes; i++)
192             pPhysGpuInfo->supportedTypeIds[i] = pPhysGpuInfo->vgpuTypes[i]->vgpuTypeId;
193 
194         return NV_OK;
195     }
196 
197     if (kvgpumgrIsHeterogeneousVgpuSupported())
198     {
199         VGPU_TYPE *vgpuTypeInfo = NULL;
200         NV_STATUS  status       = kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &vgpuTypeInfo);
201         NvU32      numSupported = 0;
202 
203         if (status != NV_OK)
204             return status;
205 
206         NvU64 totalFbAllocation = vgpuTypeInfo->profileSize;
207 
208         for (i = 0; i < pPhysGpuInfo->numVgpuTypes; i++)
209         {
210             if (pPhysGpuInfo->vgpuTypes[i]->profileSize == totalFbAllocation)
211             {
212                 pPhysGpuInfo->supportedTypeIds[numSupported] = pPhysGpuInfo->vgpuTypes[i]->vgpuTypeId;
213                 numSupported++;
214             }
215         }
216     }
217     else
218     {
219         pPhysGpuInfo->supportedTypeIds[0] = vgpuTypeId;
220     }
221 
222     return NV_OK;
223 }
224 
225 static NV_STATUS
_kvgpumgrCheckVgpuTypeSupported(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPhysGpuInfo,VGPU_TYPE * vgpuTypeInfo,NvU32 existingVgpus)226 _kvgpumgrCheckVgpuTypeSupported(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPhysGpuInfo,
227                                 VGPU_TYPE *vgpuTypeInfo, NvU32 existingVgpus)
228 {
229     NvU32 i;
230 
231     if (existingVgpus == 0)
232         return NV_OK;
233 
234     for (i = 0; i < pPhysGpuInfo->numVgpuTypes; i++)
235     {
236         if (pPhysGpuInfo->supportedTypeIds[i] == vgpuTypeInfo->vgpuTypeId)
237             break;
238         if (pPhysGpuInfo->supportedTypeIds[i] == NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE)
239             return NV_ERR_NOT_SUPPORTED;
240     }
241 
242     /*
243      * In heterogeneous vGPU mode, creatable vGPU type is not dependent on a vGPU types
244      * maxInstance. If the type is present in supportedTypeIds (populated based on placementIds),
245      * it should suffice
246      */
247     if (!pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_VGPU_HETEROGENEOUS_MODE))
248     {
249         if (existingVgpus >= vgpuTypeInfo->maxInstance)
250             return NV_ERR_INSUFFICIENT_RESOURCES;
251     }
252 
253     return NV_OK;
254 }
255 
256 NV_STATUS
kvgpumgrCheckVgpuTypeCreatable(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPhysGpuInfo,VGPU_TYPE * vgpuTypeInfo)257 kvgpumgrCheckVgpuTypeCreatable(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPhysGpuInfo, VGPU_TYPE *vgpuTypeInfo)
258 {
259     if (osIsVgpuVfioPresent() == NV_OK)
260         return _kvgpumgrCheckVgpuTypeSupported(pGpu, pPhysGpuInfo, vgpuTypeInfo, pPhysGpuInfo->numCreatedVgpu);
261     else
262         return _kvgpumgrCheckVgpuTypeSupported(pGpu, pPhysGpuInfo, vgpuTypeInfo, pPhysGpuInfo->numActiveVgpu);
263 }
264 
265 static NV_STATUS
_kvgpumgrCheckVgpuTypeActivatable(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPhysGpuInfo,VGPU_TYPE * vgpuTypeInfo)266 _kvgpumgrCheckVgpuTypeActivatable(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPhysGpuInfo, VGPU_TYPE *vgpuTypeInfo)
267 {
268     return _kvgpumgrCheckVgpuTypeSupported(pGpu, pPhysGpuInfo, vgpuTypeInfo, pPhysGpuInfo->numActiveVgpu);
269 }
270 
271 NV_STATUS
kvgpumgrGetCreatableVgpuTypes(OBJGPU * pGpu,KernelVgpuMgr * pKernelVgpuMgr,NvU32 pgpuIndex,NvU32 * numVgpuTypes,NvU32 * vgpuTypes)272 kvgpumgrGetCreatableVgpuTypes(OBJGPU *pGpu, KernelVgpuMgr *pKernelVgpuMgr, NvU32 pgpuIndex, NvU32* numVgpuTypes, NvU32* vgpuTypes)
273 {
274     NvU32 i                        = 0;
275     KERNEL_PHYS_GPU_INFO *pgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
276 
277     if (IS_MIG_ENABLED(pGpu))
278     {
279         if (IS_MIG_IN_USE(pGpu))
280         {
281             KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
282             NvU64 swizzIdInUseMask = 0;
283             NvU32 id;
284 
285             swizzIdInUseMask = kmigmgrGetSwizzIdInUseMask(pGpu, pKernelMIGManager);
286 
287             i = 0;
288             FOR_EACH_INDEX_IN_MASK(64, id, swizzIdInUseMask)
289             {
290                 KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
291                 NvU32 vgpuTypeId      = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
292                 NvU32 j, mask         = 0;
293 
294                 mask = NVBIT64(id);
295                 NV_ASSERT_OK_OR_RETURN(kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, id, &pKernelMIGGpuInstance));
296 
297                 // Do not consider vGPU type as creatable if swizzId is already in use
298                 if (!(mask & pgpuInfo->assignedSwizzIdMask))
299                 {
300                     // Find the vGPU type corresponding to the partitionFlag,
301                     NV_ASSERT_OK_OR_RETURN(
302                             _kvgpumgrGetVgpuTypeIdFromPartitionFlag(pGpu->idInfo.PCIDeviceID,
303                                                                    pKernelMIGGpuInstance->partitionFlag,
304                                                                    &vgpuTypeId));
305 
306                     // Check if we have already included this vGPU type ID.
307                     // If not, then add vgpuTypeID to out vgpuTypes array.
308                     if (vgpuTypeId != NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE)
309                     {
310                         for(j = 0; j < i; j++)
311                         {
312                             if (vgpuTypes[j] == vgpuTypeId)
313                             {
314                                 break;
315                             }
316                         }
317 
318                         // vgpuTypeId not included in vgputypes array yet, include it.
319                         if (j == i)
320                         {
321                             vgpuTypes[i] = vgpuTypeId;
322                             i++;
323                         }
324                     }
325                 }
326             }
327             FOR_EACH_INDEX_IN_MASK_END;
328             *numVgpuTypes = i;
329         }
330         else
331         {
332             // No GPU instances created, none of the profiles are creatable.
333             *numVgpuTypes = 0;
334         }
335     }
336     else
337     {
338         *numVgpuTypes = 0;
339         for (i = 0; i < pgpuInfo->numVgpuTypes; i++)
340         {
341             // Consider only non-MIG (gpuInstanceSize == 0) profiles
342             if (!pgpuInfo->vgpuTypes[i]->gpuInstanceSize &&
343                 (kvgpumgrCheckVgpuTypeCreatable(pGpu, pgpuInfo, pgpuInfo->vgpuTypes[i]) == NV_OK))
344             {
345                 vgpuTypes[*numVgpuTypes] = pgpuInfo->vgpuTypes[i]->vgpuTypeId;
346                 (*numVgpuTypes)++;
347             }
348         }
349     }
350 
351     return NV_OK;
352 }
353 
354 static NV_STATUS
_kvgpumgrCreateVgpuType(NVA081_CTRL_VGPU_INFO * pVgpuInfo,VGPU_TYPE ** ppVgpuType)355 _kvgpumgrCreateVgpuType(NVA081_CTRL_VGPU_INFO *pVgpuInfo, VGPU_TYPE **ppVgpuType)
356 {
357     OBJSYS *pSys = SYS_GET_INSTANCE();
358     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
359     VGPU_TYPE *pVgpuTypeNode;
360 
361     pVgpuTypeNode = listAppendNew(&(pKernelVgpuMgr->listVgpuTypeHead));
362     if (pVgpuTypeNode == NULL)
363         return NV_ERR_NO_MEMORY;
364 
365     vgpuMgrFillVgpuType(pVgpuInfo, pVgpuTypeNode);
366 
367     *ppVgpuType = pVgpuTypeNode;
368 
369     return NV_OK;
370 }
371 
372 NV_STATUS
kvgpumgrGetVgpuTypeInfo(NvU32 vgpuTypeId,VGPU_TYPE ** vgpuType)373 kvgpumgrGetVgpuTypeInfo(NvU32 vgpuTypeId, VGPU_TYPE **vgpuType)
374 {
375     OBJSYS *pSys = SYS_GET_INSTANCE();
376     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
377     VGPU_TYPE *pVgpuTypeNode;
378 
379     for (pVgpuTypeNode = listHead(&(pKernelVgpuMgr->listVgpuTypeHead));
380          pVgpuTypeNode != NULL;
381          pVgpuTypeNode = listNext(&(pKernelVgpuMgr->listVgpuTypeHead), pVgpuTypeNode))
382     {
383         if (vgpuTypeId == pVgpuTypeNode->vgpuTypeId)
384         {
385             *vgpuType = pVgpuTypeNode;
386             return NV_OK;
387         }
388     }
389     return NV_ERR_OBJECT_NOT_FOUND;
390 }
391 
392 static void
kvgpumgrCopyFromVgpuTypeToVgpuInfo(NVA081_CTRL_VGPU_INFO * pVgpuInfo,VGPU_TYPE * pVgpuType)393 kvgpumgrCopyFromVgpuTypeToVgpuInfo(NVA081_CTRL_VGPU_INFO *pVgpuInfo, VGPU_TYPE *pVgpuType)
394 {
395     pVgpuInfo->vgpuType                 = pVgpuType->vgpuTypeId;
396     pVgpuInfo->maxInstance              = pVgpuType->maxInstance;
397     pVgpuInfo->numHeads                 = pVgpuType->numHeads;
398     pVgpuInfo->maxResolutionX           = pVgpuType->maxResolutionX;
399     pVgpuInfo->maxResolutionY           = pVgpuType->maxResolutionY;
400     pVgpuInfo->maxPixels                = pVgpuType->maxPixels;
401     pVgpuInfo->frlConfig                = pVgpuType->frlConfig;
402     pVgpuInfo->cudaEnabled              = pVgpuType->cudaEnabled;
403     pVgpuInfo->eccSupported             = pVgpuType->eccSupported;
404     pVgpuInfo->gpuInstanceSize          = pVgpuType->gpuInstanceSize;
405     pVgpuInfo->multiVgpuSupported       = pVgpuType->multiVgpuSupported;
406     pVgpuInfo->vdevId                   = pVgpuType->vdevId;
407     pVgpuInfo->pdevId                   = pVgpuType->pdevId;
408     pVgpuInfo->profileSize              = pVgpuType->profileSize;
409     pVgpuInfo->fbLength                 = pVgpuType->fbLength;
410     pVgpuInfo->gspHeapSize              = pVgpuType->gspHeapSize;
411     pVgpuInfo->fbReservation            = pVgpuType->fbReservation;
412     pVgpuInfo->mappableVideoSize        = pVgpuType->mappableVideoSize;
413     pVgpuInfo->encoderCapacity          = pVgpuType->encoderCapacity;
414     pVgpuInfo->bar1Length               = pVgpuType->bar1Length;
415     pVgpuInfo->gpuDirectSupported       = pVgpuType->gpuDirectSupported;
416     pVgpuInfo->nvlinkP2PSupported       = pVgpuType->nvlinkP2PSupported;
417     pVgpuInfo->multiVgpuExclusive       = pVgpuType->multiVgpuExclusive;
418     pVgpuInfo->frlEnable                = pVgpuType->frlEnable;
419 
420     portStringCopy(
421         (char *) pVgpuInfo->vgpuName, sizeof(pVgpuInfo->vgpuName),
422         (char *) pVgpuType->vgpuName, sizeof(pVgpuType->vgpuName));
423     portStringCopy(
424         (char *) pVgpuInfo->vgpuClass, sizeof(pVgpuInfo->vgpuClass),
425         (char *) pVgpuType->vgpuClass, sizeof(pVgpuType->vgpuClass));
426     portStringCopy(
427         (char *) pVgpuInfo->license, sizeof(pVgpuInfo->license),
428         (char *) pVgpuType->license, sizeof(pVgpuType->license));
429     portStringCopy(
430         (char *) pVgpuInfo->vgpuExtraParams, sizeof(pVgpuInfo->vgpuExtraParams),
431         (char *) pVgpuType->vgpuExtraParams, sizeof(pVgpuType->vgpuExtraParams));
432     portMemCopy(
433         (char *) pVgpuInfo->vgpuSignature, sizeof(pVgpuInfo->vgpuSignature),
434         (char *) pVgpuType->vgpuSignature, sizeof(pVgpuType->vgpuSignature));
435 }
436 
437 NV_STATUS
kvgpumgrSendAllVgpuTypesToGsp(OBJGPU * pGpu)438 kvgpumgrSendAllVgpuTypesToGsp(OBJGPU *pGpu)
439 {
440     NV_STATUS             rmStatus       = NV_OK;
441     OBJSYS               *pSys           = SYS_GET_INSTANCE();
442     KernelVgpuMgr        *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
443     RM_API               *pRmApi         = GPU_GET_PHYSICAL_RMAPI(pGpu);
444     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
445     NV2080_CTRL_VGPU_MGR_INTERNAL_PGPU_ADD_VGPU_TYPE_PARAMS *pAddVgpuTypeParams;
446     NvU32                 index, i;
447 
448     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
449             kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &index));
450 
451     pPgpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
452 
453     // Early exit if no vgpu types found
454     if (pPgpuInfo->numVgpuTypes == 0)
455     {
456         return NV_OK;
457     }
458 
459     pAddVgpuTypeParams = portMemAllocNonPaged(sizeof(*pAddVgpuTypeParams));
460     if (pAddVgpuTypeParams == NULL)
461     {
462         NV_PRINTF(LEVEL_ERROR, "Failed to alloc memory for add vGPU type params\n");
463         return NV_ERR_NO_MEMORY;
464     }
465 
466     portMemSet(pAddVgpuTypeParams, 0, sizeof(*pAddVgpuTypeParams));
467 
468     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
469     {
470         kvgpumgrCopyFromVgpuTypeToVgpuInfo(&pAddVgpuTypeParams->vgpuInfo[i],
471                                            pPgpuInfo->vgpuTypes[i]);
472     }
473 
474     pAddVgpuTypeParams->discardVgpuTypes = NV_TRUE;
475     pAddVgpuTypeParams->vgpuInfoCount = pPgpuInfo->numVgpuTypes;
476 
477     NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_ERROR,
478             pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
479                             NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_PGPU_ADD_VGPU_TYPE,
480                             pAddVgpuTypeParams, sizeof(*pAddVgpuTypeParams)),
481             kvgpumgrSendAllVgpuTypesToGsp_exit);
482 
483 kvgpumgrSendAllVgpuTypesToGsp_exit:
484     portMemFree(pAddVgpuTypeParams);
485     return rmStatus;
486 }
487 
488 NV_STATUS
kvgpumgrPgpuAddVgpuType(OBJGPU * pGpu,NvBool discardVgpuTypes,NVA081_CTRL_VGPU_INFO * pVgpuInfo)489 kvgpumgrPgpuAddVgpuType
490 (
491     OBJGPU *pGpu,
492     NvBool discardVgpuTypes,
493     NVA081_CTRL_VGPU_INFO *pVgpuInfo
494 )
495 {
496     NV_STATUS rmStatus = NV_OK;
497     NvU32 index;
498     OBJSYS *pSys = SYS_GET_INSTANCE();
499     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
500     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
501     VGPU_TYPE *pVgpuTypeInfo;
502     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
503     NV2080_CTRL_VGPU_MGR_INTERNAL_PGPU_ADD_VGPU_TYPE_PARAMS *pAddVgpuTypeParams;
504 
505     // TODO: Eliminate the heap allocation here
506     // NV2080_CTRL_VGPU_MGR_INTERNAL_PGPU_ADD_VGPU_TYPE_PARAMS has massive size
507     // because it has an embedded struct VGPU_TYPE instead of a pointer.
508     // FINN won't be able to figure out serialization for a pointer at this moment.
509     pAddVgpuTypeParams = portMemAllocNonPaged(sizeof(*pAddVgpuTypeParams));
510     if (pAddVgpuTypeParams == NULL)
511     {
512         NV_PRINTF(LEVEL_ERROR, "Failed to alloc add vGPU type ctrl params.\n");
513         return NV_ERR_NO_MEMORY;
514     }
515     portMemSet(pAddVgpuTypeParams, 0, sizeof(*pAddVgpuTypeParams));
516 
517     pAddVgpuTypeParams->discardVgpuTypes = discardVgpuTypes;
518     pAddVgpuTypeParams->vgpuInfoCount = 1;
519     pAddVgpuTypeParams->vgpuInfo[0] = *pVgpuInfo;
520 
521     rmStatus = pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
522                                NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_PGPU_ADD_VGPU_TYPE,
523                                pAddVgpuTypeParams, sizeof(*pAddVgpuTypeParams));
524 
525     portMemFree(pAddVgpuTypeParams);
526 
527     if (rmStatus != NV_OK)
528     {
529         NV_PRINTF(LEVEL_ERROR, "Failed to create vGPU type on GSP.\n");
530         return rmStatus;
531     }
532 
533     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &index) != NV_OK)
534     {
535         return NV_ERR_OBJECT_NOT_FOUND;
536     }
537 
538     pPgpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
539 
540     if (pPgpuInfo->numVgpuTypes == NVA081_MAX_VGPU_TYPES_PER_PGPU && !discardVgpuTypes)
541     {
542         return NV_ERR_NOT_SUPPORTED;
543     }
544 
545     // TODO: This is a WAR. Need to do this change in VGPUD.
546      if (pPgpuInfo->fractionalMultiVgpu == 0 && pVgpuInfo->maxInstance != 1)
547     {
548         pVgpuInfo->multiVgpuSupported = 0;
549     }
550 
551     rmStatus = kvgpumgrGetVgpuTypeInfo(pVgpuInfo->vgpuType, &pVgpuTypeInfo);
552     if (rmStatus == NV_ERR_OBJECT_NOT_FOUND)
553     {
554         rmStatus = _kvgpumgrCreateVgpuType(pVgpuInfo, &pVgpuTypeInfo);
555         if (rmStatus != NV_OK)
556         {
557             NV_PRINTF(LEVEL_ERROR, "Failed to create vGPU type.\n");
558             return rmStatus;
559         }
560     }
561     else if (rmStatus != NV_OK)
562     {
563         NV_PRINTF(LEVEL_ERROR, "Failed to get vGPU type.\n");
564         return rmStatus;
565     }
566 
567     if (discardVgpuTypes)
568     {
569         pPgpuInfo->numVgpuTypes = 0;
570     }
571 
572     if (pPgpuInfo->numVgpuTypes == 0)
573     {
574         pPgpuInfo->sriovEnabled = gpuIsSriovEnabled(pGpu);
575     }
576 
577     pPgpuInfo->vgpuTypes[pPgpuInfo->numVgpuTypes] = pVgpuTypeInfo;
578     pPgpuInfo->numVgpuTypes++;
579 
580     return NV_OK;
581 }
582 
583 NV_STATUS
kvgpumgrAttachGpu(NvU32 gpuPciId)584 kvgpumgrAttachGpu(NvU32 gpuPciId)
585 {
586     NvU32 index;
587     OBJSYS *pSys = SYS_GET_INSTANCE();
588     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
589     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
590 
591     NV_PRINTF(LEVEL_INFO, "Enter function\n");
592 
593     NV_ASSERT_OR_RETURN((pKernelVgpuMgr != NULL), NV_ERR_NOT_SUPPORTED);
594 
595     index = 0;
596     while ((index < pKernelVgpuMgr->pgpuCount) &&
597            ((pKernelVgpuMgr->pgpuInfo[index].isAttached == NV_TRUE) ||
598            (pKernelVgpuMgr->pgpuInfo[index].gpuPciId != gpuPciId)))
599     {
600         index++;
601     }
602     NV_ASSERT_OR_RETURN((index != NV_MAX_DEVICES), NV_ERR_INSUFFICIENT_RESOURCES);
603 
604     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
605 
606     /* Probe call, RmInit is not done yet, so send pGpu as NULL */
607     kvgpumgrSetVgpuType(NULL, pPhysGpuInfo, NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE);
608     pPhysGpuInfo->numActiveVgpu    = 0;
609     pPhysGpuInfo->isAttached       = NV_TRUE;
610     pPhysGpuInfo->numCreatedVgpu   = 0;
611 
612     listInit(&(pKernelVgpuMgr->pgpuInfo[index].listVgpuConfigEventsHead), portMemAllocatorGetGlobalNonPaged());
613     listInit(&(pKernelVgpuMgr->pgpuInfo[index].listHostVgpuDeviceHead), portMemAllocatorGetGlobalNonPaged());
614 
615     if (index == pKernelVgpuMgr->pgpuCount)
616     {
617         pPhysGpuInfo->gpuPciId     = gpuPciId;
618         pPhysGpuInfo->numVgpuTypes = 0;
619         pPhysGpuInfo->vgpuConfigState = NVA081_CTRL_VGPU_CONFIG_STATE_UNINITIALIZED;
620         pKernelVgpuMgr->pgpuCount++;
621     }
622 
623     return NV_OK;
624 }
625 
626 NV_STATUS
kvgpumgrDetachGpu(NvU32 gpuPciId)627 kvgpumgrDetachGpu(NvU32 gpuPciId)
628 {
629     NvU32 i;
630     OBJSYS *pSys = SYS_GET_INSTANCE();
631     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
632     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
633     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL, *pRequestVgpuNext = NULL;
634 
635     NV_PRINTF(LEVEL_INFO, "Enter function\n");
636 
637     NV_ASSERT_OR_RETURN((pKernelVgpuMgr != NULL), NV_ERR_NOT_SUPPORTED);
638 
639     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &i) != NV_OK)
640         return NV_ERR_OBJECT_NOT_FOUND;
641 
642     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
643 
644     pPhysGpuInfo->createdVfMask = 0;
645     pPhysGpuInfo->assignedSwizzIdMask = 0;
646     pPhysGpuInfo->isAttached = NV_FALSE;
647     pPhysGpuInfo->numCreatedVgpu = 0;
648 
649     for (i = 0; i < MAX_VGPU_TYPES_PER_PGPU; i++)
650         pPhysGpuInfo->supportedTypeIds[i] = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
651 
652     if (listCount(&(pKernelVgpuMgr->listRequestVgpuHead)) > 0)
653     {
654         for (pRequestVgpu = listHead(&(pKernelVgpuMgr->listRequestVgpuHead));
655              pRequestVgpu != NULL;
656              pRequestVgpu = pRequestVgpuNext)
657         {
658             pRequestVgpuNext = listNext(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
659             if (pRequestVgpu->gpuPciId == gpuPciId)
660             {
661                 pKernelVgpuMgr->pHeap->eheapFree(pKernelVgpuMgr->pHeap, pRequestVgpu->vgpuId);
662                 listRemove(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
663             }
664         }
665     }
666 
667     listDestroy(&(pPhysGpuInfo->listHostVgpuDeviceHead));
668 
669     return NV_OK;
670 }
671 
672 /*
673  * @brief Sets Guest(VM) ID for the requested hostvgpudevice
674  *
675  * @param pParams               SET_GUEST_ID_PARAMS Pointer
676  * @param pKernelHostVgpuDevice Device for which Vm ID need to be set
677  * @param pGpu                  OBJGPU pointer
678  *
679  * @return NV_STATUS
680  */
681 NV_STATUS
kvgpumgrRegisterGuestId(SET_GUEST_ID_PARAMS * pParams,KERNEL_HOST_VGPU_DEVICE * pKernelHostVgpuDevice,OBJGPU * pGpu)682 kvgpumgrRegisterGuestId(SET_GUEST_ID_PARAMS *pParams,
683                         KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice, OBJGPU *pGpu)
684 {
685     NV_STATUS rmStatus = NV_OK;
686     OBJSYS *pSys = SYS_GET_INSTANCE();
687     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
688 
689     if (pParams->action  == SET_GUEST_ID_ACTION_SET)
690     {
691         KERNEL_VGPU_GUEST *pVgpuGuest = NULL;
692 
693         for (pVgpuGuest = listHead(&(pKernelVgpuMgr->listVgpuGuestHead));
694              pVgpuGuest != NULL;
695              pVgpuGuest = listNext(&(pKernelVgpuMgr->listVgpuGuestHead), pVgpuGuest))
696         {
697             if (pParams->vmIdType == pVgpuGuest->guestVmInfo.vmIdType)
698             {
699                 if (pParams->vmIdType == VM_ID_DOMAIN_ID)
700                 {
701                     if (pParams->guestVmId.vmId == pVgpuGuest->guestVmInfo.guestVmId.vmId)
702                     {
703                         break;
704                     }
705                 }
706                 else if (pParams->vmIdType == VM_ID_UUID)
707                 {
708                     if (!portMemCmp(pParams->guestVmId.vmUuid,
709                                   pVgpuGuest->guestVmInfo.guestVmId.vmUuid,
710                                   VM_UUID_SIZE))
711                     {
712                         break;
713                     }
714                 }
715                 else
716                     return NV_ERR_INVALID_ARGUMENT;
717             }
718         }
719 
720         if (pVgpuGuest == NULL)
721         {
722             pVgpuGuest = listAppendNew(&(pKernelVgpuMgr->listVgpuGuestHead));
723             if (pVgpuGuest == NULL)
724                 return NV_ERR_NO_MEMORY;
725 
726             portMemSet(pVgpuGuest, 0, sizeof(KERNEL_VGPU_GUEST));
727         }
728 
729         NV_ASSERT_OR_RETURN(pVgpuGuest->numVgpuDevices != MAX_VGPU_DEVICES_PER_VM,
730                             NV_ERR_INSUFFICIENT_RESOURCES);
731 
732         pVgpuGuest->numVgpuDevices++;
733 
734         pKernelHostVgpuDevice->vgpuGuest = pVgpuGuest;
735 
736         pVgpuGuest->guestVmInfo.vmIdType = pParams->vmIdType;
737 
738         if (pParams->vmIdType == VM_ID_DOMAIN_ID)
739         {
740             pVgpuGuest->guestVmInfo.guestVmId.vmId = pParams->guestVmId.vmId;
741         }
742         else if (pParams->vmIdType == VM_ID_UUID)
743         {
744             portMemCopy(pVgpuGuest->guestVmInfo.guestVmId.vmUuid,
745                         VM_UUID_SIZE,
746                         pParams->guestVmId.vmUuid,
747                         VM_UUID_SIZE);
748         }
749     }
750     else if (pParams->action == SET_GUEST_ID_ACTION_UNSET)
751     {
752         KERNEL_VGPU_GUEST *pVgpuGuest = pKernelHostVgpuDevice->vgpuGuest;
753 
754         if (pVgpuGuest)
755         {
756             pVgpuGuest->numVgpuDevices--;
757             if (pVgpuGuest->numVgpuDevices == 0)
758             {
759                 listRemove(&(pKernelVgpuMgr->listVgpuGuestHead), pVgpuGuest);
760             }
761             pKernelHostVgpuDevice->vgpuGuest = NULL;
762         }
763         else
764         {
765             return NV_WARN_NULL_OBJECT;
766         }
767     }
768     else
769     {
770         return NV_ERR_INVALID_ARGUMENT;
771     }
772 
773     return rmStatus;
774 }
775 
776 static NV_STATUS
_kvgpumgrVgpuAllocGPUInstanceSubscription(OBJGPU * pGpu,NvU32 * phClient,NvU32 * phDevice,NvU32 swizzId)777 _kvgpumgrVgpuAllocGPUInstanceSubscription
778 (
779     OBJGPU *pGpu,
780     NvU32 *phClient,
781     NvU32 *phDevice,
782     NvU32 swizzId
783 )
784 {
785     NV_STATUS rmStatus;
786     NVC637_ALLOCATION_PARAMETERS nvC637AllocParams;
787     NvU32 hSubDevice;
788     NvU32 hGPUInstanceSubscription;
789     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
790 
791     NV_ASSERT_OR_RETURN(phClient != NULL, NV_ERR_INVALID_ARGUMENT);
792     NV_ASSERT_OR_RETURN(phDevice != NULL, NV_ERR_INVALID_ARGUMENT);
793 
794     NV_ASSERT_OK_OR_RETURN(
795         rmapiutilAllocClientAndDeviceHandles(pRmApi, pGpu, phClient, phDevice, &hSubDevice));
796 
797     // Allocate GPUInstanceSubscription handle
798     NV_ASSERT_OK_OR_GOTO(
799         rmStatus,
800         serverutilGenResourceHandle(*phClient, &hGPUInstanceSubscription),
801         cleanup);
802     portMemSet(&nvC637AllocParams, 0, sizeof(nvC637AllocParams));
803     nvC637AllocParams.swizzId = swizzId;
804 
805     // Allocate GPUInstanceSubscription object
806     NV_CHECK_OK_OR_GOTO(
807         rmStatus,
808         LEVEL_ERROR,
809         pRmApi->AllocWithHandle(pRmApi,
810                                 *phClient,
811                                 hSubDevice,
812                                 hGPUInstanceSubscription,
813                                 AMPERE_SMC_PARTITION_REF,
814                                 &nvC637AllocParams,
815                                 sizeof(nvC637AllocParams)),
816         cleanup);
817 
818     return rmStatus;
819 
820 cleanup:
821     pRmApi->Free(pRmApi, *phClient, *phClient);
822     return rmStatus;
823 }
824 
825 NV_STATUS
kvgpumgrHeterogeneousGetChidOffset(NvU32 vgpuTypeId,NvU16 placementId,NvU32 numChannels,NvU64 * pChidOffset)826 kvgpumgrHeterogeneousGetChidOffset(NvU32 vgpuTypeId, NvU16 placementId,
827                                    NvU32 numChannels, NvU64 *pChidOffset)
828 {
829     VGPU_TYPE *pVgpuTypeInfo = NULL;
830     NV_STATUS status;
831     NvU32 i;
832 
833     if ((status = kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &pVgpuTypeInfo)) != NV_OK)
834         return status;
835 
836     if (placementId == NVA081_PLACEMENT_ID_INVALID)
837         return NV_ERR_INVALID_ARGUMENT;
838 
839     /* Channel count provided by plugin and calculated by RM should be same */
840     if (numChannels != pVgpuTypeInfo->channelCount)
841         return NV_ERR_INVALID_STATE;
842 
843     if (pVgpuTypeInfo->placementCount > MAX_VGPU_DEVICES_PER_PGPU)
844         return NV_ERR_INVALID_INDEX;
845 
846     for (i = 0; i < pVgpuTypeInfo->placementCount; i++)
847     {
848         /*
849          * For the placementId of the vGPU instance, find the corresponding
850          * channel offset. supportedPlacementIds and supportedChidOffsets
851          * share the same array index for a give placement ID.
852          */
853         if (placementId == pVgpuTypeInfo->supportedPlacementIds[i])
854         {
855             *pChidOffset = pVgpuTypeInfo->supportedChidOffsets[i];
856             return NV_OK;
857         }
858     }
859 
860     return NV_ERR_OBJECT_NOT_FOUND;
861 }
862 
863 
864 NV_STATUS
kvgpumgrGuestRegister(OBJGPU * pGpu,NvU32 gfid,NvU32 vgpuType,NvU32 vmPid,VM_ID_TYPE vmIdType,VM_ID guestVmId,NvHandle hPluginFBAllocationClient,NvU32 numChannels,NvU32 numPluginChannels,NvU32 swizzId,NvU32 vgpuDeviceInstanceId,NvBool bDisableDefaultSmcExecPartRestore,NvU16 placementId,NvU8 * pVgpuDevName,KERNEL_HOST_VGPU_DEVICE ** ppKernelHostVgpuDevice)865 kvgpumgrGuestRegister(OBJGPU *pGpu,
866                       NvU32 gfid,
867                       NvU32 vgpuType,
868                       NvU32 vmPid,
869                       VM_ID_TYPE vmIdType,
870                       VM_ID guestVmId,
871                       NvHandle hPluginFBAllocationClient,
872                       NvU32 numChannels,
873                       NvU32 numPluginChannels,
874                       NvU32 swizzId,
875                       NvU32 vgpuDeviceInstanceId,
876                       NvBool bDisableDefaultSmcExecPartRestore,
877                       NvU16 placementId,
878                       NvU8 *pVgpuDevName,
879                       KERNEL_HOST_VGPU_DEVICE **ppKernelHostVgpuDevice)
880 {
881     NV_STATUS                rmStatus                   = NV_OK;
882     OBJSYS                  *pSys                       = SYS_GET_INSTANCE();
883     KernelVgpuMgr           *pKernelVgpuMgr             = SYS_GET_KERNEL_VGPUMGR(pSys);
884     SET_GUEST_ID_PARAMS      setGuestIDParams           = {0};
885     NvU32                    i;
886     KERNEL_PHYS_GPU_INFO    *pPhysGpuInfo;
887     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice      = NULL;
888     NvBool                   bMIGInUse                  = IS_MIG_IN_USE(pGpu);
889 
890     NvU32                    j;
891     NvU32                    vgpuTypeId                 = 0;
892     REQUEST_VGPU_INFO_NODE  *pRequestVgpu               = NULL;
893 
894     NV_PRINTF(LEVEL_INFO, "Enter function\n");
895 
896     if (numPluginChannels > VGPU_MAX_PLUGIN_CHANNELS)
897     {
898         NV_PRINTF(LEVEL_ERROR, "failed, wrong number of plugin channels\n");
899         return NV_ERR_INVALID_PARAMETER;
900     }
901 
902     if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_VIRTUALIZATION_MODE_HOST_VSGA))
903     {
904         NV_PRINTF(LEVEL_ERROR, "GPU is previously set in vSGA mode!\n");
905         return NV_ERR_INVALID_DEVICE;
906     }
907 
908     if (gpuIsSriovEnabled(pGpu))
909     {
910         GFID_ALLOC_STATUS gfidState;
911         NV_ASSERT_OK_OR_RETURN(gpuGetGfidState(pGpu, gfid, &gfidState));
912         NV_ASSERT_OR_RETURN((gfidState == GFID_FREE), NV_ERR_INSUFFICIENT_RESOURCES);
913     }
914     else
915     {
916         // MIG is supported only with SRIOV. Legacy mode doesn't support MIG
917         NV_ASSERT_OR_RETURN(!bMIGInUse, NV_ERR_INVALID_STATE);
918         numPluginChannels = 0;
919     }
920 
921     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
922         return NV_ERR_OBJECT_NOT_FOUND;
923 
924     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
925 
926     // check if this vgpu type is allowed on physical gpu
927     for (j = 0; j < pPhysGpuInfo->numVgpuTypes; j++)
928     {
929         if (vgpuType == pPhysGpuInfo->vgpuTypes[j]->vgpuTypeId)
930         {
931             vgpuTypeId = j;
932             break;
933         }
934     }
935 
936     if (j == pPhysGpuInfo->numVgpuTypes)
937     {
938         return NV_ERR_NOT_SUPPORTED;
939     }
940 
941     // On KVM, store a link to the corresponding REQUEST_VGPU_INFO_NODE in
942     // KERNEL_HOST_VGPU_DEVICE and vice versa, so as to create a mapping between
943     // vGPU device and the corresponding mdev device.
944     if (osIsVgpuVfioPresent() == NV_OK)
945     {
946         for (pRequestVgpu = listHead(&pKernelVgpuMgr->listRequestVgpuHead);
947              pRequestVgpu != NULL;
948              pRequestVgpu = listNext(&pKernelVgpuMgr->listRequestVgpuHead, pRequestVgpu))
949         {
950             if (portMemCmp(pRequestVgpu->mdevUuid, pVgpuDevName, VM_UUID_SIZE) == 0)
951                 break;
952         }
953 
954         if (pRequestVgpu == NULL)
955         {
956             return NV_ERR_OBJECT_NOT_FOUND;
957         }
958     }
959 
960     /*
961      * For MIG mode, vGPU type is already validated based on swizzid in
962      * NVA081_CTRL_CMD_VGPU_CONFIG_[GET_FREE|VALIDATE]_SWIZZID RmCtrl.
963      * For heterogeneous vGPU mode, vGPU type is already validated based on placement ID
964      * in NVA081_CTRL_CMD_VGPU_CONFIG_UPDATE_HETEROGENEOUS_INFO RmCtrl.
965      * Both the RmCtrls are done before allocating the A084 object.
966      */
967     if (!IS_MIG_ENABLED(pGpu) && !pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_VGPU_HETEROGENEOUS_MODE))
968     {
969         rmStatus = _kvgpumgrCheckVgpuTypeActivatable(pGpu, pPhysGpuInfo, pPhysGpuInfo->vgpuTypes[vgpuTypeId]);
970         if (rmStatus != NV_OK)
971             return rmStatus;
972 
973         rmStatus = kvgpumgrSetVgpuType(pGpu, pPhysGpuInfo, vgpuType);
974         if (rmStatus != NV_OK)
975             return rmStatus;
976     }
977 
978     if (listCount(&(pPhysGpuInfo->listHostVgpuDeviceHead)) == MAX_VGPU_DEVICES_PER_PGPU)
979     {
980         rmStatus = NV_ERR_INSUFFICIENT_RESOURCES;
981         goto failed;
982     }
983 
984     // Register guest vgpu device instance
985     pKernelHostVgpuDevice = listAppendNew(&(pPhysGpuInfo->listHostVgpuDeviceHead));
986     if (pKernelHostVgpuDevice == NULL)
987     {
988         rmStatus = NV_ERR_NO_MEMORY;
989         goto failed;
990     }
991 
992     portMemSet(pKernelHostVgpuDevice, 0, sizeof(KERNEL_HOST_VGPU_DEVICE));
993 
994     pKernelHostVgpuDevice->vgpuType = vgpuType;
995 
996     setGuestIDParams.action   = SET_GUEST_ID_ACTION_SET;
997     setGuestIDParams.vmPid    = vmPid;
998     setGuestIDParams.vmIdType = vmIdType;
999     if (vmIdType == VM_ID_DOMAIN_ID)
1000     {
1001         setGuestIDParams.guestVmId.vmId = guestVmId.vmId;
1002     }
1003     else if (vmIdType == VM_ID_UUID)
1004     {
1005         portMemCopy(setGuestIDParams.guestVmId.vmUuid,
1006                     VM_UUID_SIZE,
1007                     guestVmId.vmUuid,
1008                     VM_UUID_SIZE);
1009     }
1010     if (NV_OK != (rmStatus = kvgpumgrRegisterGuestId(&setGuestIDParams, pKernelHostVgpuDevice, pGpu)))
1011     {
1012         goto failed;
1013     }
1014 
1015     pKernelHostVgpuDevice->gfid      = gfid;
1016     pKernelHostVgpuDevice->swizzId   = swizzId;
1017     pKernelHostVgpuDevice->numPluginChannels = numPluginChannels;
1018     pKernelHostVgpuDevice->bDisableDefaultSmcExecPartRestore = bDisableDefaultSmcExecPartRestore;
1019     pKernelHostVgpuDevice->placementId = placementId;
1020 
1021     if (osIsVgpuVfioPresent() == NV_OK)
1022     {
1023         pKernelHostVgpuDevice->pRequestVgpuInfoNode = pRequestVgpu;
1024         pRequestVgpu->pKernelHostVgpuDevice = pKernelHostVgpuDevice;
1025     }
1026 
1027     pKernelHostVgpuDevice->hPluginFBAllocationClient     = hPluginFBAllocationClient;
1028     pKernelHostVgpuDevice->vgpuDeviceGuestFbInfo.bValid  = NV_FALSE;
1029     pKernelHostVgpuDevice->vgpuDeviceGuestFbInfo.offset  = 0;
1030     pKernelHostVgpuDevice->vgpuDeviceGuestFbInfo.length  = 0;
1031     pKernelHostVgpuDevice->bOfflinedPageInfoValid        = NV_FALSE;
1032 
1033     pPhysGpuInfo->numActiveVgpu++;
1034 
1035     if (gpuIsSriovEnabled(pGpu))
1036     {
1037         // Set GFID in use
1038         gpuSetGfidUsage(pGpu, gfid, NV_TRUE);
1039     }
1040 
1041     // If MIG is enabled, then we need to set faultIds and per GPU instance VEID
1042     // offset in MMU_CFG registers. In MIG with memory partitioning, every
1043     // VM should be associated with a GPU instance, so set these params for
1044     // GPU instance engines
1045     //
1046     if (gpuIsSriovEnabled(pGpu) && bMIGInUse)
1047     {
1048         //
1049         // Alloc GPUInstanceSubscription object inside hostVgpuDeviceObject. This is
1050         // needed because hostVgpuDevice can be duped under any client and
1051         // will get freed after subdevice, so during hostVgpuDeviceDestruct
1052         // to get GPU instance reference, we need to keep the GPU instance alive
1053         //
1054         NV_ASSERT_OK_OR_GOTO(rmStatus, _kvgpumgrVgpuAllocGPUInstanceSubscription(pGpu,
1055                                                                                  &pKernelHostVgpuDevice->hMigClient,
1056                                                                                  &pKernelHostVgpuDevice->hMigDevice,
1057                                                                                  swizzId),
1058                              failed);
1059     }
1060 
1061     if (IS_GSP_CLIENT(pGpu))
1062     {
1063         KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
1064         ENGINE_INFO tmpEngineInfo;
1065         VGPU_TYPE *vgpuTypeInfo = NULL;
1066         Device *pMigDevice = NULL;
1067 
1068         if (gpuIsSriovEnabled(pGpu) && bMIGInUse)
1069         {
1070             RsClient *pClient;
1071 
1072             NV_ASSERT_OK_OR_GOTO(rmStatus,
1073                                  serverGetClientUnderLock(&g_resServ, pKernelHostVgpuDevice->hMigClient, &pClient),
1074                                  failed);
1075 
1076             NV_ASSERT_OK_OR_GOTO(rmStatus,
1077                                  deviceGetByHandle(pClient, pKernelHostVgpuDevice->hMigDevice, &pMigDevice),
1078                                  failed);
1079         }
1080 
1081         NV_ASSERT_OK_OR_GOTO(rmStatus,
1082                              kvgpumgrGetVgpuTypeInfo(vgpuType, &vgpuTypeInfo),
1083                              failed);
1084 
1085         portMemSet(&tmpEngineInfo, 0, sizeof(ENGINE_INFO));
1086 
1087         NV_ASSERT_OK_OR_GOTO(rmStatus,
1088                              kfifoGetHostDeviceInfoTable_HAL(pGpu, pKernelFifo, &tmpEngineInfo, pMigDevice),
1089                              failed);
1090 
1091         rmStatus = vgpuMgrReserveSystemChannelIDs(pGpu,
1092                                                   vgpuTypeInfo,
1093                                                   pKernelHostVgpuDevice->gfid,
1094                                                   pKernelHostVgpuDevice->chidOffset,
1095                                                   pKernelHostVgpuDevice->channelCount,
1096                                                   pMigDevice,
1097                                                   numChannels,
1098                                                   pKernelHostVgpuDevice->placementId,
1099                                                   tmpEngineInfo.engineInfoListSize,
1100                                                   tmpEngineInfo.engineInfoList);
1101 
1102         portMemFree(tmpEngineInfo.engineInfoList);
1103         tmpEngineInfo.engineInfoList = NULL;
1104 
1105         if (rmStatus != NV_OK)
1106         {
1107             goto failed;
1108         }
1109     }
1110 
1111     // Save/Restore default compute instance if not disabled during allocation
1112     if (gpuIsSriovEnabled(pGpu) && bMIGInUse && !pKernelHostVgpuDevice->bDisableDefaultSmcExecPartRestore)
1113     {
1114         KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1115         KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1116 
1117         // Get GPU instance
1118         NV_ASSERT_OK_OR_GOTO(rmStatus,
1119                              kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager,
1120                                                        swizzId, &pKernelMIGGpuInstance),
1121                              failed);
1122         //
1123         // Save any default compute instances as we may need to restore
1124         // them during destruct
1125         //
1126         NV_ASSERT_OK_OR_GOTO(rmStatus,
1127                              kmigmgrSaveComputeInstances(pGpu, pKernelMIGManager, pKernelMIGGpuInstance,
1128                                                          pKernelHostVgpuDevice->savedExecPartitions),
1129                              failed);
1130 
1131         // Determine if we have a VEID fragmentation between compute instances
1132         if (!kmigmgrIsPartitionVeidAllocationContiguous(pGpu, pKernelMIGManager, pKernelMIGGpuInstance))
1133         {
1134             // delete all compute instances and recreate then again
1135             NV_ASSERT_OK_OR_GOTO(rmStatus,
1136                                  kvgpuMgrRestoreSmcExecPart(pGpu,
1137                                                            pKernelHostVgpuDevice,
1138                                                            pKernelMIGGpuInstance),
1139                                  failed);
1140         }
1141     }
1142 
1143     *ppKernelHostVgpuDevice = pKernelHostVgpuDevice;
1144 
1145     return rmStatus;
1146 
1147 failed:
1148     // Unset gfid usage
1149     if (gpuIsSriovEnabled(pGpu))
1150         gpuSetGfidUsage(pGpu, gfid, NV_FALSE);
1151 
1152     if (pKernelHostVgpuDevice != NULL)
1153     {
1154         if (pKernelHostVgpuDevice->vgpuGuest != NULL)
1155         {
1156             setGuestIDParams.action = SET_GUEST_ID_ACTION_UNSET;
1157             kvgpumgrRegisterGuestId(&setGuestIDParams, pKernelHostVgpuDevice, pGpu);
1158         }
1159         listRemove(&(pPhysGpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice);
1160     }
1161 
1162     if (osIsVgpuVfioPresent() != NV_OK && // not KVM
1163         swizzId != KMIGMGR_SWIZZID_INVALID)
1164         _kvgpumgrClearAssignedSwizzIdMask(pGpu, swizzId);
1165 
1166     return rmStatus;
1167 }
1168 
1169 NV_STATUS
kvgpumgrGuestUnregister(OBJGPU * pGpu,KERNEL_HOST_VGPU_DEVICE * pKernelHostVgpuDevice)1170 kvgpumgrGuestUnregister(OBJGPU *pGpu, KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice)
1171 {
1172     NV_STATUS                    rmStatus        = NV_OK;
1173     OBJSYS                      *pSys            = SYS_GET_INSTANCE();
1174     KernelVgpuMgr               *pKernelVgpuMgr  = SYS_GET_KERNEL_VGPUMGR(pSys);
1175     RM_API                      *pRmApi          = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
1176     KERNEL_PHYS_GPU_INFO        *pPhysGpuInfo;
1177     NvU32                        gfid            = pKernelHostVgpuDevice->gfid;
1178     SET_GUEST_ID_PARAMS          setGuestIDParams = {0};
1179     NvU32                        i;
1180 
1181     NV_PRINTF(LEVEL_INFO, "Enter function\n");
1182 
1183     if (gpuIsSriovEnabled(pGpu))
1184     {
1185         GFID_ALLOC_STATUS gfidState;
1186 
1187         // Sanity check on GFID
1188         NV_ASSERT_OK_OR_GOTO(rmStatus, gpuGetGfidState(pGpu, gfid, &gfidState), done);
1189 
1190         // Keep continuing in unregister path after sanity check
1191         if (gfidState == GFID_FREE)
1192         {
1193             NV_PRINTF(LEVEL_ERROR, "Request to unregister Invalid GFID\n");
1194             rmStatus = NV_ERR_INVALID_STATE;
1195             goto done;
1196         }
1197     }
1198 
1199     if (IS_MIG_IN_USE(pGpu) && !pKernelHostVgpuDevice->bDisableDefaultSmcExecPartRestore)
1200     {
1201         KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1202         KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1203 
1204         NV_ASSERT_OK_OR_GOTO(rmStatus, kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager,
1205                                                                  pKernelHostVgpuDevice->swizzId,
1206                                                                  &pKernelMIGGpuInstance),
1207                              done);
1208 
1209         NV_ASSERT_OK_OR_GOTO(rmStatus,
1210                              kvgpuMgrRestoreSmcExecPart(pGpu,
1211                                                         pKernelHostVgpuDevice,
1212                                                         pKernelMIGGpuInstance),
1213                              done);
1214 
1215         portMemSet(&pKernelHostVgpuDevice->savedExecPartitions, 0,
1216                    sizeof(pKernelHostVgpuDevice->savedExecPartitions));
1217     }
1218 
1219     if (!gpuIsSriovEnabled(pGpu))
1220     {
1221         portMemFree(pKernelHostVgpuDevice->pGuestFbSegment);
1222         pKernelHostVgpuDevice->pGuestFbSegment = NULL;
1223     }
1224 
1225     if (pKernelHostVgpuDevice->hbmRegionList != NULL)
1226     {
1227         portMemFree(pKernelHostVgpuDevice->hbmRegionList);
1228         pKernelHostVgpuDevice->hbmRegionList = NULL;
1229         pKernelHostVgpuDevice->numValidHbmRegions = 0;
1230     }
1231 
1232     if (gpuIsSriovEnabled(pGpu))
1233     {
1234         if (IS_GSP_CLIENT(pGpu))
1235         {
1236             KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
1237             ENGINE_INFO tmpEngineInfo;
1238             Device *pMigDevice = NULL;
1239 
1240             portMemSet(&tmpEngineInfo, 0, sizeof(ENGINE_INFO));
1241 
1242             if (IS_MIG_IN_USE(pGpu))
1243             {
1244                 RsClient *pClient;
1245 
1246                 NV_ASSERT_OK_OR_GOTO(rmStatus,
1247                                      serverGetClientUnderLock(&g_resServ, pKernelHostVgpuDevice->hMigClient, &pClient),
1248                                      free_fifo_chids_exit);
1249 
1250                 NV_ASSERT_OK_OR_GOTO(rmStatus,
1251                                      deviceGetByHandle(pClient, pKernelHostVgpuDevice->hMigDevice, &pMigDevice),
1252                                      free_fifo_chids_exit);
1253             }
1254 
1255             NV_ASSERT_OK_OR_GOTO(rmStatus,
1256                                  kfifoGetHostDeviceInfoTable_HAL(pGpu, pKernelFifo, &tmpEngineInfo, pMigDevice),
1257                                  free_fifo_chids_exit);
1258 
1259             vgpuMgrFreeSystemChannelIDs(pGpu,
1260                                         pKernelHostVgpuDevice->gfid,
1261                                         pKernelHostVgpuDevice->chidOffset,
1262                                         pKernelHostVgpuDevice->channelCount,
1263                                         pMigDevice,
1264                                         tmpEngineInfo.engineInfoListSize,
1265                                         tmpEngineInfo.engineInfoList);
1266 
1267 free_fifo_chids_exit:
1268             portMemFree(tmpEngineInfo.engineInfoList);
1269             tmpEngineInfo.engineInfoList = NULL;
1270         }
1271 
1272         // Unset GFID usage
1273         gpuSetGfidUsage(pGpu, gfid, NV_FALSE);
1274     }
1275 
1276 done:
1277     if (IS_MIG_IN_USE(pGpu))
1278     {
1279         pRmApi->Free(pRmApi, pKernelHostVgpuDevice->hMigClient, pKernelHostVgpuDevice->hMigClient);
1280         pKernelHostVgpuDevice->hMigClient = NV01_NULL_OBJECT;
1281         pKernelHostVgpuDevice->hMigDevice = NV01_NULL_OBJECT;
1282     }
1283 
1284     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
1285     {
1286         return NV_ERR_OBJECT_NOT_FOUND;
1287     }
1288 
1289     // Unset the guest id for host vGPU device
1290     setGuestIDParams.action = SET_GUEST_ID_ACTION_UNSET;
1291     if (NV_OK != (rmStatus = kvgpumgrRegisterGuestId(&setGuestIDParams,
1292                                                      pKernelHostVgpuDevice,
1293                                                      pGpu)))
1294     {
1295         // In case of Hyper-V, On VM reboot KERNEL_HOST_VGPU_DEVICE is not destroyed.
1296         // As guest id is unset during VM reboot by plugin explicitly. So we
1297         // will receive NV_WARN_NULL_OBJECT here and we need to ignore it.
1298         //
1299         // In case, plugin doesn't get a chance to unset the guest id e.g. in case
1300         // of crash or Force shutdown/Turn off then we need to get it unset here.
1301         if (hypervisorIsType(OS_HYPERVISOR_HYPERV) && rmStatus == NV_WARN_NULL_OBJECT)
1302         {
1303             rmStatus = NV_OK;
1304         }
1305         else
1306         {
1307             return rmStatus;
1308         }
1309     }
1310 
1311     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
1312 
1313     NV_ASSERT_OR_RETURN((pPhysGpuInfo != NULL), NV_ERR_INVALID_ARGUMENT);
1314 
1315     pPhysGpuInfo->numActiveVgpu--;
1316 
1317     if (pPhysGpuInfo->numActiveVgpu == 0 && pPhysGpuInfo->numCreatedVgpu == 0)
1318     {
1319         kvgpumgrSetVgpuType(pGpu, pPhysGpuInfo, NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE);
1320     }
1321 
1322     if (pKernelHostVgpuDevice->pRequestVgpuInfoNode != NULL)
1323     {
1324         pKernelHostVgpuDevice->pRequestVgpuInfoNode->pKernelHostVgpuDevice = NULL;
1325     }
1326 
1327     if (osIsVgpuVfioPresent() != NV_OK) // Not KVM
1328     {
1329         if (pKernelHostVgpuDevice->swizzId != KMIGMGR_SWIZZID_INVALID)
1330             rmStatus = _kvgpumgrClearAssignedSwizzIdMask(pGpu, pKernelHostVgpuDevice->swizzId);
1331     }
1332 
1333     if (pKernelHostVgpuDevice->placementId != NVA081_PLACEMENT_ID_INVALID)
1334         _kvgpumgrUpdateCreatablePlacementIds(pGpu, pKernelHostVgpuDevice->placementId,
1335                                              pKernelHostVgpuDevice->vgpuType, NV_FALSE);
1336 
1337     listRemove(&(pPhysGpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice);
1338 
1339     return rmStatus;
1340 }
1341 
1342 //
1343 // Helper function to check if pGPU is live migration capable.
1344 //
1345 NvBool
kvgpumgrCheckPgpuMigrationSupport(OBJGPU * pGpu)1346 kvgpumgrCheckPgpuMigrationSupport(OBJGPU *pGpu)
1347 {
1348     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1349     NV2080_CTRL_VGPU_MGR_INTERNAL_GET_PGPU_MIGRATION_SUPPORT_PARAMS params = {0};
1350     NV_STATUS status;
1351 
1352     NV_CHECK_OK_OR_ELSE(status,
1353                         LEVEL_ERROR,
1354                         pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1355                                         NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_GET_PGPU_MIGRATION_SUPPORT,
1356                                         &params, sizeof(params)),
1357                         return NV_FALSE);
1358 
1359     return params.bIsMigrationSupported;
1360 }
1361 
1362 //
1363 // Function to convert a NvU32 value to a ascii-encoded string.
1364 // The value will be padded with 0 to use up the totalWidth. The value
1365 // requiring space more that totalWidth will be truncated.
1366 //
1367 static NvU32
NvU32ToAsciiStr(NvU32 uval,NvU32 totalWidth,NvU8 * dest,NvBool invalid)1368 NvU32ToAsciiStr(NvU32 uval, NvU32 totalWidth, NvU8 *dest, NvBool invalid)
1369 {
1370     NvU32 digitCount = 0;
1371     NvU8 nibble;
1372 
1373     if (totalWidth == 0)
1374         return (totalWidth);
1375 
1376     // Move the pointer to the end
1377     dest += (totalWidth - 1);
1378 
1379     // Start copying the data from the end in the reverse order
1380     while (digitCount < totalWidth)
1381     {
1382         digitCount++;
1383         if (invalid == NV_TRUE)
1384         {
1385             *dest-- = 'X';
1386             continue;
1387         }
1388 
1389         nibble = uval & 0xF;
1390         *dest-- = (nibble <= 9) ? (nibble + '0') : (nibble - 10 + 'A');
1391         uval = uval >> 4;
1392     }
1393 
1394     return (totalWidth);
1395 }
1396 
kvgpumgrGetPgpuDevIdEncoding(OBJGPU * pGpu,NvU8 * pgpuString,NvU32 strSize)1397 NvU32 kvgpumgrGetPgpuDevIdEncoding(OBJGPU *pGpu, NvU8 *pgpuString,
1398                                    NvU32 strSize)
1399 {
1400     NvU32 chipID = DRF_VAL(_PCI, _DEVID, _DEVICE, pGpu->idInfo.PCIDeviceID);
1401     NvU32 subID  = DRF_VAL(_PCI, _DEVID, _DEVICE, pGpu->idInfo.PCISubDeviceID);
1402 
1403     _get_chip_id_for_alias_pgpu(&chipID, &subID);
1404 
1405     if ((strSize < MAX_NVU32_TO_CONVERTED_STR_LEN)
1406         || (pgpuString == NULL))
1407     {
1408         return NV_U32_MAX;
1409     }
1410 
1411     // The encoding of the Dev ID is the value converted to string
1412     return (NvU32ToAsciiStr(chipID, DEVID_ENCODED_VALUE_SIZE, pgpuString, NV_FALSE));
1413 }
1414 
kvgpumgrGetPgpuSubdevIdEncoding(OBJGPU * pGpu,NvU8 * pgpuString,NvU32 strSize)1415 NvU32 kvgpumgrGetPgpuSubdevIdEncoding(OBJGPU *pGpu, NvU8 *pgpuString,
1416                                       NvU32 strSize)
1417 {
1418     NvU32 chipID = DRF_VAL(_PCI, _DEVID, _DEVICE, pGpu->idInfo.PCIDeviceID);
1419     NvU32 subID  = DRF_VAL(_PCI, _DEVID, _DEVICE, pGpu->idInfo.PCISubDeviceID);
1420     NvU32 bytes = 0;
1421 
1422     _get_chip_id_for_alias_pgpu(&chipID, &subID);
1423 
1424     if ((strSize < MAX_NVU32_TO_CONVERTED_STR_LEN)
1425         || (pgpuString == NULL))
1426     {
1427         return NV_U32_MAX;
1428     }
1429 
1430     // The encoding of the subdevice ID is its value converted to string
1431     bytes = NvU32ToAsciiStr(subID, SUBDEVID_ENCODED_VALUE_SIZE,
1432                                     pgpuString, NV_FALSE);
1433     return bytes;
1434 }
1435 
kvgpumgrGetPgpuFSEncoding(OBJGPU * pGpu,NvU8 * pgpuString,NvU32 strSize)1436 NvU32 kvgpumgrGetPgpuFSEncoding(OBJGPU *pGpu, NvU8 *pgpuString,
1437                                 NvU32 strSize)
1438 {
1439     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1440     NV2080_CTRL_VGPU_MGR_INTERNAL_GET_PGPU_FS_ENCODING_PARAMS params = {0};
1441     NV_STATUS status;
1442 
1443     params.pgpuStringSize = strSize;
1444 
1445     NV_CHECK_OK_OR_ELSE(status,
1446                           LEVEL_ERROR,
1447                           pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1448                                           NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_GET_PGPU_FS_ENCODING,
1449                                           &params, sizeof(params)),
1450                           return NV_U32_MAX);
1451 
1452     portMemCopy(pgpuString, strSize, params.pgpuString, params.pgpuStringSize);
1453 
1454     return params.pgpuStringSize;
1455 }
1456 
1457 NvU64
kvgpumgrGetEccAndPrReservedFb(OBJGPU * pGpu)1458 kvgpumgrGetEccAndPrReservedFb(OBJGPU *pGpu)
1459 {
1460     Heap *pHeap = GPU_GET_HEAP(pGpu);
1461 	const MEMORY_SYSTEM_STATIC_CONFIG *pMemorySystemConfig =
1462             kmemsysGetStaticConfig(pGpu, GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu));
1463 	NvU64 eccReservedFb = 0, pageRetirementReservedFb = 0, usableSizeFb;
1464 
1465     //
1466     // pageRetirementReservedFb is needed only in case of legacy, to account
1467     // for the pagepool used during page stitching
1468     //
1469     if (!gpuIsSriovEnabled(pGpu))
1470     {
1471         if (pGpu->getProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT))
1472         {
1473             if (IsPASCALorBetter(pGpu))
1474             {
1475                 pageRetirementReservedFb = NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES * RM_PAGE_SIZE_HUGE;
1476             }
1477             else
1478             {
1479                 pageRetirementReservedFb = NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES * RM_PAGE_SIZE_64K;
1480             }
1481         }
1482     }
1483 
1484     if (pMemorySystemConfig->bEnabledEccFBPA)
1485     {
1486         if ((pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM1) &&
1487             (pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM2) &&
1488             (pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM3))
1489         {
1490             heapGetUsableSize(pHeap, &usableSizeFb);
1491             //
1492             // FB and ECC checksum calculation
1493             // eccReservedFb = totalFBEccOff / 16
1494             // i.e. totalFbEccOff = eccReservedFb * 16
1495             //
1496             // totalFbEccOff = totalFbEccOn + eccReservedFb
1497             // eccReservedFb * 16 = totalFbEccOn + eccReservedFb
1498             // eccReservedFb * 15 = totalFbEccOn
1499             // eccReservedFb = totalFbEccOn / 15 (totalFbEccOn is same as usableSizeFb)
1500             //
1501             eccReservedFb = usableSizeFb / 15;
1502         }
1503     }
1504 
1505 	return pageRetirementReservedFb + eccReservedFb;
1506 }
1507 
1508 //
1509 // A 32-bit variable is used to consolidate various GPU capabilities like
1510 // ECC, SRIOV etc. The function sets the capabilities in the variable and
1511 // converted to an ascii-encoded format.
1512 //
kvgpumgrGetPgpuCapEncoding(OBJGPU * pGpu,NvU8 * pgpuString,NvU32 strSize)1513 NvU32 kvgpumgrGetPgpuCapEncoding(OBJGPU *pGpu, NvU8 *pgpuString, NvU32 strSize)
1514 {
1515     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1516     NvU32 pgpuCap = 0;
1517 
1518     if ((strSize < MAX_NVU32_TO_CONVERTED_STR_LEN) || (pgpuString == NULL))
1519     {
1520         return NV_U32_MAX;
1521     }
1522 
1523     {
1524         NV2080_CTRL_GPU_QUERY_ECC_STATUS_PARAMS eccStatus = {0};
1525 
1526         if (pRmApi->Control(pRmApi,
1527                             pGpu->hInternalClient,
1528                             pGpu->hInternalSubdevice,
1529                             NV2080_CTRL_CMD_GPU_QUERY_ECC_STATUS,
1530                             &eccStatus, sizeof(eccStatus)) == NV_OK)
1531         {
1532             NvU32 i;
1533             for (i = 0; i < NV2080_CTRL_GPU_ECC_UNIT_COUNT; i++)
1534             {
1535                 if (eccStatus.units[i].enabled)
1536                 {
1537                     pgpuCap |= PGPU_CAP_ECC_ON;
1538                     break;
1539                 }
1540             }
1541         }
1542     }
1543 
1544     {
1545         NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS sriovCaps = {0};
1546 
1547         if (gpuGetSriovCaps_HAL(pGpu, &sriovCaps) == NV_OK)
1548         {
1549             if (sriovCaps.bSriovEnabled)
1550                 pgpuCap |= PGPU_CAP_SRIOV_ON;
1551         }
1552     }
1553 
1554     return NvU32ToAsciiStr(pgpuCap, PGPU_CAP_ENCODED_VALUE_SIZE,
1555                            pgpuString, NV_FALSE);
1556 }
1557 
1558 /*
1559  * Get the user provide vGPU version range
1560  */
1561 NV_STATUS
kvgpumgrGetHostVgpuVersion(NvU32 * user_min_supported_version,NvU32 * user_max_supported_version)1562 kvgpumgrGetHostVgpuVersion(NvU32 *user_min_supported_version,
1563                            NvU32 *user_max_supported_version)
1564 {
1565     OBJSYS *pSys = SYS_GET_INSTANCE();
1566     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1567 
1568     *user_min_supported_version
1569         = pKernelVgpuMgr->user_min_supported_version;
1570     *user_max_supported_version
1571         = pKernelVgpuMgr->user_max_supported_version;
1572     return NV_OK;
1573 }
1574 
1575 /*
1576  * Set the user provide vGPU version range
1577  */
1578 NV_STATUS
kvgpumgrSetHostVgpuVersion(NvU32 user_min_supported_version,NvU32 user_max_supported_version)1579 kvgpumgrSetHostVgpuVersion(NvU32 user_min_supported_version,
1580                            NvU32 user_max_supported_version)
1581 {
1582     OBJSYS *pSys = SYS_GET_INSTANCE();
1583     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1584     NvU32 host_min_supported_version
1585         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
1586                                   NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
1587     NvU32 host_max_supported_version
1588         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
1589                                   NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
1590 
1591     /* Sanity check */
1592     if (user_min_supported_version > user_max_supported_version) {
1593         NV_PRINTF(LEVEL_ERROR,
1594                   "Maximum vGPU version (0x%x) being set is less than minimum version (0x%x)\n",
1595                   user_max_supported_version, user_min_supported_version);
1596         return NV_ERR_INVALID_ARGUMENT;
1597     }
1598 
1599     /* Sanity check: Fail in case the range being set by admin is a subset
1600      * of the range supported by the host driver
1601      */
1602     if ((user_min_supported_version < host_min_supported_version)
1603         || (user_max_supported_version > host_max_supported_version)) {
1604 
1605         NV_PRINTF(LEVEL_ERROR,
1606                   "vGPU version range being set (0x%x, 0x%x) is outside the range supported by host (0x%x, 0x%x)\n",
1607                   user_min_supported_version, user_max_supported_version,
1608                   host_min_supported_version, host_max_supported_version);
1609 
1610         return NV_ERR_INVALID_ARGUMENT;
1611     }
1612 
1613     NV_PRINTF(LEVEL_INFO,
1614               "vGPU version range enforced by user: (0x%x, 0x%x)\n",
1615               user_min_supported_version, user_max_supported_version);
1616 
1617     /* Save the information of the user specified range in the host */
1618     pKernelVgpuMgr->user_min_supported_version
1619         = user_min_supported_version;
1620     pKernelVgpuMgr->user_max_supported_version
1621         = user_max_supported_version;
1622 
1623     return NV_OK;
1624 }
1625 
1626 /*
1627  * Function to set swizzId is assigned to a vGPU device.
1628  */
1629 static NV_STATUS
_kvgpumgrSetAssignedSwizzIdMask(OBJGPU * pGpu,NvU32 swizzId)1630 _kvgpumgrSetAssignedSwizzIdMask(OBJGPU       *pGpu,
1631                                 NvU32         swizzId)
1632 {
1633     OBJSYS *pSys = SYS_GET_INSTANCE();
1634     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1635     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1636     NvU32 i;
1637     NvU64 mask;
1638 
1639     if (swizzId >= KMIGMGR_MAX_GPU_SWIZZID)
1640     {
1641         return NV_ERR_INVALID_ARGUMENT;
1642     }
1643 
1644     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
1645     {
1646         return NV_ERR_OBJECT_NOT_FOUND;
1647     }
1648 
1649     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
1650     NV_ASSERT_OR_RETURN((pPhysGpuInfo != NULL), NV_ERR_INVALID_ARGUMENT);
1651 
1652     /* Validate that same ID is not already set and then set the ID */
1653     mask = NVBIT64(swizzId);
1654 
1655     if (mask & pPhysGpuInfo->assignedSwizzIdMask)
1656     {
1657         NV_PRINTF(LEVEL_ERROR, "SwizzID - %d already in use\n", swizzId);
1658         DBG_BREAKPOINT();
1659         return NV_ERR_STATE_IN_USE;
1660     }
1661 
1662     pPhysGpuInfo->assignedSwizzIdMask |= mask;
1663 
1664     return NV_OK;
1665 }
1666 
1667 /*!
1668  * Function to mark swizzId is free to be used by other vGPU devices.
1669  */
1670 static NV_STATUS
_kvgpumgrClearAssignedSwizzIdMask(OBJGPU * pGpu,NvU32 swizzId)1671 _kvgpumgrClearAssignedSwizzIdMask(OBJGPU *pGpu,
1672                                   NvU32 swizzId)
1673 {
1674     OBJSYS *pSys = SYS_GET_INSTANCE();
1675     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1676     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1677     NvU32 i;
1678     NvU64 mask;
1679 
1680     if (swizzId >= KMIGMGR_MAX_GPU_SWIZZID)
1681     {
1682         return NV_ERR_INVALID_ARGUMENT;
1683     }
1684 
1685     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
1686     {
1687         return NV_ERR_OBJECT_NOT_FOUND;
1688     }
1689 
1690     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
1691     NV_ASSERT_OR_RETURN((pPhysGpuInfo != NULL), NV_ERR_INVALID_ARGUMENT);
1692 
1693     /* Validate that same ID is not already marked as free and then set the ID */
1694     mask = NVBIT64(swizzId);
1695 
1696     if (!(mask & pPhysGpuInfo->assignedSwizzIdMask))
1697     {
1698         NV_PRINTF(LEVEL_ERROR, "SwizzID - %d not in use\n", swizzId);
1699         DBG_BREAKPOINT();
1700         return NV_ERR_INVALID_STATE;
1701     }
1702 
1703     pPhysGpuInfo->assignedSwizzIdMask &= ~mask;
1704 
1705     return NV_OK;
1706 }
1707 
1708 NV_STATUS
kvgpumgrGetSwizzId(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPhysGpuInfo,NvU32 partitionFlag,NvU32 * swizzId)1709 kvgpumgrGetSwizzId(OBJGPU *pGpu,
1710                    KERNEL_PHYS_GPU_INFO *pPhysGpuInfo,
1711                    NvU32 partitionFlag,
1712                    NvU32 *swizzId)
1713 {
1714     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1715     NvU64 swizzIdInUseMask = 0;
1716     NvU32 id;
1717     NV_STATUS rmStatus = NV_OK;
1718 
1719     swizzIdInUseMask = kmigmgrGetSwizzIdInUseMask(pGpu, pKernelMIGManager);
1720 
1721     *swizzId = KMIGMGR_SWIZZID_INVALID;
1722 
1723     // Determine valid swizzids not assigned to any vGPU device.
1724     FOR_EACH_INDEX_IN_MASK(64, id, swizzIdInUseMask)
1725     {
1726         KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1727         NvU64 mask = 0;
1728 
1729         rmStatus = kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, id, &pKernelMIGGpuInstance);
1730         if (rmStatus != NV_OK)
1731         {
1732             // Didn't find requested GPU instance
1733             NV_PRINTF(LEVEL_ERROR, "No valid GPU instance with SwizzId - %d found\n", id);
1734             return rmStatus;
1735         }
1736 
1737         mask = NVBIT64(id);
1738 
1739         if (pKernelMIGGpuInstance->partitionFlag == partitionFlag)
1740         {
1741             // Validate that same ID is not already set and then set the ID
1742             if (!(mask & pPhysGpuInfo->assignedSwizzIdMask))
1743             {
1744                 NV_ASSERT_OK_OR_RETURN(_kvgpumgrSetAssignedSwizzIdMask(pGpu, pKernelMIGGpuInstance->swizzId));
1745                 *swizzId = pKernelMIGGpuInstance->swizzId;
1746                 break;
1747             }
1748         }
1749     }
1750     FOR_EACH_INDEX_IN_MASK_END;
1751 
1752     if (*swizzId == KMIGMGR_SWIZZID_INVALID)
1753     {
1754         return NV_ERR_INVALID_STATE;
1755     }
1756 
1757     return NV_OK;
1758 }
1759 
1760 NV_STATUS
kvgpumgrValidateSwizzId(OBJGPU * pGpu,NvU32 vgpuTypeId,NvU32 swizzId)1761 kvgpumgrValidateSwizzId(OBJGPU *pGpu,
1762                         NvU32 vgpuTypeId,
1763                         NvU32 swizzId)
1764 {
1765     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1766     NvU32 partitionFlag                 = PARTITIONID_INVALID;
1767     NV_STATUS rmStatus                  = NV_OK;
1768     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1769 
1770     // Check if swizzId is valid.
1771     if (!kmigmgrIsSwizzIdInUse(pGpu, pKernelMIGManager, swizzId))
1772     {
1773         return NV_ERR_INVALID_ARGUMENT;
1774     }
1775 
1776     rmStatus = kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, swizzId, &pKernelMIGGpuInstance);
1777     if (rmStatus != NV_OK)
1778     {
1779         // Didn't find requested GPU instance
1780         NV_PRINTF(LEVEL_ERROR, "No valid GPU instance with SwizzId - %d found\n", swizzId);
1781         return rmStatus;
1782     }
1783 
1784     NV_ASSERT_OK_OR_RETURN(
1785         kvgpumgrGetPartitionFlag(vgpuTypeId, &partitionFlag));
1786 
1787     // Check if swizzId is valid for vGPU type.
1788     if (pKernelMIGGpuInstance->partitionFlag == partitionFlag)
1789     {
1790         NV_ASSERT_OK_OR_RETURN(_kvgpumgrSetAssignedSwizzIdMask(pGpu, swizzId));
1791         return NV_OK;
1792     }
1793 
1794     return NV_ERR_INVALID_STATE;
1795 }
1796 
1797 NV_STATUS
kvgpumgrGetPartitionFlag(NvU32 vgpuTypeId,NvU32 * partitionFlag)1798 kvgpumgrGetPartitionFlag(NvU32 vgpuTypeId, NvU32 *partitionFlag)
1799 {
1800     NvU32 i;
1801 
1802     *partitionFlag = PARTITIONID_INVALID;
1803 
1804     for (i = 0; i < NV_ARRAY_ELEMENTS(vgpuSmcTypeIdMappings); i++)
1805     {
1806         if (vgpuSmcTypeIdMappings[i].vgpuTypeId == vgpuTypeId)
1807         {
1808             *partitionFlag = vgpuSmcTypeIdMappings[i].partitionFlag;
1809             return NV_OK;
1810         }
1811     }
1812 
1813     NV_PRINTF(LEVEL_ERROR, "Invalid SMC vGpu TypeId: 0x%x\n", vgpuTypeId);
1814     return NV_ERR_INVALID_ARGUMENT;
1815 }
1816 
1817 static NV_STATUS
_kvgpumgrGetVgpuTypeIdFromPartitionFlag(NvU32 devId,NvU32 partitionFlag,NvU32 * vgpuTypeId)1818 _kvgpumgrGetVgpuTypeIdFromPartitionFlag(NvU32 devId, NvU32 partitionFlag, NvU32 *vgpuTypeId)
1819 {
1820     NvU32 i;
1821 
1822     *vgpuTypeId = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
1823 
1824     for (i = 0; i < NV_ARRAY_ELEMENTS(vgpuSmcTypeIdMappings); i++)
1825     {
1826         // Currently vgpuTypeId to partitionFlag mapping is 1 to 1.
1827         // In future, we might potentially hit issue if multiple
1828         // type-ids map to the same partition flags
1829         if ((vgpuSmcTypeIdMappings[i].devId == devId) &&
1830             (vgpuSmcTypeIdMappings[i].partitionFlag == partitionFlag))
1831         {
1832             *vgpuTypeId = vgpuSmcTypeIdMappings[i].vgpuTypeId;
1833             return NV_OK;
1834         }
1835     }
1836 
1837     return NV_ERR_OBJECT_NOT_FOUND;
1838 }
1839 
1840 /*
1841  * Add or remove VF info to pgpuInfo of its PF
1842  * @param[in] gpuPciId          PCI ID of target PF
1843  * @param[in] cmd
1844  *      0/VGPU_CMD_PROCESS_VF_INFO.NV_VGPU_SAVE_VF_INFO     = Add VF info to VF list of target PF
1845  *      1/VGPU_CMD_PROCESS_VF_INFO.NV_VGPU_REMOVE_VF_INFO   = Remove VF info from VF list of target PF
1846  * @param[in] domain            Domain of VF to be stored
1847  * @param[in] bus               Bus no. of VF to be stored
1848  * @param[in] slot              Slot no. of VF to be stored
1849  * @param[in] function          Function of VF to be stored
1850  * @param[in] isMdevAttached    Flag to indicate if VF is registered with mdev
1851  * @param[out]vfPciInfo         Array of PCI information of VFs
1852  */
1853 NV_STATUS
kvgpumgrProcessVfInfo(NvU32 gpuPciId,NvU8 cmd,NvU32 domain,NvU32 bus,NvU32 slot,NvU32 function,NvBool isMdevAttached,vgpu_vf_pci_info * vfPciInfo)1854 kvgpumgrProcessVfInfo(NvU32 gpuPciId, NvU8 cmd, NvU32 domain, NvU32 bus, NvU32 slot, NvU32 function, NvBool isMdevAttached, vgpu_vf_pci_info *vfPciInfo)
1855 {
1856     NvU32 i;
1857     OBJSYS *pSys = SYS_GET_INSTANCE();
1858     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1859     NvU32 pgpuIndex;
1860     NV_STATUS status = NV_OK;
1861     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1862     vgpu_vf_pci_info *pVfInfo = NULL;
1863 
1864     if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
1865         return status;
1866 
1867     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[pgpuIndex]);
1868 
1869     if (cmd == NV_VGPU_SAVE_VF_INFO)
1870     {
1871         /* Find existing entry for VF and set flags if found. */
1872         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1873         {
1874             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1875 
1876             if ((domain   == pVfInfo->domain) &&
1877                 (bus      == pVfInfo->bus)    &&
1878                 (slot     == pVfInfo->slot)   &&
1879                 (function == pVfInfo->function))
1880             {
1881                 pVfInfo->isNvidiaAttached = NV_TRUE;
1882                 pVfInfo->isMdevAttached   = isMdevAttached;
1883                 break;
1884             }
1885         }
1886 
1887         /*
1888          * If entry doesn't already exist, populate an empty slot and complain
1889          * if there isn't one.
1890          */
1891         if (i == MAX_VF_COUNT_PER_GPU)
1892         {
1893             for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1894             {
1895                 pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1896                 if ((!pVfInfo->isNvidiaAttached))
1897                 {
1898                     pVfInfo->domain   = domain;
1899                     pVfInfo->bus      = bus;
1900                     pVfInfo->slot     = slot;
1901                     pVfInfo->function = function;
1902 
1903                     pVfInfo->isNvidiaAttached = NV_TRUE;
1904                     pVfInfo->isMdevAttached   = isMdevAttached;
1905                     break;
1906                 }
1907             }
1908 
1909             if (i == MAX_VF_COUNT_PER_GPU)
1910             {
1911                 NV_PRINTF(LEVEL_ERROR, "No free free slot to track VF PCI info\n");
1912                 return NV_ERR_INVALID_STATE;
1913             }
1914         }
1915     }
1916     else if ((cmd == NV_VGPU_REMOVE_VF_PCI_INFO || cmd == NV_VGPU_REMOVE_VF_MDEV_INFO) && pPhysGpuInfo)
1917     {
1918         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1919         {
1920             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1921 
1922             if ((domain   == pVfInfo->domain) &&
1923                 (bus      == pVfInfo->bus)    &&
1924                 (slot     == pVfInfo->slot)   &&
1925                 (function == pVfInfo->function))
1926             {
1927                 if (cmd == NV_VGPU_REMOVE_VF_PCI_INFO)
1928                 {
1929                     pVfInfo->isNvidiaAttached = NV_FALSE;
1930                 }
1931                 pVfInfo->isMdevAttached   = NV_FALSE;
1932                 break;
1933             }
1934         }
1935 
1936         if (i == MAX_VF_COUNT_PER_GPU)
1937         {
1938             NV_PRINTF(LEVEL_ERROR, "Could not find entry for VF PCI info\n");
1939             return NV_ERR_MISSING_TABLE_ENTRY;
1940         }
1941     }
1942     else if (cmd == NV_VGPU_GET_VF_INFO && vfPciInfo)
1943     {
1944         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1945         {
1946             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1947             portMemCopy(&vfPciInfo[i], sizeof(vgpu_vf_pci_info), pVfInfo, sizeof(vgpu_vf_pci_info));
1948         }
1949     }
1950     else
1951     {
1952         NV_PRINTF(LEVEL_ERROR, "Requested invalid operation on VF info\n");
1953         status = NV_ERR_INVALID_ARGUMENT;
1954     }
1955 
1956     return status;
1957 }
1958 
1959 NV_STATUS
kvgpumgrEnumerateVgpuPerPgpu(OBJGPU * pGpu,NV2080_CTRL_VGPU_MGR_INTERNAL_ENUMERATE_VGPU_PER_PGPU_PARAMS * pParams)1960 kvgpumgrEnumerateVgpuPerPgpu(OBJGPU *pGpu, NV2080_CTRL_VGPU_MGR_INTERNAL_ENUMERATE_VGPU_PER_PGPU_PARAMS *pParams)
1961 {
1962     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1963 
1964     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1965                                                        NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_ENUMERATE_VGPU_PER_PGPU,
1966                                                        pParams, sizeof(*pParams)));
1967 
1968     return NV_OK;
1969 }
1970 
1971 NV_STATUS
kvgpumgrClearGuestVmInfo(OBJGPU * pGpu,KERNEL_HOST_VGPU_DEVICE * pKernelHostVgpuDevice)1972 kvgpumgrClearGuestVmInfo(OBJGPU *pGpu, KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice)
1973 {
1974     NV2080_CTRL_VGPU_MGR_INTERNAL_CLEAR_GUEST_VM_INFO_PARAMS params;
1975     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1976     NV_STATUS status;
1977 
1978     portMemSet(&params, 0, sizeof(params));
1979     params.gfid = pKernelHostVgpuDevice->gfid;
1980 
1981     status = pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1982                              NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_CLEAR_GUEST_VM_INFO,
1983                              &params, sizeof(params));
1984 
1985     if (status != NV_OK)
1986         NV_PRINTF(LEVEL_ERROR, "Failed to clear guest vm info on GSP\n");
1987 
1988     return status;
1989 }
1990 
1991 NV_STATUS
kvgpumgrGetHostVgpuDeviceFromGfid(NvU32 gpuPciId,NvU32 gfid,KERNEL_HOST_VGPU_DEVICE ** ppHostVgpuDevice)1992 kvgpumgrGetHostVgpuDeviceFromGfid(NvU32 gpuPciId, NvU32 gfid,
1993                                   KERNEL_HOST_VGPU_DEVICE** ppHostVgpuDevice)
1994 {
1995     OBJSYS *pSys = SYS_GET_INSTANCE();
1996     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1997     NvU32 pgpuIndex;
1998     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
1999     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2000 
2001     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex));
2002     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
2003 
2004     if (!pPgpuInfo->sriovEnabled)
2005         return NV_ERR_NOT_SUPPORTED;
2006 
2007     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
2008          pKernelHostVgpuDevice != NULL;
2009          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2010     {
2011         if (pKernelHostVgpuDevice->gfid == gfid)
2012         {
2013             *ppHostVgpuDevice = pKernelHostVgpuDevice;
2014             return NV_OK;
2015         }
2016      }
2017 
2018     return NV_ERR_OBJECT_NOT_FOUND;
2019 }
2020 
2021 NV_STATUS
kvgpumgrGetVgpuFbUsage(OBJGPU * pGpu,NVA081_CTRL_VGPU_CONFIG_GET_VGPU_FB_USAGE_PARAMS * pParams)2022 kvgpumgrGetVgpuFbUsage(OBJGPU *pGpu, NVA081_CTRL_VGPU_CONFIG_GET_VGPU_FB_USAGE_PARAMS *pParams)
2023 {
2024     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2025     NVA081_VGPU_FB_USAGE *pVgpuFbUsage;
2026     NvU32 i = 0;
2027 
2028     NV_PRINTF(LEVEL_INFO, "%s\n", __FUNCTION__);
2029 
2030     if (gpuIsSriovEnabled(pGpu))
2031     {
2032         NV2080_CTRL_VGPU_MGR_INTERNAL_GET_VGPU_FB_USAGE_PARAMS internalParams;
2033         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2034 
2035         portMemSet(&internalParams, 0, sizeof(internalParams));
2036 
2037         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
2038                                                            NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_GET_VGPU_FB_USAGE,
2039                                                            &internalParams, sizeof(internalParams)));
2040 
2041         if (internalParams.vgpuCount > NV_ARRAY_ELEMENTS(pParams->vgpuFbUsage))
2042             return NV_ERR_INSUFFICIENT_RESOURCES;
2043 
2044         for (i = 0; i < internalParams.vgpuCount; i++)
2045         {
2046             NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2047                  kvgpumgrGetHostVgpuDeviceFromGfid(pGpu->gpuId, internalParams.vgpuFbUsage[i].gfid, &pKernelHostVgpuDevice));
2048 
2049             pVgpuFbUsage = &pParams->vgpuFbUsage[i];
2050 
2051             portMemCopy(pVgpuFbUsage->vgpuUuid, VGPU_UUID_SIZE, pKernelHostVgpuDevice->vgpuUuid, VGPU_UUID_SIZE);
2052 
2053             pVgpuFbUsage->fbUsed = internalParams.vgpuFbUsage[i].fbUsed;
2054         }
2055 
2056         pParams->vgpuCount = internalParams.vgpuCount;
2057     }
2058 
2059     return NV_OK;
2060 }
2061 
2062 NV_STATUS
kvgpumgrSetVgpuEncoderCapacity(OBJGPU * pGpu,NvU8 * vgpuUuid,NvU32 encoderCapacity)2063 kvgpumgrSetVgpuEncoderCapacity(OBJGPU *pGpu, NvU8 *vgpuUuid, NvU32 encoderCapacity)
2064 {
2065     OBJSYS *pSys = SYS_GET_INSTANCE();
2066     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2067     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2068     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
2069     NvU32 i;
2070 
2071     NV_PRINTF(LEVEL_INFO, "%s\n", __FUNCTION__);
2072 
2073     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i));
2074 
2075     pPhysGpuInfo = &pKernelVgpuMgr->pgpuInfo[i];
2076 
2077     for (pKernelHostVgpuDevice = listHead(&(pPhysGpuInfo->listHostVgpuDeviceHead));
2078          pKernelHostVgpuDevice != NULL;
2079          pKernelHostVgpuDevice = listNext(&(pPhysGpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2080     {
2081         if (portMemCmp(pKernelHostVgpuDevice->vgpuUuid, vgpuUuid, VGPU_UUID_SIZE) == 0)
2082             break;
2083     }
2084 
2085     if (pKernelHostVgpuDevice == NULL)
2086         return NV_ERR_OBJECT_NOT_FOUND;
2087 
2088     if (gpuIsSriovEnabled(pGpu))
2089     {
2090         NV2080_CTRL_VGPU_MGR_INTERNAL_SET_VGPU_ENCODER_CAPACITY_PARAMS params;
2091         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2092 
2093         params.gfid = pKernelHostVgpuDevice->gfid;
2094         params.encoderCapacity = encoderCapacity;
2095 
2096         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2097                               pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
2098                                               NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_SET_VGPU_ENCODER_CAPACITY,
2099                                               &params, sizeof(params)));
2100     }
2101 
2102     return NV_OK;
2103 }
2104 
2105 //
2106 // Add vGPU info received on mdev_create sysfs call to REQUEST_VGPU_INFO_NODE
2107 // list. REQUEST_VGPU_INFO_NODE is currently used only for vGPU on KVM.
2108 //
2109 // This funtion first checks whether the vGPU type is supported or not as
2110 // only homegeneous vGPU types are supported currently. Also, this function
2111 // only creates REQUEST_VGPU_INFO_NODE entry, actual vGPU will be created later
2112 //
2113 NV_STATUS
kvgpumgrCreateRequestVgpu(NvU32 gpuPciId,const NvU8 * pMdevUuid,NvU32 vgpuTypeId,NvU16 * vgpuId,NvU32 gpuPciBdf)2114 kvgpumgrCreateRequestVgpu(NvU32 gpuPciId, const NvU8 *pMdevUuid,
2115                           NvU32 vgpuTypeId, NvU16 *vgpuId, NvU32 gpuPciBdf)
2116 {
2117     OBJSYS *pSys = SYS_GET_INSTANCE();
2118     OBJGPU *pGpu = gpumgrGetGpuFromId(gpuPciId);
2119     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2120     OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
2121     NvU32 pgpuIndex;
2122     NV_STATUS status = NV_OK;
2123     VGPU_TYPE *vgpuTypeInfo;
2124     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
2125     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
2126     NvU32 allocFlags = NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_UP;
2127     NvU64 vgpuIdSize = 1, tmpVgpuId;
2128     NvU8 devfn = gpuDecodeDevice(gpuPciBdf);
2129     NvU32 swizzId = KMIGMGR_SWIZZID_INVALID;
2130 
2131     if (pGpu == NULL)
2132     {
2133         NV_PRINTF(LEVEL_ERROR, "GPU handle is not valid \n");
2134         return NV_ERR_INVALID_STATE;
2135     }
2136 
2137     if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
2138         return status;
2139 
2140     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[pgpuIndex]);
2141 
2142     if ((status = kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &vgpuTypeInfo)) != NV_OK)
2143         return status;
2144 
2145     /*
2146      * For DriverVM, we will defer the createdVfMask validation later
2147      * during open call when the params provided.
2148      *
2149      */
2150 
2151     if (gpuIsSriovEnabled(pGpu) &&
2152         !(pHypervisor->getProperty(pHypervisor, PDB_PROP_HYPERVISOR_DRIVERVM_ENABLED)))
2153     {
2154         NvU8 fnId = devfn - pGpu->sriovState.firstVFOffset;
2155 
2156         NV_ASSERT_OR_RETURN((fnId < 64), NV_ERR_INVALID_ARGUMENT);
2157 
2158         if (pPhysGpuInfo->createdVfMask & NVBIT64(fnId))
2159             /* mdev device is already created on VF */
2160             return NV_ERR_INVALID_OPERATION;
2161     }
2162 
2163     if (IS_MIG_ENABLED(pGpu))
2164     {
2165         NvU32 partitionFlag = PARTITIONID_INVALID;
2166 
2167         NV_CHECK_OR_RETURN(LEVEL_INFO,
2168             IS_MIG_IN_USE(pGpu),
2169             NV_ERR_INVALID_OPERATION);
2170 
2171         NV_ASSERT_OK_OR_RETURN(
2172             kvgpumgrGetPartitionFlag(vgpuTypeInfo->vgpuTypeId, &partitionFlag));
2173 
2174         NV_ASSERT_OK_OR_RETURN(
2175             kvgpumgrGetSwizzId(pGpu, pPhysGpuInfo, partitionFlag, &swizzId));
2176     }
2177     else
2178     {
2179         // Creation request for a MIG vgpuType
2180         if (vgpuTypeInfo->gpuInstanceSize)
2181             return NV_ERR_INVALID_OPERATION;
2182 
2183         status = kvgpumgrCheckVgpuTypeCreatable(pGpu, pPhysGpuInfo, vgpuTypeInfo);
2184 
2185         if (status != NV_OK)
2186             return status;
2187     }
2188 
2189     /* Initialize heap on first vGPU device creation */
2190     if (pKernelVgpuMgr->pHeap == NULL)
2191     {
2192         NvU64 tmpSize;
2193         pKernelVgpuMgr->pHeap = portMemAllocNonPaged(sizeof(OBJEHEAP));
2194         if (pKernelVgpuMgr->pHeap == NULL)
2195         {
2196             status = NV_ERR_NO_MEMORY;
2197             goto failed;
2198         }
2199 
2200         constructObjEHeap(pKernelVgpuMgr->pHeap, 1, 0xFFFF + 1, 0, 0);
2201 
2202         /* Verify if pHeap is allocated with required size */
2203         pKernelVgpuMgr->pHeap->eheapGetSize(pKernelVgpuMgr->pHeap, &tmpSize);
2204         if (tmpSize != 0xFFFF)
2205         {
2206             pKernelVgpuMgr->pHeap->eheapDestruct(pKernelVgpuMgr->pHeap);
2207             portMemFree(pKernelVgpuMgr->pHeap);
2208             pKernelVgpuMgr->pHeap = NULL;
2209             status = NV_ERR_INSUFFICIENT_RESOURCES;
2210             goto failed;
2211         }
2212     }
2213 
2214     status = pKernelVgpuMgr->pHeap->eheapAlloc(pKernelVgpuMgr->pHeap, 0xdeadbeef, &allocFlags,
2215                                          &tmpVgpuId, &vgpuIdSize, 1, 1,
2216                                          NULL, NULL, NULL);
2217     if (status != NV_OK)
2218     {
2219         NV_PRINTF(LEVEL_WARNING,
2220                   "Failed to allocate heap for vGPU ID 0x%x\n",
2221                   status);
2222         goto failed;
2223     }
2224 
2225     *vgpuId = (NvU16) tmpVgpuId;
2226     pRequestVgpu = listPrependNew(&(pKernelVgpuMgr->listRequestVgpuHead));
2227     if (pRequestVgpu == NULL)
2228     {
2229         status = NV_ERR_NO_MEMORY;
2230         goto failed;
2231     }
2232 
2233     portMemSet(pRequestVgpu, 0, sizeof(REQUEST_VGPU_INFO_NODE));
2234 
2235     portMemCopy(pRequestVgpu->mdevUuid, VGPU_UUID_SIZE, pMdevUuid, VGPU_UUID_SIZE);
2236     pRequestVgpu->gpuPciId = gpuPciId; /* For SRIOV, this is PF's gpuPciId */
2237     pRequestVgpu->gpuPciBdf = gpuPciBdf; /* For SRIOV, this is VF's gpuPciBdf */
2238     pRequestVgpu->vgpuId = *vgpuId;
2239 
2240     if (IS_MIG_IN_USE(pGpu))
2241     {
2242         pRequestVgpu->swizzId = swizzId;
2243     }
2244 
2245     kvgpumgrSetVgpuType(pGpu, pPhysGpuInfo, vgpuTypeId);
2246     pPhysGpuInfo->numCreatedVgpu++;
2247 
2248     if (gpuGetDevice(pGpu) != devfn)  /* SRIOV - VF */
2249         pPhysGpuInfo->createdVfMask |= NVBIT64(devfn - pGpu->sriovState.firstVFOffset);
2250 
2251     return NV_OK;
2252 
2253 failed:
2254     if (swizzId != KMIGMGR_SWIZZID_INVALID)
2255         _kvgpumgrClearAssignedSwizzIdMask(pGpu, swizzId);
2256 
2257     return status;
2258 }
2259 
2260 //
2261 // Delete REQUEST_VGPU_INFO_NODE structure from list.
2262 // REQUEST_VGPU_INFO_NODE is currently used only for vGPU on KVM.
2263 //
2264 NV_STATUS
kvgpumgrDeleteRequestVgpu(const NvU8 * pMdevUuid,NvU16 vgpuId)2265 kvgpumgrDeleteRequestVgpu(const NvU8 *pMdevUuid, NvU16 vgpuId)
2266 {
2267     OBJSYS *pSys = SYS_GET_INSTANCE();
2268     OBJGPU *pGpu = NULL;
2269     NV_STATUS status;
2270     NvU32 pgpuIndex;
2271     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2272     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
2273     REQUEST_VGPU_INFO_NODE *pRequestVgpuNext = NULL;
2274     NvU8 devfn = 0;
2275 
2276     for (pRequestVgpu = listHead(&(pKernelVgpuMgr->listRequestVgpuHead));
2277          pRequestVgpu != NULL;
2278          pRequestVgpu = pRequestVgpuNext)
2279     {
2280         pRequestVgpuNext = listNext(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
2281         if (portMemCmp(pMdevUuid, pRequestVgpu->mdevUuid, VGPU_UUID_SIZE) == 0)
2282         {
2283             if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pRequestVgpu->gpuPciId,
2284                                               &pgpuIndex)) != NV_OK)
2285                 return status;
2286 
2287             pGpu  = gpumgrGetGpuFromId(pRequestVgpu->gpuPciId);
2288             devfn = gpuDecodeDevice(pRequestVgpu->gpuPciBdf);
2289 
2290             pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu--;
2291 
2292             if (pGpu && (gpuGetDevice(pGpu) != devfn)) // SRIOV - VF
2293                 pKernelVgpuMgr->pgpuInfo[pgpuIndex].createdVfMask &= ~(NVBIT64(devfn - pGpu->sriovState.firstVFOffset));
2294 
2295             if (IS_MIG_ENABLED(pGpu))
2296                 _kvgpumgrClearAssignedSwizzIdMask(pGpu, pRequestVgpu->swizzId);
2297             else if (pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu == 0)
2298                 kvgpumgrSetVgpuType(pGpu, &pKernelVgpuMgr->pgpuInfo[pgpuIndex], NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE);
2299 
2300             pKernelVgpuMgr->pHeap->eheapFree(pKernelVgpuMgr->pHeap, vgpuId);
2301 
2302             listRemove(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
2303 
2304             return NV_OK;
2305         }
2306     }
2307     return NV_ERR_OBJECT_NOT_FOUND;
2308 }
2309 
kvgpumgrGetAvailableInstances(NvU32 * availInstances,OBJGPU * pGpu,VGPU_TYPE * vgpuTypeInfo,NvU32 pgpuIndex,NvU8 devfn)2310 NV_STATUS kvgpumgrGetAvailableInstances(
2311     NvU32     *availInstances,
2312     OBJGPU    *pGpu,
2313     VGPU_TYPE *vgpuTypeInfo,
2314     NvU32      pgpuIndex,
2315     NvU8       devfn
2316 )
2317 {
2318     NV_STATUS rmStatus = NV_OK;
2319     OBJSYS *pSys = SYS_GET_INSTANCE();
2320     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2321     OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
2322 
2323     *availInstances = 0;
2324 
2325     /* TODO: Needs to have a proper fix this for DriverVM config */
2326     if (gpuIsSriovEnabled(pGpu) &&
2327         !pHypervisor->getProperty(pHypervisor, PDB_PROP_HYPERVISOR_DRIVERVM_ENABLED))
2328     {
2329         NvU8 fnId = devfn - pGpu->sriovState.firstVFOffset;
2330 
2331         NV_ASSERT_OR_RETURN(fnId <= pGpu->sriovState.totalVFs, NV_ERR_INVALID_ARGUMENT);
2332 
2333         if (IS_MIG_ENABLED(pGpu))
2334         {
2335             if (IS_MIG_IN_USE(pGpu))
2336             {
2337                 NvU64 swizzIdInUseMask = 0;
2338                 NvU32 partitionFlag = PARTITIONID_INVALID;
2339                 KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
2340                 NvU32 id;
2341 
2342                 swizzIdInUseMask = kmigmgrGetSwizzIdInUseMask(pGpu, pKernelMIGManager);
2343 
2344                 if (!vgpuTypeInfo->gpuInstanceSize)
2345                 {
2346                     // Query for a non MIG vgpuType
2347                     NV_PRINTF(LEVEL_INFO, "Query for a non MIG vGPU type \n");
2348                     rmStatus = NV_OK;
2349                     goto exit;
2350                 }
2351 
2352                 rmStatus = kvgpumgrGetPartitionFlag(vgpuTypeInfo->vgpuTypeId,
2353                                                     &partitionFlag);
2354                 if (rmStatus != NV_OK)
2355                 {
2356                     // Query for a non MIG vgpuType
2357                     NV_PRINTF(LEVEL_ERROR, "Failed to get partition flags.\n");
2358                     goto exit;
2359                 }
2360 
2361                 // Determine valid swizzids not assigned to any vGPU device.
2362                 FOR_EACH_INDEX_IN_MASK(64, id, swizzIdInUseMask)
2363                 {
2364                     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
2365                     NvU64 mask = 0;
2366 
2367                     rmStatus = kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager,
2368                                                          id, &pKernelMIGGpuInstance);
2369                     if (rmStatus != NV_OK)
2370                     {
2371                         // Didn't find requested GPU instance
2372                         NV_PRINTF(LEVEL_ERROR,
2373                                   "No valid GPU instance with SwizzId - %d found\n", id);
2374                         goto exit;
2375                     }
2376 
2377                     mask = NVBIT64(id);
2378 
2379                     if (pKernelMIGGpuInstance->partitionFlag == partitionFlag)
2380                     {
2381                         // Validate that same ID is not already set and VF is available
2382                         if (!(mask & pKernelVgpuMgr->pgpuInfo[pgpuIndex].assignedSwizzIdMask) &&
2383                             !(pKernelVgpuMgr->pgpuInfo[pgpuIndex].createdVfMask & NVBIT64(fnId)))
2384                         {
2385                             *availInstances = 1;
2386                             break;
2387                         }
2388                     }
2389                 }
2390                 FOR_EACH_INDEX_IN_MASK_END;
2391             }
2392         }
2393         else
2394         {
2395             if (pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu < vgpuTypeInfo->maxInstance)
2396             {
2397                 if (vgpuTypeInfo->gpuInstanceSize)
2398                 {
2399                     // Query for a MIG vgpuType
2400                     NV_PRINTF(LEVEL_INFO, "Query for a MIG vGPU type\n");
2401                     rmStatus = NV_OK;
2402                     goto exit;
2403                 }
2404 
2405                 if (!(pKernelVgpuMgr->pgpuInfo[pgpuIndex].createdVfMask & NVBIT64(fnId)))
2406                 {
2407                     if (kvgpumgrCheckVgpuTypeCreatable(pGpu, &pKernelVgpuMgr->pgpuInfo[pgpuIndex],
2408                                                        vgpuTypeInfo) == NV_OK)
2409                         *availInstances = 1;
2410                 }
2411             }
2412         }
2413     }
2414     else
2415     {
2416         if (kvgpumgrCheckVgpuTypeCreatable(pGpu, &pKernelVgpuMgr->pgpuInfo[pgpuIndex], vgpuTypeInfo) == NV_OK)
2417             *availInstances = vgpuTypeInfo->maxInstance - pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu;
2418     }
2419 
2420 exit:
2421     return rmStatus;
2422 }
2423 
2424 NV_STATUS
kvgpumgrGetHostVgpuDeviceFromMdevUuid(NvU32 gpuPciId,const NvU8 * pMdevUuid,KERNEL_HOST_VGPU_DEVICE ** ppKernelHostVgpuDevice)2425 kvgpumgrGetHostVgpuDeviceFromMdevUuid(NvU32 gpuPciId, const NvU8 *pMdevUuid,
2426                                       KERNEL_HOST_VGPU_DEVICE **ppKernelHostVgpuDevice)
2427 {
2428     OBJSYS *pSys = SYS_GET_INSTANCE();
2429     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2430     NvU32 pgpuIndex , rmStatus;
2431     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2432     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2433 
2434     if ((rmStatus = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
2435         return rmStatus;
2436 
2437     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
2438 
2439     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
2440          pKernelHostVgpuDevice != NULL;
2441          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2442     {
2443         if (pKernelHostVgpuDevice == NULL || pKernelHostVgpuDevice->pRequestVgpuInfoNode == NULL)
2444             return NV_ERR_INVALID_POINTER;
2445 
2446         if (portMemCmp(pKernelHostVgpuDevice->pRequestVgpuInfoNode->mdevUuid,
2447                        pMdevUuid, VM_UUID_SIZE) == 0)
2448         {
2449             *ppKernelHostVgpuDevice = pKernelHostVgpuDevice;
2450             return NV_OK;
2451         }
2452      }
2453     NV_PRINTF(LEVEL_ERROR, "Object not found\n");
2454     return NV_ERR_OBJECT_NOT_FOUND;
2455 }
2456 
2457 NV_STATUS
kvgpumgrGetHostVgpuDeviceFromVgpuUuid(NvU32 gpuPciId,NvU8 * vgpuUuid,KERNEL_HOST_VGPU_DEVICE ** ppKernelHostVgpuDevice)2458 kvgpumgrGetHostVgpuDeviceFromVgpuUuid(NvU32 gpuPciId, NvU8 *vgpuUuid,
2459                                   KERNEL_HOST_VGPU_DEVICE **ppKernelHostVgpuDevice)
2460 {
2461     OBJSYS *pSys = SYS_GET_INSTANCE();
2462     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2463     NvU32 pgpuIndex;
2464     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2465     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2466 
2467     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex));
2468 
2469     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
2470 
2471     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
2472          pKernelHostVgpuDevice != NULL;
2473          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2474     {
2475         if (portMemCmp(pKernelHostVgpuDevice->vgpuUuid,
2476                              vgpuUuid, VM_UUID_SIZE) == 0)
2477         {
2478             *ppKernelHostVgpuDevice = pKernelHostVgpuDevice;
2479             return NV_OK;
2480         }
2481     }
2482 
2483     return NV_ERR_OBJECT_NOT_FOUND;
2484 }
2485 
2486 /*
2487  * On 1GB profiles on 48GB board, we do not deduct any reserved fb from vGPU FB length
2488  * as maxInstance is only 32, so guest complete 1GB of fb mem. In such cases with
2489  * heterogeneous vGPUs, for such 1G profiles on 48G board, some combinations with
2490  * other vGPU types do not work.
2491  * Due to this, A40-8Q at placement Id 0 cannot work with A40-1Q at placement Id 8 since
2492  * A40-1Q is occupying larger vGPU FB length and overlaps with A40-8Q's assigned FB.
2493  * Similar scenario happens for A40-8Q at placement Id 24 and A40-1Q at placement Id 32
2494  * So, we disable 1GB profiles in such cases at placement Id 8 and placement Id 32.
2495  */
2496 static NvBool
_kvgpumgrIsPlacementValid(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPgpuInfo,NvU32 vgpuTypeIndex,NvU32 placementId)2497 _kvgpumgrIsPlacementValid(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPgpuInfo, NvU32 vgpuTypeIndex,
2498                           NvU32 placementId)
2499 {
2500     NvU64 vgpuFbLength;
2501     NvU32 denyListAdaHopper[] = {2, 3, 8, 9, 14, 15, 20, 21, 26, 27, 32, 33, 38, 39, 44, 45};
2502     NvU32 denyListAmpere[] = {8, 32};
2503     NvU32 i, length, *invalidPlacements;
2504 
2505     if (IS_GSP_CLIENT(pGpu))
2506     {
2507         invalidPlacements = denyListAdaHopper;
2508         length = NV_ARRAY_ELEMENTS(denyListAdaHopper);
2509     }
2510     else
2511     {
2512         invalidPlacements = denyListAmpere;
2513         length = NV_ARRAY_ELEMENTS(denyListAmpere);
2514     }
2515 
2516     vgpuFbLength = pPgpuInfo->guestVmmuCount[vgpuTypeIndex] * gpuGetVmmuSegmentSize(pGpu);
2517 
2518     if (vgpuFbLength == VGPU_LOWER_FB_PROFILE_SIZE_1_GB)
2519     {
2520         for (i = 0; i < length; i++)
2521         {
2522            if (invalidPlacements[i] == placementId)
2523                return NV_FALSE;
2524         }
2525     }
2526 
2527     return NV_TRUE;
2528 }
2529 
2530 /*
2531  * This function recursively divides the placement region in 1/2, 1/4, 1/8, 1/16 partitions
2532  * and then calculates the placement IDs of each vGPU type. It will try to allocate
2533  * placement ID of 2 vGPU instances for a type in such a way that the placement ID
2534  * of first vGPU instance starts at the beginning of partition and the placement ID
2535  * of second vGPU instance ends at the end of partition.
2536  *
2537  * It finds the vGPU types whose 2 instances can be allocated in a 1/2, 1/4, 1/8, 1/16
2538  * partition and then allocates one at start of partition and other at end of partion.
2539  *
2540  * It does this recursively by taking input start and end as input alongwith the current
2541  * partition which specifies whether this is 1/1, 1/2, 1/4, 1/8, 1/16 partion.
2542  *
2543  * Similarly it also calculates the channel offsets for each supported placementId
2544  * for a vGPU type. The algorithm for calculating placementId and channel offset
2545  * is the same just that for channel offset the range is from 0 to 2048.
2546  *
2547  * For vGPU-GSP, we also need to define offsets in FB for GSP plugin heap.
2548  * For larger vGPU profiles with GSP plugin heap >=1 vMMU segment, the gsp heap is
2549  * placed at the end of vGPU FB.
2550  * For smaller profiles with gsp heap < 1 vMMU segment, heap is placed at end of
2551  * each 1/4th alignment (for 128MB vMMU segment size) OR 1/8th alighment (for 64MB
2552  * vMMU segment size). For such profiles the vMMU segment at the end of 1/4 or 1/8
2553  * partition is divided as per profile's heap size.
2554  *
2555  */
2556 static void
_kvgpumgrSetHeterogeneousResources(OBJGPU * pGpu,KERNEL_PHYS_GPU_INFO * pPgpuInfo,NvU32 placementIdMin,NvU32 placementIdMax,NvU32 chidMin,NvU32 chidMax,NvU32 vmmuSegMin,NvU32 vmmuSegMax,NvU64 gspHeapOffsetMin,NvU64 gspHeapOffsetMax,NvU32 partitionCount,NvBool isLeftPartition)2557 _kvgpumgrSetHeterogeneousResources(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPgpuInfo, NvU32 placementIdMin,
2558                                    NvU32 placementIdMax, NvU32 chidMin, NvU32 chidMax,
2559                                    NvU32 vmmuSegMin, NvU32 vmmuSegMax, NvU64 gspHeapOffsetMin,
2560                                    NvU64 gspHeapOffsetMax, NvU32 partitionCount,
2561                                    NvBool isLeftPartition)
2562 {
2563     VGPU_TYPE *pVgpuTypeInfo;
2564     NvU32 heterogeneousMaxInstance, i;
2565     NvBool isCarveOutGspHeap = NV_FALSE;
2566     NvU64 newVmmuSegMin, newVmmuSegMax, newGspHeapOffsetMin, newGspHeapOffsetMax, vmmuSegSize;
2567     NvBool isDefineLeftPlacement, isDefineRightPlacement;
2568 
2569     /*
2570      * As max vGPU per GPU is 32, the minimum partition for 2 vGPUs will be 16.
2571      * So, if this is a 1/16 partition, don't recurse further
2572      */
2573     if (partitionCount > MAX_VGPU_DEVICES_PER_PGPU / 2)
2574         return;
2575 
2576     vmmuSegSize = gpuGetVmmuSegmentSize(pGpu);
2577     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
2578     {
2579         pVgpuTypeInfo = pPgpuInfo->vgpuTypes[i];
2580 
2581         if (pVgpuTypeInfo->placementSize == 0)
2582             continue;
2583 
2584         isDefineLeftPlacement = NV_FALSE;
2585         isDefineRightPlacement = NV_FALSE;
2586 
2587         heterogeneousMaxInstance = nvPrevPow2_U32(pVgpuTypeInfo->maxInstance);
2588 
2589         /*
2590          * If homogeneous maxInstances of vGPU type are in power-of-2 and can fit in this partition,
2591          * then define both the placements in this recursive call
2592          */
2593         if (partitionCount * 2 == pVgpuTypeInfo->maxInstance)
2594         {
2595             isDefineLeftPlacement = NV_TRUE;
2596             isDefineRightPlacement = NV_TRUE;
2597 
2598             /*
2599              * Check if the next recursive partition will be a smaller partition for which
2600              * we need to carve out GSP heap at the end of smaller partition.
2601              */
2602             if (IS_GSP_CLIENT(pGpu) && (isCarveOutGspHeap == NV_FALSE) &&
2603                 (pVgpuTypeInfo->gspHeapSize == vmmuSegSize))
2604                 isCarveOutGspHeap = NV_TRUE;
2605         }
2606         else if (((heterogeneousMaxInstance < pVgpuTypeInfo->maxInstance) &&
2607                   (heterogeneousMaxInstance == partitionCount)) ||
2608                  ((partitionCount == 1) && (pVgpuTypeInfo->maxInstance == 1)))
2609         {
2610             /*
2611              * If only one instance of vGPU type can fit in this partition, then define
2612              * placement depending on whether it is a left or right partition
2613              */
2614             isDefineLeftPlacement = isLeftPartition;
2615             isDefineRightPlacement = !isLeftPartition;
2616         }
2617 
2618 
2619         if (isDefineLeftPlacement == NV_TRUE)
2620         {
2621             /*
2622              * Fill placement ID / channel / FB offset of first vGPU in this partition
2623              * First vGPU is aligned to the starting of partition
2624              */
2625             if (_kvgpumgrIsPlacementValid(pGpu, pPgpuInfo, i, placementIdMin))
2626             {
2627                 pVgpuTypeInfo->supportedPlacementIds[pVgpuTypeInfo->placementCount] = placementIdMin;
2628                 pVgpuTypeInfo->supportedChidOffsets[pVgpuTypeInfo->placementCount] = chidMin;
2629 
2630                 if (!IS_GSP_CLIENT(pGpu))
2631                     pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2632                 else
2633                 {
2634                     /* If profile occupies > 1 vMMU segment for GSP heap, place heap at end of vGPU FB. */
2635                     if (pVgpuTypeInfo->gspHeapSize >= vmmuSegSize)
2636                     {
2637                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2638                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2639                             (vmmuSegMin + pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize;
2640                     }
2641                     else
2642                     {
2643                         /*
2644                          * If we're in smaller parition, GSP vMMU segment will be input to the function.
2645                          * Place the gsp heap of first vGPU at the starting of the GSP vMMU segment.
2646                          */
2647                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2648                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] = gspHeapOffsetMin;
2649                     }
2650 
2651                     /* For 32:1 vGPU types, the GSP heap is placed between 2 consecutive guest vMMU segments */
2652                     if (heterogeneousMaxInstance == 32)
2653                     {
2654                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2655                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2656                             (vmmuSegMin + pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize;
2657                     }
2658                 }
2659 
2660                 pVgpuTypeInfo->placementCount++;
2661             }
2662         }
2663 
2664         if (isDefineRightPlacement == NV_TRUE)
2665         {
2666             /*
2667              * Fill placement ID / channel / FB offset of second vGPU in this partition
2668              * Second vGPU is aligned to the end of partition
2669              */
2670             if (_kvgpumgrIsPlacementValid(pGpu, pPgpuInfo, i,
2671                                           placementIdMax - pVgpuTypeInfo->placementSize))
2672             {
2673                 pVgpuTypeInfo->supportedPlacementIds[pVgpuTypeInfo->placementCount] =
2674                                            placementIdMax - pVgpuTypeInfo->placementSize;
2675 
2676                 pVgpuTypeInfo->supportedChidOffsets[pVgpuTypeInfo->placementCount] =
2677                                            chidMax - pVgpuTypeInfo->channelCount;
2678 
2679                 if (!IS_GSP_CLIENT(pGpu))
2680                     pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2681                                                vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2682                 else
2683                 {
2684                     /* If profile occupies > 1 vMMU segment for GSP heap, place heap at end of vGPU FB. */
2685                     if (pVgpuTypeInfo->gspHeapSize >= vmmuSegSize)
2686                     {
2687                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2688                             vmmuSegMax - pPgpuInfo->guestVmmuCount[i] - (pVgpuTypeInfo->gspHeapSize / vmmuSegSize);
2689                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2690                             (vmmuSegMax * vmmuSegSize) - pVgpuTypeInfo->gspHeapSize;
2691                     }
2692                     else
2693                     {
2694                         /*
2695                          * If we're in smaller parition, GSP vMMU segment will be input to the function.
2696                          * Place the gsp heap of first vGPU at the starting of the GSP vMMU segment.
2697                          */
2698                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2699                                                                 vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2700                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2701                                                                     gspHeapOffsetMax - pVgpuTypeInfo->gspHeapSize;
2702                     }
2703 
2704                     /* For 32:1 vGPU types, the GSP heap is placed between 2 consecutive guest vMMU segments */
2705                     if (heterogeneousMaxInstance == 32)
2706                     {
2707                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2708                                                        vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2709                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2710                             ((vmmuSegMax - pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize) - pVgpuTypeInfo->gspHeapSize;
2711                     }
2712                 }
2713 
2714                 pVgpuTypeInfo->placementCount++;
2715             }
2716         }
2717     }
2718 
2719     /*
2720      * If the next recursive partition is for a left smaller partition which has GSP heap at
2721      * of start of partition, then update vmmuSegMin to reserve one segment at the
2722      * start of smaller partition. Also, init gsp min/max value for the reserved vMMU segment
2723      * at the start.
2724      */
2725     newVmmuSegMax = ((vmmuSegMin + vmmuSegMax) / 2);
2726     if (isCarveOutGspHeap)
2727     {
2728         NV_ASSERT((gspHeapOffsetMin == 0));
2729 
2730         newVmmuSegMin = vmmuSegMin + 1;
2731         newGspHeapOffsetMin = vmmuSegMin * vmmuSegSize;
2732         newGspHeapOffsetMax = newGspHeapOffsetMin + vmmuSegSize;
2733     }
2734     else
2735     {
2736         newVmmuSegMin = vmmuSegMin;
2737         newGspHeapOffsetMin = gspHeapOffsetMin;
2738         newGspHeapOffsetMax = (gspHeapOffsetMin + gspHeapOffsetMax) / 2;
2739     }
2740 
2741     /* Recursively call to get placment ID in left half of this partition */
2742     _kvgpumgrSetHeterogeneousResources(pGpu, pPgpuInfo, placementIdMin,
2743                              (placementIdMin + placementIdMax) / 2,
2744                              chidMin, (chidMin + chidMax) / 2, newVmmuSegMin,
2745                              newVmmuSegMax, newGspHeapOffsetMin, newGspHeapOffsetMax, partitionCount * 2,
2746                              NV_TRUE);
2747 
2748     /*
2749      * If the next recursive partition is for a right smaller partition which has GSP heap at
2750      * of end of partition, then update vmmuSegMax to reserve one segment at the
2751      * end of right partition. Also, init gsp min/max value for the reserved vMMU segment
2752      * at the end.
2753      */
2754     newVmmuSegMin = (vmmuSegMin + vmmuSegMax) / 2;
2755     if (isCarveOutGspHeap)
2756     {
2757         newVmmuSegMax = vmmuSegMax - 1;
2758         newGspHeapOffsetMin = newVmmuSegMax * vmmuSegSize;
2759         newGspHeapOffsetMax = newGspHeapOffsetMin + vmmuSegSize;
2760     }
2761     else
2762     {
2763         newVmmuSegMax = vmmuSegMax;
2764         newGspHeapOffsetMin = (gspHeapOffsetMin + gspHeapOffsetMax) / 2;;
2765         newGspHeapOffsetMax = gspHeapOffsetMax;
2766     }
2767 
2768     /* Recursively call to get placment ID in right half of this partition */
2769     _kvgpumgrSetHeterogeneousResources(pGpu, pPgpuInfo, (placementIdMin + placementIdMax) / 2,
2770                              placementIdMax, (chidMin + chidMax) / 2,
2771                              chidMax, newVmmuSegMin, newVmmuSegMax,
2772                              newGspHeapOffsetMin, newGspHeapOffsetMax, partitionCount * 2,
2773                              NV_FALSE);
2774 }
2775 
2776 NV_STATUS
kvgpumgrSetSupportedPlacementIds(OBJGPU * pGpu)2777 kvgpumgrSetSupportedPlacementIds(OBJGPU *pGpu)
2778 {
2779     OBJSYS     *pSys     = SYS_GET_INSTANCE();
2780     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2781     KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
2782     MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
2783     NV_STATUS rmStatus = NV_OK;
2784     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2785     NvU32 index, i;
2786     VGPU_TYPE *pVgpuTypeInfo;
2787     NvU32 hostChannelCount = 0, totalVmmuCount = 0;
2788     NvU64 totalReservedFb, vgpuReservedFb, guestFbLength, totalAvailableFb, totalRequiredFb;
2789     NvU64 gspHeapOffsetMax, gspHeapOffsetMin, pmaRegionLength, pmaBaseOffset, largestOffset;
2790     NvU64 vmmuOffsetMin, vmmuOffsetMax, vmmuSegmentMin, vmmuSegmentMax;
2791     Heap *pHeap = GPU_GET_HEAP(pGpu);
2792 
2793     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2794             kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &index));
2795 
2796     pPgpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
2797 
2798     pPgpuInfo->heterogeneousTimesliceSizesSupported = NV_FALSE;
2799 
2800     /* Heterogeneous vgpus enabled for SRIOV vGPUs on VMware/KVM */
2801     if (gpuIsSriovEnabled(pGpu)
2802         )
2803     {
2804         if (osIsVgpuVfioPresent() == NV_OK)
2805             pPgpuInfo->heterogeneousTimesliceSizesSupported = NV_TRUE;
2806     }
2807 
2808     if (!pPgpuInfo->heterogeneousTimesliceSizesSupported)
2809         return rmStatus;
2810 
2811     hostChannelCount = kfifoChidMgrGetNumChannels(pGpu, pKernelFifo, pKernelFifo->ppChidMgr[0]);
2812 
2813     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
2814     {
2815         pVgpuTypeInfo = pPgpuInfo->vgpuTypes[i];
2816         if (pVgpuTypeInfo == NULL)
2817             break;
2818 
2819         /* Set to NVA081_PLACEMENT_ID_INVALID initially */
2820         portMemSet(pVgpuTypeInfo->supportedPlacementIds, NV_U8_MAX,
2821                    sizeof(pVgpuTypeInfo->supportedPlacementIds));
2822 
2823         /* Ignore MIG vGPUs, only used for timesliced vGPUs */
2824         if (pVgpuTypeInfo->gpuInstanceSize != 0)
2825         {
2826             pVgpuTypeInfo->placementSize = 0;
2827             continue;
2828         }
2829 
2830         pVgpuTypeInfo->placementCount = 0;
2831         pPgpuInfo->guestVmmuCount[i] = 0;
2832         pVgpuTypeInfo->placementSize = pVgpuTypeInfo->profileSize / (1024 * 1024 * 1024);
2833 
2834         if (gpuIsSriovEnabled(pGpu))
2835         {
2836             if (!gpuIsNonPowerOf2ChannelCountSupported(pGpu))
2837                 pVgpuTypeInfo->channelCount = nvPrevPow2_U32(hostChannelCount /
2838                                                              pVgpuTypeInfo->maxInstance);
2839 
2840             /*
2841              * For sriov vGPUs with GSP disabled, guest FB length is only dependent on
2842              * profile fb length and RM reserved fb (including ECC). Calculate the
2843              * guest fb length here by reducing reserved FB from profile fb length
2844              * depending on max instance and aligning it to VMMU segment size.
2845              */
2846             if (!IS_GSP_CLIENT(pGpu))
2847             {
2848                 totalReservedFb = memmgrGetVgpuHostRmReservedFb_HAL(pGpu,
2849                                     pMemoryManager, pVgpuTypeInfo->vgpuTypeId) +
2850                                   kvgpumgrGetEccAndPrReservedFb(pGpu);
2851 
2852                 vgpuReservedFb = NV_ALIGN_UP((totalReservedFb / pVgpuTypeInfo->maxInstance),
2853                                      gpuGetVmmuSegmentSize(pGpu));
2854 
2855                 /*
2856                  * For 1GB profiles on 48GB board, maxInstances is limited to 32. For such
2857                  * profiles, there is no per vgpu reserved fb carved out from guest fb as
2858                  * host has space for reserved fb.
2859                  */
2860                 if (pVgpuTypeInfo->profileSize == VGPU_LOWER_FB_PROFILE_SIZE_1_GB)
2861                 {
2862                     heapGetUsableSize(pHeap, &totalAvailableFb);
2863 
2864                     /* Total FB needed if vgpu reserved fb is 0 and not carved from guest fb */
2865                     totalRequiredFb = pVgpuTypeInfo->maxInstance *
2866                                       (VGPU_LOWER_FB_PROFILE_SIZE_1_GB + vgpuReservedFb);
2867 
2868                     if (totalRequiredFb < totalAvailableFb)
2869                         vgpuReservedFb = 0;
2870                 }
2871 
2872                 guestFbLength = pVgpuTypeInfo->profileSize - vgpuReservedFb;
2873 
2874                 pPgpuInfo->guestVmmuCount[i] = guestFbLength / gpuGetVmmuSegmentSize(pGpu);
2875             }
2876             else
2877             {
2878                 /* Calculate the guest FB using similar calculation as done in vGPU plugin */
2879                 totalAvailableFb = pMemoryManager->Ram.fbTotalMemSizeMb << 20;
2880                 totalAvailableFb = NV_ALIGN_UP(totalAvailableFb, 8 * gpuGetVmmuSegmentSize(pGpu));
2881 
2882                 guestFbLength = (totalAvailableFb / pVgpuTypeInfo->maxInstance) -
2883                                 pVgpuTypeInfo->fbReservation - pVgpuTypeInfo->gspHeapSize;
2884                 guestFbLength = NV_MIN(guestFbLength, pVgpuTypeInfo->fbLength);
2885                 guestFbLength = NV_ALIGN_DOWN(guestFbLength, gpuGetVmmuSegmentSize(pGpu));
2886 
2887                 pPgpuInfo->guestVmmuCount[i] = guestFbLength / gpuGetVmmuSegmentSize(pGpu);
2888             }
2889         }
2890 
2891         if (pVgpuTypeInfo->maxInstance == 1)
2892         {
2893             pPgpuInfo->placementRegionSize = pVgpuTypeInfo->placementSize;
2894 
2895             if (gpuIsSriovEnabled(pGpu))
2896             {
2897                 if (pPgpuInfo->guestVmmuCount[i])
2898                 {
2899                     totalVmmuCount = pPgpuInfo->guestVmmuCount[i];
2900 
2901                     if (IS_GSP_CLIENT(pGpu))
2902                         totalVmmuCount += (pVgpuTypeInfo->gspHeapSize / gpuGetVmmuSegmentSize(pGpu));
2903                 }
2904             }
2905         }
2906     }
2907 
2908     /*
2909      * For SRIOV, the placement IDs are aligned to 1/2, 1/4, 1/8, 1/16 partitions
2910      * due to restrictions on channels assigned to VF being in power-of-2.
2911      */
2912     if (gpuIsSriovEnabled(pGpu))
2913     {
2914         pmaGetLargestFree(&pHeap->pmaObject, &pmaRegionLength,
2915                           &pmaBaseOffset, &largestOffset);
2916 
2917         vmmuOffsetMin = NV_ALIGN_UP(pmaBaseOffset, gpuGetVmmuSegmentSize(pGpu));
2918         vmmuOffsetMax = pmaBaseOffset + pmaRegionLength;
2919 
2920         totalRequiredFb = (totalVmmuCount * gpuGetVmmuSegmentSize(pGpu));
2921         if ((vmmuOffsetMax - vmmuOffsetMin) < totalRequiredFb)
2922         {
2923             NV_PRINTF(LEVEL_ERROR, "Required FB for heterogeneous vGPU (%llu) less "
2924                       "than available FB (%llu)\n", totalRequiredFb, pmaRegionLength);
2925             NV_ASSERT(0);
2926 
2927             // Disable heterogeneous vGPU support, but return success to allow homogeneous vGPUs.
2928             pPgpuInfo->heterogeneousTimesliceSizesSupported = NV_FALSE;
2929             return NV_OK;
2930         }
2931 
2932         vmmuSegmentMin = vmmuOffsetMin / gpuGetVmmuSegmentSize(pGpu);
2933         vmmuSegmentMax = vmmuSegmentMin + totalVmmuCount;
2934 
2935         gspHeapOffsetMin = 0;
2936         gspHeapOffsetMax = 0;
2937 
2938         _kvgpumgrSetHeterogeneousResources(pGpu, pPgpuInfo, 0, pPgpuInfo->placementRegionSize,
2939                                            0, hostChannelCount, vmmuSegmentMin, vmmuSegmentMax,
2940                                            gspHeapOffsetMin, gspHeapOffsetMax, 1, NV_TRUE);
2941     }
2942 
2943     return rmStatus;
2944 }
2945 
2946 static NvBool
isPlacementOverlapping(NvU16 minId1,NvU16 maxId1,NvU16 id2,NvU16 size2)2947 isPlacementOverlapping(NvU16 minId1, NvU16 maxId1, NvU16 id2, NvU16 size2)
2948 {
2949     NvU16 max, min, size1;
2950 
2951     min = NV_MIN(minId1, id2);
2952     max = NV_MAX(maxId1, (id2 + size2));
2953     size1 = maxId1 - minId1;
2954 
2955     if ((size1 + size2) > (max - min))
2956         return NV_TRUE;
2957 
2958     return NV_FALSE;
2959 }
2960 
2961 static NvBool
isPlacementSubset(NvU16 min,NvU16 max,NvU16 id,NvU16 size)2962 isPlacementSubset(NvU16 min, NvU16 max, NvU16 id, NvU16 size)
2963 {
2964     if ((min <= id) && (max >= (id + size - 1)))
2965         return NV_TRUE;
2966 
2967     return NV_FALSE;
2968 }
2969 
2970 static NV_STATUS
_kvgpumgrUpdateCreatablePlacementIds(OBJGPU * pGpu,NvU16 placementId,NvU32 vgpuTypeId,NvBool isAlloc)2971 _kvgpumgrUpdateCreatablePlacementIds(OBJGPU *pGpu, NvU16 placementId, NvU32 vgpuTypeId, NvBool isAlloc)
2972 {
2973     OBJSYS *pSys = SYS_GET_INSTANCE();
2974     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2975     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2976     VGPU_TYPE *pVgpuTypeInfo;
2977     NvU32 index, i , j, placementSize, min = 0, max = 0, numCreatable = 0;
2978     NV_RANGE range;
2979     NvBool isVgpuTypeCreatable;
2980 
2981     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2982             kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &index));
2983 
2984     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2985             kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &pVgpuTypeInfo));
2986 
2987     pPgpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
2988     placementSize = pVgpuTypeInfo->placementSize;
2989 
2990     range = rangeMake(placementId, placementId + placementSize - 1);
2991 
2992     if (isAlloc)
2993     {
2994         /* Update the placment region bitmap to set (id + size) slots */
2995         bitVectorSetRange(&pPgpuInfo->usedPlacementRegionMap, range);
2996         min = placementId;
2997         max = placementId + placementSize;
2998     }
2999     else
3000     {
3001         /* Update the placment region bitmap to unset (id + size) slots */
3002         bitVectorClrRange(&pPgpuInfo->usedPlacementRegionMap, range);
3003 
3004         /* find the minimum slot before placement ID which is not occupied */
3005         min = placementId;
3006         for (j = placementId; j > 0;)
3007         {
3008             j--;
3009 
3010             if (bitVectorTest(&pPgpuInfo->usedPlacementRegionMap, j))
3011                 break;
3012 
3013             min = j;
3014         }
3015 
3016         /* find the maximum slot after placement ID + placementSize which is not occupied */
3017         max = placementId + placementSize - 1;
3018         for (j = placementId + placementSize; j < pPgpuInfo->placementRegionSize; j++)
3019         {
3020             if (bitVectorTest(&pPgpuInfo->usedPlacementRegionMap, j))
3021                 break;
3022 
3023              max = j;
3024         }
3025     }
3026 
3027     for (i = 0; i < MAX_VGPU_TYPES_PER_PGPU; i++)
3028         pPgpuInfo->supportedTypeIds[i] = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
3029 
3030     /* Update creatable placement Ids of all vGPU type IDs */
3031     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
3032     {
3033         pVgpuTypeInfo = pPgpuInfo->vgpuTypes[i];
3034         if (pVgpuTypeInfo == NULL)
3035             break;
3036 
3037         if (pVgpuTypeInfo->placementSize == 0)
3038             continue;
3039 
3040         isVgpuTypeCreatable = NV_FALSE;
3041 
3042         for (j = 0; j < pVgpuTypeInfo->placementCount; j++)
3043         {
3044             /*
3045              * Creatable Placement IDs will be updated either on VM boot or VM shutdown.
3046              * 1. VM boot.
3047              *      Here, we compare every (id + size) of each vGPU type if it's partial/full
3048              *      overlapping with the (id + size) of the vGPU VM that is booting up.
3049              *      If yes, then mark that placement ID as INVALID.
3050              * 2. VM shutdown
3051              *      Here, we compare every INVALID id of each vGPU type and
3052              *      see if the corresponding supported (id + size) is a complete subset
3053              *      of (max - min) range of available placement slots.
3054              *      If it is subset, then the INVALID id is overwritten with
3055              *      corresponding supported id as it is now creatable.
3056              */
3057             if (pPgpuInfo->creatablePlacementIds[i][j] != NVA081_PLACEMENT_ID_INVALID)
3058             {
3059                 if (isAlloc && isPlacementOverlapping(min, max,
3060                                                       pPgpuInfo->creatablePlacementIds[i][j],
3061                                                       pVgpuTypeInfo->placementSize))
3062                     pPgpuInfo->creatablePlacementIds[i][j] = NVA081_PLACEMENT_ID_INVALID;
3063 
3064             }
3065             else
3066             {
3067                 if (!isAlloc && isPlacementSubset(min, max, pVgpuTypeInfo->supportedPlacementIds[j],
3068                                                   pVgpuTypeInfo->placementSize))
3069                     pPgpuInfo->creatablePlacementIds[i][j] = pVgpuTypeInfo->supportedPlacementIds[j];
3070             }
3071 
3072             if (pPgpuInfo->creatablePlacementIds[i][j] != NVA081_PLACEMENT_ID_INVALID)
3073                 isVgpuTypeCreatable = NV_TRUE;
3074         }
3075 
3076         if (isVgpuTypeCreatable)
3077             pPgpuInfo->supportedTypeIds[numCreatable++] = pVgpuTypeInfo->vgpuTypeId;
3078     }
3079 
3080     return NV_OK;
3081 }
3082 
3083 NV_STATUS
kvgpumgrUpdateHeterogeneousInfo(OBJGPU * pGpu,NvU32 vgpuTypeId,NvU16 * placementId,NvU64 * guestFbLength,NvU64 * guestFbOffset,NvU64 * gspHeapOffset)3084 kvgpumgrUpdateHeterogeneousInfo(OBJGPU *pGpu, NvU32 vgpuTypeId, NvU16 *placementId,
3085                                 NvU64 *guestFbLength, NvU64 *guestFbOffset,
3086                                 NvU64 *gspHeapOffset)
3087 {
3088     OBJSYS *pSys = SYS_GET_INSTANCE();
3089     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
3090     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
3091     VGPU_TYPE *pVgpuTypeInfo;
3092     NvU32 index, i , j;
3093     NvBool bIdFound = NV_FALSE;
3094 
3095     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
3096             kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &index));
3097 
3098     pPgpuInfo = &(pKernelVgpuMgr->pgpuInfo[index]);
3099 
3100     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
3101     {
3102         pVgpuTypeInfo = pPgpuInfo->vgpuTypes[i];
3103         if (pVgpuTypeInfo == NULL)
3104             break;
3105 
3106         if (pVgpuTypeInfo->vgpuTypeId == vgpuTypeId)
3107         {
3108             for (j = 0; j < pVgpuTypeInfo->placementCount; j++)
3109             {
3110                 /*
3111                  * If hypervisor hasn't provided the placement ID as input, look
3112                  * for the first available placement ID for the input vGPU type.
3113                  * If hypervisor has provided the placement ID as input, just
3114                  * validate if it is a creatable placement ID.
3115                  */
3116                 if (*placementId == NVA081_PLACEMENT_ID_INVALID)
3117                 {
3118                     if (pPgpuInfo->creatablePlacementIds[i][j] != NVA081_PLACEMENT_ID_INVALID)
3119                     {
3120                         *placementId = pPgpuInfo->creatablePlacementIds[i][j];
3121                         if (gpuIsSriovEnabled(pGpu))
3122                         {
3123                             *guestFbOffset = pPgpuInfo->supportedVmmuOffsets[i][j] *
3124                                              gpuGetVmmuSegmentSize(pGpu);
3125                             *guestFbLength = pPgpuInfo->guestVmmuCount[i] *
3126                                              gpuGetVmmuSegmentSize(pGpu);
3127                             *gspHeapOffset = pPgpuInfo->gspHeapOffsets[i][j];
3128                         }
3129                         bIdFound = NV_TRUE;
3130                         break;
3131                     }
3132                 }
3133                 else
3134                 {
3135                     if (pPgpuInfo->creatablePlacementIds[i][j] == *placementId)
3136                     {
3137                         if (gpuIsSriovEnabled(pGpu))
3138                         {
3139                             *guestFbOffset = pPgpuInfo->supportedVmmuOffsets[i][j] *
3140                                              gpuGetVmmuSegmentSize(pGpu);
3141                             *guestFbLength = pPgpuInfo->guestVmmuCount[i] *
3142                                              gpuGetVmmuSegmentSize(pGpu);
3143                             *gspHeapOffset = pPgpuInfo->gspHeapOffsets[i][j];
3144                         }
3145                         bIdFound = NV_TRUE;
3146                         break;
3147                     }
3148                 }
3149             }
3150         }
3151     }
3152 
3153     /* No creatable placement ID found */
3154     if (!bIdFound)
3155         return NV_ERR_INVALID_STATE;
3156 
3157     return _kvgpumgrUpdateCreatablePlacementIds(pGpu, *placementId, vgpuTypeId, NV_TRUE);
3158 }
3159 
3160 NV_STATUS
kvgpumgrGetConfigEventInfoFromDb(NvHandle hClient,NvHandle hVgpuConfig,VGPU_CONFIG_EVENT_INFO_NODE ** ppVgpuConfigEventInfoNode,NvU32 pgpuIndex)3161 kvgpumgrGetConfigEventInfoFromDb(NvHandle hClient,
3162                                  NvHandle hVgpuConfig,
3163                                  VGPU_CONFIG_EVENT_INFO_NODE **ppVgpuConfigEventInfoNode,
3164                                  NvU32 pgpuIndex)
3165 {
3166     OBJSYS     *pSys     = SYS_GET_INSTANCE();
3167     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
3168     VGPU_CONFIG_EVENT_INFO_NODE *pVgpuConfigEventInfoNodeTemp;
3169 
3170     if (!ppVgpuConfigEventInfoNode)
3171     {
3172         return NV_ERR_INVALID_ARGUMENT;
3173     }
3174 
3175     for (pVgpuConfigEventInfoNodeTemp = listHead(&(pKernelVgpuMgr->pgpuInfo[pgpuIndex].listVgpuConfigEventsHead));
3176          pVgpuConfigEventInfoNodeTemp != NULL;
3177          pVgpuConfigEventInfoNodeTemp = listNext(&(pKernelVgpuMgr->pgpuInfo[pgpuIndex].listVgpuConfigEventsHead), pVgpuConfigEventInfoNodeTemp))
3178     {
3179         if ((pVgpuConfigEventInfoNodeTemp->hClient == hClient) &&
3180             (pVgpuConfigEventInfoNodeTemp->hVgpuConfig == hVgpuConfig))
3181         {
3182             *ppVgpuConfigEventInfoNode = pVgpuConfigEventInfoNodeTemp;
3183             return NV_OK;
3184         }
3185     }
3186 
3187     *ppVgpuConfigEventInfoNode = NULL;
3188     return NV_ERR_OBJECT_NOT_FOUND;
3189 }
3190 
3191 NV_STATUS
kvgpuMgrRestoreSmcExecPart(OBJGPU * pGpu,KERNEL_HOST_VGPU_DEVICE * pKernelHostVgpuDevice,KERNEL_MIG_GPU_INSTANCE * pKernelMIGGpuInstance)3192 kvgpuMgrRestoreSmcExecPart
3193 (
3194     OBJGPU *pGpu,
3195     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice,
3196     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance
3197 )
3198 {
3199     NV_STATUS rmStatus = NV_OK;
3200     NvU32 CIIdx;
3201     NVC637_CTRL_EXEC_PARTITIONS_IMPORT_EXPORT_PARAMS *pExecPartImportParams = NULL;
3202     RM_API *pRmApi = rmapiGetInterface(RMAPI_GPU_LOCK_INTERNAL);
3203 
3204     //
3205     // Delete any compute instances which are alive in system. This may delete
3206     // instances existing in system even if they are same as default instance,
3207     // as we are not comparing instances
3208     //
3209     for (CIIdx = 0; CIIdx < NV_ARRAY_ELEMENTS(pKernelMIGGpuInstance->MIGComputeInstance); ++CIIdx)
3210     {
3211         NVC637_CTRL_EXEC_PARTITIONS_DELETE_PARAMS params;
3212         MIG_COMPUTE_INSTANCE *pMIGComputeInstance =
3213             &pKernelMIGGpuInstance->MIGComputeInstance[CIIdx];
3214 
3215         if (!pMIGComputeInstance->bValid)
3216             continue;
3217 
3218         portMemSet(&params, 0, sizeof(params));
3219         params.execPartCount = 1;
3220         params.execPartId[0] = CIIdx;
3221 
3222         //
3223         // There is no revert or failure in this call as we have to do best case
3224         // effort to delete and restore default compute instances
3225         //
3226         NV_ASSERT_OK(
3227             pRmApi->Control(pRmApi,
3228                             pKernelMIGGpuInstance->instanceHandles.hClient,
3229                             pKernelMIGGpuInstance->instanceHandles.hSubscription,
3230                             NVC637_CTRL_CMD_EXEC_PARTITIONS_DELETE,
3231                             &params,
3232                             sizeof(params)));
3233     }
3234 
3235     // Restore all saved compute instances
3236     pExecPartImportParams = portMemAllocNonPaged(sizeof(*pExecPartImportParams));
3237     NV_ASSERT_OR_RETURN(pExecPartImportParams != NULL, NV_ERR_NO_MEMORY);
3238 
3239     for (CIIdx = 0; CIIdx < NV_ARRAY_ELEMENTS(pKernelMIGGpuInstance->MIGComputeInstance); ++CIIdx)
3240     {
3241         GPUMGR_SAVE_COMPUTE_INSTANCE *pComputeInstanceSave = &pKernelHostVgpuDevice->savedExecPartitions[CIIdx];
3242         if (!pComputeInstanceSave->bValid)
3243             continue;
3244 
3245         portMemSet(pExecPartImportParams, 0, sizeof(*pExecPartImportParams));
3246         pExecPartImportParams->id = pComputeInstanceSave->id;
3247         pExecPartImportParams->bCreateCap = NV_TRUE;
3248         portMemCopy(&pExecPartImportParams->info, sizeof(pExecPartImportParams->info),
3249                           &pComputeInstanceSave->ciInfo, sizeof(pComputeInstanceSave->ciInfo));
3250 
3251         NV_ASSERT_OK_OR_GOTO(rmStatus,
3252                       pRmApi->Control(pRmApi,
3253                                       pKernelMIGGpuInstance->instanceHandles.hClient,
3254                                       pKernelMIGGpuInstance->instanceHandles.hSubscription,
3255                                       NVC637_CTRL_CMD_EXEC_PARTITIONS_IMPORT,
3256                                       pExecPartImportParams,
3257                                       sizeof(*pExecPartImportParams)),
3258                 done);
3259     }
3260 
3261     //
3262     // Generate a subdevice event stating something has changed in GPU partition
3263     // config.
3264     //
3265     gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_SMC_CONFIG_UPDATE, NULL, 0, 0, 0);
3266 
3267 done:
3268     portMemFree(pExecPartImportParams);
3269     return rmStatus;
3270 }
3271