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(&notifRecord, 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                                        &notifRecord.timestamp,
276                                        &notifRecord.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, &notifRecord);
385             }
386 
387             // Notify event buffers listening for all UIDs
388             pSubmap = multimapFindSubmap(&pFecsGlobalTraceInfo->fecsEventBufferBindingsUid, 0);
389             notifyEventBuffers(pGpu, pSubmap, &notifRecord);
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(&notifyEvent, 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, &notifyEvent, notifyIndex, &bNotify, &notificationHandle);
449 
450     if ((status == NV_OK) && bNotify && notificationHandle)
451     {
452         osEventNotification(pGpu,
453                 pBind->pEventBuffer->pListeners,
454                 notifyIndex,
455                 &notifyEvent,
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                                              &params.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                                 &params,
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                                              &params.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                                 &params,
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