1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2018-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: fecs_event_list.c *
27 * Description: *
28 * This module contains an implementation of the Event Buffer *
29 * callback for FECS events *
30 * *
31 \***************************************************************************/
32
33 #include "kernel/gpu/gr/kernel_graphics.h"
34 #include "kernel/rmapi/event.h"
35 #include "kernel/rmapi/event_buffer.h"
36 #include "libraries/resserv/rs_server.h"
37 #include "kernel/core/locks.h"
38 #include "kernel/os/os.h"
39 #include "kernel/gpu/gr/fecs_event_list.h"
40 #include "kernel/gpu/mig_mgr/gpu_instance_subscription.h"
41 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
42 #include "kernel/gpu/bus/kern_bus.h"
43 #include "kernel/gpu/mem_mgr/mem_mgr.h"
44 #include "kernel/gpu/fifo/kernel_channel.h"
45 #include "kernel/gpu/subdevice/subdevice.h"
46 #include "kernel/virtualization/hypervisor/hypervisor.h"
47 #include "rmapi/client.h"
48 #include "objtmr.h"
49 #include "vgpu/sdk-structures.h"
50
51 #include "class/cl90cdtypes.h"
52 #include "ctrl/ctrl90cd.h"
53
54 #define NV_FECS_TRACE_MAX_TIMESTAMPS 5
55 #define NV_FECS_TRACE_MAGIC_INVALIDATED 0xdededede // magic number for entries that have been read
56 #define NV_FECS_TRACE_CALLBACK_TIME_NS 33333333 // Approximating 30Hz callback
57
58 typedef struct
59 {
60 NvU32 magic_lo;
61 NvU32 magic_hi;
62 NvU32 context_id;
63 NvU32 context_ptr;
64 NvU32 new_context_id;
65 NvU32 new_context_ptr;
66 NvU64 ts[NV_FECS_TRACE_MAX_TIMESTAMPS];
67 NvU32 reserved[13];
68 NvU32 seqno;
69 } FECS_EVENT_RECORD;
70
71 /*! Opaque pointer to private data */
72 typedef struct VGPU_FECS_TRACE_STAGING_BUFFER VGPU_FECS_TRACE_STAGING_BUFFER;
73
74 /*! Private FECS event buffer data stored per-KGR */
75 struct KGRAPHICS_FECS_TRACE_INFO
76 {
77 NvU8 *pFecsBufferMapping;
78 NvU16 fecsCtxswLogRecordsPerIntr;
79 NvU16 fecsTraceRdOffset;
80 NvU16 fecsTraceCounter;
81 NvU32 fecsCtxswLogIntrPending;
82 NvU32 fecsLastSeqno;
83
84 #if PORT_IS_MODULE_SUPPORTED(crypto)
85 PORT_CRYPTO_PRNG *pFecsLogPrng;
86 #endif
87
88 //
89 // GR Routing information for GPU instance to which this engine is assigned if MIG is enabled.
90 // Will be 0/NULL for unassigned GR engines or if MIG is disabled
91 //
92 NvHandle hClient;
93 NvHandle hSubdevice;
94 NvU32 localGrEngineIdx;
95
96 // vGPU FECS staging eventbuffer (guest only)
97 VGPU_FECS_TRACE_STAGING_BUFFER *pVgpuStaging;
98 };
99
100 /*! Private FECS event buffer data stored for the GPU as a whole */
101 struct KGRMGR_FECS_GLOBAL_TRACE_INFO
102 {
103 // map: { UserInfo* -> { pEventBuffer -> NV_EVENT_BUFFER_BIND_POINT* }}
104 FecsEventBufferBindMultiMap fecsEventBufferBindingsUid;
105
106 // Timer event to periodically the processing callback
107 TMR_EVENT *pFecsTimerEvent;
108
109 // Timer interval in nanoseconds
110 NvU32 fecsTimerInterval;
111
112 // Atomic for scheduling the fecs callback in timer mode
113 NvU32 fecsCallbackScheduled;
114
115 // Number of consumer clients
116 NvS16 fecsCtxswLogConsumerCount;
117 };
118
119 /*!
120 * @brief Function to populate client/subdevice/grRouteInfo from cached
121 * information in order to make calls into the specific MIG GPU instance
122 * to which a GR engine is assigned. If MIG is not enabled, GPU
123 * internal client/subdevice handles will be used and grRouteInfo is
124 * cleared
125 *
126 * @param[in] pGpu
127 * @param[in] pKernelGraphics
128 * @param[out] phClient Client handle to populate
129 * @param[out] phSubdevice Subdevice handle to populate
130 * @param[out] pGrRouteInfo Internal GR Routing info to populate
131 */
132 static NV_STATUS
_fecsLoadInternalRoutingInfo(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,NvHandle * phClient,NvHandle * phSubdevice,NV2080_CTRL_GR_ROUTE_INFO * pGrRouteInfo)133 _fecsLoadInternalRoutingInfo
134 (
135 OBJGPU *pGpu,
136 KernelGraphics *pKernelGraphics,
137 NvHandle *phClient,
138 NvHandle *phSubdevice,
139 NV2080_CTRL_GR_ROUTE_INFO *pGrRouteInfo
140 )
141 {
142 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
143
144 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_ERR_INVALID_STATE);
145
146 portMemSet(pGrRouteInfo, 0, sizeof(*pGrRouteInfo));
147
148 if (!IS_MIG_IN_USE(pGpu))
149 {
150 *phClient = pGpu->hInternalClient;
151 *phSubdevice = pGpu->hInternalSubdevice;
152 return NV_OK;
153 }
154
155 // GR Engines not allocated to any GPU instance will have null handles
156 NV_CHECK_OR_RETURN(LEVEL_INFO, pFecsTraceInfo->hClient != NV01_NULL_OBJECT, NV_ERR_INVALID_ARGUMENT);
157
158 kgrmgrCtrlSetEngineID(pFecsTraceInfo->localGrEngineIdx, pGrRouteInfo);
159 *phClient = pFecsTraceInfo->hClient;
160 *phSubdevice = pFecsTraceInfo->hSubdevice;
161
162 return NV_OK;
163 }
164
165 static NV_STATUS
fecsExtractTagAndTimestamp(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,NvU64 rawTimestamp,NvU64 * pTimestampVal,NvU8 * pTag)166 fecsExtractTagAndTimestamp
167 (
168 OBJGPU *pGpu,
169 KernelGraphics *pKernelGraphics,
170 NvU64 rawTimestamp,
171 NvU64 *pTimestampVal,
172 NvU8 *pTag
173 )
174 {
175 const KGRAPHICS_STATIC_INFO *pKernelGraphicsStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
176 NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo != NULL, NV_ERR_INVALID_STATE);
177 NV_ASSERT_OR_RETURN(pKernelGraphicsStaticInfo->pFecsTraceDefines != NULL, NV_ERR_INVALID_STATE);
178
179 *pTag = ((NvU64_HI32(rawTimestamp)) >> pKernelGraphicsStaticInfo->pFecsTraceDefines->timestampHiTagShift) & pKernelGraphicsStaticInfo->pFecsTraceDefines->timestampHiTagMask;
180 *pTimestampVal = rawTimestamp & pKernelGraphicsStaticInfo->pFecsTraceDefines->timestampVMask;
181
182 // timestamp encoded as right shifted N bits, since they hold zeros. RM needs to reverse that here.
183 *pTimestampVal <<= pKernelGraphicsStaticInfo->pFecsTraceDefines->numLowerBitsZeroShift;
184 return NV_OK;
185 }
186
187 //
188 // The function formats the information from the FECS Buffer into a format
189 // suitable for EventBuffer, and then checks to see whether the subscriber
190 // needs to be notified. If so, the subscriber is notified.
191 //
192 // pGpu is used to retrieve data on the pid, and
193 // seqno provides the sequence number for the user to keep track of
194 // whether any entry has been dropped.
195 // pRecord is the current FECS entry.
196 //
197 static void
formatAndNotifyFecsRecord(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,FECS_EVENT_RECORD * pRecord)198 formatAndNotifyFecsRecord
199 (
200 OBJGPU *pGpu,
201 KernelGraphics *pKernelGraphics,
202 FECS_EVENT_RECORD *pRecord
203 )
204 {
205 FECS_EVENT_NOTIFICATION_DATA notifRecord;
206 KernelFifo *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
207 KernelChannel *pKernelChannel = NULL;
208 KernelChannel *pKernelChannelNew = NULL;
209 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
210 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
211 MIG_INSTANCE_REF *pChannelRef;
212 MIG_INSTANCE_REF *pNewChannelRef;
213 INST_BLOCK_DESC inst;
214 NvU32 timestampId;
215 NvU64 noisyTimestampStart = 0;
216 NvU64 noisyTimestampRange = 0;
217 NvU32 instSize;
218 NvU32 instShift;
219 NV_STATUS status;
220
221 if (pRecord == NULL)
222 {
223 NV_PRINTF(LEVEL_ERROR, "Invalid FECS record!\n");
224 DBG_BREAKPOINT();
225 return;
226 }
227
228 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
229
230 kfifoGetInstBlkSizeAlign_HAL(pKernelFifo, &instSize, &instShift);
231
232 portMemSet(¬ifRecord, 0, sizeof(notifRecord));
233
234 inst.address = ((NvU64)pRecord->context_ptr) << instShift;
235 inst.aperture = INST_BLOCK_APERTURE_VIDEO_MEMORY;
236 inst.gfid = GPU_GFID_PF;
237 if (pRecord->context_ptr &&
238 (kfifoConvertInstToKernelChannel_HAL(pGpu, pKernelFifo, &inst, &pKernelChannel) != NV_OK))
239 {
240 NV_PRINTF(LEVEL_INFO, "Error getting channel!\n");
241 pKernelChannel = NULL;
242 }
243
244 inst.address = ((NvU64)pRecord->new_context_ptr) << instShift;
245 inst.aperture = INST_BLOCK_APERTURE_VIDEO_MEMORY;
246 inst.gfid = GPU_GFID_PF;
247 if (pRecord->new_context_ptr &&
248 (kfifoConvertInstToKernelChannel_HAL(pGpu, pKernelFifo, &inst, &pKernelChannelNew) != NV_OK))
249 {
250 NV_PRINTF(LEVEL_INFO, "Error getting new channel!\n");
251 pKernelChannelNew = NULL;
252 }
253
254 pChannelRef = (pKernelChannel != NULL) ? kchannelGetMIGReference(pKernelChannel) : NULL;
255 pNewChannelRef = (pKernelChannelNew != NULL) ? kchannelGetMIGReference(pKernelChannelNew) : NULL;
256
257 if (kgraphicsIsFecsRecordUcodeSeqnoSupported(pGpu, pKernelGraphics))
258 {
259 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
260
261 // Dropped at least 1 event
262 if ((pFecsTraceInfo->fecsLastSeqno + 1) != pRecord->seqno)
263 {
264 notifRecord.dropCount = pRecord->seqno - pFecsTraceInfo->fecsLastSeqno - 1;
265 }
266
267 pFecsTraceInfo->fecsLastSeqno = pRecord->seqno;
268 }
269
270 for (timestampId = 0; timestampId < NV_FECS_TRACE_MAX_TIMESTAMPS; timestampId++)
271 {
272 NV_ASSERT_OK_OR_ELSE(status,
273 fecsExtractTagAndTimestamp(pGpu, pKernelGraphics,
274 pRecord->ts[timestampId],
275 ¬ifRecord.timestamp,
276 ¬ifRecord.tag),
277 return);
278
279 //
280 // determine a few more fields of the current record by subevent type,
281 // before we notify the subscriber
282 //
283 switch (notifRecord.tag)
284 {
285 case NV_EVENT_BUFFER_FECS_CTXSWTAG_RESTORE_START:
286 case NV_EVENT_BUFFER_FECS_CTXSWTAG_CONTEXT_START:
287 if (pKernelChannelNew != NULL)
288 {
289 notifRecord.pid = pKernelChannelNew->ProcessID;
290 notifRecord.subpid = pKernelChannelNew->SubProcessID;
291 notifRecord.userInfo = (NvU64)(NvUPtr)pKernelChannelNew->pUserInfo;
292 notifRecord.context_id = kchannelGetCid(pKernelChannelNew);
293
294 if (kmigmgrIsMIGReferenceValid(pNewChannelRef))
295 {
296 notifRecord.swizzId = pNewChannelRef->pKernelMIGGpuInstance->swizzId;
297 if (pNewChannelRef->pMIGComputeInstance)
298 notifRecord.computeInstanceId = pNewChannelRef->pMIGComputeInstance->id;
299 else
300 notifRecord.computeInstanceId = NV_EVENT_BUFFER_KERNEL_MIG_CI;
301 }
302
303 if (notifRecord.tag == NV_EVENT_BUFFER_FECS_CTXSWTAG_RESTORE_START)
304 {
305 noisyTimestampStart = notifRecord.timestamp;
306 }
307 else
308 {
309 noisyTimestampRange = notifRecord.timestamp - noisyTimestampStart;
310 }
311 }
312 break;
313
314 case NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_WFI:
315 case NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_GFXP:
316 case NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_CTAP:
317 case NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_CILP:
318 if (pKernelChannel != NULL)
319 {
320 notifRecord.pid = pKernelChannel->ProcessID;
321 notifRecord.subpid = pKernelChannel->SubProcessID;
322 notifRecord.userInfo = (NvU64)(NvUPtr)pKernelChannel->pUserInfo;
323 notifRecord.context_id = kchannelGetCid(pKernelChannel);
324
325 if (kmigmgrIsMIGReferenceValid(pChannelRef))
326 {
327 notifRecord.swizzId = pChannelRef->pKernelMIGGpuInstance->swizzId;
328 if (pChannelRef->pMIGComputeInstance)
329 notifRecord.computeInstanceId = pChannelRef->pMIGComputeInstance->id;
330 else
331 notifRecord.computeInstanceId = NV_EVENT_BUFFER_KERNEL_MIG_CI;
332 }
333 }
334 break;
335
336 case NV_EVENT_BUFFER_FECS_CTXSWTAG_CTXSW_REQ_BY_HOST:
337 case NV_EVENT_BUFFER_FECS_CTXSWTAG_SAVE_END:
338 if (pKernelChannel != NULL)
339 {
340 notifRecord.pid = pKernelChannel->ProcessID;
341 notifRecord.subpid = pKernelChannel->SubProcessID;
342 notifRecord.userInfo = (NvU64)(NvUPtr)pKernelChannel->pUserInfo;
343 notifRecord.context_id = kchannelGetCid(pKernelChannel);
344
345 if (kmigmgrIsMIGReferenceValid(pChannelRef))
346 {
347 notifRecord.swizzId = pChannelRef->pKernelMIGGpuInstance->swizzId;
348 if (pChannelRef->pMIGComputeInstance != NULL)
349 notifRecord.computeInstanceId = pChannelRef->pMIGComputeInstance->id;
350 else
351 notifRecord.computeInstanceId = NV_EVENT_BUFFER_KERNEL_MIG_CI;
352 }
353
354 if (notifRecord.tag == NV_EVENT_BUFFER_FECS_CTXSWTAG_CTXSW_REQ_BY_HOST)
355 {
356 noisyTimestampStart = notifRecord.timestamp;
357 }
358 else
359 {
360 noisyTimestampRange = notifRecord.timestamp - noisyTimestampStart;
361 }
362 }
363 break;
364
365 default:
366 continue;
367 }
368
369 if ((pKernelChannel != NULL) || (pKernelChannelNew != NULL))
370 {
371 FecsEventBufferBindMultiMapSubmap *pSubmap;
372 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
373
374 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
375
376 notifRecord.noisyTimestamp = 0;
377 if ((noisyTimestampRange > 0) && (pFecsTraceInfo->pFecsLogPrng != NULL))
378 notifRecord.noisyTimestamp = noisyTimestampStart + portCryptoPseudoRandomGeneratorGetU32(pFecsTraceInfo->pFecsLogPrng) % noisyTimestampRange;
379
380 if (notifRecord.userInfo != 0)
381 {
382 // Notify event buffers listening for the current UID
383 pSubmap = multimapFindSubmap(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, notifRecord.userInfo);
384 notifyEventBuffers(pGpu, pSubmap, ¬ifRecord);
385 }
386
387 // Notify event buffers listening for all UIDs
388 pSubmap = multimapFindSubmap(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, 0);
389 notifyEventBuffers(pGpu, pSubmap, ¬ifRecord);
390
391 // Clear so we don't report drops for every event in this record
392 notifRecord.dropCount = 0;
393 }
394 }
395 }
396
397 static NV_STATUS
_fecsEventBufferAdd(OBJGPU * pGpu,NV_EVENT_BUFFER_BIND_POINT_FECS * pBind,NvU8 tag,NvU32 pid,NvU8 swizzId,NvU8 computeInstanceId,NvU32 context_id,NvU64 timestamp)398 _fecsEventBufferAdd
399 (
400 OBJGPU *pGpu,
401 NV_EVENT_BUFFER_BIND_POINT_FECS *pBind,
402 NvU8 tag,
403 NvU32 pid,
404 NvU8 swizzId,
405 NvU8 computeInstanceId,
406 NvU32 context_id,
407 NvU64 timestamp
408 )
409 {
410 NV_STATUS status;
411 NvBool bNotify;
412 NvP64 notificationHandle;
413 EVENT_BUFFER_PRODUCER_DATA notifyEvent;
414 NvU32 notifyIndex;
415
416 switch (pBind->version)
417 {
418 case 2:
419 notifyIndex = NV_EVENT_BUFFER_RECORD_TYPE_FECS_CTX_SWITCH_V2;
420 break;
421 case 1:
422 notifyIndex = NV_EVENT_BUFFER_RECORD_TYPE_FECS_CTX_SWITCH;
423 break;
424 default:
425 return NV_ERR_INVALID_ARGUMENT;
426 }
427
428 portMemSet(¬ifyEvent, 0, sizeof(notifyEvent));
429 notifyEvent.pVardata = NV_PTR_TO_NvP64(NULL);
430 notifyEvent.vardataSize = 0;
431
432 NV_EVENT_BUFFER_FECS_RECORD_V2 fecsRecord;
433 portMemSet(&fecsRecord, 0, sizeof(fecsRecord));
434 fecsRecord.tag = tag;
435 fecsRecord.pid = pid;
436 if (pBind->version >= 2)
437 {
438 fecsRecord.migGpuInstanceId = swizzId;
439 fecsRecord.migComputeInstanceId = computeInstanceId;
440 }
441 fecsRecord.context_id = context_id;
442 fecsRecord.timestamp = timestamp;
443 fecsRecord.seqno = pBind->pEventBuffer->seqNo++;
444
445 notifyEvent.pPayload = NV_PTR_TO_NvP64(&fecsRecord);
446 notifyEvent.payloadSize = sizeof(fecsRecord);
447
448 status = eventBufferAdd(pBind->pEventBuffer, ¬ifyEvent, notifyIndex, &bNotify, ¬ificationHandle);
449
450 if ((status == NV_OK) && bNotify && notificationHandle)
451 {
452 osEventNotification(pGpu,
453 pBind->pEventBuffer->pListeners,
454 notifyIndex,
455 ¬ifyEvent,
456 0); // Do not copy structure -- embedded pointers.
457 pBind->pEventBuffer->bNotifyPending = NV_TRUE;
458 }
459
460 return status;
461 }
462
463 void
notifyEventBuffers(OBJGPU * pGpu,FecsEventBufferBindMultiMapSubmap * pSubmap,FECS_EVENT_NOTIFICATION_DATA const * pRecord)464 notifyEventBuffers
465 (
466 OBJGPU *pGpu,
467 FecsEventBufferBindMultiMapSubmap *pSubmap,
468 FECS_EVENT_NOTIFICATION_DATA const *pRecord
469 )
470 {
471 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
472 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
473 NvBool bMIGInUse = IS_MIG_IN_USE(pGpu);
474
475 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
476
477 if (pSubmap != NULL)
478 {
479 FecsEventBufferBindMultiMapIter iter = multimapSubmapIterItems(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, pSubmap);
480
481 while (multimapItemIterNext(&iter))
482 {
483 NV_EVENT_BUFFER_BIND_POINT_FECS *pBind = iter.pValue;
484 NvBool bSanitizeKernel = (!pBind->bKernel) && (pRecord->userInfo == 0);
485 NvBool bSanitizeUser = (!pBind->bAdmin) && (pBind->pUserInfo != pRecord->userInfo);
486 NvBool bSanitize = bSanitizeKernel || bSanitizeUser;
487 NvU32 pid;
488 NvU32 context_id;
489 NvU64 timestamp;
490 NvU32 tag = pRecord->tag;
491 NvU8 swizzId = pRecord->swizzId;
492 NvU8 computeInstanceId = pRecord->computeInstanceId;
493
494 pBind->pEventBuffer->seqNo += pRecord->dropCount;
495
496 if (bSanitize || !(NVBIT(pRecord->tag) & pBind->eventMask))
497 {
498 //
499 // Re-map CONTEXT_START as SIMPLE_START and SAVE_END as SIMPLE_END if
500 // the binding has simple level-of-detail or is being sanitized
501 //
502 if ((bSanitize || (pBind->eventMask & NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_START)) &&
503 (tag == NV_EVENT_BUFFER_FECS_CTXSWTAG_CONTEXT_START))
504 {
505 tag = NV_EVENT_BUFFER_FECS_CTXSWTAG_SIMPLE_START;
506 }
507 else if ((bSanitize || (pBind->eventMask & NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_END)) &&
508 (tag == NV_EVENT_BUFFER_FECS_CTXSWTAG_SAVE_END))
509 {
510 tag = NV_EVENT_BUFFER_FECS_CTXSWTAG_SIMPLE_END;
511 }
512 else if ((tag != NV_EVENT_BUFFER_FECS_CTXSWTAG_SIMPLE_START) &&
513 (tag != NV_EVENT_BUFFER_FECS_CTXSWTAG_SIMPLE_END))
514 {
515 continue;
516 }
517 }
518
519 //
520 // While MIG is enabled, if the bindpoint is registered for a specific MIG GPU instance
521 // then filter out records from other GPU instances
522 //
523 if (bMIGInUse &&
524 ((pBind->swizzId != NV2080_CTRL_GPU_PARTITION_ID_INVALID) &&
525 (pRecord->swizzId != pBind->swizzId)))
526 continue;
527
528 // While MIG is enabled, pause tracing of V1 bindpoints
529 if (bMIGInUse && (pBind->version < 2))
530 continue;
531
532 if (bSanitizeKernel)
533 {
534 timestamp = pRecord->noisyTimestamp;
535 pid = NV_EVENT_BUFFER_KERNEL_PID;
536 context_id = NV_EVENT_BUFFER_KERNEL_CONTEXT;
537 swizzId = NV_EVENT_BUFFER_KERNEL_MIG_GI;
538 computeInstanceId = NV_EVENT_BUFFER_KERNEL_MIG_CI;
539 }
540 else if (bSanitizeUser)
541 {
542 timestamp = pRecord->noisyTimestamp;
543 pid = NV_EVENT_BUFFER_HIDDEN_PID;
544 context_id = NV_EVENT_BUFFER_HIDDEN_CONTEXT;
545 swizzId = NV_EVENT_BUFFER_HIDDEN_MIG_GI;
546 computeInstanceId = NV_EVENT_BUFFER_HIDDEN_MIG_CI;
547 }
548 else
549 {
550 timestamp = pRecord->timestamp;
551 pid = pRecord->pid;
552 context_id = pRecord->context_id;
553 }
554
555 _fecsEventBufferAdd(pGpu, pBind, tag,
556 pid,
557 bMIGInUse ? swizzId : NV_EVENT_BUFFER_INVALID_MIG_GI,
558 bMIGInUse ? computeInstanceId : NV_EVENT_BUFFER_INVALID_MIG_CI,
559 context_id, timestamp);
560 }
561 }
562 }
563
564 static NV_STATUS
_getFecsMemDesc(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,MEMORY_DESCRIPTOR ** ppFecsMemDesc)565 _getFecsMemDesc
566 (
567 OBJGPU *pGpu,
568 KernelGraphics *pKernelGraphics,
569 MEMORY_DESCRIPTOR **ppFecsMemDesc
570 )
571 {
572 MEMORY_DESCRIPTOR *pMemDesc;
573 GR_GLOBALCTX_BUFFERS *pGlobalCtxBuffers = kgraphicsGetGlobalCtxBuffers(pGpu, pKernelGraphics, GPU_GFID_PF);
574
575 *ppFecsMemDesc = NULL;
576 NV_CHECK_OR_RETURN(LEVEL_SILENT, pGlobalCtxBuffers != NULL, NV_ERR_INVALID_STATE);
577 pMemDesc = pGlobalCtxBuffers->memDesc[GR_GLOBALCTX_BUFFER_FECS_EVENT];
578 if (pMemDesc != NULL)
579 pMemDesc = memdescGetMemDescFromGpu(pMemDesc, pGpu);
580
581 *ppFecsMemDesc = pMemDesc;
582
583 return NV_OK;
584 }
585
586 static NV_STATUS
_getFecsEventListParameters(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,MEMORY_DESCRIPTOR ** ppFecsMemDesc,NvU32 * pFecsRecordSize)587 _getFecsEventListParameters
588 (
589 OBJGPU *pGpu,
590 KernelGraphics *pKernelGraphics,
591 MEMORY_DESCRIPTOR **ppFecsMemDesc,
592 NvU32 *pFecsRecordSize
593 )
594 {
595 const KGRAPHICS_STATIC_INFO *pStaticInfo;
596 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
597 _getFecsMemDesc(pGpu, pKernelGraphics, ppFecsMemDesc));
598
599 pStaticInfo = kgraphicsGetStaticInfo(pGpu, pKernelGraphics);
600 NV_CHECK_OR_RETURN(LEVEL_ERROR, pStaticInfo != NULL, NV_ERR_INVALID_STATE);
601 NV_ASSERT_OR_RETURN(pStaticInfo->pFecsTraceDefines != NULL, NV_ERR_INVALID_STATE);
602 *pFecsRecordSize = pStaticInfo->pFecsTraceDefines->fecsRecordSize;
603
604 return NV_OK;
605 }
606
607 /*!
608 * @brief Set cached routing info for this KernelGraphics engine to make RPC calls
609 * into the specific MIG GPU instance to which this engine is assigned
610 *
611 * @param[in] pGpu
612 * @param[in] pKernelGraphics
613 * @param[in] hClient Client handle to make calls into MIG GPU instance
614 * @param[in] hSubdevice Subdevice handle to make calls into MIG GPU instance
615 * @param[in] localGrEngineIdx Local GR index for this GR engine in MIG GPU instance
616 */
fecsSetRoutingInfo(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,NvHandle hClient,NvHandle hSubdevice,NvU32 localGrEngineIdx)617 void fecsSetRoutingInfo
618 (
619 OBJGPU *pGpu,
620 KernelGraphics *pKernelGraphics,
621 NvHandle hClient,
622 NvHandle hSubdevice,
623 NvU32 localGrEngineIdx
624 )
625 {
626 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
627
628 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
629
630 pFecsTraceInfo->hClient = hClient;
631 pFecsTraceInfo->hSubdevice = hSubdevice;
632 pFecsTraceInfo->localGrEngineIdx = localGrEngineIdx;
633 }
634
635 // Clear cached routing info used to make GR calls into specific MIG GPU instance
fecsClearRoutingInfo(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)636 void fecsClearRoutingInfo
637 (
638 OBJGPU *pGpu,
639 KernelGraphics *pKernelGraphics
640 )
641 {
642 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
643
644 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
645
646 pFecsTraceInfo->hClient = NV01_NULL_OBJECT;
647 pFecsTraceInfo->hSubdevice = NV01_NULL_OBJECT;
648 pFecsTraceInfo->localGrEngineIdx = 0;
649 }
650
651 NV_STATUS
fecsCtxswLoggingInit(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,KGRAPHICS_FECS_TRACE_INFO ** ppFecsTraceInfo)652 fecsCtxswLoggingInit
653 (
654 OBJGPU *pGpu,
655 KernelGraphics *pKernelGraphics,
656 KGRAPHICS_FECS_TRACE_INFO **ppFecsTraceInfo
657 )
658 {
659 NvU64 seed;
660 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo;
661
662 NV_ASSERT_OR_RETURN(ppFecsTraceInfo != NULL, NV_ERR_NOT_SUPPORTED);
663 pFecsTraceInfo = portMemAllocNonPaged(sizeof(*pFecsTraceInfo));
664 if (pFecsTraceInfo == NULL)
665 return NV_ERR_NO_MEMORY;
666 portMemSet(pFecsTraceInfo, 0, sizeof(*pFecsTraceInfo));
667
668 osGetCurrentTick(&seed);
669 pFecsTraceInfo->pFecsLogPrng = portCryptoPseudoRandomGeneratorCreate(seed);
670
671 *ppFecsTraceInfo = pFecsTraceInfo;
672
673 kgraphicsInitFecsRegistryOverrides_HAL(pGpu, pKernelGraphics);
674
675 return NV_OK;
676 }
677
678 void
fecsCtxswLoggingTeardown(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)679 fecsCtxswLoggingTeardown
680 (
681 OBJGPU *pGpu,
682 KernelGraphics *pKernelGraphics
683 )
684 {
685 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
686
687 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
688
689 portCryptoPseudoRandomGeneratorDestroy(pFecsTraceInfo->pFecsLogPrng);
690 pFecsTraceInfo->pFecsLogPrng = NULL;
691 portMemFree(pFecsTraceInfo);
692 }
693
694 NV_STATUS
fecsGlobalLoggingInit(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager,KGRMGR_FECS_GLOBAL_TRACE_INFO ** ppFecsGlobalTraceInfo)695 fecsGlobalLoggingInit
696 (
697 OBJGPU *pGpu,
698 KernelGraphicsManager *pKernelGraphicsManager,
699 KGRMGR_FECS_GLOBAL_TRACE_INFO **ppFecsGlobalTraceInfo
700 )
701 {
702 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo;
703
704 pFecsGlobalTraceInfo = portMemAllocNonPaged(sizeof(*pFecsGlobalTraceInfo));
705 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_NO_MEMORY);
706 portMemSet(pFecsGlobalTraceInfo, 0, sizeof(*pFecsGlobalTraceInfo));
707
708 multimapInit(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, portMemAllocatorGetGlobalNonPaged());
709
710 *ppFecsGlobalTraceInfo = pFecsGlobalTraceInfo;
711
712 pFecsGlobalTraceInfo->fecsTimerInterval = NV_FECS_TRACE_CALLBACK_TIME_NS;
713
714 return NV_OK;
715 }
716
717 void
fecsGlobalLoggingTeardown(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager)718 fecsGlobalLoggingTeardown
719 (
720 OBJGPU *pGpu,
721 KernelGraphicsManager *pKernelGraphicsManager
722 )
723 {
724 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
725
726 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
727
728 multimapDestroy(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid);
729
730 portMemFree(pFecsGlobalTraceInfo);
731 }
732
733 /*! set num records to process per intr */
fecsSetRecordsPerIntr(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,NvU32 recordsPerIntr)734 void fecsSetRecordsPerIntr
735 (
736 OBJGPU *pGpu,
737 KernelGraphics *pKernelGraphics,
738 NvU32 recordsPerIntr
739 )
740 {
741 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
742
743 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
744 pFecsTraceInfo->fecsCtxswLogRecordsPerIntr = recordsPerIntr;
745 }
746
747 NvBool
fecsBufferChanged(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)748 fecsBufferChanged
749 (
750 OBJGPU *pGpu,
751 KernelGraphics *pKernelGraphics
752 )
753 {
754 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
755 NvU8 *pFecsBufferMapping;
756 MEMORY_DESCRIPTOR *pFecsMemDesc = NULL;
757 NvU32 fecsRecordSize;
758 FECS_EVENT_RECORD *pPeekRecord;
759 NV_STATUS status;
760
761 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_FALSE);
762 pFecsBufferMapping = pFecsTraceInfo->pFecsBufferMapping;
763
764 status = _getFecsEventListParameters(pGpu, pKernelGraphics, &pFecsMemDesc, &fecsRecordSize);
765 if ((status != NV_OK) || (pFecsMemDesc == NULL) || (pFecsBufferMapping == NULL))
766 return NV_FALSE;
767
768 pPeekRecord = (FECS_EVENT_RECORD*)(pFecsBufferMapping +
769 (pFecsTraceInfo->fecsTraceRdOffset * fecsRecordSize));
770
771 if (pPeekRecord->magic_lo != NV_FECS_TRACE_MAGIC_INVALIDATED)
772 {
773 return NV_TRUE;
774 }
775
776 return NV_FALSE;
777 }
778
779 static void
_fecsClearCallbackScheduled(KGRMGR_FECS_GLOBAL_TRACE_INFO * pFecsGlobalTraceInfo)780 _fecsClearCallbackScheduled
781 (
782 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo
783 )
784 {
785 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
786 portAtomicSetU32(&pFecsGlobalTraceInfo->fecsCallbackScheduled, 0);
787 }
788
789 /*!
790 * @brief Atomically set fecs callback scheduled, return NV_TRUE if wasn't scheduled
791 */
792 static NvBool
_fecsSignalCallbackScheduled(KGRMGR_FECS_GLOBAL_TRACE_INFO * pFecsGlobalTraceInfo)793 _fecsSignalCallbackScheduled
794 (
795 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo
796 )
797 {
798 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, 0);
799 return portAtomicCompareAndSwapU32(&pFecsGlobalTraceInfo->fecsCallbackScheduled, 1, 0);
800 }
801
802 static void
_fecsOsWorkItem(NvU32 gpuInstance,void * data)803 _fecsOsWorkItem
804 (
805 NvU32 gpuInstance,
806 void *data
807 )
808 {
809 OBJGPU *pGpu = gpumgrGetGpu(gpuInstance);
810 KernelGraphicsManager *pKernelGraphicsManager;
811 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo;
812
813 NV_CHECK_OR_RETURN_VOID(LEVEL_ERROR, pGpu != NULL);
814 pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
815 pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
816
817 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
818
819 nvEventBufferFecsCallback(pGpu, NULL);
820 _fecsClearCallbackScheduled(pFecsGlobalTraceInfo);
821 }
822
823 static NV_STATUS
_fecsTimerCallback(OBJGPU * pGpu,OBJTMR * pTmr,TMR_EVENT * pTmrEvent)824 _fecsTimerCallback
825 (
826 OBJGPU *pGpu,
827 OBJTMR *pTmr,
828 TMR_EVENT *pTmrEvent
829 )
830 {
831 NV_STATUS status = NV_OK;
832 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
833 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
834 NvU32 i;
835 NvU32 numIter = GPU_MAX_GRS;
836
837 if (!IS_MIG_IN_USE(pGpu))
838 numIter = 1;
839
840 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_INVALID_STATE);
841
842 // If any Kgraphics have events, schedule work item
843 for (i = 0; i < numIter; i++)
844 {
845 KernelGraphics *pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, i);
846
847 if (pKernelGraphics == NULL)
848 continue;
849
850 if (fecsBufferChanged(pGpu, pKernelGraphics) && _fecsSignalCallbackScheduled(pFecsGlobalTraceInfo))
851 {
852 NV_CHECK_OK(status, LEVEL_ERROR, osQueueWorkItemWithFlags(pGpu, _fecsOsWorkItem, NULL, OS_QUEUE_WORKITEM_FLAGS_LOCK_GPU_GROUP_DEVICE_RW));
853
854 if (status != NV_OK)
855 _fecsClearCallbackScheduled(pFecsGlobalTraceInfo);
856
857 break;
858 }
859 }
860
861 // TMR_FLAG_RECUR does not work, so reschedule it here.
862 NV_CHECK_OK_OR_CAPTURE_FIRST_ERROR(status,
863 LEVEL_ERROR,
864 tmrEventScheduleRel(pTmr, pTmrEvent, pFecsGlobalTraceInfo->fecsTimerInterval));
865
866 return status;
867 }
868
869 static NV_STATUS
_fecsTimerCreate(OBJGPU * pGpu)870 _fecsTimerCreate
871 (
872 OBJGPU *pGpu
873 )
874 {
875 OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
876 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
877 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
878 NvU32 timerFlags = TMR_FLAG_RECUR;
879 // Unix needs to use the OS timer to avoid corrupting records, but Windows doesn't have an OS timer implementation
880 timerFlags |= TMR_FLAG_USE_OS_TIMER;
881
882 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_INVALID_STATE);
883
884 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
885 tmrEventCreate(pTmr, &pFecsGlobalTraceInfo->pFecsTimerEvent, _fecsTimerCallback, NULL, timerFlags));
886
887 // This won't be a true 30Hz timer as the callbacks are scheduled from the time they're called
888 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
889 tmrEventScheduleRel(pTmr, pFecsGlobalTraceInfo->pFecsTimerEvent, pFecsGlobalTraceInfo->fecsTimerInterval));
890
891 return NV_OK;
892 }
893
894 static void
_fecsTimerDestroy(OBJGPU * pGpu)895 _fecsTimerDestroy
896 (
897 OBJGPU *pGpu
898 )
899 {
900 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
901 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
902
903 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
904
905 if (pFecsGlobalTraceInfo->pFecsTimerEvent != NULL)
906 {
907 OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
908
909 tmrEventCancel(pTmr, pFecsGlobalTraceInfo->pFecsTimerEvent);
910 tmrEventDestroy(pTmr, pFecsGlobalTraceInfo->pFecsTimerEvent);
911 pFecsGlobalTraceInfo->pFecsTimerEvent = NULL;
912 }
913 }
914
915 /**
916 * @brief The callback function that transfers FECS Buffer entries to an EventBuffer
917 */
918 void
nvEventBufferFecsCallback(OBJGPU * pGpu,void * pArgs)919 nvEventBufferFecsCallback
920 (
921 OBJGPU *pGpu,
922 void *pArgs
923 )
924 {
925 KernelGraphics *pKernelGraphics = (KernelGraphics*)pArgs;
926 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
927 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
928 NvU32 fecsReadOffset;
929 NvU32 fecsReadOffsetPrev;
930 NvU64 fecsBufferSize;
931 NvU32 fecsRecordSize;
932 NvU32 i, j;
933 NvU8 *pFecsBufferMapping;
934 MEMORY_DESCRIPTOR *pFecsMemDesc = NULL;
935 FECS_EVENT_RECORD *pPeekRecord;
936 NvU16 maxFecsRecordsPerIntr;
937 NV_STATUS status;
938 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
939 NvU8 numIterations = (pArgs == NULL)
940 ? KGRMGR_MAX_GR
941 : 1;
942
943 if (!IS_MIG_IN_USE(pGpu))
944 numIterations = 1;
945
946 NV_ASSERT_OR_RETURN_VOID(rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
947
948 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
949 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount >= 0);
950 if (pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount <= 0)
951 return;
952
953 for (j = 0; j < numIterations; j++)
954 {
955 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo;
956
957 if (pArgs == NULL)
958 {
959 pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, j);
960 if (pKernelGraphics == NULL)
961 continue;
962 }
963
964 pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
965 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
966
967 pFecsBufferMapping = pFecsTraceInfo->pFecsBufferMapping;
968 maxFecsRecordsPerIntr = pFecsTraceInfo->fecsCtxswLogRecordsPerIntr;
969
970 if (pFecsBufferMapping == NULL)
971 continue;
972
973 status = _getFecsEventListParameters(pGpu, pKernelGraphics, &pFecsMemDesc, &fecsRecordSize);
974 if ((status != NV_OK) || (pFecsMemDesc == NULL))
975 continue;
976
977 fecsBufferSize = memdescGetSize(pFecsMemDesc) / fecsRecordSize;
978 NV_ASSERT_OR_RETURN_VOID(fecsBufferSize > 0);
979 fecsReadOffset = pFecsTraceInfo->fecsTraceRdOffset;
980
981 if (!osIsRaisedIRQL())
982 maxFecsRecordsPerIntr = fecsBufferSize;
983
984 // Bail out if the buffer has not changed
985 pPeekRecord = (FECS_EVENT_RECORD*)(pFecsBufferMapping +
986 (fecsReadOffset * fecsRecordSize));
987
988 if (pPeekRecord->magic_lo == NV_FECS_TRACE_MAGIC_INVALIDATED)
989 continue;
990
991 // Get the read offset from hw if the buffer wrapped around
992 fecsReadOffsetPrev = (fecsReadOffset - 1) % fecsBufferSize;
993 pPeekRecord = (FECS_EVENT_RECORD*)(pFecsBufferMapping +
994 (fecsReadOffsetPrev * fecsRecordSize));
995
996 if (pPeekRecord->magic_lo != NV_FECS_TRACE_MAGIC_INVALIDATED)
997 {
998 NvHandle hClient;
999 NvHandle hSubdevice;
1000 NV2080_CTRL_INTERNAL_GR_GET_FECS_TRACE_RD_OFFSET_PARAMS params;
1001
1002 NV_PRINTF(LEVEL_ERROR, "FECS buffer overflow detected\n");
1003
1004 NV_ASSERT_OK_OR_ELSE(
1005 status,
1006 _fecsLoadInternalRoutingInfo(pGpu,
1007 pKernelGraphics,
1008 &hClient,
1009 &hSubdevice,
1010 ¶ms.grRouteInfo),
1011 return);
1012
1013 NV_ASSERT_OK_OR_ELSE(
1014 status,
1015 pRmApi->Control(pRmApi,
1016 hClient,
1017 hSubdevice,
1018 NV2080_CTRL_CMD_INTERNAL_GR_GET_FECS_TRACE_RD_OFFSET,
1019 ¶ms,
1020 sizeof(params)),
1021 return);
1022 fecsReadOffset = params.offset;
1023 pFecsTraceInfo->fecsTraceCounter = 0;
1024 }
1025
1026 //
1027 // Over here we want to go through all EVENTNOTIFICATION nodes and
1028 // loop through them in lockstep with the FECS_EVENT_RECORD records
1029 //
1030 for (i = 0; i < maxFecsRecordsPerIntr; ++i)
1031 {
1032 FECS_EVENT_RECORD *pCurrRecord = (FECS_EVENT_RECORD *)(pFecsBufferMapping +
1033 (fecsReadOffset * fecsRecordSize));
1034
1035 if (pCurrRecord->magic_lo == NV_FECS_TRACE_MAGIC_INVALIDATED)
1036 break;
1037
1038 pCurrRecord->magic_lo = NV_FECS_TRACE_MAGIC_INVALIDATED;
1039 osFlushCpuWriteCombineBuffer();
1040
1041 // Loop through all bound event buffers and copy filtered data to user buffers
1042 formatAndNotifyFecsRecord(pGpu, pKernelGraphics, pCurrRecord);
1043
1044 // Update read reg
1045 pFecsTraceInfo->fecsTraceCounter++;
1046 fecsReadOffset++;
1047 if (fecsReadOffset >= fecsBufferSize)
1048 {
1049 fecsReadOffset = 0;
1050 }
1051 }
1052
1053 if (pFecsTraceInfo->fecsTraceCounter > 0)
1054 {
1055 NvHandle hClient;
1056 NvHandle hSubdevice;
1057 NV2080_CTRL_INTERNAL_GR_SET_FECS_TRACE_RD_OFFSET_PARAMS params;
1058
1059 params.offset = fecsReadOffset;
1060 NV_ASSERT_OK_OR_ELSE(
1061 status,
1062 _fecsLoadInternalRoutingInfo(pGpu,
1063 pKernelGraphics,
1064 &hClient,
1065 &hSubdevice,
1066 ¶ms.grRouteInfo),
1067 return);
1068
1069 NV_ASSERT_OK_OR_ELSE(
1070 status,
1071 pRmApi->Control(pRmApi,
1072 hClient,
1073 hSubdevice,
1074 NV2080_CTRL_CMD_INTERNAL_GR_SET_FECS_TRACE_RD_OFFSET,
1075 ¶ms,
1076 sizeof(params)),
1077 return);
1078 pFecsTraceInfo->fecsTraceCounter = 0;
1079 }
1080 pFecsTraceInfo->fecsTraceRdOffset = fecsReadOffset;
1081
1082 // Re-arm interrupt if there may be more records
1083 if (i == maxFecsRecordsPerIntr)
1084 fecsSignalIntrPendingIfNotPending(pGpu, pKernelGraphics);
1085 }
1086 }
1087
1088 NV_STATUS
fecsAddBindpoint(OBJGPU * pGpu,RmClient * pClient,RsResourceRef * pEventBufferRef,Subdevice * pNotifier,NvBool bAllUsers,NV2080_CTRL_GR_FECS_BIND_EVTBUF_LOD levelOfDetail,NvU32 eventFilter,NvU8 version,NvU32 * pReasonCode)1089 fecsAddBindpoint
1090 (
1091 OBJGPU *pGpu,
1092 RmClient *pClient,
1093 RsResourceRef *pEventBufferRef,
1094 Subdevice *pNotifier,
1095 NvBool bAllUsers,
1096 NV2080_CTRL_GR_FECS_BIND_EVTBUF_LOD levelOfDetail,
1097 NvU32 eventFilter,
1098 NvU8 version,
1099 NvU32 *pReasonCode
1100 )
1101 {
1102 NV_STATUS status;
1103 NvHandle hClient = staticCast(pClient, RsClient)->hClient;
1104 NvHandle hEventBuffer = pEventBufferRef->hResource;
1105 NvHandle hNotifier = RES_GET_HANDLE(pNotifier);
1106 EventBuffer *pEventBuffer;
1107 NvBool bAdmin = osIsAdministrator();
1108 NvU32 eventMask = 0;
1109 NvU64 targetUser;
1110 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
1111 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1112 NvS32 gpuConsumerCount;
1113 NvBool bFecsBindingActive;
1114 NvBool bIntrDriven = NV_FALSE;
1115 KernelMIGManager *pKernelMIGManager = GPU_GET_KERNEL_MIG_MANAGER(pGpu);
1116 NvBool bMIGInUse = IS_MIG_IN_USE(pGpu);
1117 NvU8 numIterations;
1118 NvU8 grIdx;
1119 NvBool bKernel;
1120 NvBool bSelectLOD;
1121 NV_EVENT_BUFFER_BIND_POINT_FECS *pBind;
1122
1123 CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
1124 NV_ASSERT_OR_RETURN(pCallContext != NULL, NV_ERR_INVALID_STATE);
1125 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_INVALID_STATE);
1126
1127 gpuConsumerCount = pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount;
1128 bFecsBindingActive = (pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount > 0);
1129
1130 bKernel = pCallContext->secInfo.privLevel >= RS_PRIV_LEVEL_KERNEL;
1131
1132 bSelectLOD = bKernel;
1133
1134 #if defined(DEBUG) || defined(DEVELOP) || defined(NV_VERIF_FEATURES)
1135 bSelectLOD = NV_TRUE;
1136 #endif
1137
1138 LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner() && rmDeviceGpuLockIsOwner(pGpu->gpuInstance));
1139
1140 // Early bail-out if profiling capability is not enabled on vGPU
1141 if (IS_VIRTUAL(pGpu))
1142 {
1143 VGPU_STATIC_INFO *pVSI = GPU_GET_STATIC_INFO(pGpu);
1144 if ((pVSI == NULL) || !pVSI->vgpuStaticProperties.bProfilingTracingEnabled)
1145 {
1146 if (pReasonCode != NULL)
1147 *pReasonCode = NV2080_CTRL_GR_FECS_BIND_REASON_CODE_NEED_CAPABILITY;
1148
1149 return NV_ERR_NOT_SUPPORTED;
1150 }
1151 }
1152
1153 // On a hypervisor or VM: bail-out early if admin is required
1154 if (IS_VIRTUAL(pGpu) || hypervisorIsVgxHyper())
1155 {
1156 if (pGpu->bRmProfilingPrivileged && !bAdmin)
1157 {
1158 if (pReasonCode != NULL)
1159 *pReasonCode = NV2080_CTRL_GR_FECS_BIND_REASON_CODE_NEED_ADMIN;
1160
1161 return NV_ERR_NOT_SUPPORTED;
1162 }
1163 }
1164
1165 if (bSelectLOD)
1166 {
1167 switch (levelOfDetail)
1168 {
1169 case NV2080_CTRL_GR_FECS_BIND_EVTBUF_LOD_FULL:
1170 eventMask = ~0;
1171 break;
1172 case NV2080_CTRL_GR_FECS_BIND_EVTBUF_LOD_COMPAT:
1173 eventMask |= NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_RESTORE_START |
1174 NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_CONTEXT_START |
1175 NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_CTXSW_REQ_BY_HOST;
1176 break;
1177 case NV2080_CTRL_GR_FECS_BIND_EVTBUF_LOD_CUSTOM:
1178 eventMask = eventFilter;
1179 break;
1180 default:
1181 // Default to SIMPLIFIED level-of-detail
1182 eventMask |= NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_START |
1183 NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_END;
1184 }
1185 }
1186 else
1187 {
1188 // Default to SIMPLIFIED level-of-detail
1189 eventMask |= NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_START |
1190 NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_SIMPLE_END;
1191 }
1192
1193 if (eventMask & NV_EVENT_BUFFER_FECS_BITMASK_CTXSWTAG_FE_ACK)
1194 {
1195 eventMask |= NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_WFI |
1196 NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_GFXP |
1197 NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_CTAP |
1198 NV_EVENT_BUFFER_FECS_CTXSWTAG_FE_ACK_CILP;
1199 }
1200
1201 if (bAllUsers)
1202 {
1203 targetUser = 0;
1204 }
1205 else
1206 {
1207 targetUser = (NvU64)(NvUPtr)pClient->pUserInfo;
1208
1209 // Filtering UIDs is not yet implemented in legacy vGPU
1210 if (IS_VIRTUAL_WITHOUT_SRIOV(pGpu))
1211 {
1212 if (pReasonCode != NULL)
1213 *pReasonCode = NV2080_CTRL_GR_FECS_BIND_REASON_CODE_NOT_ENABLED;
1214
1215 return NV_ERR_NOT_SUPPORTED;
1216 }
1217 }
1218
1219 pEventBuffer = dynamicCast(pEventBufferRef->pResource, EventBuffer);
1220 if (pEventBuffer == NULL)
1221 return NV_ERR_INVALID_ARGUMENT;
1222
1223 if (multimapFindSubmap(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, targetUser) == NULL)
1224 {
1225 if (multimapInsertSubmap(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, targetUser) == NULL)
1226 {
1227 NV_PRINTF(LEVEL_ERROR, "failed to add UID binding!\n");
1228 return NV_ERR_INSUFFICIENT_RESOURCES;
1229 }
1230 }
1231
1232 // If the binding exists already, we're done
1233 if (multimapFindItem(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, targetUser, (NvU64)(NvUPtr)pEventBuffer) != NULL)
1234 return NV_OK;
1235
1236 pBind = multimapInsertItemNew(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, targetUser, (NvU64)(NvUPtr)pEventBuffer);
1237 if (pBind == NULL)
1238 return NV_ERR_INVALID_ARGUMENT;
1239 ++pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount;
1240
1241 pBind->hClient = hClient;
1242 pBind->hNotifier = hNotifier;
1243 pBind->hEventBuffer = hEventBuffer;
1244 pBind->pEventBuffer = pEventBuffer;
1245 pBind->pUserInfo = (NvU64)(NvUPtr)pClient->pUserInfo;
1246 pBind->bAdmin = bAdmin;
1247 pBind->eventMask = eventMask;
1248 pBind->bKernel = bKernel;
1249 pBind->version = version;
1250
1251 status = registerEventNotification(&pEventBuffer->pListeners,
1252 staticCast(pClient, RsClient),
1253 hNotifier,
1254 hEventBuffer,
1255 (version == 2 ?
1256 NV_EVENT_BUFFER_RECORD_TYPE_FECS_CTX_SWITCH_V2 :
1257 NV_EVENT_BUFFER_RECORD_TYPE_FECS_CTX_SWITCH) | NV01_EVENT_WITHOUT_EVENT_DATA,
1258 NV_EVENT_BUFFER_BIND,
1259 pEventBuffer->producerInfo.notificationHandle,
1260 NV_FALSE);
1261 if (status != NV_OK)
1262 goto done;
1263
1264 if (bMIGInUse)
1265 {
1266 if (kmigmgrIsDeviceUsingDeviceProfiling(pGpu, pKernelMIGManager, GPU_RES_GET_DEVICE(pNotifier)))
1267 {
1268 pBind->swizzId = NV2080_CTRL_GPU_PARTITION_ID_INVALID;
1269 }
1270 else
1271 {
1272 GPUInstanceSubscription *pGPUInstanceSubscription;
1273 status = gisubscriptionGetGPUInstanceSubscription(
1274 staticCast(pClient, RsClient), hNotifier, &pGPUInstanceSubscription);
1275 if (status != NV_OK)
1276 goto done;
1277
1278 if (gisubscriptionGetMIGGPUInstance(pGPUInstanceSubscription) == NULL)
1279 {
1280 if (pReasonCode != NULL)
1281 *pReasonCode = NV2080_CTRL_GR_FECS_BIND_REASON_CODE_NOT_ENABLED;
1282
1283 status = NV_ERR_NOT_SUPPORTED;
1284 goto done;
1285 }
1286
1287 pBind->swizzId = gisubscriptionGetMIGGPUInstance(pGPUInstanceSubscription)->swizzId;
1288 }
1289 }
1290
1291 numIterations = bMIGInUse ? GPU_MAX_GRS: 1;
1292 for (grIdx = 0; grIdx < numIterations; grIdx++)
1293 {
1294 KernelGraphics *pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, grIdx);
1295 if (pKernelGraphics == NULL)
1296 continue;
1297
1298 if (!kgraphicsIsCtxswLoggingSupported(pGpu, pKernelGraphics))
1299 {
1300 if (pReasonCode)
1301 *pReasonCode = NV2080_CTRL_GR_FECS_BIND_REASON_CODE_NOT_ENABLED_GPU;
1302
1303 status = NV_ERR_NOT_SUPPORTED;
1304 goto done;
1305 }
1306
1307 if (!bFecsBindingActive)
1308 {
1309
1310 fecsBufferReset(pGpu, pKernelGraphics);
1311 }
1312
1313 bIntrDriven |= kgraphicsIsIntrDrivenCtxswLoggingEnabled(pGpu, pKernelGraphics);
1314 }
1315
1316 if (!bFecsBindingActive && !bIntrDriven)
1317 {
1318 NV_CHECK_OK_OR_GOTO(status, LEVEL_ERROR, _fecsTimerCreate(pGpu), done);
1319 }
1320
1321 done:
1322 if (status != NV_OK)
1323 {
1324 if (gpuConsumerCount != pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount)
1325 fecsRemoveBindpoint(pGpu, targetUser, pBind);
1326
1327 _fecsTimerDestroy(pGpu);
1328 }
1329
1330 return status;
1331 }
1332
1333 void
fecsRemoveBindpoint(OBJGPU * pGpu,NvU64 uid,NV_EVENT_BUFFER_BIND_POINT_FECS * pBind)1334 fecsRemoveBindpoint
1335 (
1336 OBJGPU *pGpu,
1337 NvU64 uid,
1338 NV_EVENT_BUFFER_BIND_POINT_FECS *pBind
1339 )
1340 {
1341 EventBuffer *pEventBuffer = pBind->pEventBuffer;
1342 KernelGraphicsManager *pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
1343 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1344
1345 NV_ASSERT_OR_RETURN_VOID(pFecsGlobalTraceInfo != NULL);
1346
1347 --pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount;
1348
1349 unregisterEventNotificationWithData(&pEventBuffer->pListeners,
1350 pBind->hClient,
1351 pBind->hNotifier,
1352 pBind->hEventBuffer,
1353 NV_TRUE,
1354 pEventBuffer->producerInfo.notificationHandle);
1355
1356 multimapRemoveItemByKey(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid,
1357 uid,
1358 (NvU64)(NvUPtr)pEventBuffer);
1359
1360 if (pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount == 0)
1361 {
1362 NvBool bMIGInUse = IS_MIG_IN_USE(pGpu);
1363 NvU8 grIdx;
1364 NvBool bIntrDriven = NV_FALSE;
1365
1366 NvU8 numIterations = bMIGInUse ? GPU_MAX_GRS : 1;
1367 for (grIdx = 0; grIdx < numIterations; grIdx++)
1368 {
1369 KernelGraphics *pKernelGraphics = GPU_GET_KERNEL_GRAPHICS(pGpu, grIdx);
1370 if (pKernelGraphics == NULL)
1371 continue;
1372
1373 //
1374 // Disable HW without unmapping buffer so that new event buffers still work properly
1375 // HW enable will happen on bindpoint creation.
1376 // Mapping only occurs on Graphics load/alloc, so unmapping should only occur when Graphics is destroyed.
1377 //
1378 fecsBufferDisableHw(pGpu, pKernelGraphics);
1379 bIntrDriven |= kgraphicsIsIntrDrivenCtxswLoggingEnabled(pGpu, pKernelGraphics);
1380
1381 }
1382
1383 if (!bIntrDriven)
1384 {
1385 _fecsTimerDestroy(pGpu);
1386 }
1387 }
1388 }
1389
1390 void
fecsRemoveAllBindpoints(EventBuffer * pEventBuffer)1391 fecsRemoveAllBindpoints
1392 (
1393 EventBuffer *pEventBuffer
1394 )
1395 {
1396 OBJGPU *pGpu = NULL;
1397 NvU32 gpuMask = 0;
1398 NvU32 gpuIndex = 0;
1399 KernelGraphicsManager *pKernelGraphicsManager;
1400 FecsEventBufferBindMultiMapSupermapIter uidBindIter;
1401
1402 eventBufferSetEnable(&pEventBuffer->producerInfo, NV_FALSE);
1403
1404 gpumgrGetGpuAttachInfo(NULL, &gpuMask);
1405 while ((pGpu = gpumgrGetNextGpu(gpuMask, &gpuIndex)) != NULL)
1406 {
1407 pKernelGraphicsManager = GPU_GET_KERNEL_GRAPHICS_MANAGER(pGpu);
1408 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1409
1410 NV_CHECK_OR_ELSE(LEVEL_ERROR, pFecsGlobalTraceInfo != NULL, continue;);
1411
1412 uidBindIter = multimapSubmapIterAll(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid);
1413 while (multimapSubmapIterNext(&uidBindIter))
1414 {
1415 FecsEventBufferBindMultiMapSubmap *pSubmap = uidBindIter.pValue;
1416 NV_EVENT_BUFFER_BIND_POINT_FECS *pBind = NULL;
1417 NvU64 uid = mapKey_IMPL(uidBindIter.iter.pMap, pSubmap);
1418
1419 while ((pBind = multimapFindItem(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid,
1420 uid,
1421 (NvU64)(NvUPtr)pEventBuffer)) != NULL)
1422 {
1423 fecsRemoveBindpoint(pGpu, uid, pBind);
1424 }
1425 }
1426
1427 }
1428 }
1429
1430 void
fecsBufferReset(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1431 fecsBufferReset
1432 (
1433 OBJGPU *pGpu,
1434 KernelGraphics *pKernelGraphics
1435 )
1436 {
1437 MEMORY_DESCRIPTOR *pFecsMemDesc = NULL;
1438 NV_STATUS status;
1439 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1440 NV2080_CTRL_INTERNAL_GR_GET_FECS_TRACE_HW_ENABLE_PARAMS getHwEnableParams;
1441 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1442 NvHandle hClient;
1443 NvHandle hSubdevice;
1444
1445 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
1446
1447 if (pFecsTraceInfo->pFecsBufferMapping == NULL)
1448 return;
1449
1450 NV_ASSERT_OK_OR_ELSE(
1451 status,
1452 _fecsLoadInternalRoutingInfo(pGpu,
1453 pKernelGraphics,
1454 &hClient,
1455 &hSubdevice,
1456 &getHwEnableParams.grRouteInfo),
1457 return);
1458
1459 NV_ASSERT_OK_OR_ELSE(
1460 status,
1461 pRmApi->Control(pRmApi,
1462 hClient,
1463 hSubdevice,
1464 NV2080_CTRL_CMD_INTERNAL_GR_GET_FECS_TRACE_HW_ENABLE,
1465 &getHwEnableParams,
1466 sizeof(getHwEnableParams)),
1467 return);
1468
1469 status = _getFecsMemDesc(pGpu, pKernelGraphics, &pFecsMemDesc);
1470
1471 if ((status == NV_OK) && (pFecsMemDesc != NULL) && (getHwEnableParams.bEnable != NV_TRUE))
1472 {
1473 NV2080_CTRL_INTERNAL_GR_SET_FECS_TRACE_WR_OFFSET_PARAMS traceWrOffsetParams;
1474 NV2080_CTRL_INTERNAL_GR_SET_FECS_TRACE_RD_OFFSET_PARAMS traceRdOffsetParams;
1475 NV2080_CTRL_INTERNAL_GR_SET_FECS_TRACE_HW_ENABLE_PARAMS setHwEnableParams;
1476
1477 portMemSet(pFecsTraceInfo->pFecsBufferMapping,
1478 (NvU8)(NV_FECS_TRACE_MAGIC_INVALIDATED & 0xff),
1479 memdescGetSize(pFecsMemDesc));
1480
1481 pFecsTraceInfo->fecsLastSeqno = 0;
1482
1483 // Routing info is the same for all future calls in this series
1484 traceWrOffsetParams.grRouteInfo = getHwEnableParams.grRouteInfo;
1485 traceRdOffsetParams.grRouteInfo = getHwEnableParams.grRouteInfo;
1486 setHwEnableParams.grRouteInfo = getHwEnableParams.grRouteInfo;
1487
1488 traceWrOffsetParams.offset = 0;
1489 NV_ASSERT_OK_OR_ELSE(
1490 status,
1491 pRmApi->Control(pRmApi,
1492 hClient,
1493 hSubdevice,
1494 NV2080_CTRL_CMD_INTERNAL_GR_SET_FECS_TRACE_WR_OFFSET,
1495 &traceWrOffsetParams,
1496 sizeof(traceWrOffsetParams)),
1497 return);
1498
1499 traceRdOffsetParams.offset = 0;
1500 NV_ASSERT_OK_OR_ELSE(
1501 status,
1502 pRmApi->Control(pRmApi,
1503 hClient,
1504 hSubdevice,
1505 NV2080_CTRL_CMD_INTERNAL_GR_SET_FECS_TRACE_RD_OFFSET,
1506 &traceRdOffsetParams,
1507 sizeof(traceRdOffsetParams)),
1508 return);
1509 pFecsTraceInfo->fecsTraceRdOffset = 0;
1510
1511 setHwEnableParams.bEnable = NV_TRUE;
1512 NV_ASSERT_OK_OR_ELSE(
1513 status,
1514 pRmApi->Control(pRmApi,
1515 hClient,
1516 hSubdevice,
1517 NV2080_CTRL_CMD_INTERNAL_GR_SET_FECS_TRACE_HW_ENABLE,
1518 &setHwEnableParams,
1519 sizeof(setHwEnableParams)),
1520 return);
1521 }
1522 }
1523
1524 void
fecsBufferDisableHw(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1525 fecsBufferDisableHw
1526 (
1527 OBJGPU *pGpu,
1528 KernelGraphics *pKernelGraphics
1529 )
1530 {
1531 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
1532 NvHandle hClient;
1533 NvHandle hSubdevice;
1534 NV2080_CTRL_INTERNAL_GR_GET_FECS_TRACE_HW_ENABLE_PARAMS getHwEnableParams;
1535 NV2080_CTRL_INTERNAL_GR_SET_FECS_TRACE_HW_ENABLE_PARAMS setHwEnableParams;
1536 NV_STATUS status;
1537
1538 // This function may be called with unused GR Engines
1539 NV_CHECK_OK_OR_ELSE(
1540 status,
1541 LEVEL_INFO,
1542 _fecsLoadInternalRoutingInfo(pGpu,
1543 pKernelGraphics,
1544 &hClient,
1545 &hSubdevice,
1546 &getHwEnableParams.grRouteInfo),
1547 return);
1548
1549 NV_ASSERT_OK_OR_ELSE(
1550 status,
1551 pRmApi->Control(pRmApi,
1552 hClient,
1553 hSubdevice,
1554 NV2080_CTRL_CMD_INTERNAL_GR_GET_FECS_TRACE_HW_ENABLE,
1555 &getHwEnableParams,
1556 sizeof(getHwEnableParams)),
1557 return);
1558
1559 if (getHwEnableParams.bEnable)
1560 {
1561 // Copy previously loaded routing info
1562 setHwEnableParams.grRouteInfo = getHwEnableParams.grRouteInfo;
1563 setHwEnableParams.bEnable = NV_FALSE;
1564
1565 NV_ASSERT_OK_OR_ELSE(
1566 status,
1567 pRmApi->Control(pRmApi,
1568 hClient,
1569 hSubdevice,
1570 NV2080_CTRL_CMD_INTERNAL_GR_SET_FECS_TRACE_HW_ENABLE,
1571 &setHwEnableParams,
1572 sizeof(setHwEnableParams)),
1573 return);
1574 }
1575 }
1576
1577 void
fecsBufferTeardown(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1578 fecsBufferTeardown
1579 (
1580 OBJGPU *pGpu,
1581 KernelGraphics *pKernelGraphics
1582 )
1583 {
1584 fecsBufferDisableHw(pGpu, pKernelGraphics);
1585 fecsBufferUnmap(pGpu, pKernelGraphics);
1586 }
1587
1588 /*! Is the FECS trace buffer mapped? */
1589 NvBool
fecsBufferIsMapped(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1590 fecsBufferIsMapped
1591 (
1592 OBJGPU *pGpu,
1593 KernelGraphics *pKernelGraphics
1594 )
1595 {
1596 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1597
1598 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_FALSE);
1599 return pFecsTraceInfo->pFecsBufferMapping != NULL;
1600 }
1601
1602 NV_STATUS
fecsBufferMap(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1603 fecsBufferMap
1604 (
1605 OBJGPU *pGpu,
1606 KernelGraphics *pKernelGraphics
1607 )
1608 {
1609 MEMORY_DESCRIPTOR *pFecsMemDesc = NULL;
1610 NvU8 *pFecsBufferMapping = NULL;
1611 NV_STATUS status;
1612 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1613 TRANSFER_SURFACE surf = {0};
1614 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
1615
1616 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_ERR_INVALID_STATE);
1617
1618 if (IS_VIRTUAL_WITHOUT_SRIOV(pGpu))
1619 return NV_OK;
1620
1621 if (pFecsTraceInfo->pFecsBufferMapping != NULL)
1622 return NV_OK;
1623
1624 status = _getFecsMemDesc(pGpu, pKernelGraphics, &pFecsMemDesc);
1625 if ((status != NV_OK) || (pFecsMemDesc == NULL))
1626 return NV_ERR_INVALID_STATE;
1627
1628 surf.pMemDesc = pFecsMemDesc;
1629 surf.offset = 0;
1630
1631 pFecsBufferMapping = memmgrMemBeginTransfer(pMemoryManager, &surf,
1632 memdescGetSize(pFecsMemDesc),
1633 TRANSFER_FLAGS_PREFER_PROCESSOR |
1634 TRANSFER_FLAGS_PERSISTENT_CPU_MAPPING);
1635 if (pFecsBufferMapping == NULL)
1636 return NV_ERR_INSUFFICIENT_RESOURCES;
1637
1638 pFecsTraceInfo->pFecsBufferMapping = pFecsBufferMapping;
1639
1640 return NV_OK;
1641 }
1642
1643 void
fecsBufferUnmap(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1644 fecsBufferUnmap
1645 (
1646 OBJGPU *pGpu,
1647 KernelGraphics *pKernelGraphics
1648 )
1649 {
1650 MEMORY_DESCRIPTOR *pFecsMemDesc = NULL;
1651 NV_STATUS status;
1652 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1653 TRANSFER_SURFACE surf = {0};
1654 MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
1655
1656 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
1657
1658 if (IS_VIRTUAL_WITHOUT_SRIOV(pGpu))
1659 return;
1660
1661 status = _getFecsMemDesc(pGpu, pKernelGraphics, &pFecsMemDesc);
1662 if ((status != NV_OK) || (pFecsMemDesc == NULL))
1663 return;
1664
1665 surf.pMemDesc = pFecsMemDesc;
1666 surf.offset = 0;
1667
1668 if (pFecsTraceInfo->pFecsBufferMapping != NULL)
1669 {
1670 memmgrMemEndTransfer(pMemoryManager, &surf,
1671 memdescGetSize(pFecsMemDesc),
1672 TRANSFER_FLAGS_PREFER_PROCESSOR |
1673 TRANSFER_FLAGS_PERSISTENT_CPU_MAPPING);
1674
1675 pFecsTraceInfo->pFecsBufferMapping = NULL;
1676 }
1677 }
1678
1679 /*! Atomically set intr callback pending, return NV_TRUE if wasn't pending prior */
1680 NvBool
fecsSignalIntrPendingIfNotPending(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1681 fecsSignalIntrPendingIfNotPending
1682 (
1683 OBJGPU *pGpu,
1684 KernelGraphics *pKernelGraphics
1685 )
1686 {
1687 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1688
1689 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_FALSE);
1690
1691 return portAtomicCompareAndSwapU32(&pFecsTraceInfo->fecsCtxswLogIntrPending, 1, 0);
1692 }
1693
1694 /*! Atomically clear intr callback pending, return NV_TRUE if was pending */
1695 NvBool
fecsClearIntrPendingIfPending(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1696 fecsClearIntrPendingIfPending
1697 (
1698 OBJGPU *pGpu,
1699 KernelGraphics *pKernelGraphics
1700 )
1701 {
1702 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1703
1704 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_FALSE);
1705
1706 return portAtomicCompareAndSwapU32(&pFecsTraceInfo->fecsCtxswLogIntrPending, 0, 1);
1707 }
1708
1709 /*! Atomically check if intr callback pending */
fecsIsIntrPending(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1710 NvBool fecsIsIntrPending
1711 (
1712 OBJGPU *pGpu,
1713 KernelGraphics *pKernelGraphics
1714 )
1715 {
1716 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1717
1718 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NV_FALSE);
1719
1720 return portAtomicOrU32(&pFecsTraceInfo->fecsCtxswLogIntrPending, 0) != 0;
1721 }
1722
1723 NvS16
fecsGetCtxswLogConsumerCount(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager)1724 fecsGetCtxswLogConsumerCount
1725 (
1726 OBJGPU *pGpu,
1727 KernelGraphicsManager *pKernelGraphicsManager
1728 )
1729 {
1730 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1731
1732 NV_CHECK_OR_RETURN(LEVEL_ERROR, pFecsGlobalTraceInfo != NULL, 0);
1733
1734 return pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount;
1735 }
1736
1737 NV_STATUS
fecsIncrementCtxswLogConsumerCount(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager)1738 fecsIncrementCtxswLogConsumerCount
1739 (
1740 OBJGPU *pGpu,
1741 KernelGraphicsManager *pKernelGraphicsManager
1742 )
1743 {
1744 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1745
1746 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_INVALID_STATE);
1747
1748 pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount++;
1749
1750 return NV_OK;
1751 }
1752
1753 NV_STATUS
fecsDecrementCtxswLogConsumerCount(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager)1754 fecsDecrementCtxswLogConsumerCount
1755 (
1756 OBJGPU *pGpu,
1757 KernelGraphicsManager *pKernelGraphicsManager
1758 )
1759 {
1760 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1761
1762 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NV_ERR_INVALID_STATE);
1763
1764 pFecsGlobalTraceInfo->fecsCtxswLogConsumerCount--;
1765
1766 return NV_OK;
1767 }
1768
1769 /*! Retrieve the current VGPU staging buffer */
1770 VGPU_FECS_TRACE_STAGING_BUFFER *
fecsGetVgpuStagingBuffer(OBJGPU * pGpu,KernelGraphics * pKernelGraphics)1771 fecsGetVgpuStagingBuffer
1772 (
1773 OBJGPU *pGpu,
1774 KernelGraphics *pKernelGraphics
1775 )
1776 {
1777 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1778
1779 NV_ASSERT_OR_RETURN(pFecsTraceInfo != NULL, NULL);
1780
1781 return pFecsTraceInfo->pVgpuStaging;
1782 }
1783
1784 /*! Store the given VGPU staging buffer */
1785 void
fecsSetVgpuStagingBuffer(OBJGPU * pGpu,KernelGraphics * pKernelGraphics,VGPU_FECS_TRACE_STAGING_BUFFER * pStagingBuffer)1786 fecsSetVgpuStagingBuffer
1787 (
1788 OBJGPU *pGpu,
1789 KernelGraphics *pKernelGraphics,
1790 VGPU_FECS_TRACE_STAGING_BUFFER *pStagingBuffer
1791 )
1792 {
1793 KGRAPHICS_FECS_TRACE_INFO *pFecsTraceInfo = kgraphicsGetFecsTraceInfo(pGpu, pKernelGraphics);
1794
1795 NV_ASSERT_OR_RETURN_VOID(pFecsTraceInfo != NULL);
1796
1797 pFecsTraceInfo->pVgpuStaging = pStagingBuffer;
1798 }
1799
1800 FecsEventBufferBindMultiMap *
fecsGetEventBufferBindMultiMap(OBJGPU * pGpu,KernelGraphicsManager * pKernelGraphicsManager)1801 fecsGetEventBufferBindMultiMap
1802 (
1803 OBJGPU *pGpu,
1804 KernelGraphicsManager *pKernelGraphicsManager
1805 )
1806 {
1807 KGRMGR_FECS_GLOBAL_TRACE_INFO *pFecsGlobalTraceInfo = kgrmgrGetFecsGlobalTraceInfo(pGpu, pKernelGraphicsManager);
1808
1809 NV_ASSERT_OR_RETURN(pFecsGlobalTraceInfo != NULL, NULL);
1810
1811 return &pFecsGlobalTraceInfo->fecsEventBufferBindingsUid;
1812 }
1813
1814