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