1 /* 2 * SPDX-FileCopyrightText: Copyright (c) 2020-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 * Module: videoeventlist.c * 27 * Description: * 28 * This module contains an implementation of the Event Buffer * 29 * callback for video events * 30 * * 31 \***************************************************************************/ 32 33 #include "rmapi/client.h" 34 #include "rmapi/event.h" 35 #include "rmapi/event_buffer.h" 36 #include "resserv/rs_server.h" 37 #include "core/locks.h" 38 #include "os/os.h" 39 #include "gpuvideo/video_event.h" 40 #include "gpuvideo/videoeventlist.h" 41 #include "objtmr.h" 42 #include "kernel/gpu/video/kernel_video_engine.h" 43 #include "kernel/gpu/fifo/kernel_channel_group.h" 44 #include "kernel/gpu/bus/kern_bus.h" 45 46 #include "class/cl90cd.h" 47 #include "class/cl90cdtypes.h" 48 #include "class/cl90cdvideo.h" 49 50 #include "ctrl/ctrl2080/ctrl2080internal.h" 51 52 #define NV_VIDEO_TRACE_CALLBACK_TIME_NS 50000000 // Approximating 20Hz callback 53 54 /*! 55 * This helper function initializes the context used for video event trace. 56 */ 57 NV_STATUS 58 videoEventTraceCtxInit 59 ( 60 OBJGPU *pGpu, 61 KernelChannel *pKernelChannel, 62 ENGDESCRIPTOR engDesc 63 ) 64 { 65 KernelVideoEngine *pKernelVideoEngine; 66 MEMORY_DESCRIPTOR *pCtxMemDesc; 67 VIDEO_ENGINE_EVENT__LOG_INFO logInfo; 68 69 if (RMCFG_FEATURE_PLATFORM_GSP || !IS_VIDEO_ENGINE(engDesc) || !kvidengIsVideoTraceLogSupported(pGpu)) 70 return NV_OK; 71 72 pKernelVideoEngine = kvidengFromEngDesc(pGpu, engDesc); 73 NV_CHECK_OR_RETURN(LEVEL_ERROR, pKernelVideoEngine != NULL, NV_OK); 74 NV_CHECK_OR_RETURN(LEVEL_SILENT, pKernelVideoEngine->bVideoTraceEnabled, NV_OK); 75 76 // Fill some channel specific information for event logging 77 logInfo.userInfo = (NvU64)(NvUPtr)pKernelChannel->pUserInfo; 78 logInfo.pid = pKernelChannel->ProcessID; 79 logInfo.context_id = kchannelGetCid(pKernelChannel); 80 logInfo.engine_id = ENGDESC_FIELD(engDesc, _INST); 81 logInfo.gfid = kchannelGetGfid(pKernelChannel); 82 83 kchangrpGetEngineContextMemDesc(pGpu, 84 pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup, 85 &pCtxMemDesc); 86 87 if (pCtxMemDesc != NULL) 88 { 89 NvU8 *pInstMem; 90 NvU32 i; 91 NvU32 *pLogInfo = (NvU32 *)&logInfo; 92 93 // Is context allocation too small to hold the client info for event trace? 94 NV_CHECK_OR_RETURN(LEVEL_INFO, 95 memdescGetSize(pCtxMemDesc) >= (VIDEO_ENGINE_EVENT__LOG_INFO__OFFSET + VIDEO_ENGINE_EVENT__LOG_INFO__SIZE), 96 NV_ERR_BUFFER_TOO_SMALL); 97 98 pInstMem = kbusMapRmAperture_HAL(pGpu, pCtxMemDesc); 99 NV_CHECK_OR_RETURN(LEVEL_ERROR, pInstMem != NULL, NV_ERR_INSUFFICIENT_RESOURCES); 100 101 for (i = 0; i < sizeof(VIDEO_ENGINE_EVENT__LOG_INFO); i += 4) 102 { 103 // Initialize client information in context allocation. 104 MEM_WR32(pInstMem + VIDEO_ENGINE_EVENT__LOG_INFO__OFFSET + i, pLogInfo[i / sizeof(NvU32)]); 105 } 106 107 kbusUnmapRmAperture_HAL(pGpu, pCtxMemDesc, &pInstMem, NV_TRUE); 108 } 109 110 return NV_OK; 111 } 112 113 static 114 NV_STATUS 115 _videoEventBufferAdd 116 ( 117 OBJGPU *pGpu, 118 NV_EVENT_BUFFER_BIND_POINT_VIDEO *pBind, 119 NOTIFY_VIDEO_EVENT *pNotifyRecord, 120 NvU32 *pLogData, 121 NvBool bSanitizeUser, 122 NvBool bSanitizeKernel 123 ) 124 { 125 NV_STATUS status; 126 NvBool bNotify; 127 NvP64 notificationHandle; 128 EVENT_BUFFER_PRODUCER_DATA notifyEvent; 129 NvU32 notifyIndex = NV_EVENT_BUFFER_RECORD_TYPE_VIDEO_TRACE; 130 VIDEO_ENGINE_EVENT__RECORD const * pRecord; 131 132 if (pNotifyRecord == NULL) 133 { 134 return NV_OK; 135 } 136 pRecord = (VIDEO_ENGINE_EVENT__RECORD const *)(pNotifyRecord->pEventData); 137 138 portMemSet(¬ifyEvent, 0, sizeof(notifyEvent)); 139 notifyEvent.pVardata = NV_PTR_TO_NvP64(NULL); 140 notifyEvent.vardataSize = 0; 141 142 NV_EVENT_BUFFER_VIDEO_RECORD_V1 videoRecord; 143 portMemSet(&videoRecord, 0, sizeof(videoRecord)); 144 videoRecord.event_id = pRecord->event_id; 145 videoRecord.vmid = pRecord->gfid; 146 videoRecord.timestamp = pRecord->ts; 147 videoRecord.seqno = pRecord->seq_no; 148 videoRecord.context_id = pRecord->context_id; 149 videoRecord.pid = pRecord->pid; 150 videoRecord.api_id = pRecord->api_id; 151 152 if (bSanitizeKernel) 153 { 154 videoRecord.pid = NV_EVENT_BUFFER_VIDEO_KERNEL_PID; 155 videoRecord.context_id = NV_EVENT_BUFFER_VIDEO_KERNEL_CONTEXT; 156 videoRecord.api_id = NV_EVENT_BUFFER_VIDEO_KERNEL_CONTEXT; 157 } 158 else if (bSanitizeUser) 159 { 160 videoRecord.pid = NV_EVENT_BUFFER_VIDEO_HIDDEN_PID; 161 videoRecord.context_id = NV_EVENT_BUFFER_VIDEO_HIDDEN_CONTEXT; 162 videoRecord.api_id = NV_EVENT_BUFFER_VIDEO_HIDDEN_CONTEXT; 163 } 164 165 #if PORT_IS_MODULE_SUPPORTED(crypto) 166 // Randomized timestamp if sanitization is needed 167 if (bSanitizeKernel || bSanitizeUser) 168 { 169 // 170 // pNotifyRecord->noisyTimestampStart is copied from pKernelVideoEngine->videoTraceInfo->noisyTimestampStart which is initialized to 0 171 // during engine initialization when trace surface is allocated before session starts. pKernelVideoEngine->videoTraceInfo->noisyTimestampStart 172 // is recorded with the timestamp of a SESSION_START event. Engine will always log event in sequence and every SESSION_END event 173 // should have a SESSION_START event in front of it. Also, we are assuming NSight will discard a SESSION_END event 174 // without a SESSION_START event before it. 175 // 176 if ((pNotifyRecord->noisyTimestampStart != videoRecord.timestamp) && (pNotifyRecord->pVideoLogPrng != NULL)) 177 { 178 NvU64 noisyTimestampRange; 179 // The range is always non-zero since we had check 180 // (pNotifyRecord->noisyTimestampStart != videoRecord.timestamp) 181 // above. 182 noisyTimestampRange = (videoRecord.timestamp >= pNotifyRecord->noisyTimestampStart) 183 ? (videoRecord.timestamp - pNotifyRecord->noisyTimestampStart) 184 : (((NvU64)(-1) - pNotifyRecord->noisyTimestampStart) + videoRecord.timestamp); 185 videoRecord.timestamp = pNotifyRecord->noisyTimestampStart 186 + portCryptoPseudoRandomGeneratorGetU32(pNotifyRecord->pVideoLogPrng) % noisyTimestampRange; 187 } 188 } 189 #endif // PORT_IS_MODULE_SUPPORTED(crypto) 190 191 switch (pRecord->event_id) 192 { 193 case VIDEO_ENGINE_EVENT_ID__SESSION_START: 194 videoRecord.session.engine_type = pRecord->event_start.engine_type; 195 videoRecord.session.engine_id = pRecord->event_start.engine_id; 196 videoRecord.session.codec_id = pRecord->event_start.codec_id; 197 break; 198 case VIDEO_ENGINE_EVENT_ID__SESSION_END: 199 videoRecord.session.engine_type = pRecord->event_start.engine_type; 200 videoRecord.session.engine_id = pRecord->event_end.engine_id; 201 videoRecord.session.codec_id = pRecord->event_end.codec_id; 202 videoRecord.session.status = pRecord->event_end.status; 203 break; 204 case VIDEO_ENGINE_EVENT_ID__POWER_STATE_CHANGE: 205 videoRecord.stateChange.to = pRecord->event_pstate_change.to; 206 videoRecord.stateChange.from = pRecord->event_pstate_change.from; 207 break; 208 case VIDEO_ENGINE_EVENT_ID__LOG_DATA: 209 videoRecord.logData.engine_type = pRecord->event_start.engine_type; 210 videoRecord.logData.engine_id = pRecord->event_start.engine_id; 211 videoRecord.logData.codec_id = pRecord->event_start.codec_id; 212 videoRecord.logData.size = pRecord->event_log_data.size; 213 notifyEvent.pVardata = NV_PTR_TO_NvP64(pLogData); 214 notifyEvent.vardataSize = videoRecord.logData.size; 215 break; 216 default: 217 videoRecord.event_data = pRecord->event_data; 218 } 219 220 notifyEvent.pPayload = NV_PTR_TO_NvP64(&videoRecord); 221 notifyEvent.payloadSize = sizeof(videoRecord); 222 223 status = eventBufferAdd(pBind->pEventBuffer, ¬ifyEvent, notifyIndex, &bNotify, ¬ificationHandle); 224 225 if ((status == NV_OK) && bNotify && notificationHandle) 226 { 227 osEventNotification(pGpu, 228 pBind->pEventBuffer->pListeners, 229 notifyIndex, 230 ¬ifyEvent, 231 0); // Do not copy structure -- embedded pointers. 232 pBind->pEventBuffer->bNotifyPending = NV_TRUE; 233 } 234 235 return status; 236 } 237 238 static void _notifyEventBuffers 239 ( 240 OBJGPU *pGpu, 241 VideoEventBufferBindMultiMapSubmap *pSubmap, 242 NOTIFY_VIDEO_EVENT *pNotifyRecord, 243 NvU32 *pLogData 244 ) 245 { 246 VIDEO_ENGINE_EVENT__RECORD const * pRecord = (VIDEO_ENGINE_EVENT__RECORD const *)pNotifyRecord->pEventData; 247 248 if (pSubmap != NULL) 249 { 250 VideoEventBufferBindMultiMapIter iter = multimapSubmapIterItems(&pGpu->videoEventBufferBindingsUid, pSubmap); 251 252 while (multimapItemIterNext(&iter)) 253 { 254 NV_EVENT_BUFFER_BIND_POINT_VIDEO* pBind = iter.pValue; 255 NvBool bSanitizeKernel = (!pBind->bKernel) && (pRecord->userInfo == 0); 256 NvBool bSanitizeUser = (!pBind->bAdmin) && (pBind->pUserInfo != pRecord->userInfo); 257 258 if (!(NVBIT(pRecord->event_id) & pBind->eventMask)) 259 continue; 260 261 _videoEventBufferAdd(pGpu, pBind, pNotifyRecord, pLogData, bSanitizeUser, bSanitizeKernel); 262 } 263 } 264 } 265 266 static void _videoGetTraceEvents 267 ( 268 OBJGPU *pGpu, 269 KernelVideoEngine *pKernelVideoEngine, 270 VideoEventBufferBindMultiMapSubmap *pSubmapAll 271 ) 272 { 273 VideoEventBufferBindMultiMapSubmap *pSubmapUserOnly = NULL; 274 NvU64 cachedUserInfo = 0; 275 NvU32 magicHi = ENG_VIDEO_TRACE_EVENT_MAGIC_HI; 276 NvU32 magicLo = ENG_VIDEO_TRACE_EVENT_MAGIC_LO; 277 VIDEO_TRACE_RING_BUFFER *pRingbuffer; 278 VIDEO_ENGINE_EVENT__RECORD videoRecord; 279 NvU32 gotSize; 280 281 NV_ASSERT_OR_RETURN_VOID(pKernelVideoEngine != NULL); 282 NV_CHECK_OR_RETURN_VOID(LEVEL_INFO, pKernelVideoEngine->bVideoTraceEnabled); 283 284 pRingbuffer = pKernelVideoEngine->videoTraceInfo.pTraceBufferEngine; 285 286 if (pRingbuffer == NULL) 287 return; 288 289 while (kvidengRingbufferGetDataSize(pGpu, pRingbuffer) >= sizeof(VIDEO_ENGINE_EVENT__RECORD)) 290 { 291 NOTIFY_VIDEO_EVENT notifyRecord; 292 293 NvU32 oldReadPtr = pRingbuffer->readPtr; 294 295 gotSize = kvidengEventbufferGetRecord(pGpu, 296 pKernelVideoEngine, 297 pRingbuffer, 298 &videoRecord, 299 magicHi, 300 magicLo); 301 302 // If the read pointer was not moved by us, this record may be invalid 303 if ((oldReadPtr + sizeof(VIDEO_ENGINE_EVENT__RECORD)) != pRingbuffer->readPtr) 304 continue; 305 306 if (gotSize == 0) 307 continue; 308 309 if (videoRecord.event_id == VIDEO_ENGINE_EVENT_ID__SESSION_START) 310 { 311 pKernelVideoEngine->videoTraceInfo.noisyTimestampStart = videoRecord.ts; 312 } 313 notifyRecord.noisyTimestampStart = pKernelVideoEngine->videoTraceInfo.noisyTimestampStart; 314 notifyRecord.pVideoLogPrng = pKernelVideoEngine->videoTraceInfo.pVideoLogPrng; 315 notifyRecord.pEventData = (void *)(&videoRecord); 316 317 if (videoRecord.userInfo != 0) 318 { 319 if (cachedUserInfo != videoRecord.userInfo) 320 { 321 pSubmapUserOnly = multimapFindSubmap(&pGpu->videoEventBufferBindingsUid, videoRecord.userInfo); 322 cachedUserInfo = videoRecord.userInfo; 323 } 324 325 _notifyEventBuffers(pGpu, 326 pSubmapUserOnly, 327 ¬ifyRecord, 328 (NvU32 *)(pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData)); 329 } 330 331 _notifyEventBuffers(pGpu, 332 pSubmapAll, 333 ¬ifyRecord, 334 (NvU32 *)(pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData)); 335 } 336 } 337 338 static NV_STATUS 339 _videoEventBufferSetFlag(OBJGPU *pGpu, NvU32 flag) 340 { 341 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu); 342 NV2080_CTRL_INTERNAL_FLCN_SET_VIDEO_EVENT_BUFFER_FLAGS_PARAMS params = {0}; 343 344 params.flags = flag; 345 NV_ASSERT_OK_OR_RETURN( 346 pRmApi->Control(pRmApi, 347 pGpu->hInternalClient, 348 pGpu->hInternalSubdevice, 349 NV2080_CTRL_CMD_INTERNAL_FLCN_SET_VIDEO_EVENT_BUFFER_FLAGS, 350 ¶ms, 351 sizeof(params))); 352 353 return NV_OK; 354 } 355 356 static void 357 _videoOsWorkItem 358 ( 359 NvU32 gpuInstance, 360 void *data 361 ) 362 { 363 OBJGPU *pGpu = gpumgrGetGpu(gpuInstance); 364 365 nvEventBufferVideoCallback(pGpu, NULL); 366 } 367 368 static NV_STATUS 369 _videoTimerCallback 370 ( 371 OBJGPU *pGpu, 372 OBJTMR *pTmr, 373 TMR_EVENT *pTmrEvent 374 ) 375 { 376 NV_STATUS status; 377 378 NV_CHECK_OK(status, LEVEL_ERROR, osQueueWorkItemWithFlags(pGpu, _videoOsWorkItem, NULL, OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_DEVICE_RW)); 379 380 // TMR_FLAG_RECUR does not work, so reschedule it here. 381 NV_CHECK_OK_OR_CAPTURE_FIRST_ERROR(status, LEVEL_ERROR, tmrEventScheduleRel(pTmr, pTmrEvent, NV_VIDEO_TRACE_CALLBACK_TIME_NS)); 382 383 return status; 384 } 385 386 static NV_STATUS 387 _videoTimerCreate 388 ( 389 OBJGPU *pGpu 390 ) 391 { 392 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 393 NvU32 timerFlags = TMR_FLAG_RECUR; 394 // Unix needs to use the OS timer to avoid corrupting records, but Windows doesn't have an OS timer implementation 395 timerFlags |= TMR_FLAG_USE_OS_TIMER; 396 397 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, 398 tmrEventCreate(pTmr, &pGpu->pVideoTimerEvent, _videoTimerCallback, NULL, timerFlags)); 399 400 // This won't be a true 20Hz timer as the callbacks are scheduled from the time they're called 401 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR, 402 tmrEventScheduleRel(pTmr, pGpu->pVideoTimerEvent, NV_VIDEO_TRACE_CALLBACK_TIME_NS)); 403 404 return NV_OK; 405 } 406 407 static void 408 _videoTimerDestroy 409 ( 410 OBJGPU *pGpu 411 ) 412 { 413 if (pGpu->pVideoTimerEvent != NULL) 414 { 415 OBJTMR *pTmr = GPU_GET_TIMER(pGpu); 416 417 tmrEventCancel(pTmr, pGpu->pVideoTimerEvent); 418 tmrEventDestroy(pTmr, pGpu->pVideoTimerEvent); 419 pGpu->pVideoTimerEvent = NULL; 420 } 421 } 422 423 void 424 nvEventBufferVideoCallback 425 ( 426 OBJGPU *pGpu, 427 void *pArgs 428 ) 429 { 430 VideoEventBufferBindMultiMapSubmap *pSubmapAll = NULL; 431 NvU8 i; 432 433 if (!rmDeviceGpuLockIsOwner(pGpu->gpuInstance)) 434 { 435 NV_ASSERT(0); 436 return; 437 } 438 439 if (pGpu->videoCtxswLogConsumerCount <= 0) 440 { 441 NV_ASSERT(pGpu->videoCtxswLogConsumerCount >= 0); 442 return; 443 } 444 445 pSubmapAll = multimapFindSubmap(&pGpu->videoEventBufferBindingsUid, 0); 446 if (pSubmapAll == NULL) 447 return; 448 449 for (i = 0; i < pGpu->numKernelVideoEngines; i++) 450 { 451 KernelVideoEngine *pKernelVideoEngine = pGpu->kernelVideoEngines[i]; 452 _videoGetTraceEvents(pGpu, pKernelVideoEngine, pSubmapAll); 453 } 454 455 } 456 457 void 458 videoRemoveBindpoint 459 ( 460 OBJGPU *pGpu, 461 NvU64 uid, 462 NV_EVENT_BUFFER_BIND_POINT_VIDEO* pBind 463 ) 464 { 465 EventBuffer *pEventBuffer = pBind->pEventBuffer; 466 467 --pGpu->videoCtxswLogConsumerCount; 468 if (pGpu->videoCtxswLogConsumerCount == 0) 469 { 470 // When last client is unbound, disable engine event logging. 471 _videoEventBufferSetFlag(pGpu, 0); 472 } 473 474 unregisterEventNotificationWithData(&pEventBuffer->pListeners, 475 pBind->hClient, 476 pBind->hNotifier, 477 pBind->hEventBuffer, 478 NV_TRUE, 479 pEventBuffer->producerInfo.notificationHandle); 480 481 multimapRemoveItemByKey(&pGpu->videoEventBufferBindingsUid, 482 uid, 483 (NvU64)(NvUPtr)pEventBuffer); 484 } 485 486 NV_STATUS 487 videoAddBindpoint 488 ( 489 OBJGPU *pGpu, 490 RsClient *pClient, 491 RsResourceRef *pEventBufferRef, 492 NvHandle hNotifier, 493 NvBool bAllUsers, 494 NV2080_CTRL_EVENT_VIDEO_BIND_EVTBUF_LOD levelOfDetail, 495 NvU32 eventFilter 496 ) 497 { 498 NV_STATUS status; 499 NvHandle hClient = pClient->hClient; 500 RmClient *pRmClient = dynamicCast(pClient, RmClient); 501 NvHandle hEventBuffer = pEventBufferRef->hResource; 502 EventBuffer *pEventBuffer; 503 NvBool bVideoBindingActive = (pGpu->videoCtxswLogConsumerCount > 0); 504 NvU64 targetUser; 505 506 NvBool bAdmin = osIsAdministrator(); 507 NvBool bKernel; 508 NvU32 eventMask = 0; 509 NvBool bSelectLOD; 510 511 CALL_CONTEXT *pCallContext = resservGetTlsCallContext(); 512 NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE); 513 bKernel = pCallContext->secInfo.privLevel >= RS_PRIV_LEVEL_KERNEL; 514 bSelectLOD = bKernel; 515 516 #if defined(DEBUG) || defined(DEVELOP) || defined(NV_VERIF_FEATURES) 517 bSelectLOD = NV_TRUE; 518 #endif 519 520 LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(pGpu->gpuInstance)); 521 522 if (!kvidengIsVideoTraceLogSupported(pGpu)) 523 return NV_ERR_NOT_SUPPORTED; 524 525 if (bSelectLOD) 526 { 527 switch(levelOfDetail) 528 { 529 case NV2080_CTRL_EVENT_VIDEO_BIND_EVTBUF_LOD_FULL: 530 eventMask = ~0; 531 break; 532 case NV2080_CTRL_EVENT_VIDEO_BIND_EVTBUF_LOD_CUSTOM: 533 eventMask = eventFilter; 534 break; 535 case NV2080_CTRL_EVENT_VIDEO_BIND_EVTBUF_LOD_SIMPLE: 536 default: 537 // Default to SIMPLIFIED level-of-detail 538 eventMask |= NV_EVENT_BUFFER_VIDEO_BITMASK_TAG_ENGINE_START | 539 NV_EVENT_BUFFER_VIDEO_BITMASK_TAG_ENGINE_END; 540 } 541 } 542 else 543 { 544 // Default to SIMPLIFIED level-of-detail 545 eventMask |= NV_EVENT_BUFFER_VIDEO_BITMASK_TAG_ENGINE_START | 546 NV_EVENT_BUFFER_VIDEO_BITMASK_TAG_ENGINE_END; 547 } 548 549 if (bAllUsers) 550 { 551 targetUser = 0; 552 } 553 else 554 { 555 // Clients requesting only their own events will not work 556 NV_ASSERT_OR_RETURN(bAllUsers, NV_ERR_INVALID_ARGUMENT); 557 } 558 559 pEventBuffer = dynamicCast(pEventBufferRef->pResource, EventBuffer); 560 if (NULL == pEventBuffer) 561 return NV_ERR_INVALID_ARGUMENT; 562 563 if (NULL == multimapFindSubmap(&pGpu->videoEventBufferBindingsUid, targetUser)) 564 { 565 if (NULL == multimapInsertSubmap(&pGpu->videoEventBufferBindingsUid, targetUser)) 566 { 567 NV_PRINTF(LEVEL_ERROR, "failed to add UID binding!\n"); 568 return NV_ERR_INSUFFICIENT_RESOURCES; 569 } 570 } 571 572 // If the binding exists already, we're done 573 if (NULL != multimapFindItem(&pGpu->videoEventBufferBindingsUid, targetUser, (NvU64)(NvUPtr)pEventBuffer)) 574 return NV_OK; 575 576 NV_EVENT_BUFFER_BIND_POINT_VIDEO* pBind = multimapInsertItemNew(&pGpu->videoEventBufferBindingsUid, 0, (NvU64)(NvUPtr)pEventBuffer); 577 if (pBind == NULL) 578 return NV_ERR_INVALID_ARGUMENT; 579 580 pBind->hClient = hClient; 581 pBind->hNotifier = hNotifier; 582 pBind->hEventBuffer = hEventBuffer; 583 pBind->pEventBuffer = pEventBuffer; 584 pBind->pUserInfo = (NvU64)(NvUPtr)pRmClient->pUserInfo; 585 pBind->bAdmin = bAdmin; 586 pBind->eventMask = eventMask; 587 pBind->bKernel = bKernel; 588 589 ++pGpu->videoCtxswLogConsumerCount; 590 if (pGpu->videoCtxswLogConsumerCount == 1) 591 { 592 // When first client is bound, enable engine event logging. 593 NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, 594 _videoEventBufferSetFlag(pGpu, VIDEO_TRACE_FLAG__LOGGING_ENABLED), 595 done); 596 } 597 598 status = registerEventNotification(&pEventBuffer->pListeners, 599 pClient, 600 hNotifier, 601 hEventBuffer, 602 NV_EVENT_BUFFER_RECORD_TYPE_VIDEO_TRACE | NV01_EVENT_WITHOUT_EVENT_DATA, 603 NV_EVENT_BUFFER_BIND, 604 pEventBuffer->producerInfo.notificationHandle, 605 NV_FALSE); 606 if (status != NV_OK) 607 goto done; 608 609 if (!bVideoBindingActive) 610 { 611 NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, _videoTimerCreate(pGpu), done); 612 } 613 614 done: 615 if (status != NV_OK) 616 { 617 videoRemoveBindpoint(pGpu, 0, pBind); 618 619 _videoTimerDestroy(pGpu); 620 } 621 622 return status; 623 } 624 625 void 626 videoRemoveAllBindpointsForGpu 627 ( 628 OBJGPU *pGpu 629 ) 630 { 631 NvS16 prevConsumerCount = pGpu->videoCtxswLogConsumerCount; 632 VideoEventBufferBindMultiMapSupermapIter iter; 633 634 if (pGpu->videoEventBufferBindingsUid.real.base.map.pAllocator == NULL) 635 return; 636 637 iter = multimapSubmapIterAll(&pGpu->videoEventBufferBindingsUid); 638 while (multimapSubmapIterNext(&iter)) 639 { 640 VideoEventBufferBindMultiMapSubmap *pSubmap = iter.pValue; 641 VideoEventBufferBindMultiMapIter subIter = multimapSubmapIterItems(&pGpu->videoEventBufferBindingsUid, pSubmap); 642 NvU64 uid = mapKey_IMPL(iter.iter.pMap, pSubmap); 643 644 while (multimapItemIterNext(&subIter)) 645 { 646 NV_EVENT_BUFFER_BIND_POINT_VIDEO* pBind = subIter.pValue; 647 videoRemoveBindpoint(pGpu, uid, pBind); 648 subIter = multimapSubmapIterItems(&pGpu->videoEventBufferBindingsUid, pSubmap); 649 } 650 } 651 652 if ((prevConsumerCount != 0) && (pGpu->videoCtxswLogConsumerCount == 0)) 653 videoBufferTeardown(pGpu); 654 } 655 656 void 657 videoRemoveAllBindpoints 658 ( 659 EventBuffer *pEventBuffer 660 ) 661 { 662 OBJGPU *pGpu = NULL; 663 NvU32 gpuMask = 0; 664 NvU32 gpuIndex = 0; 665 VideoEventBufferBindMultiMapSupermapIter iter; 666 667 gpumgrGetGpuAttachInfo(NULL, &gpuMask); 668 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuIndex)) != NULL) 669 { 670 iter = multimapSubmapIterAll(&pGpu->videoEventBufferBindingsUid); 671 while (multimapSubmapIterNext(&iter)) 672 { 673 VideoEventBufferBindMultiMapSubmap *pSubmap = iter.pValue; 674 NV_EVENT_BUFFER_BIND_POINT_VIDEO* pBind = NULL; 675 NvU64 uid = mapKey_IMPL(iter.iter.pMap, pSubmap); 676 677 while ((pBind = multimapFindItem(&pGpu->videoEventBufferBindingsUid, 678 uid, 679 (NvU64)(NvUPtr)pEventBuffer)) != NULL) 680 { 681 videoRemoveBindpoint(pGpu, uid, pBind); 682 } 683 } 684 685 if (pGpu->videoCtxswLogConsumerCount == 0) 686 videoBufferTeardown(pGpu); 687 } 688 } 689 690 void 691 videoBufferTeardown 692 ( 693 OBJGPU *pGpu 694 ) 695 { 696 _videoTimerDestroy(pGpu); 697 } 698 699