1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 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 #include "kernel/gpu/video/kernel_video_engine.h"
26 #include "kernel/gpu/mem_mgr/mem_desc.h"
27 #include "kernel/gpu/bus/kern_bus.h"
28 #include "kernel/os/os.h"
29 #include "nvrm_registry.h"
30 
31 NV_STATUS kvidengConstruct_IMPL
32 (
33     KernelVideoEngine *pKernelVideoEngine,
34     OBJGPU *pGpu,
35     ENGDESCRIPTOR physEngDesc
36 )
37 {
38     pKernelVideoEngine->physEngDesc = physEngDesc;
39     return NV_OK;
40 }
41 
42 NV_STATUS kvidengInitLogging_IMPL
43 (
44     OBJGPU *pGpu,
45     KernelVideoEngine *pKernelVideoEngine
46 )
47 {
48     NV_STATUS status;
49     NvU32 data = NV_REG_STR_RM_VIDEO_EVENT_TRACE_DISABLED;
50     NvBool alwaysLogging;
51 
52     if (!gpuIsVideoTraceLogSupported(pGpu))
53         return NV_OK;
54 
55     NV_ASSERT_OR_RETURN(pKernelVideoEngine != NULL, NV_ERR_INVALID_STATE);
56 
57     status = osReadRegistryDword(pGpu, NV_REG_STR_RM_VIDEO_EVENT_TRACE, &data);
58     if (status != NV_OK)
59     {
60         // When GLOBAL_FEATURE_GR2069_VIDEO_EVENT is enabled and the registry is not set,
61         // default eventbuffer size to 32K and staging buffer to 4K.
62         data = DRF_NUM(_REG_STR, _RM_VIDEO_EVENT_TRACE, _STAGING_BUFFER_SIZE_IN_4k, 1) |
63                DRF_NUM(_REG_STR, _RM_VIDEO_EVENT_TRACE, _EVENT_BUFFER_SIZE_IN_4k, 0x8);
64     }
65 
66     alwaysLogging = DRF_VAL(_REG_STR, _RM_VIDEO_EVENT_TRACE, _ALWAYS_LOG, (data)) ==
67                     NV_REG_STR_RM_VIDEO_EVENT_TRACE_ALWAYS_LOG_ENABLED;
68 
69     if (data != NV_REG_STR_RM_VIDEO_EVENT_TRACE_DISABLED)
70     {
71         NvU32 eventBufferSize;
72         VIDEO_TRACE_RING_BUFFER *pTraceBuf;
73         NvU64 seed;
74         NvBool bIsFbBroken = NV_FALSE;
75         NV_ADDRESS_SPACE videoBufferAddressSpace = ADDR_FBMEM;
76 
77         eventBufferSize = DRF_VAL(_REG_STR, _RM_VIDEO_EVENT_TRACE, _EVENT_BUFFER_SIZE_IN_4k, (data)) * 0x1000;
78 
79         bIsFbBroken = pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) ||
80                       pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_ALL_INST_IN_SYSMEM);
81 
82         if (bIsFbBroken)
83             videoBufferAddressSpace = ADDR_SYSMEM;
84 
85         // Allocate the staging buffer
86         NV_ASSERT_OK_OR_GOTO(
87             status,
88             memdescCreate(&pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc,
89                           pGpu,
90                           eventBufferSize,
91                           0,
92                           NV_TRUE,
93                           videoBufferAddressSpace,
94                           NV_MEMORY_UNCACHED,
95                           MEMDESC_FLAGS_NONE),
96             exit);
97 
98         NV_ASSERT_OK_OR_GOTO(
99             status,
100             memdescAlloc(pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc),
101             exit);
102 
103         pTraceBuf = (VIDEO_TRACE_RING_BUFFER *)kbusMapRmAperture_HAL(pGpu, pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc);
104 
105         NV_ASSERT_OR_ELSE(pTraceBuf != NULL,
106             status = NV_ERR_INSUFFICIENT_RESOURCES;
107             goto exit;);
108 
109         // clear trace buffer
110         portMemSet(pTraceBuf, 0, eventBufferSize);
111 
112         pTraceBuf->bufferSize = eventBufferSize - sizeof(VIDEO_TRACE_RING_BUFFER);
113         pTraceBuf->readPtr = 0;
114         pTraceBuf->writePtr = 0;
115         pTraceBuf->flags = alwaysLogging ? VIDEO_TRACE_FLAG__LOGGING_ENABLED : 0;
116 
117         pKernelVideoEngine->videoTraceInfo.pTraceBufferEngine = pTraceBuf;
118 
119         // Allocate allocate scratch pad for variable data
120         pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData = portMemAllocNonPaged(RM_VIDEO_TRACE_MAX_VARIABLE_DATA_SIZE);
121 
122         if (pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData == NULL)
123         {
124             status = NV_ERR_NO_MEMORY;
125             goto exit;
126         }
127         portMemSet(pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData, 0x00, RM_VIDEO_TRACE_MAX_VARIABLE_DATA_SIZE);
128 
129         /*!
130          * Random number generator used for generate noisy timestamp
131          */
132         osGetCurrentTick(&seed);
133         pKernelVideoEngine->videoTraceInfo.pVideoLogPrng = portCryptoPseudoRandomGeneratorCreate(seed);
134     }
135 
136 exit:
137     if (status != NV_OK)
138     {
139         kvidengFreeLogging(pGpu, pKernelVideoEngine);
140 
141         if (status == NV_WARN_NOTHING_TO_DO)
142             status = NV_OK;
143     }
144     else
145     {
146         pKernelVideoEngine->bVideoTraceEnabled = NV_TRUE;
147     }
148 
149     return status;
150 }
151 
152 void kvidengFreeLogging_IMPL
153 (
154     OBJGPU *pGpu,
155     KernelVideoEngine *pKernelVideoEngine
156 )
157 {
158     if (pKernelVideoEngine->videoTraceInfo.pTraceBufferEngine != NULL)
159     {
160         kbusUnmapRmAperture_HAL(pGpu, pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc,
161                                 &(pKernelVideoEngine->videoTraceInfo.pTraceBufferEngine),
162                                 NV_TRUE);
163         pKernelVideoEngine->videoTraceInfo.pTraceBufferEngine = NULL;
164     }
165 
166     if (pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc != NULL)
167     {
168         memdescFree(pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc);
169         memdescDestroy(pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc);
170         pKernelVideoEngine->videoTraceInfo.pTraceBufferEngineMemDesc = NULL;
171     }
172 
173     portMemFree(pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData);
174     pKernelVideoEngine->videoTraceInfo.pTraceBufferVariableData = NULL;
175 
176     /*!
177      * Free random number generator used for generate noisy timestamp
178      */
179     portCryptoPseudoRandomGeneratorDestroy(pKernelVideoEngine->videoTraceInfo.pVideoLogPrng);
180     pKernelVideoEngine->videoTraceInfo.pVideoLogPrng = NULL;
181 
182     pKernelVideoEngine->bVideoTraceEnabled = NV_FALSE;
183 }
184