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