1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-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 is a device resource implementation.
28 *
29 ******************************************************************************/
30 
31 
32 
33 #include "resserv/resserv.h"
34 #include "resserv/rs_server.h"
35 #include "resserv/rs_client.h"
36 #include "resserv/rs_resource.h"
37 #include "gpu_mgr/gpu_mgr.h"
38 #include "gpu/device/device.h"
39 #include "gpu/subdevice/subdevice.h"
40 #include "platform/sli/sli.h"
41 
42 #include "class/cl0080.h"
43 #include "core/locks.h"
44 #include "vgpu/rpc.h"
45 #include "mem_mgr/mem.h"
46 
47 #include "rmapi/rs_utils.h"
48 #include "nvsecurityinfo.h"
49 
50 #include "gpu/gr/kernel_sm_debugger_session.h"
51 #include "kernel/gpu/rc/kernel_rc.h"
52 #include "Nvcm.h"
53 #include "diagnostics/gpu_acct.h"
54 #include "gpu/perf/kern_cuda_limit.h"
55 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
56 
57 static NV_STATUS _deviceTeardown(Device *pDevice, CALL_CONTEXT *pCallContext);
58 static NV_STATUS _deviceTeardownRef(Device *pDevice, CALL_CONTEXT *pCallContext);
59 static NV_STATUS _deviceInit(Device *pDevice, CALL_CONTEXT *pCallContext,
60                              NvHandle hClient, NvHandle hDevice, NvU32 deviceInst,
61                              NvHandle hClientShare, NvHandle hTargetClient, NvHandle hTargetDevice,
62                              NvU64 vaSize, NvU64 vaStartInternal, NvU64 vaLimitInternal,
63                              NvU32 allocFlags, NvU32 vaMode, NvBool *pbIsFirstDevice);
64 
65 NV_STATUS
66 deviceConstruct_IMPL
67 (
68     Device *pDevice,
69     CALL_CONTEXT *pCallContext,
70     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
71 )
72 {
73     NV0080_ALLOC_PARAMETERS         *pNv0080AllocParams = pParams->pAllocParams;
74     NvU32                            deviceInst, flags, vaMode;
75     NvU32                            deviceClass        = pParams->externalClassId;
76     NvHandle                         hClientShare;
77     NvHandle                         hTargetClient      = NV01_NULL_OBJECT;
78     NvHandle                         hTargetDevice      = NV01_NULL_OBJECT;
79     NvU64                            vaSize             = 0;
80     NV_STATUS                        rmStatus           = NV_OK;
81     OBJSYS                          *pSys               = SYS_GET_INSTANCE();
82     OBJOS                           *pOS                = SYS_GET_OS(pSys);
83     OBJGPU                          *pGpu;
84     NvU64                            vaStartInternal     = 0;
85     NvU64                            vaLimitInternal     = 0;
86     NvU32                            physicalAllocFlags;
87     NvBool                           bIsFirstDevice;
88 
89     if (pNv0080AllocParams == NULL)
90     {
91         deviceInst   = pParams->externalClassId - NV01_DEVICE_0;
92         hClientShare = NV01_NULL_OBJECT;
93         flags        = 0;
94         vaSize       = 0;
95         vaMode       = 0;
96     }
97     else
98     {
99         deviceInst      = pNv0080AllocParams->deviceId;
100         hClientShare    = pNv0080AllocParams->hClientShare;
101         hTargetClient   = pNv0080AllocParams->hTargetClient;
102         hTargetDevice   = pNv0080AllocParams->hTargetDevice;
103         flags           = pNv0080AllocParams->flags;
104         vaSize          = pNv0080AllocParams->vaSpaceSize;
105         vaMode          = pNv0080AllocParams->vaMode;
106 
107         // valid only if NV_DEVICE_ALLOCATION_FLAGS_RESTRICT_RESERVED_VALIMITS is flagged.
108         if (flags & NV_DEVICE_ALLOCATION_FLAGS_RESTRICT_RESERVED_VALIMITS)
109         {
110             vaStartInternal = pNv0080AllocParams->vaStartInternal;
111             vaLimitInternal = pNv0080AllocParams->vaLimitInternal;
112 
113             if ((vaLimitInternal < vaStartInternal)  || (vaLimitInternal == 0))
114             {
115                 return NV_ERR_INVALID_ARGUMENT;
116             }
117         }
118     }
119 
120     // validate device instance
121     if (gpumgrIsDeviceInstanceValid(deviceInst) != NV_OK)
122     {
123         return NV_ERR_INVALID_CLASS;
124     }
125 
126     // Make sure this device has not been disabled
127     if (gpumgrIsDeviceEnabled(deviceInst) == NV_FALSE)
128     {
129         return NV_ERR_INVALID_ARGUMENT;
130     }
131 
132     // add new device to client and set the device context
133     rmStatus = _deviceInit(pDevice, pCallContext, pParams->hClient, pParams->hResource, deviceInst,
134                            hClientShare, hTargetClient, hTargetDevice, vaSize, vaStartInternal, vaLimitInternal,
135                            flags, vaMode, &bIsFirstDevice);
136     if (rmStatus != NV_OK)
137         return rmStatus;
138 
139     pGpu = GPU_RES_GET_GPU(pDevice);
140 
141     if (pCallContext->secInfo.privLevel < RS_PRIV_LEVEL_KERNEL)
142     {
143         if (!osIsGpuAccessible(pGpu))
144         {
145             // Delete the device from the client since we should not be allocating it
146             _deviceTeardownRef(pDevice, pCallContext);
147             _deviceTeardown(pDevice, pCallContext);
148             return NV_ERR_INSUFFICIENT_PERMISSIONS;
149         }
150     }
151 
152     //
153     // Make sure this device is not in fullchip reset on OSes where it is
154     // restricted.
155     //
156     if (pOS->getProperty(pOS, PDB_PROP_OS_LIMIT_GPU_RESET) &&
157         pGpu->getProperty(pGpu, PDB_PROP_GPU_IN_FULLCHIP_RESET))
158     {
159         // Delete the device from the client since we should not be allocating it
160         _deviceTeardownRef(pDevice, pCallContext);
161         _deviceTeardown(pDevice, pCallContext);
162         return NV_ERR_GPU_IN_FULLCHIP_RESET;
163     }
164 
165     {
166         //
167         // If using thwap to generate an allocation failure here, fail the alloc
168         // right away
169         //
170         KernelRc *pKernelRc = GPU_GET_KERNEL_RC(pGpu);
171         if (pKernelRc != NULL &&
172             !krcTestAllowAlloc(pGpu, pKernelRc,
173                                NV_ROBUST_CHANNEL_ALLOCFAIL_DEVICE))
174         {
175             _deviceTeardownRef(pDevice, pCallContext);
176             _deviceTeardown(pDevice, pCallContext);
177             return NV_ERR_GENERIC;
178         }
179     }
180 
181     if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
182     {
183         physicalAllocFlags = flags & ~(NV_DEVICE_ALLOCATION_FLAGS_PLUGIN_CONTEXT
184             | NV_DEVICE_ALLOCATION_FLAGS_HOST_VGPU_DEVICE);
185 
186         NV_RM_RPC_ALLOC_SHARE_DEVICE(pGpu, pParams->hParent, pParams->hResource, pDevice->hClientShare,
187                                      hTargetClient, hTargetDevice, deviceClass,
188                                      physicalAllocFlags, vaSize, vaMode, bIsFirstDevice, rmStatus);
189         if (rmStatus != NV_OK)
190         {
191             return rmStatus;
192         }
193     }
194 
195     return rmStatus;
196 } // end of deviceConstruct_IMPL
197 
198 void
199 deviceDestruct_IMPL
200 (
201     Device *pDevice
202 )
203 {
204     CALL_CONTEXT           *pCallContext;
205     RS_RES_FREE_PARAMS_INTERNAL *pParams;
206     NV_STATUS               rmStatus = NV_OK;
207     NV_STATUS               tmpStatus;
208     NvHandle                hClient;
209 
210     resGetFreeParams(staticCast(pDevice, RsResource), &pCallContext, &pParams);
211 
212     hClient = pCallContext->pClient->hClient;
213 
214     NV_PRINTF(LEVEL_INFO, "    type: device\n");
215 
216     LOCK_METER_DATA(FREE_DEVICE, 0, 0, 0);
217 
218     // free the device
219     if (_deviceTeardownRef(pDevice, pCallContext) != NV_OK ||
220         _deviceTeardown(pDevice, pCallContext) != NV_OK)
221     {
222         tmpStatus = NV_ERR_INVALID_OBJECT_HANDLE;
223         if (tmpStatus != NV_OK && rmStatus == NV_OK)
224             rmStatus = tmpStatus;
225     }
226 
227     //
228     // If the client was created, but never had any devices successfully
229     // attached, we'll get here.  The client's device structure will have
230     // been created, but pGpu will be NULL if the device was later found
231     // to be non-existent
232     //
233     if (GPU_RES_GET_GPU(pDevice))
234     {
235         OBJGPU *pGpu = GPU_RES_GET_GPU(pDevice);
236         // vGpu support
237         if (IS_VIRTUAL(pGpu) || IS_GSP_CLIENT(pGpu))
238         {
239             RsResourceRef *pResourceRef = pCallContext->pResourceRef;
240             NvHandle       hDevice = pResourceRef->hResource;
241             NvBool         bClientInUse = NV_FALSE;
242             RsClient      *pRsClient = pCallContext->pClient;
243             NvBool         bNonOffloadVgpu = (IS_VIRTUAL(pGpu) && !IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu));
244             RS_ITERATOR    it;
245 
246             if (rmStatus == NV_OK)
247             {
248                 NV_RM_RPC_FREE(pGpu, hClient, hClient, hDevice, rmStatus);
249             }
250 
251             if (rmStatus != NV_OK)
252             {
253                 pParams->status = rmStatus;
254                 return;
255             }
256 
257             // check if there are any more devices in use.
258             it = clientRefIter(pRsClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE);
259 
260             while (clientRefIterNext(it.pClient, &it))
261             {
262                 Device *pDeviceTest = dynamicCast(it.pResourceRef->pResource, Device);
263                 NvBool bSameGpu = (GPU_RES_GET_GPU(pDeviceTest) == pGpu);
264 
265                 if ((pDeviceTest != pDevice) && (bNonOffloadVgpu || bSameGpu))
266                 {
267                     bClientInUse = NV_TRUE;
268                     break;
269                 }
270             }
271 
272             // check if there are any more KernelSMDebuggerSession in use.
273             it = clientRefIter(pRsClient, NULL, classId(KernelSMDebuggerSession), RS_ITERATE_CHILDREN, NV_TRUE);
274 
275             while (clientRefIterNext(it.pClient, &it))
276             {
277                 KernelSMDebuggerSession *pKernelSMDebuggerSession = dynamicCast(it.pResourceRef->pResource, KernelSMDebuggerSession);
278 
279                 if (pKernelSMDebuggerSession != NULL &&
280                     (!IS_VGPU_GSP_PLUGIN_OFFLOAD_ENABLED(pGpu) || GPU_RES_GET_GPU(pKernelSMDebuggerSession) == pGpu))
281                 {
282                     bClientInUse = NV_TRUE;
283                     break;
284                 }
285             }
286 
287             //  If neither any devices nor KernelSMDebuggerSession are in use, free up the client on host.
288             if (!bClientInUse)
289             {
290                 NV_RM_RPC_FREE(pGpu, hClient, NV01_NULL_OBJECT, hClient, rmStatus);
291             }
292         }
293     }
294 } // end of deviceDestruct_IMPL
295 
296 NV_STATUS
297 deviceControl_IMPL
298 (
299     Device *pDevice,
300     CALL_CONTEXT *pCallContext,
301     RS_RES_CONTROL_PARAMS_INTERNAL *pParams
302 )
303 {
304 
305     //
306     // Some assertions to make RMCTRL to NVOC migration smooth
307     // Those will be removed at the end of ctrl0080.def migration
308     //
309     NV_ASSERT_OR_RETURN(pParams->hClient == RES_GET_CLIENT_HANDLE(pDevice), NV_ERR_INVALID_STATE);
310     NV_ASSERT_OR_RETURN(pParams->hObject == RES_GET_HANDLE(pDevice), NV_ERR_INVALID_STATE);
311     NV_ASSERT_OR_RETURN(pParams->hParent == RES_GET_PARENT_HANDLE(pDevice), NV_ERR_INVALID_STATE);
312 
313     pParams->pGpuGrp      = GPU_RES_GET_GPUGRP(pDevice);
314     return gpuresControl_IMPL(staticCast(pDevice, GpuResource),
315             pCallContext, pParams);
316 }
317 
318 NV_STATUS
319 deviceInternalControlForward_IMPL
320 (
321     Device *pDevice,
322     NvU32 command,
323     void *pParams,
324     NvU32 size
325 )
326 {
327     return gpuresInternalControlForward_IMPL(staticCast(pDevice, GpuResource), command, pParams, size);
328 }
329 
330 //
331 // add a device with specified handle, instance num, within a specified client
332 // (hClientShare also specified)
333 //
334 static NV_STATUS
335 _deviceInit
336 (
337     Device  *pDevice,
338     CALL_CONTEXT *pCallContext,
339     NvHandle hClient,
340     NvHandle hDevice,
341     NvU32    deviceInst,
342     NvHandle hClientShare,
343     NvHandle hTargetClient,
344     NvHandle hTargetDevice,
345     NvU64    vaSize,
346     NvU64    vaStartInternal,
347     NvU64    vaLimitInternal,
348     NvU32    allocFlags,
349     NvU32    vaMode,
350     NvBool  *pbIsFirstDevice
351 )
352 {
353     OBJGPU      *pGpu;
354     NV_STATUS    status;
355     GpuResource *pGpuResource = staticCast(pDevice, GpuResource);
356     Device      *pExistingDevice;
357     NvU32        gpuInst;
358 
359     if (deviceInst >= NV_MAX_DEVICES)
360         return NV_ERR_INVALID_ARGUMENT;
361 
362     // Look up GPU and GPU Group
363     gpuInst = gpumgrGetPrimaryForDevice(deviceInst);
364 
365     if ((pGpu = gpumgrGetGpu(gpuInst)) == NULL)
366     {
367         return NV_ERR_INVALID_STATE;
368     }
369 
370     // Check if device inst already allocated, fail if this call succeeds.
371     status = deviceGetByInstance(pCallContext->pClient, deviceInst, &pExistingDevice);
372     if (status == NV_OK)
373     {
374         //
375         // RS-TODO: Status code should be NV_ERR_STATE_IN_USE, however keeping
376         // existing code from CliAllocElement (for now)
377         //
378         // Allow many Device objects on the same deviceInst in MIG mode.
379         //
380         if (!IS_MIG_ENABLED(pGpu) || IS_VIRTUAL(pGpu))
381             return NV_ERR_INSUFFICIENT_RESOURCES;
382     }
383 
384     *pbIsFirstDevice = (status != NV_OK);
385 
386     pDevice->hTargetClient  = hTargetClient;
387     pDevice->hTargetDevice  = hTargetDevice;
388     pDevice->pKernelHostVgpuDevice = NULL;
389 
390     pDevice->deviceInst = deviceInst;
391 
392     // Update VA Mode
393     pDevice->vaMode = vaMode;
394 
395     gpuresSetGpu(pGpuResource, pGpu, NV_TRUE);
396 
397     //
398     // In case of a SR-IOV enabled guest we create a default client inside
399     // the guest whose handle can be used for VAS sharing. Setting hClientShare
400     // to 0 on baremetal causes any VA alloc made under this device to use the
401     // global vaspace. We do not support use of the global vaspace inside guest.
402     // The legacy paravirtualization config also makes use of a default client.
403     // But, in the legacy case, the client is created by the plugin and not guest
404     // RM . On SR-IOV, vaspace management has been pushed inside the guest. So,
405     // having a vaspace only on the plugin side won't help since RmMapMemoryDma
406     // calls will no longer be RPCed to host RM.
407     //
408     if (IS_VIRTUAL_WITH_SRIOV(pGpu) &&
409         gpuIsSplitVasManagementServerClientRmEnabled(pGpu))
410     {
411         if (hClientShare == NV01_NULL_OBJECT)
412         {
413             hClientShare = pGpu->hDefaultClientShare;
414         }
415     }
416 
417     status = deviceSetClientShare(pDevice, hClientShare, vaSize,
418                                   vaStartInternal, vaLimitInternal, allocFlags);
419     if (NV_OK != status)
420         goto done;
421 
422     {
423         OBJSYS      *pSys = SYS_GET_INSTANCE();
424         GpuAccounting *pGpuAcct = SYS_GET_GPUACCT(pSys);
425         RsClient *pRsClient = pCallContext->pClient;
426         RmClient *pClient = dynamicCast(pCallContext->pClient, RmClient);
427 
428         if (pGpu->getProperty(pGpu, PDB_PROP_GPU_ACCOUNTING_ON))
429         {
430             // Try to start accounting for this procId/SubProcessId.
431             // If gpuacctStartGpuAccounting() fails, just assert and print error.
432             // gpuacctStartGpuAccounting() is not a major failure, we will continue with deviceInit() as normal.
433             if ((pRsClient->type == CLIENT_TYPE_USER) && (gpuacctStartGpuAccounting(pGpuAcct,
434                 pGpu->gpuInstance, pClient->ProcID, pClient->SubProcessID) != NV_OK))
435             {
436                 NV_ASSERT(0);
437                 NV_PRINTF(LEVEL_ERROR,
438                           "gpuacctStartGpuAccounting() failed for procId : %d and SubProcessID : "
439                           "%d. Ignoring the failure and continuing.\n",
440                           pClient->ProcID, pClient->SubProcessID);
441             }
442         }
443     }
444 
445     if (allocFlags & NV_DEVICE_ALLOCATION_FLAGS_PLUGIN_CONTEXT)
446     {
447         NV_ASSERT_OR_RETURN(allocFlags & NV_DEVICE_ALLOCATION_FLAGS_HOST_VGPU_DEVICE,
448             NV_ERR_INVALID_ARGUMENT);
449     }
450 
451 done:
452     if (status != NV_OK)
453     {
454         deviceRemoveFromClientShare(pDevice);
455     }
456 
457     return status;
458 }
459 
460 //
461 // delete a device with a specified handle within a client
462 //
463 static NV_STATUS
464 _deviceTeardown
465 (
466     Device  *pDevice,
467     CALL_CONTEXT *pCallContext
468 )
469 {
470     OBJGPU    *pGpu     = GPU_RES_GET_GPU(pDevice);
471     PORT_UNREFERENCED_VARIABLE(pGpu);
472 
473     deviceRemoveFromClientShare(pDevice);
474 
475     // DM-TODO: Force the client to move to Unicast...
476     NV_STATUS status = deviceKPerfCudaLimitCliDisable(pDevice, pGpu);
477 
478     // Adding status check here, but not returning it as we do not want to
479     // introduce any change in functionality.
480     if (status != NV_OK)
481     {
482         NV_PRINTF(LEVEL_ERROR,"Disable of Cuda limit activation failed");
483         DBG_BREAKPOINT();
484     }
485 
486     {
487         OBJSYS    *pSys = SYS_GET_INSTANCE();
488         GpuAccounting *pGpuAcct = SYS_GET_GPUACCT(pSys);
489         RsClient *pRsClient = pCallContext->pClient;
490         RmClient *pClient = dynamicCast(pCallContext->pClient, RmClient);
491 
492         if ((pRsClient->type == CLIENT_TYPE_USER) &&
493              pGpu->getProperty(pGpu, PDB_PROP_GPU_ACCOUNTING_ON))
494         {
495             gpuacctStopGpuAccounting(pGpuAcct,
496                 pGpu->gpuInstance, pClient->ProcID, pClient->SubProcessID);
497         }
498     }
499 
500     return NV_OK;
501 }
502 
503 static NV_STATUS _deviceTeardownRef
504 (
505     Device *pDevice,
506     CALL_CONTEXT *pCallContext
507 )
508 {
509 
510     return NV_OK;
511 }
512 
513 NV_STATUS
514 deviceGetByHandle_IMPL
515 (
516     RsClient         *pClient,
517     NvHandle          hDevice,
518     Device          **ppDevice
519 )
520 {
521     RsResourceRef  *pResourceRef;
522     NV_STATUS       status;
523 
524     *ppDevice = NULL;
525 
526     status = clientGetResourceRef(pClient, hDevice, &pResourceRef);
527     if (status != NV_OK)
528         return status;
529 
530     *ppDevice = dynamicCast(pResourceRef->pResource, Device);
531 
532     return (*ppDevice) ? NV_OK : NV_ERR_INVALID_OBJECT_HANDLE;
533 }
534 
535 NV_STATUS
536 deviceGetByInstance_IMPL
537 (
538     RsClient         *pClient,
539     NvU32             deviceInstance,
540     Device          **ppDevice
541 )
542 {
543     RS_ITERATOR  it;
544     Device      *pDevice;
545 
546     *ppDevice = NULL;
547 
548     it = clientRefIter(pClient, NULL, classId(Device), RS_ITERATE_CHILDREN, NV_TRUE);
549 
550     while (clientRefIterNext(it.pClient, &it))
551     {
552         pDevice = dynamicCast(it.pResourceRef->pResource, Device);
553 
554         if ((pDevice != NULL) && (deviceInstance == pDevice->deviceInst))
555         {
556             *ppDevice = pDevice;
557             return NV_OK;
558         }
559     }
560 
561     return NV_ERR_OBJECT_NOT_FOUND;
562 }
563 
564 NV_STATUS
565 deviceGetByGpu_IMPL
566 (
567     RsClient         *pClient,
568     OBJGPU           *pGpu,
569     NvBool            bAnyInGroup,
570     Device          **ppDevice
571 )
572 {
573     NvU32     deviceInstance = gpuGetDeviceInstance(pGpu);
574     NV_STATUS status;
575 
576     status = deviceGetByInstance(pClient, deviceInstance, ppDevice);
577     if (status != NV_OK)
578         return status;
579 
580     // If pGpu is not the primary GPU return failure
581     if (!bAnyInGroup && pGpu != GPU_RES_GET_GPU(*ppDevice))
582     {
583         *ppDevice = NULL;
584         return NV_ERR_OBJECT_NOT_FOUND;
585     }
586 
587     return NV_OK;
588 }
589 
590 // ****************************************************************************
591 //                            Deprecated Functions
592 // ****************************************************************************
593 
594 /**
595  * WARNING: This function is deprecated and use is *strongly* discouraged
596  * (especially for new code!)
597  *
598  * From the function name (CliSetGpuContext) it appears as a simple accessor but
599  * violates expectations by modifying the SLI BC threadstate (calls to
600  * GPU_RES_SET_THREAD_BC_STATE). This can be dangerous if not carefully managed
601  * by the caller.
602  *
603  * Instead of using this routine, please use deviceGetByHandle then call
604  * GPU_RES_GET_GPU, GPU_RES_GET_GPUGRP, GPU_RES_SET_THREAD_BC_STATE as needed.
605  *
606  * Note that GPU_RES_GET_GPU supports returning a pGpu for both pDevice,
607  * pSubdevice, the base pResource type, and any resource that inherits from
608  * GpuResource. That is, instead of using CliSetGpuContext or
609  * CliSetSubDeviceContext, please use following pattern to look up the pGpu:
610  *
611  * OBJGPU *pGpu = GPU_RES_GET_GPU(pResource or pResourceRef->pResource)
612  *
613  * To set the threadstate, please use:
614  *
615  * GPU_RES_SET_THREAD_BC_STATE(pResource or pResourceRef->pResource);
616  */
617 NV_STATUS
618 CliSetGpuContext
619 (
620     NvHandle    hClient,
621     NvHandle    hDevice,
622     OBJGPU    **ppGpu,
623     OBJGPUGRP **ppGpuGrp
624 )
625 {
626     Device    *pDevice;
627     RsClient  *pClient;
628     NV_STATUS  status;
629 
630     if (ppGpuGrp != NULL)
631         *ppGpuGrp = NULL;
632 
633     if (ppGpu != NULL)
634         *ppGpu = NULL;
635 
636     status = serverGetClientUnderLock(&g_resServ, hClient, &pClient);
637     if (status != NV_OK)
638         return status;
639 
640     status = deviceGetByHandle(pClient, hDevice, &pDevice);
641     if (status != NV_OK)
642         return status;
643 
644     if (ppGpu != NULL)
645         *ppGpu = GPU_RES_GET_GPU(pDevice);
646 
647     if (ppGpuGrp != NULL)
648         *ppGpuGrp = GPU_RES_GET_GPUGRP(pDevice);
649 
650     GPU_RES_SET_THREAD_BC_STATE(pDevice);
651 
652     return NV_OK;
653 }
654 
655 /**
656  * WARNING: This function is deprecated! Please use gpuGetByRef()
657  */
658 POBJGPU
659 CliGetGpuFromContext
660 (
661     RsResourceRef *pContextRef,
662     NvBool        *pbBroadcast
663 )
664 {
665     NV_STATUS status;
666     OBJGPU   *pGpu;
667 
668     status = gpuGetByRef(pContextRef, pbBroadcast, &pGpu);
669 
670     return (status == NV_OK) ? pGpu : NULL;
671 }
672 
673 /**
674  * WARNING: This function is deprecated! Please use gpuGetByHandle()
675  */
676 POBJGPU
677 CliGetGpuFromHandle
678 (
679     NvHandle hClient,
680     NvHandle hResource,
681     NvBool *pbBroadcast
682 )
683 {
684     RsClient    *pClient;
685     NV_STATUS    status;
686     OBJGPU      *pGpu;
687 
688     status = serverGetClientUnderLock(&g_resServ, hClient, &pClient);
689     if (status != NV_OK)
690         return NULL;
691 
692     status = gpuGetByHandle(pClient, hResource, pbBroadcast, &pGpu);
693 
694     return (status == NV_OK) ? pGpu : NULL;
695 }
696