1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 1993-2022 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 functions managing the display - both Disp and DispCommon 28 * entries with their insides (DispChannelList and DispDmaControlList) 29 * 30 ******************************************************************************/ 31 32 #define RM_STRICT_CONFIG_EMIT_DISP_ENGINE_DEFINITIONS 0 33 34 #include "core/locks.h" 35 #include "resserv/rs_client.h" 36 37 #include "gpu/gpu.h" 38 #include "gpu/device/device.h" 39 #include "gpu/disp/disp_objs.h" 40 #include "gpu/disp/disp_channel.h" 41 #include "gpu/disp/kern_disp.h" 42 #include "gpu_mgr/gpu_mgr.h" 43 44 #include "kernel/gpu/intr/intr.h" 45 46 #include "class/cl0073.h" // NV04_DISPLAY_COMMON 47 #include "class/cl5070.h" // NV50_DISPLAY 48 #include "class/clc370.h" // NVC370_DISPLAY 49 50 NV_STATUS 51 dispapiConstruct_IMPL 52 ( 53 DisplayApi *pDisplayApi, 54 CALL_CONTEXT *pCallContext, 55 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 56 ) 57 { 58 NV_STATUS status; 59 CLASSDESCRIPTOR *pClassDescriptor; 60 RsResourceRef *pResourceRef = pCallContext->pResourceRef; 61 OBJGPU *pGpu; 62 KernelDisplay *pKernelDisplay; 63 NvBool bBcResource; 64 NvU32 i; 65 66 LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner()); 67 68 // Use gpuGetByRef instead of GpuResource because it will work even if resource 69 // isn't a GpuResource. 70 status = gpuGetByRef(pResourceRef, &bBcResource, &pGpu); 71 if (status != NV_OK) 72 return status; 73 74 // Find class in class db (verifies class is valid for this GPU) 75 status = gpuGetClassByClassId(pGpu, pParams->externalClassId, &pClassDescriptor); 76 if (status != NV_OK) 77 { 78 NV_PRINTF(LEVEL_WARNING, "bad class 0x%x\n", pParams->externalClassId); 79 return NV_ERR_INVALID_CLASS; 80 } 81 82 // Check display is enabled (i.e. not displayless) 83 pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 84 if (pKernelDisplay == NULL) 85 { 86 return NV_ERR_NOT_SUPPORTED; 87 } 88 89 for (i = 0; i < NV2080_MAX_SUBDEVICES; i++) 90 pDisplayApi->pNotifyActions[i] = NULL; 91 92 pDisplayApi->pGpuInRmctrl = NULL; 93 pDisplayApi->pGpuGrp = gpumgrGetGpuGrpFromGpu(pGpu); 94 pDisplayApi->bBcResource = bBcResource; 95 pDisplayApi->hNotifierMemory = NV01_NULL_OBJECT; 96 pDisplayApi->pNotifierMemory = NULL; 97 98 gpuSetThreadBcState(pGpu, bBcResource); 99 100 return status; 101 } 102 103 void 104 dispapiDestruct_IMPL 105 ( 106 DisplayApi *pDisplayApi 107 ) 108 { 109 NvU32 i; 110 111 // Free notify actions memory if it's been allocated 112 for (i = 0; i < NV2080_MAX_SUBDEVICES; i++) 113 { 114 portMemFree(pDisplayApi->pNotifyActions[i]); 115 pDisplayApi->pNotifyActions[i] = NULL; 116 } 117 } 118 119 static NV_STATUS 120 _dispapiNotifierInit 121 ( 122 DisplayApi *pDisplayApi, 123 NvU32 numNotifiers, 124 NvU32 disableCmd 125 ) 126 { 127 NvU32 i, j; 128 NV_STATUS status = NV_OK; 129 130 pDisplayApi->numNotifiers = numNotifiers; 131 132 for (i = 0; i < NV2080_MAX_SUBDEVICES; i++) 133 { 134 // get memory for pNotifyActions table 135 pDisplayApi->pNotifyActions[i] = portMemAllocNonPaged( 136 pDisplayApi->numNotifiers * sizeof(NvU32)); 137 if (pDisplayApi->pNotifyActions[i] != NULL) 138 { 139 // default actions for each notifier type is disabled 140 for (j = 0; j < pDisplayApi->numNotifiers; j++) 141 { 142 pDisplayApi->pNotifyActions[i][j] = disableCmd; 143 } 144 } 145 else 146 { 147 goto fail; 148 } 149 } 150 151 return status; 152 153 fail: 154 // first release any notifyActions memory 155 for (i = 0; i < NV2080_MAX_SUBDEVICES; i++) 156 { 157 portMemFree(pDisplayApi->pNotifyActions[i]); 158 pDisplayApi->pNotifyActions[i] = NULL; 159 } 160 161 return NV_ERR_INSUFFICIENT_RESOURCES; 162 } 163 164 NV_STATUS 165 dispobjConstructHal_IMPL 166 ( 167 DispObject *pDispObject, 168 CALL_CONTEXT *pCallContext, 169 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 170 ) 171 { 172 DisplayApi *pDisplayApi = staticCast(pDispObject, DisplayApi); 173 Device *pDevice = dynamicCast(pCallContext->pResourceRef->pParentRef->pResource, Device); 174 GpuResource *pGpuResource = staticCast(pDevice, GpuResource); 175 OBJGPU *pGpu = pGpuResource->pGpu; 176 NV_STATUS rmStatus = NV_ERR_INVALID_STATE; 177 178 SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY); 179 { 180 KernelDisplay *pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu); 181 182 rmStatus = kdispSelectClass_HAL(pGpu, pKernelDisplay, pCallContext->pResourceRef->externalClassId); 183 184 if (rmStatus != NV_OK) 185 { 186 // If the operation fails, it should fail on the first try 187 NV_ASSERT(gpumgrIsParentGPU(pGpu)); 188 SLI_LOOP_BREAK; 189 } 190 } 191 SLI_LOOP_END; 192 193 if (rmStatus != NV_OK) 194 return rmStatus; 195 196 if(dynamicCast(pDisplayApi, NvDispApi)) 197 { 198 rmStatus = _dispapiNotifierInit(pDisplayApi, 199 NVC370_NOTIFIERS_MAXCOUNT, 200 NVC370_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE); 201 } 202 else 203 { 204 rmStatus = _dispapiNotifierInit(pDisplayApi, 205 NV5070_NOTIFIERS_MAXCOUNT, 206 NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE); 207 } 208 209 return rmStatus; 210 } 211 212 NV_STATUS 213 dispobjConstruct_IMPL 214 ( 215 DispObject *pDispObject, 216 CALL_CONTEXT *pCallContext, 217 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 218 ) 219 { 220 pDispObject->rmFreeFlags = NV5070_CTRL_SET_RMFREE_FLAGS_NONE; 221 222 if (pParams->pSecInfo->privLevel < RS_PRIV_LEVEL_USER_ROOT) 223 { 224 NV_PRINTF(LEVEL_ERROR, 225 "Failure allocating display class 0x%08x: Only root(admin)/kernel clients are allowed\n", 226 pParams->externalClassId); 227 228 // 229 // GPUSWSEC-1560 introduced a central object privilege check in RS. Please mark derived external classes 230 // of DispObject privileged in their RS_ENTRY. Since DispObject doesn't have an external class of its own 231 // and is used as a base class, leaving this check inline to catch future derivations. 232 // 233 osAssertFailed(); 234 235 return NV_ERR_INSUFFICIENT_PERMISSIONS; 236 } 237 238 return dispobjConstructHal_HAL(pDispObject, pCallContext, pParams); 239 } 240 241 NV_STATUS 242 dispobjGetByHandle_IMPL 243 ( 244 RsClient *pClient, 245 NvHandle hDispObject, 246 DispObject **ppDispObject 247 ) 248 { 249 NV_STATUS status; 250 RsResourceRef *pResourceRef; 251 252 status = clientGetResourceRef(pClient, hDispObject, &pResourceRef); 253 if (status != NV_OK) 254 return status; 255 256 *ppDispObject = dynamicCast(pResourceRef->pResource, DispObject); 257 258 return (*ppDispObject) ? NV_OK : NV_ERR_INVALID_OBJECT_HANDLE; 259 } 260 261 NV_STATUS 262 dispobjGetByDevice_IMPL 263 ( 264 RsClient *pClient, 265 Device *pDevice, 266 DispObject **ppDispObject 267 ) 268 { 269 NV_STATUS status; 270 RsResourceRef *pResourceRef; 271 272 status = refFindChildOfType(RES_GET_REF(pDevice), classId(DispObject), NV_FALSE /*bExactMatch*/, &pResourceRef); 273 if (status != NV_OK) 274 return status; 275 276 *ppDispObject = dynamicCast(pResourceRef->pResource, DispObject); 277 278 return (*ppDispObject) ? NV_OK : NV_ERR_INVALID_OBJECT_HANDLE; 279 } 280 281 // 282 // Most display control calls take a subDeviceInstance argument. 283 // We need to verify that this argument is valid and then use it to 284 // locate the correct OBJGPU for the particular subdevice. 285 // 286 NV_STATUS 287 dispapiSetUnicastAndSynchronize_KERNEL 288 ( 289 DisplayApi *pDisplayApi, 290 OBJGPUGRP *pGpuGroup, 291 OBJGPU **ppGpu, 292 NvU32 subDeviceInstance 293 ) 294 { 295 NV_STATUS nvStatus = NV_OK; 296 297 nvStatus = gpugrpGetGpuFromSubDeviceInstance(pGpuGroup, subDeviceInstance, ppGpu); 298 if (nvStatus != NV_OK) 299 return nvStatus; 300 301 gpumgrSetBcEnabledStatus(*ppGpu, NV_FALSE); 302 303 return nvStatus; 304 } 305 306 NV_STATUS 307 dispapiControl_Prologue_IMPL 308 ( 309 DisplayApi *pDisplayApi, 310 CALL_CONTEXT *pCallContext, 311 RS_RES_CONTROL_PARAMS_INTERNAL *pRmCtrlParams 312 ) 313 { 314 NvU32 subdeviceIndex; 315 NV_STATUS status; 316 RmResource *pResource = staticCast(pDisplayApi, RmResource); 317 318 if (dynamicCast(pDisplayApi, DispCommon)) 319 { 320 Device *pDevice = dynamicCast(pCallContext->pResourceRef->pParentRef->pResource, Device); 321 GpuResource *pGpuResource = staticCast(pDevice, GpuResource); 322 323 pResource->rpcGpuInstance = gpuGetInstance(pGpuResource->pGpu); 324 pDisplayApi->pGpuInRmctrl = pGpuResource->pGpu; 325 return rmresControl_Prologue_IMPL(pResource, pCallContext, pRmCtrlParams); 326 } 327 328 // Read the subdevice ID out and swap GPU pointer 329 if (dynamicCast(pDisplayApi, NvDispApi)) 330 { 331 NVC370_CTRL_CMD_BASE_PARAMS *pBaseParameters = pRmCtrlParams->pParams; 332 333 // 334 // All non-NULL disp control 5070 methods have 335 // NVC370_CTRL_CMD_BASE_PARAMS as their first member. 336 // 337 if ((pBaseParameters == NULL) || (pRmCtrlParams->paramsSize < sizeof(NVC370_CTRL_CMD_BASE_PARAMS))) 338 { 339 status = NV_ERR_INVALID_PARAM_STRUCT; 340 goto done; 341 } 342 subdeviceIndex = pBaseParameters->subdeviceIndex; 343 } 344 else if (dynamicCast(pDisplayApi, DispSwObj)) 345 { 346 NVC372_CTRL_CMD_BASE_PARAMS *pBaseParameters = pRmCtrlParams->pParams; 347 348 // 349 // All non-NULL disp control C372 methods have 350 // NVC372_CTRL_CMD_BASE_PARAMS as their first member. 351 // 352 if ((pBaseParameters == NULL) || (pRmCtrlParams->paramsSize < sizeof(NVC372_CTRL_CMD_BASE_PARAMS))) 353 { 354 status = NV_ERR_INVALID_PARAM_STRUCT; 355 goto done; 356 } 357 subdeviceIndex = pBaseParameters->subdeviceIndex; 358 } 359 else 360 { 361 NV5070_CTRL_CMD_BASE_PARAMS *pBaseParameters = pRmCtrlParams->pParams; 362 363 // 364 // All non-NULL disp control 5070 methods have 365 // NV5070_CTRL_CMD_BASE_PARAMS as their first member. 366 // 367 if ((pBaseParameters == NULL) || (pRmCtrlParams->paramsSize < sizeof(NV5070_CTRL_CMD_BASE_PARAMS))) 368 { 369 status = NV_ERR_INVALID_PARAM_STRUCT; 370 goto done; 371 } 372 subdeviceIndex = pBaseParameters->subdeviceIndex; 373 } 374 375 status = dispapiSetUnicastAndSynchronize_HAL(pDisplayApi, 376 pRmCtrlParams->pGpuGrp, 377 &pRmCtrlParams->pGpu, 378 subdeviceIndex); 379 380 if (status == NV_OK) 381 { 382 pResource->rpcGpuInstance = gpuGetInstance(pRmCtrlParams->pGpu); 383 pDisplayApi->pGpuInRmctrl = pRmCtrlParams->pGpu; 384 return rmresControl_Prologue_IMPL(pResource, pCallContext, pRmCtrlParams); 385 } 386 387 done: 388 return status; 389 } 390 391 void 392 dispapiControl_Epilogue_IMPL 393 ( 394 DisplayApi *pDisplayApi, 395 CALL_CONTEXT *pCallContext, 396 RS_RES_CONTROL_PARAMS_INTERNAL *pRmCtrlParams 397 ) 398 { 399 if (dynamicCast(pDisplayApi, DispCommon) == NULL) 400 { 401 RmResource *pResource = staticCast(pDisplayApi, RmResource); 402 pResource->rpcGpuInstance = ~0; 403 } 404 405 pDisplayApi->pGpuInRmctrl = NULL; 406 } 407 408 NV_STATUS 409 dispapiControl_IMPL 410 ( 411 DisplayApi *pDisplayApi, 412 CALL_CONTEXT *pCallContext, 413 RS_RES_CONTROL_PARAMS_INTERNAL *pParams 414 ) 415 { 416 Intr *pIntr; 417 NV_STATUS status = NV_OK; 418 Device *pDevice = dynamicCast(pCallContext->pResourceRef->pParentRef->pResource, Device); 419 GpuResource *pGpuResource = staticCast(pDevice, GpuResource); 420 RmCtrlParams *pRmCtrlParams = pParams->pLegacyParams; 421 OBJGPU *pGpu = pGpuResource->pGpu; 422 423 NV_PRINTF(LEVEL_INFO, "class: 0x%x cmd 0x%x\n", 424 RES_GET_EXT_CLASS_ID(pDisplayApi), 425 pRmCtrlParams->cmd); 426 427 pRmCtrlParams->pGpu = pGpu; 428 pRmCtrlParams->pGpuGrp = pGpuResource->pGpuGrp; 429 430 gpuSetThreadBcState(pGpu, NV_TRUE); 431 432 pIntr = GPU_GET_INTR(pGpu); 433 if (pIntr != NULL) 434 { 435 bitVectorClrAll(&pIntr->helperEngineMask); 436 bitVectorSet(&pIntr->helperEngineMask, MC_ENGINE_IDX_GR); 437 bitVectorSet(&pIntr->helperEngineMask, MC_ENGINE_IDX_DISP); 438 bitVectorSet(&pIntr->helperEngineMask, MC_ENGINE_IDX_FIFO); 439 } 440 441 status = resControl_IMPL(staticCast(pDisplayApi, RsResource), 442 pCallContext, pParams); 443 444 if (pIntr != NULL) 445 { 446 bitVectorClrAll(&pIntr->helperEngineMask); 447 } 448 449 return status; 450 } 451 452 NV_STATUS 453 dispswobjConstruct_IMPL 454 ( 455 DispSwObj *pDispSwObj, 456 CALL_CONTEXT *pCallContext, 457 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 458 ) 459 { 460 return NV_OK; 461 } 462 463 NV_STATUS 464 dispcmnConstruct_IMPL 465 ( 466 DispCommon *pDispCommon, 467 CALL_CONTEXT *pCallContext, 468 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 469 ) 470 { 471 DisplayApi *pDisplayApi = staticCast(pDispCommon, DisplayApi); 472 473 // 474 // Not adding the priv-level check for this class 475 // as it is being used by OpenGL from userspace.Once the Cleanup is done from the OpenGL 476 // we can add the priv level check here below 477 // 478 479 pDispCommon->hotPlugMaskToBeReported = 0; 480 pDispCommon->hotUnplugMaskToBeReported = 0; 481 482 return _dispapiNotifierInit(pDisplayApi, 483 NV0073_NOTIFIERS_MAXCOUNT, 484 NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE); 485 } 486 487 NV_STATUS 488 dispcmnGetByHandle_IMPL 489 ( 490 RsClient *pClient, 491 NvHandle hDispCommon, 492 DispCommon **ppDispCommon 493 ) 494 { 495 NV_STATUS status; 496 RsResourceRef *pResourceRef; 497 498 status = clientGetResourceRef(pClient, hDispCommon, &pResourceRef); 499 if (status != NV_OK) 500 return status; 501 502 *ppDispCommon = dynamicCast(pResourceRef->pResource, DispCommon); 503 504 return (*ppDispCommon) ? NV_OK : NV_ERR_INVALID_OBJECT_HANDLE; 505 } 506 507 void 508 dispcmnGetByDevice_IMPL 509 ( 510 RsClient *pClient, 511 NvHandle hDevice, 512 DispCommon **ppDispCommon 513 ) 514 { 515 Device *pDevice; 516 RsResourceRef *pResourceRef; 517 518 *ppDispCommon = NULL; /* return failure by default */ 519 520 if (deviceGetByHandle(pClient, hDevice, &pDevice) != NV_OK) 521 return; 522 523 if (refFindChildOfType(RES_GET_REF(pDevice), 524 classId(DispCommon), 525 NV_FALSE, 526 &pResourceRef) != NV_OK) 527 return; 528 529 *ppDispCommon = dynamicCast(pResourceRef->pResource, DispCommon); 530 } 531 532 /** 533 * @brief Return NV_TRUE if RmFree() needs to preserve the HW, otherwise NV_FALSE 534 * 535 * @param[in] DispObject Pointer 536 */ 537 NvBool dispobjGetRmFreeFlags_IMPL(DispObject *pDispObject) 538 { 539 return !!(pDispObject->rmFreeFlags & NV5070_CTRL_SET_RMFREE_FLAGS_PRESERVE_HW); 540 } 541 542 /** 543 * @brief Clears the RmFree() temporary flags 544 * 545 * @param[in] DispObject Pointer 546 * 547 * @return void 548 */ 549 void dispobjClearRmFreeFlags_IMPL(DispObject *pDispObject) 550 { 551 pDispObject->rmFreeFlags = NV5070_CTRL_SET_RMFREE_FLAGS_NONE; 552 } 553 554 NV_STATUS 555 nvdispapiConstruct_IMPL 556 ( 557 NvDispApi *pNvdispApi, 558 CALL_CONTEXT *pCallContext, 559 RS_RES_ALLOC_PARAMS_INTERNAL *pParams 560 ) 561 { 562 return NV_OK; 563 } 564 565 // **************************************************************************** 566 // Deprecated Functions 567 // **************************************************************************** 568 569 /** 570 * @warning This function is deprecated! Please use dispchnGetByHandle. 571 */ 572 NV_STATUS 573 CliFindDispChannelInfo 574 ( 575 NvHandle hClient, 576 NvHandle hDispChannel, 577 DispChannel **ppDispChannel, 578 NvHandle *phParent 579 ) 580 { 581 RsClient *pClient; 582 NV_STATUS status; 583 584 *ppDispChannel = NULL; 585 586 status = serverGetClientUnderLock(&g_resServ, hClient, &pClient); 587 if (status != NV_OK) 588 return NV_ERR_INVALID_CLIENT; 589 590 status = dispchnGetByHandle(pClient, hDispChannel, ppDispChannel); 591 if (status != NV_OK) 592 return status; 593 594 if (phParent) 595 *phParent = RES_GET_PARENT_HANDLE(*ppDispChannel); 596 597 return NV_OK; 598 } 599 600 /** 601 * @warning This function is deprecated! Please use dispcmnGetByHandle. 602 */ 603 NvBool 604 CliGetDispCommonInfo 605 ( 606 NvHandle hClient, 607 NvHandle hDispCommon, 608 DisplayApi **ppDisplayApi 609 ) 610 { 611 RsClient *pClient; 612 NV_STATUS status; 613 DispCommon *pDispCommon; 614 615 *ppDisplayApi = NULL; 616 617 status = serverGetClientUnderLock(&g_resServ, hClient, &pClient); 618 if (status != NV_OK) 619 return NV_FALSE; 620 621 status = dispcmnGetByHandle(pClient, hDispCommon, &pDispCommon); 622 if (status != NV_OK) 623 return NV_FALSE; 624 625 *ppDisplayApi = staticCast(pDispCommon, DisplayApi); 626 627 return NV_TRUE; 628 } 629 630 /** 631 * @warning This function is deprecated! Please use dispobjGetByHandle. 632 */ 633 NvBool 634 CliGetDispInfo 635 ( 636 NvHandle hClient, 637 NvHandle hObject, 638 DisplayApi **pDisplayApi 639 ) 640 { 641 if (!pDisplayApi) 642 return NV_FALSE; 643 644 *pDisplayApi = CliGetDispFromDispHandle(hClient, hObject); 645 646 return *pDisplayApi ? NV_TRUE : NV_FALSE; 647 } 648 649 /** 650 * @warning This function is deprecated! Please use dispobjGetByHandle. 651 */ 652 DisplayApi * 653 CliGetDispFromDispHandle 654 ( 655 NvHandle hClient, 656 NvHandle hDisp 657 ) 658 { 659 RsClient *pClient; 660 NV_STATUS status; 661 DispObject *pDispObject; 662 663 status = serverGetClientUnderLock(&g_resServ, hClient, &pClient); 664 if (status != NV_OK) 665 return NULL; 666 667 status = dispobjGetByHandle(pClient, hDisp, &pDispObject); 668 if (status != NV_OK) 669 return NULL; 670 671 return staticCast(pDispObject, DisplayApi); 672 } 673 674 // 675 // DISP Event RM Controls 676 // 677 NV_STATUS 678 dispapiCtrlCmdEventSetNotification_IMPL 679 ( 680 DisplayApi *pDisplayApi, 681 NV5070_CTRL_EVENT_SET_NOTIFICATION_PARAMS *pSetEventParams 682 ) 683 { 684 OBJGPU *pGpu = DISPAPI_GET_GPU(pDisplayApi); 685 NvU32 *pNotifyActions; 686 NV_STATUS status = NV_OK; 687 PEVENTNOTIFICATION pEventNotifications = inotifyGetNotificationList(staticCast(pDisplayApi, INotifier)); 688 689 // NV01_EVENT must have been plugged into this subdevice 690 if (pEventNotifications == NULL) 691 { 692 NV_PRINTF(LEVEL_INFO, "cmd 0x%x: no event list\n", NV5070_CTRL_CMD_EVENT_SET_NOTIFICATION); 693 return NV_ERR_INVALID_STATE; 694 } 695 696 // error check event index 697 if (pSetEventParams->event >= pDisplayApi->numNotifiers) 698 { 699 NV_PRINTF(LEVEL_INFO, "bad event 0x%x\n", pSetEventParams->event); 700 return NV_ERR_INVALID_ARGUMENT; 701 } 702 703 // error check subDeviceInstance 704 if (pSetEventParams->subDeviceInstance >= gpumgrGetSubDeviceMaxValuePlus1(pGpu)) 705 { 706 NV_PRINTF(LEVEL_INFO, "bad subDeviceInstance 0x%x\n", 707 pSetEventParams->subDeviceInstance); 708 return NV_ERR_INVALID_ARGUMENT; 709 } 710 711 pNotifyActions = pDisplayApi->pNotifyActions[pSetEventParams->subDeviceInstance]; 712 713 switch (pSetEventParams->action) 714 { 715 case NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_SINGLE: 716 case NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_REPEAT: 717 { 718 // must be in disabled state to transition to an active state 719 if (pNotifyActions[pSetEventParams->event] != NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE) 720 { 721 status = NV_ERR_INVALID_STATE; 722 break; 723 } 724 725 // bind hEvent to particular subdeviceInst 726 status = bindEventNotificationToSubdevice(pEventNotifications, 727 pSetEventParams->hEvent, 728 pSetEventParams->subDeviceInstance); 729 if (status != NV_OK) 730 return status; 731 732 pNotifyActions[pSetEventParams->event] = pSetEventParams->action; 733 break; 734 } 735 736 case NV5070_CTRL_EVENT_SET_NOTIFICATION_ACTION_DISABLE: 737 { 738 pNotifyActions[pSetEventParams->event] = pSetEventParams->action; 739 break; 740 } 741 default: 742 { 743 status = NV_ERR_INVALID_ARGUMENT; 744 break; 745 } 746 } 747 748 return status; 749 } 750