1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2019-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /******************************************************************************
25  *
26  *   Description:
27  *       This file contains the functions managing MIG compute instance subscriptions
28  *
29  *****************************************************************************/
30 
31 #define NVOC_COMPUTE_INSTANCE_SUBSCRIPTION_H_PRIVATE_ACCESS_ALLOWED
32 
33 #include "core/core.h"
34 #include "gpu/gpu.h"
35 #include "core/system.h"
36 #include "os/os.h"
37 #include "gpu/subdevice/subdevice.h"
38 
39 #include "kernel/gpu/mig_mgr/gpu_instance_subscription.h"
40 #include "kernel/gpu/mig_mgr/compute_instance_subscription.h"
41 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
42 
43 #include "class/clc638.h"
44 #include "rmapi/rs_utils.h"
45 #include "gpu/gpu_uuid.h"
46 #include "vgpu/rpc.h"
47 
48 NV_STATUS
49 cisubscriptionConstruct_IMPL
50 (
51     ComputeInstanceSubscription  *pComputeInstanceSubscription,
52     CALL_CONTEXT                 *pCallContext,
53     RS_RES_ALLOC_PARAMS_INTERNAL *pRmAllocParams
54 )
55 {
56     NVC638_ALLOCATION_PARAMETERS *pUserParams = pRmAllocParams->pAllocParams;
57     RsClient *pRsClient = pCallContext->pClient;
58     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
59     RsResourceRef *pParentRef = pResourceRef->pParentRef;
60     GPUInstanceSubscription *pGPUInstanceSubscription = dynamicCast(pParentRef->pResource, GPUInstanceSubscription);
61     OBJGPU *pGpu;
62     MIG_COMPUTE_INSTANCE *pMIGComputeInstance;
63     NV_STATUS status;
64 
65     pGpu = GPU_RES_GET_GPU(pComputeInstanceSubscription);
66 
67     osRmCapInitDescriptor(&pComputeInstanceSubscription->dupedCapDescriptor);
68 
69     if (RS_IS_COPY_CTOR(pRmAllocParams))
70         return cisubscriptionCopyConstruct_IMPL(pComputeInstanceSubscription, pCallContext, pRmAllocParams);
71 
72     if (!IS_MIG_IN_USE(pGpu))
73     {
74         NV_ASSERT_FAILED("Compute instance Subscription failed: MIG GPU partitioning not done");
75         return NV_ERR_NOT_SUPPORTED;
76     }
77 
78     NV_CHECK_OR_RETURN(LEVEL_SILENT, pUserParams->execPartitionId < KMIGMGR_MAX_COMPUTE_INSTANCES, NV_ERR_INVALID_ARGUMENT);
79     NV_CHECK_OR_RETURN(LEVEL_SILENT, gisubscriptionGetMIGGPUInstance(pGPUInstanceSubscription) != NULL, NV_ERR_INVALID_STATE);
80     NV_CHECK_OR_RETURN(LEVEL_SILENT, gisubscriptionGetMIGGPUInstance(pGPUInstanceSubscription)->bValid, NV_ERR_INVALID_STATE);
81 
82     pMIGComputeInstance = &gisubscriptionGetMIGGPUInstance(pGPUInstanceSubscription)->MIGComputeInstance[pUserParams->execPartitionId];
83     NV_CHECK_OR_RETURN(LEVEL_SILENT, pMIGComputeInstance->bValid, NV_ERR_INVALID_ARGUMENT);
84 
85     //
86     // For now skip kernel clients, such as UVM, until Bug 2729768 is fixed.
87     //
88     if (pRsClient->type == CLIENT_TYPE_USER)
89     {
90         status = osRmCapAcquire(pMIGComputeInstance->pOsRmCaps,
91                                 NV_RM_CAP_SMC_EXEC_PARTITION_ACCESS,
92                                 pUserParams->capDescriptor,
93                                 &pComputeInstanceSubscription->dupedCapDescriptor);
94         if ((status != NV_ERR_NOT_SUPPORTED) && (status != NV_OK))
95         {
96             NV_PRINTF(LEVEL_ERROR,
97                       "Capability validation failed: ID 0x%0x!\n",
98                       pUserParams->execPartitionId);
99             return status;
100         }
101     }
102 
103     pComputeInstanceSubscription->pMIGComputeInstance = pMIGComputeInstance;
104 
105     NV_ASSERT_OK_OR_GOTO(status,
106         kmigmgrIncRefCount(pMIGComputeInstance->pShare),
107         cleanup_duped_desc);
108 
109     return NV_OK;
110 
111 cleanup_duped_desc:
112     osRmCapRelease(pComputeInstanceSubscription->dupedCapDescriptor);
113 
114     return status;
115 }
116 
117 NV_STATUS
118 cisubscriptionCopyConstruct_IMPL
119 (
120     ComputeInstanceSubscription *pComputeInstanceSubscription,
121     CALL_CONTEXT *pCallContext,
122     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
123 )
124 {
125     RsResourceRef *pSrcRef = pParams->pSrcRef;
126     ComputeInstanceSubscription *pComputeInstanceSubscriptionSrc = dynamicCast(pSrcRef->pResource, ComputeInstanceSubscription);
127     OBJGPU *pGpu = GPU_RES_GET_GPU(pComputeInstanceSubscription);
128 
129     // non kernel clients are not allowed to dup MIG instances
130     NV_CHECK_OR_RETURN(LEVEL_SILENT, pCallContext->secInfo.privLevel >= RS_PRIV_LEVEL_KERNEL,
131                        NV_ERR_NOT_SUPPORTED);
132 
133     if (IS_VIRTUAL_WITH_SRIOV(pGpu) || IS_GSP_CLIENT(pGpu))
134     {
135         RsResourceRef *pDstRef = pCallContext->pResourceRef;
136         NV_STATUS status = NV_OK;
137 
138         NV_RM_RPC_DUP_OBJECT(pGpu,
139             pCallContext->pClient->hClient,
140             pDstRef->pParentRef->hResource,
141             pDstRef->hResource,
142             pParams->pSrcClient->hClient,
143             pSrcRef->hResource,
144             0, NV_TRUE, // Send RPC for object free
145             pDstRef, status);
146         NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, status);
147     }
148 
149     pComputeInstanceSubscription->pMIGComputeInstance = pComputeInstanceSubscriptionSrc->pMIGComputeInstance;
150 
151     NV_ASSERT_OK(
152         kmigmgrIncRefCount(pComputeInstanceSubscription->pMIGComputeInstance->pShare));
153 
154     return NV_OK;
155 }
156 
157 void
158 cisubscriptionDestruct_IMPL
159 (
160     ComputeInstanceSubscription *pComputeInstanceSubscription
161 )
162 {
163     CALL_CONTEXT *pCallContext;
164     RS_RES_FREE_PARAMS_INTERNAL *pParams;
165 
166     resGetFreeParams(staticCast(pComputeInstanceSubscription, RsResource), &pCallContext, &pParams);
167 
168     osRmCapRelease(pComputeInstanceSubscription->dupedCapDescriptor);
169 
170     gisubscriptionCleanupOnUnsubscribe(pCallContext);
171 
172     NV_ASSERT_OK(
173         kmigmgrDecRefCount(pComputeInstanceSubscription->pMIGComputeInstance->pShare));
174 }
175 
176 NV_STATUS
177 cisubscriptionGetComputeInstanceSubscription_IMPL
178 (
179     RsClient *pClient,
180     NvHandle hParent,
181     ComputeInstanceSubscription **ppComputeInstanceSubscription
182 )
183 {
184     RsResourceRef *pResourceRef;
185 
186     NV_ASSERT_OR_RETURN(ppComputeInstanceSubscription != NULL, NV_ERR_INVALID_ARGUMENT);
187 
188     pResourceRef = serverutilFindChildRefByType(pClient->hClient,
189                                                 hParent, classId(ComputeInstanceSubscription),
190                                                 NV_TRUE);
191     if (pResourceRef == NULL)
192         return NV_ERR_OBJECT_NOT_FOUND;
193 
194     *ppComputeInstanceSubscription = dynamicCast(pResourceRef->pResource, ComputeInstanceSubscription);
195 
196     return NV_OK;
197 }
198 
199 NvBool
200 cisubscriptionCanCopy_IMPL
201 (
202     ComputeInstanceSubscription *pComputeInstanceSubscription
203 )
204 {
205     return NV_TRUE;
206 }
207 
208 NV_STATUS
209 cisubscriptionCtrlCmdGetUuid_IMPL
210 (
211     ComputeInstanceSubscription *pComputeInstanceSubscription,
212     NVC638_CTRL_GET_UUID_PARAMS *pParams
213 )
214 {
215     ct_assert(NV_UUID_LEN == NVC638_UUID_LEN);
216     ct_assert(NV_UUID_STR_LEN == NVC638_UUID_STR_LEN);
217 
218     portMemCopy(pParams->uuid, NVC638_UUID_LEN,
219                 pComputeInstanceSubscription->pMIGComputeInstance->uuid.uuid, NV_UUID_LEN);
220 
221     nvGetSmcUuidString(&pComputeInstanceSubscription->pMIGComputeInstance->uuid,
222                        pParams->uuidStr);
223 
224     return NV_OK;
225 }
226