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 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     // The encoding of the subdevice ID is its value converted to string
1400     bytes = NvU32ToAsciiStr(subID, SUBDEVID_ENCODED_VALUE_SIZE,
1401                                     pgpuString, NV_FALSE);
1402     return bytes;
1403 }
1404 
1405 NvU32 kvgpumgrGetPgpuFSEncoding(OBJGPU *pGpu, NvU8 *pgpuString,
1406                                 NvU32 strSize)
1407 {
1408     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1409     NV2080_CTRL_VGPU_MGR_INTERNAL_GET_PGPU_FS_ENCODING_PARAMS params = {0};
1410     NV_STATUS status;
1411 
1412     params.pgpuStringSize = strSize;
1413 
1414     NV_CHECK_OK_OR_ELSE(status,
1415                           LEVEL_ERROR,
1416                           pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1417                                           NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_GET_PGPU_FS_ENCODING,
1418                                           &params, sizeof(params)),
1419                           return NV_U32_MAX);
1420 
1421     portMemCopy(pgpuString, strSize, params.pgpuString, params.pgpuStringSize);
1422 
1423     return params.pgpuStringSize;
1424 }
1425 
1426 NvU64
1427 kvgpumgrGetEccAndPrReservedFb(OBJGPU *pGpu)
1428 {
1429     Heap *pHeap = GPU_GET_HEAP(pGpu);
1430 	const MEMORY_SYSTEM_STATIC_CONFIG *pMemorySystemConfig =
1431             kmemsysGetStaticConfig(pGpu, GPU_GET_KERNEL_MEMORY_SYSTEM(pGpu));
1432 	NvU64 eccReservedFb = 0, pageRetirementReservedFb = 0, usableSizeFb;
1433 
1434     //
1435     // pageRetirementReservedFb is needed only in case of legacy, to account
1436     // for the pagepool used during page stitching
1437     //
1438     if (!gpuIsSriovEnabled(pGpu))
1439     {
1440         if (pGpu->getProperty(pGpu, PDB_PROP_GPU_ALLOW_PAGE_RETIREMENT))
1441         {
1442             if (IsPASCALorBetter(pGpu))
1443             {
1444                 pageRetirementReservedFb = NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES * RM_PAGE_SIZE_HUGE;
1445             }
1446             else
1447             {
1448                 pageRetirementReservedFb = NV2080_CTRL_FB_OFFLINED_PAGES_MAX_PAGES * RM_PAGE_SIZE_64K;
1449             }
1450         }
1451     }
1452 
1453     if (pMemorySystemConfig->bEnabledEccFBPA)
1454     {
1455         if ((pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM1) &&
1456             (pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM2) &&
1457             (pMemorySystemConfig->ramType != NV2080_CTRL_FB_INFO_RAM_TYPE_HBM3))
1458         {
1459             heapGetUsableSize(pHeap, &usableSizeFb);
1460             //
1461             // FB and ECC checksum calculation
1462             // eccReservedFb = totalFBEccOff / 16
1463             // i.e. totalFbEccOff = eccReservedFb * 16
1464             //
1465             // totalFbEccOff = totalFbEccOn + eccReservedFb
1466             // eccReservedFb * 16 = totalFbEccOn + eccReservedFb
1467             // eccReservedFb * 15 = totalFbEccOn
1468             // eccReservedFb = totalFbEccOn / 15 (totalFbEccOn is same as usableSizeFb)
1469             //
1470             eccReservedFb = usableSizeFb / 15;
1471         }
1472     }
1473 
1474 	return pageRetirementReservedFb + eccReservedFb;
1475 }
1476 
1477 //
1478 // A 32-bit variable is used to consolidate various GPU capabilities like
1479 // ECC, SRIOV etc. The function sets the capabilities in the variable and
1480 // converted to an ascii-encoded format.
1481 //
1482 NvU32 kvgpumgrGetPgpuCapEncoding(OBJGPU *pGpu, NvU8 *pgpuString, NvU32 strSize)
1483 {
1484     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1485     NvU32 pgpuCap = 0;
1486 
1487     if ((strSize < MAX_NVU32_TO_CONVERTED_STR_LEN) || (pgpuString == NULL))
1488     {
1489         return NV_U32_MAX;
1490     }
1491 
1492     {
1493         NV2080_CTRL_GPU_QUERY_ECC_STATUS_PARAMS eccStatus = {0};
1494 
1495         if (pRmApi->Control(pRmApi,
1496                             pGpu->hInternalClient,
1497                             pGpu->hInternalSubdevice,
1498                             NV2080_CTRL_CMD_GPU_QUERY_ECC_STATUS,
1499                             &eccStatus, sizeof(eccStatus)) == NV_OK)
1500         {
1501             NvU32 i;
1502             for (i = 0; i < NV2080_CTRL_GPU_ECC_UNIT_COUNT; i++)
1503             {
1504                 if (eccStatus.units[i].enabled)
1505                 {
1506                     pgpuCap |= PGPU_CAP_ECC_ON;
1507                     break;
1508                 }
1509             }
1510         }
1511     }
1512 
1513     {
1514         NV0080_CTRL_GPU_GET_SRIOV_CAPS_PARAMS sriovCaps = {0};
1515 
1516         if (gpuGetSriovCaps_HAL(pGpu, &sriovCaps) == NV_OK)
1517         {
1518             if (sriovCaps.bSriovEnabled)
1519                 pgpuCap |= PGPU_CAP_SRIOV_ON;
1520         }
1521     }
1522 
1523     return NvU32ToAsciiStr(pgpuCap, PGPU_CAP_ENCODED_VALUE_SIZE,
1524                            pgpuString, NV_FALSE);
1525 }
1526 
1527 /*
1528  * Get the user provide vGPU version range
1529  */
1530 NV_STATUS
1531 kvgpumgrGetHostVgpuVersion(NvU32 *user_min_supported_version,
1532                            NvU32 *user_max_supported_version)
1533 {
1534     OBJSYS *pSys = SYS_GET_INSTANCE();
1535     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1536 
1537     *user_min_supported_version
1538         = pKernelVgpuMgr->user_min_supported_version;
1539     *user_max_supported_version
1540         = pKernelVgpuMgr->user_max_supported_version;
1541     return NV_OK;
1542 }
1543 
1544 /*
1545  * Set the user provide vGPU version range
1546  */
1547 NV_STATUS
1548 kvgpumgrSetHostVgpuVersion(NvU32 user_min_supported_version,
1549                            NvU32 user_max_supported_version)
1550 {
1551     OBJSYS *pSys = SYS_GET_INSTANCE();
1552     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1553     NvU32 host_min_supported_version
1554         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
1555                                   NV_VGPU_MIN_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
1556     NvU32 host_max_supported_version
1557         = GRIDSW_VERSION_EXTERNAL(NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MAJOR,
1558                                   NV_VGPU_MAX_SUPPORTED_GRIDSW_VERSION_EXTERNAL_MINOR);
1559 
1560     /* Sanity check */
1561     if (user_min_supported_version > user_max_supported_version) {
1562         NV_PRINTF(LEVEL_ERROR,
1563                   "Maximum vGPU version (0x%x) being set is less than minimum version (0x%x)\n",
1564                   user_max_supported_version, user_min_supported_version);
1565         return NV_ERR_INVALID_ARGUMENT;
1566     }
1567 
1568     /* Sanity check: Fail in case the range being set by admin is a subset
1569      * of the range supported by the host driver
1570      */
1571     if ((user_min_supported_version < host_min_supported_version)
1572         || (user_max_supported_version > host_max_supported_version)) {
1573 
1574         NV_PRINTF(LEVEL_ERROR,
1575                   "vGPU version range being set (0x%x, 0x%x) is outside the range supported by host (0x%x, 0x%x)\n",
1576                   user_min_supported_version, user_max_supported_version,
1577                   host_min_supported_version, host_max_supported_version);
1578 
1579         return NV_ERR_INVALID_ARGUMENT;
1580     }
1581 
1582     NV_PRINTF(LEVEL_INFO,
1583               "vGPU version range enforced by user: (0x%x, 0x%x)\n",
1584               user_min_supported_version, user_max_supported_version);
1585 
1586     /* Save the information of the user specified range in the host */
1587     pKernelVgpuMgr->user_min_supported_version
1588         = user_min_supported_version;
1589     pKernelVgpuMgr->user_max_supported_version
1590         = user_max_supported_version;
1591 
1592     return NV_OK;
1593 }
1594 
1595 /*
1596  * Function to set swizzId is assigned to a vGPU device.
1597  */
1598 static NV_STATUS
1599 _kvgpumgrSetAssignedSwizzIdMask(OBJGPU       *pGpu,
1600                                 NvU32         swizzId)
1601 {
1602     OBJSYS *pSys = SYS_GET_INSTANCE();
1603     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1604     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1605     NvU32 i;
1606     NvU64 mask;
1607 
1608     if (swizzId >= KMIGMGR_MAX_GPU_SWIZZID)
1609     {
1610         return NV_ERR_INVALID_ARGUMENT;
1611     }
1612 
1613     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
1614     {
1615         return NV_ERR_OBJECT_NOT_FOUND;
1616     }
1617 
1618     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
1619     NV_ASSERT_OR_RETURN((pPhysGpuInfo != NULL), NV_ERR_INVALID_ARGUMENT);
1620 
1621     /* Validate that same ID is not already set and then set the ID */
1622     mask = NVBIT64(swizzId);
1623 
1624     if (mask & pPhysGpuInfo->assignedSwizzIdMask)
1625     {
1626         NV_PRINTF(LEVEL_ERROR, "SwizzID - %d already in use\n", swizzId);
1627         DBG_BREAKPOINT();
1628         return NV_ERR_STATE_IN_USE;
1629     }
1630 
1631     pPhysGpuInfo->assignedSwizzIdMask |= mask;
1632 
1633     return NV_OK;
1634 }
1635 
1636 /*!
1637  * Function to mark swizzId is free to be used by other vGPU devices.
1638  */
1639 static NV_STATUS
1640 _kvgpumgrClearAssignedSwizzIdMask(OBJGPU *pGpu,
1641                                   NvU32 swizzId)
1642 {
1643     OBJSYS *pSys = SYS_GET_INSTANCE();
1644     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1645     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1646     NvU32 i;
1647     NvU64 mask;
1648 
1649     if (swizzId >= KMIGMGR_MAX_GPU_SWIZZID)
1650     {
1651         return NV_ERR_INVALID_ARGUMENT;
1652     }
1653 
1654     if (kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i) != NV_OK)
1655     {
1656         return NV_ERR_OBJECT_NOT_FOUND;
1657     }
1658 
1659     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[i]);
1660     NV_ASSERT_OR_RETURN((pPhysGpuInfo != NULL), NV_ERR_INVALID_ARGUMENT);
1661 
1662     /* Validate that same ID is not already marked as free and then set the ID */
1663     mask = NVBIT64(swizzId);
1664 
1665     if (!(mask & pPhysGpuInfo->assignedSwizzIdMask))
1666     {
1667         NV_PRINTF(LEVEL_ERROR, "SwizzID - %d not in use\n", swizzId);
1668         DBG_BREAKPOINT();
1669         return NV_ERR_INVALID_STATE;
1670     }
1671 
1672     pPhysGpuInfo->assignedSwizzIdMask &= ~mask;
1673 
1674     return NV_OK;
1675 }
1676 
1677 NV_STATUS
1678 kvgpumgrGetSwizzId(OBJGPU *pGpu,
1679                    KERNEL_PHYS_GPU_INFO *pPhysGpuInfo,
1680                    NvU32 partitionFlag,
1681                    NvU32 *swizzId)
1682 {
1683     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1684     NvU64 swizzIdInUseMask = 0;
1685     NvU32 id;
1686     NV_STATUS rmStatus = NV_OK;
1687 
1688     swizzIdInUseMask = kmigmgrGetSwizzIdInUseMask(pGpu, pKernelMIGManager);
1689 
1690     *swizzId = KMIGMGR_SWIZZID_INVALID;
1691 
1692     // Determine valid swizzids not assigned to any vGPU device.
1693     FOR_EACH_INDEX_IN_MASK(64, id, swizzIdInUseMask)
1694     {
1695         KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1696         NvU64 mask = 0;
1697 
1698         rmStatus = kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, id, &pKernelMIGGpuInstance);
1699         if (rmStatus != NV_OK)
1700         {
1701             // Didn't find requested GPU instance
1702             NV_PRINTF(LEVEL_ERROR, "No valid GPU instance with SwizzId - %d found\n", id);
1703             return rmStatus;
1704         }
1705 
1706         mask = NVBIT64(id);
1707 
1708         if (pKernelMIGGpuInstance->partitionFlag == partitionFlag)
1709         {
1710             // Validate that same ID is not already set and then set the ID
1711             if (!(mask & pPhysGpuInfo->assignedSwizzIdMask))
1712             {
1713                 NV_ASSERT_OK_OR_RETURN(_kvgpumgrSetAssignedSwizzIdMask(pGpu, pKernelMIGGpuInstance->swizzId));
1714                 *swizzId = pKernelMIGGpuInstance->swizzId;
1715                 break;
1716             }
1717         }
1718     }
1719     FOR_EACH_INDEX_IN_MASK_END;
1720 
1721     if (*swizzId == KMIGMGR_SWIZZID_INVALID)
1722     {
1723         return NV_ERR_INVALID_STATE;
1724     }
1725 
1726     return NV_OK;
1727 }
1728 
1729 NV_STATUS
1730 kvgpumgrValidateSwizzId(OBJGPU *pGpu,
1731                         NvU32 vgpuTypeId,
1732                         NvU32 swizzId)
1733 {
1734     KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1735     NvU32 partitionFlag                 = PARTITIONID_INVALID;
1736     NV_STATUS rmStatus                  = NV_OK;
1737     KERNEL_MIG_GPU_INSTANCE *pKernelMIGGpuInstance;
1738 
1739     // Check if swizzId is valid.
1740     if (!kmigmgrIsSwizzIdInUse(pGpu, pKernelMIGManager, swizzId))
1741     {
1742         return NV_ERR_INVALID_ARGUMENT;
1743     }
1744 
1745     rmStatus = kmigmgrGetGPUInstanceInfo(pGpu, pKernelMIGManager, swizzId, &pKernelMIGGpuInstance);
1746     if (rmStatus != NV_OK)
1747     {
1748         // Didn't find requested GPU instance
1749         NV_PRINTF(LEVEL_ERROR, "No valid GPU instance with SwizzId - %d found\n", swizzId);
1750         return rmStatus;
1751     }
1752 
1753     NV_ASSERT_OK_OR_RETURN(
1754         kvgpumgrGetPartitionFlag(vgpuTypeId, &partitionFlag));
1755 
1756     // Check if swizzId is valid for vGPU type.
1757     if (pKernelMIGGpuInstance->partitionFlag == partitionFlag)
1758     {
1759         NV_ASSERT_OK_OR_RETURN(_kvgpumgrSetAssignedSwizzIdMask(pGpu, swizzId));
1760         return NV_OK;
1761     }
1762 
1763     return NV_ERR_INVALID_STATE;
1764 }
1765 
1766 NV_STATUS
1767 kvgpumgrGetPartitionFlag(NvU32 vgpuTypeId, NvU32 *partitionFlag)
1768 {
1769     NvU32 i;
1770 
1771     *partitionFlag = PARTITIONID_INVALID;
1772 
1773     for (i = 0; i < NV_ARRAY_ELEMENTS(vgpuSmcTypeIdMappings); i++)
1774     {
1775         if (vgpuSmcTypeIdMappings[i].vgpuTypeId == vgpuTypeId)
1776         {
1777             *partitionFlag = vgpuSmcTypeIdMappings[i].partitionFlag;
1778             return NV_OK;
1779         }
1780     }
1781 
1782     NV_PRINTF(LEVEL_ERROR, "Invalid SMC vGpu TypeId: 0x%x\n", vgpuTypeId);
1783     return NV_ERR_INVALID_ARGUMENT;
1784 }
1785 
1786 static NV_STATUS
1787 _kvgpumgrGetVgpuTypeIdFromPartitionFlag(NvU32 devId, NvU32 partitionFlag, NvU32 *vgpuTypeId)
1788 {
1789     NvU32 i;
1790 
1791     *vgpuTypeId = NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE;
1792 
1793     for (i = 0; i < NV_ARRAY_ELEMENTS(vgpuSmcTypeIdMappings); i++)
1794     {
1795         // Currently vgpuTypeId to partitionFlag mapping is 1 to 1.
1796         // In future, we might potentially hit issue if multiple
1797         // type-ids map to the same partition flags
1798         if ((vgpuSmcTypeIdMappings[i].devId == devId) &&
1799             (vgpuSmcTypeIdMappings[i].partitionFlag == partitionFlag))
1800         {
1801             *vgpuTypeId = vgpuSmcTypeIdMappings[i].vgpuTypeId;
1802             return NV_OK;
1803         }
1804     }
1805 
1806     return NV_ERR_OBJECT_NOT_FOUND;
1807 }
1808 
1809 /*
1810  * Add or remove VF info to pgpuInfo of its PF
1811  * @param[in] gpuPciId          PCI ID of target PF
1812  * @param[in] cmd
1813  *      0/VGPU_CMD_PROCESS_VF_INFO.NV_VGPU_SAVE_VF_INFO     = Add VF info to VF list of target PF
1814  *      1/VGPU_CMD_PROCESS_VF_INFO.NV_VGPU_REMOVE_VF_INFO   = Remove VF info from VF list of target PF
1815  * @param[in] domain            Domain of VF to be stored
1816  * @param[in] bus               Bus no. of VF to be stored
1817  * @param[in] slot              Slot no. of VF to be stored
1818  * @param[in] function          Function of VF to be stored
1819  * @param[in] isMdevAttached    Flag to indicate if VF is registered with mdev
1820  * @param[out]vfPciInfo         Array of PCI information of VFs
1821  */
1822 NV_STATUS
1823 kvgpumgrProcessVfInfo(NvU32 gpuPciId, NvU8 cmd, NvU32 domain, NvU32 bus, NvU32 slot, NvU32 function, NvBool isMdevAttached, vgpu_vf_pci_info *vfPciInfo)
1824 {
1825     NvU32 i;
1826     OBJSYS *pSys = SYS_GET_INSTANCE();
1827     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1828     NvU32 pgpuIndex;
1829     NV_STATUS status = NV_OK;
1830     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
1831     vgpu_vf_pci_info *pVfInfo = NULL;
1832 
1833     if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
1834         return status;
1835 
1836     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[pgpuIndex]);
1837 
1838     if (cmd == NV_VGPU_SAVE_VF_INFO)
1839     {
1840         /* Find existing entry for VF and set flags if found. */
1841         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1842         {
1843             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1844 
1845             if ((domain   == pVfInfo->domain) &&
1846                 (bus      == pVfInfo->bus)    &&
1847                 (slot     == pVfInfo->slot)   &&
1848                 (function == pVfInfo->function))
1849             {
1850                 pVfInfo->isNvidiaAttached = NV_TRUE;
1851                 pVfInfo->isMdevAttached   = isMdevAttached;
1852                 break;
1853             }
1854         }
1855 
1856         /*
1857          * If entry doesn't already exist, populate an empty slot and complain
1858          * if there isn't one.
1859          */
1860         if (i == MAX_VF_COUNT_PER_GPU)
1861         {
1862             for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1863             {
1864                 pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1865                 if ((!pVfInfo->isNvidiaAttached))
1866                 {
1867                     pVfInfo->domain   = domain;
1868                     pVfInfo->bus      = bus;
1869                     pVfInfo->slot     = slot;
1870                     pVfInfo->function = function;
1871 
1872                     pVfInfo->isNvidiaAttached = NV_TRUE;
1873                     pVfInfo->isMdevAttached   = isMdevAttached;
1874                     break;
1875                 }
1876             }
1877 
1878             if (i == MAX_VF_COUNT_PER_GPU)
1879             {
1880                 NV_PRINTF(LEVEL_ERROR, "No free free slot to track VF PCI info\n");
1881                 return NV_ERR_INVALID_STATE;
1882             }
1883         }
1884     }
1885     else if ((cmd == NV_VGPU_REMOVE_VF_PCI_INFO || cmd == NV_VGPU_REMOVE_VF_MDEV_INFO) && pPhysGpuInfo)
1886     {
1887         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1888         {
1889             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1890 
1891             if ((domain   == pVfInfo->domain) &&
1892                 (bus      == pVfInfo->bus)    &&
1893                 (slot     == pVfInfo->slot)   &&
1894                 (function == pVfInfo->function))
1895             {
1896                 if (cmd == NV_VGPU_REMOVE_VF_PCI_INFO)
1897                 {
1898                     pVfInfo->isNvidiaAttached = NV_FALSE;
1899                 }
1900                 pVfInfo->isMdevAttached   = NV_FALSE;
1901                 break;
1902             }
1903         }
1904 
1905         if (i == MAX_VF_COUNT_PER_GPU)
1906         {
1907             NV_PRINTF(LEVEL_ERROR, "Could not find entry for VF PCI info\n");
1908             return NV_ERR_MISSING_TABLE_ENTRY;
1909         }
1910     }
1911     else if (cmd == NV_VGPU_GET_VF_INFO && vfPciInfo)
1912     {
1913         for (i = 0; i < MAX_VF_COUNT_PER_GPU; i++)
1914         {
1915             pVfInfo = &pPhysGpuInfo->vfPciInfo[i];
1916             portMemCopy(&vfPciInfo[i], sizeof(vgpu_vf_pci_info), pVfInfo, sizeof(vgpu_vf_pci_info));
1917         }
1918     }
1919     else
1920     {
1921         NV_PRINTF(LEVEL_ERROR, "Requested invalid operation on VF info\n");
1922         status = NV_ERR_INVALID_ARGUMENT;
1923     }
1924 
1925     return status;
1926 }
1927 
1928 NV_STATUS
1929 kvgpumgrEnumerateVgpuPerPgpu(OBJGPU *pGpu, NV2080_CTRL_VGPU_MGR_INTERNAL_ENUMERATE_VGPU_PER_PGPU_PARAMS *pParams)
1930 {
1931     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1932 
1933     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1934                                                        NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_ENUMERATE_VGPU_PER_PGPU,
1935                                                        pParams, sizeof(*pParams)));
1936 
1937     return NV_OK;
1938 }
1939 
1940 NV_STATUS
1941 kvgpumgrClearGuestVmInfo(OBJGPU *pGpu, KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice)
1942 {
1943     NV2080_CTRL_VGPU_MGR_INTERNAL_CLEAR_GUEST_VM_INFO_PARAMS params;
1944     RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1945     NV_STATUS status;
1946 
1947     portMemSet(&params, 0, sizeof(params));
1948     params.gfid = pKernelHostVgpuDevice->gfid;
1949 
1950     status = pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
1951                              NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_CLEAR_GUEST_VM_INFO,
1952                              &params, sizeof(params));
1953 
1954     if (status != NV_OK)
1955         NV_PRINTF(LEVEL_ERROR, "Failed to clear guest vm info on GSP\n");
1956 
1957     return status;
1958 }
1959 
1960 NV_STATUS
1961 kvgpumgrGetHostVgpuDeviceFromGfid(NvU32 gpuPciId, NvU32 gfid,
1962                                   KERNEL_HOST_VGPU_DEVICE** ppHostVgpuDevice)
1963 {
1964     OBJSYS *pSys = SYS_GET_INSTANCE();
1965     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
1966     NvU32 pgpuIndex;
1967     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
1968     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
1969 
1970     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex));
1971     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
1972 
1973     if (!pPgpuInfo->sriovEnabled)
1974         return NV_ERR_NOT_SUPPORTED;
1975 
1976     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
1977          pKernelHostVgpuDevice != NULL;
1978          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
1979     {
1980         if (pKernelHostVgpuDevice->gfid == gfid)
1981         {
1982             *ppHostVgpuDevice = pKernelHostVgpuDevice;
1983             return NV_OK;
1984         }
1985      }
1986 
1987     return NV_ERR_OBJECT_NOT_FOUND;
1988 }
1989 
1990 NV_STATUS
1991 kvgpumgrGetVgpuFbUsage(OBJGPU *pGpu, NVA081_CTRL_VGPU_CONFIG_GET_VGPU_FB_USAGE_PARAMS *pParams)
1992 {
1993     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
1994     NVA081_VGPU_FB_USAGE *pVgpuFbUsage;
1995     NvU32 i = 0;
1996 
1997     NV_PRINTF(LEVEL_INFO, "%s\n", __FUNCTION__);
1998 
1999     if (gpuIsSriovEnabled(pGpu))
2000     {
2001         NV2080_CTRL_VGPU_MGR_INTERNAL_GET_VGPU_FB_USAGE_PARAMS internalParams;
2002         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2003 
2004         portMemSet(&internalParams, 0, sizeof(internalParams));
2005 
2006         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
2007                                                            NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_GET_VGPU_FB_USAGE,
2008                                                            &internalParams, sizeof(internalParams)));
2009 
2010         if (internalParams.vgpuCount > NV_ARRAY_ELEMENTS(pParams->vgpuFbUsage))
2011             return NV_ERR_INSUFFICIENT_RESOURCES;
2012 
2013         for (i = 0; i < internalParams.vgpuCount; i++)
2014         {
2015             NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2016                  kvgpumgrGetHostVgpuDeviceFromGfid(pGpu->gpuId, internalParams.vgpuFbUsage[i].gfid, &pKernelHostVgpuDevice));
2017 
2018             pVgpuFbUsage = &pParams->vgpuFbUsage[i];
2019 
2020             portMemCopy(pVgpuFbUsage->vgpuUuid, VGPU_UUID_SIZE, pKernelHostVgpuDevice->vgpuUuid, VGPU_UUID_SIZE);
2021 
2022             pVgpuFbUsage->fbUsed = internalParams.vgpuFbUsage[i].fbUsed;
2023         }
2024 
2025         pParams->vgpuCount = internalParams.vgpuCount;
2026     }
2027 
2028     return NV_OK;
2029 }
2030 
2031 NV_STATUS
2032 kvgpumgrSetVgpuEncoderCapacity(OBJGPU *pGpu, NvU8 *vgpuUuid, NvU32 encoderCapacity)
2033 {
2034     OBJSYS *pSys = SYS_GET_INSTANCE();
2035     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2036     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2037     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
2038     NvU32 i;
2039 
2040     NV_PRINTF(LEVEL_INFO, "%s\n", __FUNCTION__);
2041 
2042     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pGpu->gpuId, &i));
2043 
2044     pPhysGpuInfo = &pKernelVgpuMgr->pgpuInfo[i];
2045 
2046     for (pKernelHostVgpuDevice = listHead(&(pPhysGpuInfo->listHostVgpuDeviceHead));
2047          pKernelHostVgpuDevice != NULL;
2048          pKernelHostVgpuDevice = listNext(&(pPhysGpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2049     {
2050         if (portMemCmp(pKernelHostVgpuDevice->vgpuUuid, vgpuUuid, VGPU_UUID_SIZE) == 0)
2051             break;
2052     }
2053 
2054     if (pKernelHostVgpuDevice == NULL)
2055         return NV_ERR_OBJECT_NOT_FOUND;
2056 
2057     if (gpuIsSriovEnabled(pGpu))
2058     {
2059         NV2080_CTRL_VGPU_MGR_INTERNAL_SET_VGPU_ENCODER_CAPACITY_PARAMS params;
2060         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
2061 
2062         params.gfid = pKernelHostVgpuDevice->gfid;
2063         params.encoderCapacity = encoderCapacity;
2064 
2065         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
2066                               pRmApi->Control(pRmApi, pGpu->hInternalClient, pGpu->hInternalSubdevice,
2067                                               NV2080_CTRL_CMD_VGPU_MGR_INTERNAL_SET_VGPU_ENCODER_CAPACITY,
2068                                               &params, sizeof(params)));
2069     }
2070 
2071     return NV_OK;
2072 }
2073 
2074 NV_STATUS
2075 kvgpumgrStart(const NvU8 *pMdevUuid, void *waitQueue, NvS32 *returnStatus,
2076               NvU8 *vmName, NvU32 qemuPid)
2077 {
2078     OBJSYS *pSys = SYS_GET_INSTANCE();
2079     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2080     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
2081 
2082     for (pRequestVgpu = listHead(&(pKernelVgpuMgr->listRequestVgpuHead));
2083          pRequestVgpu != NULL;
2084          pRequestVgpu = listNext(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu))
2085     {
2086         if (portMemCmp(pMdevUuid, pRequestVgpu->mdevUuid, VGPU_UUID_SIZE) == 0)
2087         {
2088             pRequestVgpu->waitQueue = waitQueue;
2089             pRequestVgpu->returnStatus = returnStatus;
2090             pRequestVgpu->vmName = vmName;
2091             pRequestVgpu->qemuPid = qemuPid;
2092 
2093             CliAddSystemEvent(NV0000_NOTIFIERS_VM_START, 0);
2094             return NV_OK;
2095         }
2096     }
2097     return NV_ERR_OBJECT_NOT_FOUND;
2098 }
2099 
2100 //
2101 // Add vGPU info received on mdev_create sysfs call to REQUEST_VGPU_INFO_NODE
2102 // list. REQUEST_VGPU_INFO_NODE is currently used only for vGPU on KVM.
2103 //
2104 // This funtion first checks whether the vGPU type is supported or not as
2105 // only homegeneous vGPU types are supported currently. Also, this function
2106 // only creates REQUEST_VGPU_INFO_NODE entry, actual vGPU will be created later
2107 //
2108 NV_STATUS
2109 kvgpumgrCreateRequestVgpu(NvU32 gpuPciId, const NvU8 *pMdevUuid,
2110                           NvU32 vgpuTypeId, NvU16 *vgpuId, NvU32 gpuPciBdf)
2111 {
2112     OBJSYS *pSys = SYS_GET_INSTANCE();
2113     OBJGPU *pGpu = gpumgrGetGpuFromId(gpuPciId);
2114     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2115     OBJHYPERVISOR *pHypervisor = SYS_GET_HYPERVISOR(pSys);
2116     NvU32 pgpuIndex;
2117     NV_STATUS status = NV_OK;
2118     VGPU_TYPE *vgpuTypeInfo;
2119     KERNEL_PHYS_GPU_INFO *pPhysGpuInfo;
2120     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
2121     NvU32 allocFlags = NVOS32_ALLOC_FLAGS_FORCE_MEM_GROWS_UP;
2122     NvU64 vgpuIdSize = 1, tmpVgpuId;
2123     NvU8 devfn = gpuDecodeDevice(gpuPciBdf);
2124     NvU32 swizzId = KMIGMGR_SWIZZID_INVALID;
2125 
2126     if (pGpu == NULL)
2127     {
2128         NV_PRINTF(LEVEL_ERROR, "GPU handle is not valid \n");
2129         return NV_ERR_INVALID_STATE;
2130     }
2131 
2132     if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
2133         return status;
2134 
2135     pPhysGpuInfo = &(pKernelVgpuMgr->pgpuInfo[pgpuIndex]);
2136 
2137     if ((status = kvgpumgrGetVgpuTypeInfo(vgpuTypeId, &vgpuTypeInfo)) != NV_OK)
2138         return status;
2139 
2140     /*
2141      * For DriverVM, we will defer the createdVfMask validation later
2142      * during open call when the params provided.
2143      *
2144      */
2145 
2146     if (gpuIsSriovEnabled(pGpu) &&
2147         !(pHypervisor->getProperty(pHypervisor, PDB_PROP_HYPERVISOR_DRIVERVM_ENABLED)))
2148     {
2149         NvU8 fnId = devfn - pGpu->sriovState.firstVFOffset;
2150 
2151         NV_ASSERT_OR_RETURN((fnId < 64), NV_ERR_INVALID_ARGUMENT);
2152 
2153         if (pPhysGpuInfo->createdVfMask & NVBIT64(fnId))
2154             /* mdev device is already created on VF */
2155             return NV_ERR_INVALID_OPERATION;
2156     }
2157 
2158     if (IS_MIG_ENABLED(pGpu))
2159     {
2160         NvU32 partitionFlag = PARTITIONID_INVALID;
2161 
2162         NV_CHECK_OR_RETURN(LEVEL_INFO,
2163             IS_MIG_IN_USE(pGpu),
2164             NV_ERR_INVALID_OPERATION);
2165 
2166         NV_ASSERT_OK_OR_RETURN(
2167             kvgpumgrGetPartitionFlag(vgpuTypeInfo->vgpuTypeId, &partitionFlag));
2168 
2169         NV_ASSERT_OK_OR_RETURN(
2170             kvgpumgrGetSwizzId(pGpu, pPhysGpuInfo, partitionFlag, &swizzId));
2171     }
2172     else
2173     {
2174         // Creation request for a MIG vgpuType
2175         if (vgpuTypeInfo->gpuInstanceSize)
2176             return NV_ERR_INVALID_OPERATION;
2177 
2178         status = kvgpumgrCheckVgpuTypeCreatable(pGpu, pPhysGpuInfo, vgpuTypeInfo);
2179 
2180         if (status != NV_OK)
2181             return status;
2182     }
2183 
2184     /* Initialize heap on first vGPU device creation */
2185     if (pKernelVgpuMgr->pHeap == NULL)
2186     {
2187         NvU64 tmpSize;
2188         pKernelVgpuMgr->pHeap = portMemAllocNonPaged(sizeof(OBJEHEAP));
2189         if (pKernelVgpuMgr->pHeap == NULL)
2190         {
2191             status = NV_ERR_NO_MEMORY;
2192             goto failed;
2193         }
2194 
2195         constructObjEHeap(pKernelVgpuMgr->pHeap, 1, 0xFFFF + 1, 0, 0);
2196 
2197         /* Verify if pHeap is allocated with required size */
2198         pKernelVgpuMgr->pHeap->eheapGetSize(pKernelVgpuMgr->pHeap, &tmpSize);
2199         if (tmpSize != 0xFFFF)
2200         {
2201             pKernelVgpuMgr->pHeap->eheapDestruct(pKernelVgpuMgr->pHeap);
2202             portMemFree(pKernelVgpuMgr->pHeap);
2203             pKernelVgpuMgr->pHeap = NULL;
2204             status = NV_ERR_INSUFFICIENT_RESOURCES;
2205             goto failed;
2206         }
2207     }
2208 
2209     status = pKernelVgpuMgr->pHeap->eheapAlloc(pKernelVgpuMgr->pHeap, 0xdeadbeef, &allocFlags,
2210                                          &tmpVgpuId, &vgpuIdSize, 1, 1,
2211                                          NULL, NULL, NULL);
2212     if (status != NV_OK)
2213     {
2214         NV_PRINTF(LEVEL_WARNING,
2215                   "Failed to allocate heap for vGPU ID 0x%x\n",
2216                   status);
2217         goto failed;
2218     }
2219 
2220     *vgpuId = (NvU16) tmpVgpuId;
2221     pRequestVgpu = listPrependNew(&(pKernelVgpuMgr->listRequestVgpuHead));
2222     if (pRequestVgpu == NULL)
2223     {
2224         status = NV_ERR_NO_MEMORY;
2225         goto failed;
2226     }
2227 
2228     portMemSet(pRequestVgpu, 0, sizeof(REQUEST_VGPU_INFO_NODE));
2229 
2230     portMemCopy(pRequestVgpu->mdevUuid, VGPU_UUID_SIZE, pMdevUuid, VGPU_UUID_SIZE);
2231     pRequestVgpu->gpuPciId = gpuPciId; /* For SRIOV, this is PF's gpuPciId */
2232     pRequestVgpu->vgpuId = *vgpuId;
2233     pRequestVgpu->gpuPciBdf = gpuPciBdf; /* For SRIOV, this is VF's gpuPciBdf */
2234 
2235     if (IS_MIG_IN_USE(pGpu))
2236     {
2237         pRequestVgpu->swizzId = swizzId;
2238     }
2239 
2240     kvgpumgrSetVgpuType(pGpu, pPhysGpuInfo, vgpuTypeId);
2241     pPhysGpuInfo->numCreatedVgpu++;
2242 
2243     if (gpuGetDevice(pGpu) != devfn)  /* SRIOV - VF */
2244         pPhysGpuInfo->createdVfMask |= NVBIT64(devfn - pGpu->sriovState.firstVFOffset);
2245 
2246     return NV_OK;
2247 
2248 failed:
2249     if (swizzId != KMIGMGR_SWIZZID_INVALID)
2250         _kvgpumgrClearAssignedSwizzIdMask(pGpu, swizzId);
2251 
2252     return status;
2253 }
2254 
2255 //
2256 // Delete REQUEST_VGPU_INFO_NODE structure from list.
2257 // REQUEST_VGPU_INFO_NODE is currently used only for vGPU on KVM.
2258 //
2259 NV_STATUS
2260 kvgpumgrDeleteRequestVgpu(const NvU8 *pMdevUuid, NvU16 vgpuId)
2261 {
2262     OBJSYS *pSys = SYS_GET_INSTANCE();
2263     OBJGPU *pGpu = NULL;
2264     NV_STATUS status;
2265     NvU32 pgpuIndex;
2266     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2267     REQUEST_VGPU_INFO_NODE *pRequestVgpu = NULL;
2268     REQUEST_VGPU_INFO_NODE *pRequestVgpuNext = NULL;
2269     NvU8 devfn = 0;
2270 
2271     for (pRequestVgpu = listHead(&(pKernelVgpuMgr->listRequestVgpuHead));
2272          pRequestVgpu != NULL;
2273          pRequestVgpu = pRequestVgpuNext)
2274     {
2275         pRequestVgpuNext = listNext(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
2276         if (portMemCmp(pMdevUuid, pRequestVgpu->mdevUuid, VGPU_UUID_SIZE) == 0)
2277         {
2278             if ((status = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, pRequestVgpu->gpuPciId,
2279                                               &pgpuIndex)) != NV_OK)
2280                 return status;
2281 
2282             pGpu  = gpumgrGetGpuFromId(pRequestVgpu->gpuPciId);
2283             devfn = gpuDecodeDevice(pRequestVgpu->gpuPciBdf);
2284 
2285             pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu--;
2286 
2287             if (pGpu && (gpuGetDevice(pGpu) != devfn)) // SRIOV - VF
2288                 pKernelVgpuMgr->pgpuInfo[pgpuIndex].createdVfMask &= ~(NVBIT64(devfn - pGpu->sriovState.firstVFOffset));
2289 
2290             if (IS_MIG_ENABLED(pGpu))
2291                 _kvgpumgrClearAssignedSwizzIdMask(pGpu, pRequestVgpu->swizzId);
2292             else if (pKernelVgpuMgr->pgpuInfo[pgpuIndex].numCreatedVgpu == 0)
2293                 kvgpumgrSetVgpuType(pGpu, &pKernelVgpuMgr->pgpuInfo[pgpuIndex], NVA081_CTRL_VGPU_CONFIG_INVALID_TYPE);
2294 
2295             pKernelVgpuMgr->pHeap->eheapFree(pKernelVgpuMgr->pHeap, vgpuId);
2296 
2297             listRemove(&(pKernelVgpuMgr->listRequestVgpuHead), pRequestVgpu);
2298 
2299             return NV_OK;
2300         }
2301     }
2302     return NV_ERR_OBJECT_NOT_FOUND;
2303 }
2304 
2305 NV_STATUS
2306 kvgpumgrGetHostVgpuDeviceFromMdevUuid(NvU32 gpuPciId, const NvU8 *pMdevUuid,
2307                                       KERNEL_HOST_VGPU_DEVICE **ppKernelHostVgpuDevice)
2308 {
2309     OBJSYS *pSys = SYS_GET_INSTANCE();
2310     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2311     NvU32 pgpuIndex , rmStatus;
2312     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2313     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2314 
2315     if ((rmStatus = kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex)) != NV_OK)
2316         return rmStatus;
2317 
2318     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
2319 
2320     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
2321          pKernelHostVgpuDevice != NULL;
2322          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2323     {
2324         if (pKernelHostVgpuDevice == NULL || pKernelHostVgpuDevice->pRequestVgpuInfoNode == NULL)
2325             return NV_ERR_INVALID_POINTER;
2326 
2327         if (portMemCmp(pKernelHostVgpuDevice->pRequestVgpuInfoNode->mdevUuid,
2328                        pMdevUuid, VM_UUID_SIZE) == 0)
2329         {
2330             *ppKernelHostVgpuDevice = pKernelHostVgpuDevice;
2331             return NV_OK;
2332         }
2333      }
2334     NV_PRINTF(LEVEL_ERROR, "Object not found\n");
2335     return NV_ERR_OBJECT_NOT_FOUND;
2336 }
2337 
2338 NV_STATUS
2339 kvgpumgrGetHostVgpuDeviceFromVgpuUuid(NvU32 gpuPciId, NvU8 *vgpuUuid,
2340                                   KERNEL_HOST_VGPU_DEVICE **ppKernelHostVgpuDevice)
2341 {
2342     OBJSYS *pSys = SYS_GET_INSTANCE();
2343     KernelVgpuMgr *pKernelVgpuMgr = SYS_GET_KERNEL_VGPUMGR(pSys);
2344     NvU32 pgpuIndex;
2345     KERNEL_PHYS_GPU_INFO *pPgpuInfo;
2346     KERNEL_HOST_VGPU_DEVICE *pKernelHostVgpuDevice;
2347 
2348     NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, kvgpumgrGetPgpuIndex(pKernelVgpuMgr, gpuPciId, &pgpuIndex));
2349 
2350     pPgpuInfo = &pKernelVgpuMgr->pgpuInfo[pgpuIndex];
2351 
2352     for (pKernelHostVgpuDevice = listHead(&(pPgpuInfo->listHostVgpuDeviceHead));
2353          pKernelHostVgpuDevice != NULL;
2354          pKernelHostVgpuDevice = listNext(&(pPgpuInfo->listHostVgpuDeviceHead), pKernelHostVgpuDevice))
2355     {
2356         if (portMemCmp(pKernelHostVgpuDevice->vgpuUuid,
2357                              vgpuUuid, VM_UUID_SIZE) == 0)
2358         {
2359             *ppKernelHostVgpuDevice = pKernelHostVgpuDevice;
2360             return NV_OK;
2361         }
2362     }
2363 
2364     return NV_ERR_OBJECT_NOT_FOUND;
2365 }
2366 
2367 /*
2368  * On 1GB profiles on 48GB board, we do not deduct any reserved fb from vGPU FB length
2369  * as maxInstance is only 32, so guest complete 1GB of fb mem. In such cases with
2370  * heterogeneous vGPUs, for such 1G profiles on 48G board, some combinations with
2371  * other vGPU types do not work.
2372  * Due to this, A40-8Q at placement Id 0 cannot work with A40-1Q at placement Id 8 since
2373  * A40-1Q is occupying larger vGPU FB length and overlaps with A40-8Q's assigned FB.
2374  * Similar scenario happens for A40-8Q at placement Id 24 and A40-1Q at placement Id 32
2375  * So, we disable 1GB profiles in such cases at placement Id 8 and placement Id 32.
2376  */
2377 static NvBool
2378 _kvgpumgrIsPlacementValid(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPgpuInfo, NvU32 vgpuTypeIndex,
2379                           NvU32 placementId)
2380 {
2381     NvU64 vgpuFbLength;
2382     NvU32 denyListAdaHopper[] = {2, 3, 8, 9, 14, 15, 20, 21, 26, 27, 32, 33, 38, 39, 44, 45};
2383     NvU32 denyListAmpere[] = {8, 32};
2384     NvU32 i, length, *invalidPlacements;
2385 
2386     if (IS_GSP_CLIENT(pGpu))
2387     {
2388         invalidPlacements = denyListAdaHopper;
2389         length = sizeof(denyListAdaHopper) / sizeof(NvU32);
2390     }
2391     else
2392     {
2393         invalidPlacements = denyListAmpere;
2394         length = sizeof(denyListAmpere) / sizeof(NvU32);
2395     }
2396 
2397     vgpuFbLength = pPgpuInfo->guestVmmuCount[vgpuTypeIndex] * gpuGetVmmuSegmentSize(pGpu);
2398 
2399     if (vgpuFbLength == VGPU_LOWER_FB_PROFILE_SIZE_1_GB)
2400     {
2401         for (i = 0; i < length; i++)
2402         {
2403            if (invalidPlacements[i] == placementId)
2404                return NV_FALSE;
2405         }
2406     }
2407 
2408     return NV_TRUE;
2409 }
2410 
2411 /*
2412  * This function recursively divides the placement region in 1/2, 1/4, 1/8, 1/16 partitions
2413  * and then calculates the placement IDs of each vGPU type. It will try to allocate
2414  * placement ID of 2 vGPU instances for a type in such a way that the placement ID
2415  * of first vGPU instance starts at the beginning of partition and the placement ID
2416  * of second vGPU instance ends at the end of partition.
2417  *
2418  * It finds the vGPU types whose 2 instances can be allocated in a 1/2, 1/4, 1/8, 1/16
2419  * partition and then allocates one at start of partition and other at end of partion.
2420  *
2421  * It does this recursively by taking input start and end as input alongwith the current
2422  * partition which specifies whether this is 1/1, 1/2, 1/4, 1/8, 1/16 partion.
2423  *
2424  * Similarly it also calculates the channel offsets for each supported placementId
2425  * for a vGPU type. The algorithm for calculating placementId and channel offset
2426  * is the same just that for channel offset the range is from 0 to 2048.
2427  *
2428  * For vGPU-GSP, we also need to define offsets in FB for GSP plugin heap.
2429  * For larger vGPU profiles with GSP plugin heap >=1 vMMU segment, the gsp heap is
2430  * placed at the end of vGPU FB.
2431  * For smaller profiles with gsp heap < 1 vMMU segment, heap is placed at end of
2432  * each 1/4th alignment (for 128MB vMMU segment size) OR 1/8th alighment (for 64MB
2433  * vMMU segment size). For such profiles the vMMU segment at the end of 1/4 or 1/8
2434  * partition is divided as per profile's heap size.
2435  *
2436  */
2437 static void
2438 _kvgpumgrSetHeterogeneousResources(OBJGPU *pGpu, KERNEL_PHYS_GPU_INFO *pPgpuInfo, NvU32 placementIdMin,
2439                                    NvU32 placementIdMax, NvU32 chidMin, NvU32 chidMax,
2440                                    NvU32 vmmuSegMin, NvU32 vmmuSegMax, NvU64 gspHeapOffsetMin,
2441                                    NvU64 gspHeapOffsetMax, NvU32 partitionCount,
2442                                    NvBool isLeftPartition)
2443 {
2444     VGPU_TYPE *pVgpuTypeInfo;
2445     NvU32 heterogeneousMaxInstance, i;
2446     NvBool isCarveOutGspHeap = NV_FALSE;
2447     NvU64 newVmmuSegMin, newVmmuSegMax, newGspHeapOffsetMin, newGspHeapOffsetMax, vmmuSegSize;
2448     NvBool isDefineLeftPlacement, isDefineRightPlacement;
2449 
2450     /*
2451      * As max vGPU per GPU is 32, the minimum partition for 2 vGPUs will be 16.
2452      * So, if this is a 1/16 partition, don't recurse further
2453      */
2454     if (partitionCount > MAX_VGPU_DEVICES_PER_PGPU / 2)
2455         return;
2456 
2457     vmmuSegSize = gpuGetVmmuSegmentSize(pGpu);
2458     for (i = 0; i < pPgpuInfo->numVgpuTypes; i++)
2459     {
2460         pVgpuTypeInfo = pPgpuInfo->vgpuTypes[i];
2461 
2462         if (pVgpuTypeInfo->placementSize == 0)
2463             continue;
2464 
2465         isDefineLeftPlacement = NV_FALSE;
2466         isDefineRightPlacement = NV_FALSE;
2467 
2468         heterogeneousMaxInstance = nvPrevPow2_U32(pVgpuTypeInfo->maxInstance);
2469 
2470         /*
2471          * If homogeneous maxInstances of vGPU type are in power-of-2 and can fit in this partition,
2472          * then define both the placements in this recursive call
2473          */
2474         if (partitionCount * 2 == pVgpuTypeInfo->maxInstance)
2475         {
2476             isDefineLeftPlacement = NV_TRUE;
2477             isDefineRightPlacement = NV_TRUE;
2478 
2479             /*
2480              * Check if the next recursive partition will be a smaller partition for which
2481              * we need to carve out GSP heap at the end of smaller partition.
2482              */
2483             if (IS_GSP_CLIENT(pGpu) && (isCarveOutGspHeap == NV_FALSE) &&
2484                 (pVgpuTypeInfo->gspHeapSize == vmmuSegSize))
2485                 isCarveOutGspHeap = NV_TRUE;
2486         }
2487         else if (((heterogeneousMaxInstance < pVgpuTypeInfo->maxInstance) &&
2488                   (heterogeneousMaxInstance == partitionCount)) ||
2489                  ((partitionCount == 1) && (pVgpuTypeInfo->maxInstance == 1)))
2490         {
2491             /*
2492              * If only one instance of vGPU type can fit in this partition, then define
2493              * placement depending on whether it is a left or right partition
2494              */
2495             isDefineLeftPlacement = isLeftPartition;
2496             isDefineRightPlacement = !isLeftPartition;
2497         }
2498 
2499 
2500         if (isDefineLeftPlacement == NV_TRUE)
2501         {
2502             /*
2503              * Fill placement ID / channel / FB offset of first vGPU in this partition
2504              * First vGPU is aligned to the starting of partition
2505              */
2506             if (_kvgpumgrIsPlacementValid(pGpu, pPgpuInfo, i, placementIdMin))
2507             {
2508                 pVgpuTypeInfo->supportedPlacementIds[pVgpuTypeInfo->placementCount] = placementIdMin;
2509                 pVgpuTypeInfo->supportedChidOffsets[pVgpuTypeInfo->placementCount] = chidMin;
2510 
2511                 if (!IS_GSP_CLIENT(pGpu))
2512                     pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2513                 else
2514                 {
2515                     /* If profile occupies > 1 vMMU segment for GSP heap, place heap at end of vGPU FB. */
2516                     if (pVgpuTypeInfo->gspHeapSize >= vmmuSegSize)
2517                     {
2518                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2519                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2520                             (vmmuSegMin + pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize;
2521                     }
2522                     else
2523                     {
2524                         /*
2525                          * If we're in smaller parition, GSP vMMU segment will be input to the function.
2526                          * Place the gsp heap of first vGPU at the starting of the GSP vMMU segment.
2527                          */
2528                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2529                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] = gspHeapOffsetMin;
2530                     }
2531 
2532                     /* For 32:1 vGPU types, the GSP heap is placed between 2 consecutive guest vMMU segments */
2533                     if (heterogeneousMaxInstance == 32)
2534                     {
2535                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] = vmmuSegMin;
2536                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2537                             (vmmuSegMin + pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize;
2538                     }
2539                 }
2540 
2541                 pVgpuTypeInfo->placementCount++;
2542             }
2543         }
2544 
2545         if (isDefineRightPlacement == NV_TRUE)
2546         {
2547             /*
2548              * Fill placement ID / channel / FB offset of second vGPU in this partition
2549              * Second vGPU is aligned to the end of partition
2550              */
2551             if (_kvgpumgrIsPlacementValid(pGpu, pPgpuInfo, i,
2552                                           placementIdMax - pVgpuTypeInfo->placementSize))
2553             {
2554                 pVgpuTypeInfo->supportedPlacementIds[pVgpuTypeInfo->placementCount] =
2555                                            placementIdMax - pVgpuTypeInfo->placementSize;
2556 
2557                 pVgpuTypeInfo->supportedChidOffsets[pVgpuTypeInfo->placementCount] =
2558                                            chidMax - pVgpuTypeInfo->channelCount;
2559 
2560                 if (!IS_GSP_CLIENT(pGpu))
2561                     pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2562                                                vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2563                 else
2564                 {
2565                     /* If profile occupies > 1 vMMU segment for GSP heap, place heap at end of vGPU FB. */
2566                     if (pVgpuTypeInfo->gspHeapSize >= vmmuSegSize)
2567                     {
2568                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2569                             vmmuSegMax - pPgpuInfo->guestVmmuCount[i] - (pVgpuTypeInfo->gspHeapSize / vmmuSegSize);
2570                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2571                             (vmmuSegMax * vmmuSegSize) - pVgpuTypeInfo->gspHeapSize;
2572                     }
2573                     else
2574                     {
2575                         /*
2576                          * If we're in smaller parition, GSP vMMU segment will be input to the function.
2577                          * Place the gsp heap of first vGPU at the starting of the GSP vMMU segment.
2578                          */
2579                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2580                                                                 vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2581                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2582                                                                     gspHeapOffsetMax - pVgpuTypeInfo->gspHeapSize;
2583                     }
2584 
2585                     /* For 32:1 vGPU types, the GSP heap is placed between 2 consecutive guest vMMU segments */
2586                     if (heterogeneousMaxInstance == 32)
2587                     {
2588                         pPgpuInfo->supportedVmmuOffsets[i][pVgpuTypeInfo->placementCount] =
2589                                                        vmmuSegMax - pPgpuInfo->guestVmmuCount[i];
2590                         pPgpuInfo->gspHeapOffsets[i][pVgpuTypeInfo->placementCount] =
2591                             ((vmmuSegMax - pPgpuInfo->guestVmmuCount[i]) * vmmuSegSize) - pVgpuTypeInfo->gspHeapSize;
2592                     }
2593                 }
2594 
2595                 pVgpuTypeInfo->placementCount++;
2596             }
2597         }
2598     }
2599 
2600     /*
2601      * If the next recursive partition is for a left smaller partition which has GSP heap at
2602      * of start of partition, then update vmmuSegMin to reserve one segment at the
2603      * start of smaller partition. Also, init gsp min/max value for the reserved vMMU segment
2604      * at the start.
2605      */
2606     newVmmuSegMax = ((vmmuSegMin + vmmuSegMax) / 2);
2607     if ((isCarveOutGspHeap == NV_TRUE))
2608     {
2609         NV_ASSERT((gspHeapOffsetMin == 0));
2610 
2611         newVmmuSegMin = vmmuSegMin + 1;
2612         newGspHeapOffsetMin = vmmuSegMin * vmmuSegSize;
2613         newGspHeapOffsetMax = newGspHeapOffsetMin + vmmuSegSize;
2614     }
2615     else
2616     {
2617         newVmmuSegMin = vmmuSegMin;
2618         newGspHeapOffsetMin = gspHeapOffsetMin;
2619         newGspHeapOffsetMax = (gspHeapOffsetMin + gspHeapOffsetMax) / 2;
2620     }
2621 
2622     /* Recursively call to get placment ID in left half of this partition */
2623     _kvgpumgrSetHeterogeneousResources(pGpu, pPgpuInfo, placementIdMin,
2624                              (placementIdMin + placementIdMax) / 2,
2625                              chidMin, (chidMin + chidMax) / 2, newVmmuSegMin,
2626                              newVmmuSegMax, newGspHeapOffsetMin, newGspHeapOffsetMax, partitionCount * 2,
2627                              NV_TRUE);
2628 
2629     /*
2630      * If the next recursive partition is for a right smaller partition which has GSP heap at
2631      * of end of partition, then update vmmuSegMax to reserve one segment at the
2632      * end of right partition. Also, init gsp min/max value for the reserved vMMU segment
2633      * at the end.
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 right 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