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 #include "core/core.h"
24 #include "os/os.h"
25 #include "rmapi/event.h"
26 #include "rmapi/resource_fwd_decls.h"
27 #include "vgpu/rpc.h"
28 #include "gpu/device/device.h"
29 #include "core/locks.h"
30 #include "rmapi/rs_utils.h"
31 
32 #include "virtualization/kernel_hostvgpudeviceapi.h"
33 
34 #include "gpu/external_device/gsync_api.h"
35 
36 #include "resserv/rs_client.h"
37 #include "class/cl0005.h"
38 
39 #include "ctrl/ctrl0000/ctrl0000event.h" // NV0000_CTRL_EVENT_SET_NOTIFICATION_ACTION_*
40 
41 #if (!NV_RM_STUB_RPC)
42 static NV_STATUS _eventRpcForType(NvHandle hClient, NvHandle hObject);
43 #endif
44 
45 NV_STATUS
46 eventConstruct_IMPL
47 (
48     Event *pEvent,
49     CALL_CONTEXT *pCallContext,
50     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
51 )
52 {
53     NV0005_ALLOC_PARAMETERS *pNv0050AllocParams = pParams->pAllocParams;
54     RsClient *pRsClient = pCallContext->pClient;
55     RsResourceRef *pClientRef;
56     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
57     NV_STATUS rmStatus = NV_OK;
58     PEVENTNOTIFICATION *ppEventNotification;
59     NvHandle hChannel = 0x0;
60     OBJGPU *pGpu = NULL;
61     RS_PRIV_LEVEL privLevel = pParams->pSecInfo->privLevel;
62     NvBool bUserOsEventHandle = NV_FALSE;
63     NvHandle hParentClient = pNv0050AllocParams->hParentClient;
64 
65     //
66     // Allow hParentClient being zero to imply the allocating client should be
67     // the parent client of this event.
68     //
69     if (hParentClient == NV01_NULL_OBJECT)
70     {
71         hParentClient = pRsClient->hClient;
72     }
73 
74     // never allow user mode/non-root clients to create ring0 callbacks as
75     // we can not trust the function pointer (encoded in data).
76     if ((NV01_EVENT_KERNEL_CALLBACK == pResourceRef->externalClassId) ||
77         (NV01_EVENT_KERNEL_CALLBACK_EX == pResourceRef->externalClassId))
78     {
79         if (privLevel < RS_PRIV_LEVEL_KERNEL)
80         {
81             // sometimes it is nice to hook up callbacks for debug purposes
82             // -- but disable the override for release builds!
83 #if defined(DEBUG) || defined(DEVELOP)
84             if (!(pNv0050AllocParams->notifyIndex & NV01_EVENT_PERMIT_NON_ROOT_EVENT_KERNEL_CALLBACK_CREATION))
85 #endif
86             {
87                 return NV_ERR_ILLEGAL_ACTION;
88             }
89         }
90     }
91 
92 #if (!NV_RM_STUB_RPC)
93     if (_eventRpcForType(hParentClient, pNv0050AllocParams->hSrcResource))
94     {
95         RsResourceRef *pSrcRef;
96         NV_STATUS tmpStatus;
97 
98         tmpStatus = serverutilGetResourceRef(hParentClient,
99                                              pNv0050AllocParams->hSrcResource,
100                                              &pSrcRef);
101 
102         if (tmpStatus == NV_OK)
103         {
104             hChannel = pSrcRef->pParentRef ? pSrcRef->pParentRef->hResource : 0;
105             pGpu = CliGetGpuFromContext(pSrcRef, NULL);
106 
107             if (pGpu == NULL)
108             {
109                 NV_PRINTF(LEVEL_ERROR,
110                           "RmAllocEvent could not set pGpu. hClient=0x%x, hObject=0x%x\n",
111                           pRsClient->hClient, pResourceRef->hResource);
112             }
113         }
114     }
115 #endif
116 
117     NV_ASSERT_OK_OR_RETURN(clientGetResourceRef(pRsClient, pRsClient->hClient, &pClientRef));
118 
119     // add event to client and parent object
120     rmStatus = eventInit(pEvent,
121                         pCallContext,
122                         hParentClient,
123                         pNv0050AllocParams->hSrcResource,
124                         &ppEventNotification);
125     if (rmStatus == NV_OK)
126     {
127         //
128         // vGPU:
129         //
130         // Since vGPU does all real hardware management in the
131         // host, if we are in guest OS (where IS_VIRTUAL(pGpu) is true),
132         // do an RPC to the host to do the hardware update.
133         //
134         // In RM-offload, we don't allocate ContextDma in GSP-RM unless there
135         // is any necessity to use it (e.g. display channel binding time). So
136         // GSP-RM will find no valid object if the event is associated with
137         // ContextDma object. So we are ignoring the event allocation here if
138         // the event is associated with ContextDma object.
139         //
140         if (pGpu != NULL)
141         {
142             RsResourceRef *pSourceRef;
143 
144             if (IS_GSP_CLIENT(pGpu))
145             {
146                 NV_ASSERT_OK_OR_RETURN(
147                     serverutilGetResourceRef(hParentClient,
148                                              pNv0050AllocParams->hSrcResource,
149                                              &pSourceRef));
150             }
151 
152             if (
153                 !(IS_GSP_CLIENT(pGpu) && (pSourceRef->internalClassId == classId(KernelHostVgpuDeviceApi))) &&
154                 (IS_VIRTUAL_WITHOUT_SRIOV(pGpu) ||
155                 (IS_GSP_CLIENT(pGpu) && pSourceRef->internalClassId != classId(ContextDma)) ||
156                 (IS_VIRTUAL_WITH_SRIOV(pGpu) && !(pNv0050AllocParams->notifyIndex & NV01_EVENT_NONSTALL_INTR))))
157             {
158                 //
159                 // In SR-IOV enabled systems, nonstall events can be registered
160                 // directly with guest RM since guest RM is capable of
161                 // receiving and handling nonstall interrupts itself. In
162                 // paravirtualized systems, we always need to use the RPC to
163                 // host RM.
164                 //
165                 NV_RM_RPC_ALLOC_EVENT(pGpu,
166                                       pRsClient->hClient,
167                                       pEvent->hNotifierClient,
168                                       hChannel,
169                                       pEvent->hNotifierResource,
170                                       pResourceRef->hResource,
171                                       pResourceRef->externalClassId,
172                                       pNv0050AllocParams->notifyIndex,
173                                       rmStatus);
174             }
175         }
176 
177         if (NV01_EVENT_OS_EVENT == pResourceRef->externalClassId)
178         {
179             // convert a user event handle to its kernel equivalent.
180             if (privLevel <= RS_PRIV_LEVEL_USER_ROOT)
181             {
182                 rmStatus = osUserHandleToKernelPtr(pRsClient->hClient,
183                                                    pNv0050AllocParams->data,
184                                                    &pNv0050AllocParams->data);
185                 bUserOsEventHandle = NV_TRUE;
186             }
187         }
188 
189         if (rmStatus == NV_OK)
190             rmStatus = registerEventNotification(ppEventNotification,
191                                                  pRsClient,
192                                                  pEvent->hNotifierResource,
193                                                  pResourceRef->hResource,
194                                                  pNv0050AllocParams->notifyIndex,
195                                                  pResourceRef->externalClassId,
196                                                  pNv0050AllocParams->data,
197                                                  bUserOsEventHandle);
198     }
199 
200     if (rmStatus != NV_OK)
201         goto cleanup;
202 
203     return NV_OK;
204 
205 cleanup:
206     eventDestruct_IMPL(pEvent);
207     return rmStatus;
208 }
209 
210 void eventDestruct_IMPL
211 (
212     Event *pEvent
213 )
214 {
215     CALL_CONTEXT *pCallContext;
216     RS_RES_FREE_PARAMS_INTERNAL *pParams;
217 
218     RsClient* pRsClient;
219     NvHandle hEventClient;
220     NV_STATUS status = NV_OK;
221     NvHandle hEvent;
222     NotifShare *pNotifierShare;
223 
224     resGetFreeParams(staticCast(pEvent, RsResource), &pCallContext, &pParams);
225     pRsClient = pCallContext->pClient;
226     hEventClient = pRsClient->hClient;
227     hEvent = pCallContext->pResourceRef->hResource;
228 
229     LOCK_METER_DATA(FREE_EVENT, 0, 0, 0);
230 
231     pNotifierShare = pEvent->pNotifierShare;
232     if (pNotifierShare != NULL)
233     {
234         if (pNotifierShare->pNotifier != NULL)
235         {
236             status = inotifyUnregisterEvent(pNotifierShare->pNotifier,
237                     pNotifierShare->hNotifierClient,
238                     pNotifierShare->hNotifierResource,
239                     hEventClient,
240                     hEvent);
241         }
242         serverFreeShare(&g_resServ, staticCast(pEvent->pNotifierShare, RsShared));
243     }
244 
245     if (pParams != NULL)
246         pParams->status = status;
247 }
248 
249 NV_STATUS notifyUnregisterEvent_IMPL
250 (
251     Notifier           *pNotifier,
252     NvHandle            hNotifierClient,
253     NvHandle            hNotifierResource,
254     NvHandle            hEventClient,
255     NvHandle            hEvent
256 )
257 {
258     NV_STATUS status = NV_OK;
259     PEVENTNOTIFICATION *ppEventNotification;
260 
261     ppEventNotification = inotifyGetNotificationListPtr(staticCast(pNotifier, INotifier));
262 
263     // delete the event from the parent object and client
264     if (*ppEventNotification != NULL)
265     {
266 
267 #if (!NV_RM_STUB_RPC)
268         if (_eventRpcForType(hNotifierClient, hNotifierResource))
269         {
270             OBJGPU *pGpu = CliGetGpuFromHandle(hNotifierClient, hNotifierResource, NULL);
271 
272             if (pGpu != NULL)
273             {
274                 RsResourceRef *pNotifierRef = NULL;
275 
276                 if (IS_GSP_CLIENT(pGpu))
277                 {
278                     NV_ASSERT_OK_OR_RETURN(serverutilGetResourceRef(hNotifierClient, hNotifierResource, &pNotifierRef));
279                 }
280 
281                 //
282                 // vGPU:
283                 //
284                 // Since vGPU does all real hardware management in the
285                 // host, if we are in guest OS (where IS_VIRTUAL(pGpu) is true),
286                 // do an RPC to the host to do the hardware update.
287                 //
288                 if (
289                     !(IS_GSP_CLIENT(pGpu) && (pNotifierRef->internalClassId == classId(KernelHostVgpuDeviceApi))) &&
290                     (IS_VIRTUAL_WITHOUT_SRIOV(pGpu) ||
291                     (IS_GSP_CLIENT(pGpu) && pNotifierRef->internalClassId != classId(ContextDma)) ||
292                     (IS_VIRTUAL_WITH_SRIOV(pGpu) && !((*ppEventNotification)->bNonStallIntrEvent))))
293                 {
294                     //
295                     // In SR-IOV enabled systems, nonstall events are registered
296                     // directly with guest RM since guest RM is capable of
297                     // receiving and handling nonstall interrupts itself. We skip
298                     // the allocation, so here, we skip the free too. In
299                     // paravirtualized systems, we always need to use the RPC to
300                     // host RM.
301                     //
302                     NV_RM_RPC_FREE(pGpu, hEventClient, hEventClient, hEvent, status);
303                 }
304             }
305             else
306             {
307                 NV_PRINTF(LEVEL_ERROR,
308                           "RmFreeEvent could not set pGpu. hClient=0x%x, hObject=0x%x\n",
309                           hNotifierClient, hNotifierResource);
310             }
311         }
312 #endif
313 
314         unregisterEventNotification(ppEventNotification,
315                           hEventClient,
316                           hNotifierResource,
317                           hEvent);
318 
319     }
320 
321     // Gsync needs special event handling (ugh).
322     //
323     GSyncApi *pGSyncApi = dynamicCast(pNotifier, GSyncApi);
324     if (pGSyncApi != NULL)
325     {
326         NvU32          eventNum;
327 
328         // check all events bound to this gsync object
329         for (eventNum = 0; eventNum < NV30F1_CTRL_GSYNC_EVENT_TYPES; eventNum++)
330         {
331             if ((pGSyncApi->pEventByType[eventNum]) &&
332                 (pGSyncApi->pEventByType[eventNum]->hEventClient == hEventClient) &&
333                 (pGSyncApi->pEventByType[eventNum]->hEvent == hEvent))
334             {
335                 unregisterEventNotification(&pGSyncApi->pEventByType[eventNum],
336                         hEventClient,
337                         hNotifierResource,
338                         hEvent);
339             }
340         }
341     }
342 
343     return status;
344 }
345 
346 NV_STATUS
347 eventInit_IMPL
348 (
349     Event *pEvent,
350     CALL_CONTEXT *pCallContext,
351     NvHandle hNotifierClient,
352     NvHandle hNotifierResource,
353     PEVENTNOTIFICATION **pppEventNotification
354 )
355 {
356     NV_STATUS        rmStatus = NV_OK;
357     RsClient        *pRsClient = pCallContext->pClient;
358     RsClient        *pNotifierClient;
359     RsResourceRef   *pResourceRef = pCallContext->pResourceRef;
360     NotifShare      *pNotifierShare = NULL;
361 
362     // validate event class
363     switch (pResourceRef->externalClassId)
364     {
365         case NV01_EVENT_KERNEL_CALLBACK:
366         case NV01_EVENT_KERNEL_CALLBACK_EX:
367         case NV01_EVENT_OS_EVENT:
368             break;
369 
370         default:
371             return NV_ERR_INVALID_CLASS;
372     }
373 
374     // RS-TODO remove support for this after per-client locking is enabled
375     if (pRsClient->hClient != hNotifierClient)
376     {
377         rmStatus = serverGetClientUnderLock(&g_resServ, hNotifierClient, &pNotifierClient);
378         if (rmStatus != NV_OK)
379             return rmStatus;
380     }
381     else
382     {
383         pNotifierClient = pRsClient;
384     }
385 
386     if (pNotifierClient != NULL)
387     {
388         RsResourceRef *pNotifierRef;
389         INotifier *pNotifier;
390         if (clientGetResourceRef(pNotifierClient, hNotifierResource, &pNotifierRef) != NV_OK)
391             return NV_ERR_INVALID_OBJECT;
392 
393         pNotifier = dynamicCast(pNotifierRef->pResource, INotifier);
394         if (pNotifier == NULL)
395             return NV_ERR_INVALID_OBJECT;
396 
397         rmStatus = inotifyGetOrAllocNotifShare(pNotifier, hNotifierClient, hNotifierResource, &pNotifierShare);
398         if (rmStatus != NV_OK)
399             return rmStatus;
400 
401         *pppEventNotification = inotifyGetNotificationListPtr(pNotifierShare->pNotifier);
402     }
403 
404     serverRefShare(&g_resServ, staticCast(pNotifierShare, RsShared));
405     pEvent->pNotifierShare = pNotifierShare;
406 
407     // RS-TODO these can be looked up from share
408     pEvent->hNotifierClient    = hNotifierClient;
409     pEvent->hNotifierResource  = hNotifierResource;
410     pEvent->hEvent = pCallContext->pResourceRef->hResource;
411 
412     return rmStatus;
413 }
414 
415 NV_STATUS
416 notifyGetOrAllocNotifShare_IMPL
417 (
418     Notifier    *pNotifier,
419     NvHandle     hNotifierClient,
420     NvHandle     hNotifierResource,
421     NotifShare **ppNotifierShare
422 )
423 {
424     NV_STATUS status;
425     NotifShare *pNotifierShare;
426 
427     //
428     // Most objects that are notifiers will never have any events to notify so
429     // notifier shares are allocated as needed (i.e., when an event
430     // registers itself with the notifier.)
431     //
432     pNotifierShare = inotifyGetNotificationShare(staticCast(pNotifier, INotifier));
433     if (pNotifierShare == NULL)
434     {
435         RsShared *pShare;
436         status = serverAllocShare(&g_resServ, classInfo(NotifShare), &pShare);
437         if (status != NV_OK)
438             return status;
439 
440         pNotifierShare = dynamicCast(pShare, NotifShare);
441         pNotifierShare->pNotifier = staticCast(pNotifier, INotifier);
442         pNotifierShare->hNotifierClient = hNotifierClient;
443         pNotifierShare->hNotifierResource = hNotifierResource;
444         inotifySetNotificationShare(staticCast(pNotifier, INotifier), pNotifierShare);
445     }
446 
447     if (ppNotifierShare)
448         *ppNotifierShare = pNotifierShare;
449 
450     return NV_OK;
451 }
452 
453 NV_STATUS
454 CliGetEventNotificationList
455 (
456     NvHandle             hClient,
457     NvHandle             hObject,
458     INotifier          **ppNotifier,
459     PEVENTNOTIFICATION **pppEventNotification
460 )
461 {
462     NV_STATUS                     status = NV_OK;
463     RsResourceRef                *pResourceRef;
464     RsClient                     *pRsClient;
465     INotifier                    *pNotifier;
466 
467     *pppEventNotification = NULL;
468 
469     // Populate Resource Server information
470     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
471     if (status != NV_OK)
472         return status;
473 
474     status = clientGetResourceRef(pRsClient, hObject, &pResourceRef);
475     if (status != NV_OK)
476         return status;
477 
478     pNotifier = dynamicCast(pResourceRef->pResource, INotifier);
479     if (pNotifier != NULL)
480         *pppEventNotification = inotifyGetNotificationListPtr(pNotifier);
481 
482     if (*pppEventNotification == NULL)
483         return NV_ERR_INVALID_OBJECT;
484 
485     if (ppNotifier != NULL)
486         *ppNotifier = pNotifier;
487 
488     return NV_OK;
489 }
490 
491 NvBool
492 CliGetEventInfo
493 (
494     NvHandle         hClient,
495     NvHandle         hEvent,
496     Event          **ppEvent
497 )
498 {
499     RsClient       *pRsClient;
500     RsResourceRef  *pResourceRef;
501     RmClient       *pClient = serverutilGetClientUnderLock(hClient);
502 
503     if (pClient == NULL)
504         return NV_FALSE;
505 
506     pRsClient = staticCast(pClient, RsClient);
507     if (clientGetResourceRefByType(pRsClient, hEvent, classId(Event), &pResourceRef) != NV_OK)
508         return NV_FALSE;
509 
510     if (pResourceRef->pResource != NULL)
511     {
512         *ppEvent = dynamicCast(pResourceRef->pResource, Event);
513         return NV_TRUE;
514     }
515 
516     return NV_FALSE;
517 
518 }
519 
520 NvBool
521 CliDelObjectEvents
522 (
523     NvHandle hClient,
524     NvHandle hResource
525 )
526 {
527     NotifShare    *pNotifierShare;
528     INotifier     *pNotifier;
529     RsClient      *pRsClient;
530     NV_STATUS      status = NV_OK;
531     RsResourceRef *pResourceRef;
532 
533     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
534     if (status != NV_OK)
535         return NV_FALSE;
536 
537     status = clientGetResourceRef(pRsClient, hResource, &pResourceRef);
538     if (status != NV_OK)
539         return NV_FALSE;
540 
541     // If not a notifier object, there aren't any events to free
542     pNotifier = dynamicCast(pResourceRef->pResource, INotifier);
543 
544     if (pNotifier == NULL)
545         return NV_TRUE;
546 
547     pNotifierShare = inotifyGetNotificationShare(pNotifier);
548     if (pNotifierShare != NULL)
549     {
550         while(pNotifierShare->pEventList != NULL)
551         {
552             PEVENTNOTIFICATION pEventNotif = pNotifierShare->pEventList;
553             status = inotifyUnregisterEvent(pNotifier,
554                     pNotifierShare->hNotifierClient,
555                     pNotifierShare->hNotifierResource,
556                     pEventNotif->hEventClient,
557                     pEventNotif->hEvent);
558         }
559         pNotifierShare->pNotifier = NULL;
560     }
561 
562     return NV_TRUE;
563 
564 } // end of CliDelObjectEvents()
565 
566 // ****************************************************************************
567 //                                  System events
568 // ****************************************************************************
569 
570 void CliAddSystemEvent(
571     NvU32 event,
572     NvU32 status
573 )
574 {
575     NvU32 temp;
576     PEVENTNOTIFICATION pEventNotification = NULL;
577     RmClient **ppClient;
578     RmClient  *pClient;
579     RsClient  *pRsClient;
580     RsResourceRef *pCliResRef;
581     NV_STATUS      rmStatus = NV_OK;
582     Notifier  *pNotifier;
583 
584     for (ppClient = serverutilGetFirstClientUnderLock();
585          ppClient;
586          ppClient = serverutilGetNextClientUnderLock(ppClient))
587     {
588         pClient = *ppClient;
589         pRsClient = staticCast(pClient, RsClient);
590 
591         if (pClient->CliSysEventInfo.notifyActions[event] == NV2080_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE)
592         {
593             continue;
594         }
595 
596         temp = (pClient->CliSysEventInfo.systemEventsQueue.Head + 1) % NV_SYSTEM_EVENT_QUEUE_SIZE;
597 
598         if (temp == pClient->CliSysEventInfo.systemEventsQueue.Tail)
599         {
600             NV_PRINTF(LEVEL_ERROR, "system event queue is full");
601             return;
602         }
603 
604         pClient->CliSysEventInfo.systemEventsQueue.EventQueue[pClient->CliSysEventInfo.systemEventsQueue.Head].event  = event;
605         pClient->CliSysEventInfo.systemEventsQueue.EventQueue[pClient->CliSysEventInfo.systemEventsQueue.Head].status = status;
606         pClient->CliSysEventInfo.systemEventsQueue.Head = temp;
607 
608         rmStatus = clientGetResourceRef(staticCast(pClient, RsClient), pRsClient->hClient, &pCliResRef);
609         if (rmStatus != NV_OK)
610         {
611             NV_PRINTF(LEVEL_ERROR,
612                       "Failed to look up resource reference handle: 0x%x\n",
613                       pRsClient->hClient);
614             return;
615         }
616 
617         pNotifier = dynamicCast(pCliResRef->pResource, Notifier);
618         if (pNotifier != NULL)
619             pEventNotification = inotifyGetNotificationList(staticCast(pNotifier, INotifier));
620 
621         if (pEventNotification != NULL)
622         {
623             while (pEventNotification)
624             {
625                 if (pEventNotification->NotifyIndex == event)
626                 {
627                     if (osNotifyEvent(NULL, pEventNotification, 0, 0, 0) != NV_OK)
628                     {
629                         NV_PRINTF(LEVEL_ERROR, "failed to deliver event 0x%x",
630                                   event);
631                     }
632                 }
633                 pEventNotification = pEventNotification->Next;
634             }
635 
636             if (pClient->CliSysEventInfo.notifyActions[event] == NV0000_CTRL_EVENT_SET_NOTIFICATION_ACTION_SINGLE)
637             {
638                 pClient->CliSysEventInfo.notifyActions[event] = NV0000_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE;
639             }
640         }
641     }
642 
643     return;
644 }
645 
646 #if (!NV_RM_STUB_RPC)
647 static NV_STATUS
648 _eventRpcForType(NvHandle hClient, NvHandle hObject)
649 {
650     NV_STATUS status;
651     RsResourceRef *pResourceRef;
652 
653     status = serverutilGetResourceRef(hClient, hObject, &pResourceRef);
654 
655     if (status != NV_OK)
656     {
657         return NV_FALSE;
658     }
659 
660     if (objDynamicCastById(pResourceRef->pResource, classId(Subdevice)) ||
661         objDynamicCastById(pResourceRef->pResource, classId(KernelHostVgpuDeviceApi)) ||
662         objDynamicCastById(pResourceRef->pResource, classId(ChannelDescendant)) ||
663         objDynamicCastById(pResourceRef->pResource, classId(ContextDma)) ||
664         objDynamicCastById(pResourceRef->pResource, classId(DispChannel)) ||
665         objDynamicCastById(pResourceRef->pResource, classId(TimerApi)) ||
666         objDynamicCastById(pResourceRef->pResource, classId(KernelSMDebuggerSession)))
667     {
668         return NV_TRUE;
669     }
670 
671     return NV_FALSE;
672 }
673 #endif
674