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 #define NVOC_CRASHCAT_ENGINE_H_PRIVATE_ACCESS_ALLOWED
25 #include "crashcat/crashcat_engine.h"
26 #include "crashcat/crashcat_queue.h"
27 #include "crashcat/crashcat_wayfinder.h"
28 #include "utils/nvassert.h"
29 #include "nv-crashcat-decoder.h"
30
31 static NV_INLINE NvU64 _crashcatEngineComputeDescriptorKey(NV_CRASHCAT_MEM_APERTURE, NvU64);
32 static CrashCatBufferDescriptor *_crashcatEngineCreateBufferDescriptor(CrashCatEngine *,
33 NV_CRASHCAT_MEM_APERTURE,
34 NvU64, NvU64, void *);
35 static NV_INLINE void _crashcatEngineDestroyBufferDescriptor(CrashCatEngine *,
36 CrashCatBufferDescriptor *);
37 static void *_crashcatEngineMapBufferDescriptor(CrashCatEngine *, CrashCatBufferDescriptor *);
38 static void _crashcatEngineUnmapBufferDescriptor(CrashCatEngine *, CrashCatBufferDescriptor *);
39
crashcatEngineLoadWayfinder_IMPL(CrashCatEngine * pCrashCatEng)40 NV_STATUS crashcatEngineLoadWayfinder_IMPL(CrashCatEngine *pCrashCatEng)
41 {
42 NvU32 wfl0Offset = crashcatEngineGetWFL0Offset(pCrashCatEng);
43 NvU32 wfl0 = crashcatEnginePriRead(pCrashCatEng, wfl0Offset);
44
45 // Has the L0 wayfinder been populated yet?
46 if (!crashcatWayfinderL0Valid(wfl0))
47 return NV_WARN_NOTHING_TO_DO;
48
49 NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
50 objCreate(&pCrashCatEng->pWayfinder, pCrashCatEng, CrashCatWayfinder,
51 crashcatWayfinderL0Version(wfl0), // halspec args
52 wfl0)); // constructor args
53
54 return NV_OK;
55 }
56
crashcatEngineGetNextCrashReport_IMPL(CrashCatEngine * pCrashCatEng)57 CrashCatReport *crashcatEngineGetNextCrashReport_IMPL(CrashCatEngine *pCrashCatEng)
58 {
59 // Don't attempt to probe for reports if CrashCat is not configured
60 if (!crashcatEngineConfigured(pCrashCatEng))
61 return NULL;
62
63 // No reports if there's no wayfinder yet
64 if ((pCrashCatEng->pWayfinder == NULL) &&
65 (crashcatEngineLoadWayfinder(pCrashCatEng) != NV_OK))
66 return NULL;
67
68 CrashCatQueue *pQueue = crashcatWayfinderGetReportQueue_HAL(pCrashCatEng->pWayfinder);
69 if (pQueue != NULL)
70 return crashcatQueueConsumeNextReport_HAL(pQueue);
71
72 return NULL;
73 }
74
crashcatEngineConstruct_IMPL(CrashCatEngine * pCrashCatEng)75 NV_STATUS crashcatEngineConstruct_IMPL
76 (
77 CrashCatEngine *pCrashCatEng
78 )
79 {
80 mapInitIntrusive(&pCrashCatEng->registeredCrashBuffers);
81 mapInitIntrusive(&pCrashCatEng->mappedCrashBuffers);
82
83 return NV_OK;
84 }
85
crashcatEngineDestruct_IMPL(CrashCatEngine * pCrashCatEng)86 void crashcatEngineDestruct_IMPL
87 (
88 CrashCatEngine *pCrashCatEng
89 )
90 {
91 crashcatEngineUnload(pCrashCatEng);
92
93 // All buffers should be unmapped and unregistered before the destructor is called
94 NV_ASSERT(mapCount(&pCrashCatEng->mappedCrashBuffers) == 0);
95 NV_ASSERT(mapCount(&pCrashCatEng->registeredCrashBuffers) == 0);
96
97 mapDestroy(&pCrashCatEng->mappedCrashBuffers);
98 mapDestroy(&pCrashCatEng->registeredCrashBuffers);
99 }
100
crashcatEngineUnload_IMPL(CrashCatEngine * pCrashCatEng)101 void crashcatEngineUnload_IMPL
102 (
103 CrashCatEngine *pCrashCatEng
104 )
105 {
106 objDelete(pCrashCatEng->pWayfinder);
107 }
108
109 // Non-NVOC wrapper to handle variadic arguments
crashcatEnginePrintf(CrashCatEngine * pCrashCatEng,NvBool bReportStart,const char * fmt,...)110 void crashcatEnginePrintf(CrashCatEngine *pCrashCatEng, NvBool bReportStart, const char *fmt, ...)
111 {
112 va_list args;
113 va_start(args, fmt);
114 // Dispatches virtual function with va_list
115 crashcatEngineVprintf(pCrashCatEng, bReportStart, fmt, args);
116 va_end(args);
117 }
118
_crashcatEngineComputeDescriptorKey(NV_CRASHCAT_MEM_APERTURE aperture,NvU64 offset)119 static NV_INLINE NvU64 _crashcatEngineComputeDescriptorKey
120 (
121 NV_CRASHCAT_MEM_APERTURE aperture,
122 NvU64 offset
123 )
124 {
125 // Offset should be at least 8-byte aligned so that the aperture bits can be stuffed
126 NV_ASSERT_CHECKED((offset & (sizeof(NvU64) - 1)) == 0);
127 return (offset | (NvU64)aperture);
128 }
129
_crashcatEngineCreateBufferDescriptor(CrashCatEngine * pCrashCatEng,NV_CRASHCAT_MEM_APERTURE aperture,NvU64 offset,NvU64 size,void * pEngPriv)130 static CrashCatBufferDescriptor *_crashcatEngineCreateBufferDescriptor
131 (
132 CrashCatEngine *pCrashCatEng,
133 NV_CRASHCAT_MEM_APERTURE aperture,
134 NvU64 offset,
135 NvU64 size,
136 void *pEngPriv
137 )
138 {
139 CrashCatBufferDescriptor *pBufDesc = portMemAllocNonPaged(sizeof(*pBufDesc));
140 if (pBufDesc == NULL)
141 return NULL;
142
143 portMemSet(pBufDesc, 0, sizeof(*pBufDesc));
144
145 pBufDesc->bRegistered = NV_FALSE;
146 pBufDesc->aperture = aperture;
147 pBufDesc->physOffset = offset;
148 pBufDesc->size = size;
149 pBufDesc->pEngPriv = pEngPriv;
150
151 return pBufDesc;
152 }
153
_crashcatEngineDestroyBufferDescriptor(CrashCatEngine * pCrashCatEng,CrashCatBufferDescriptor * pBufDesc)154 static NV_INLINE void _crashcatEngineDestroyBufferDescriptor
155 (
156 CrashCatEngine *pCrashCatEng,
157 CrashCatBufferDescriptor *pBufDesc
158 )
159 {
160 portMemFree(pBufDesc);
161 }
162
_crashcatEngineMapBufferDescriptor(CrashCatEngine * pCrashCatEng,CrashCatBufferDescriptor * pBufDesc)163 static void *_crashcatEngineMapBufferDescriptor
164 (
165 CrashCatEngine *pCrashCatEng,
166 CrashCatBufferDescriptor *pBufDesc
167 )
168 {
169 void *ptr = NULL;
170
171 switch (pBufDesc->aperture)
172 {
173 case NV_CRASHCAT_MEM_APERTURE_SYSGPA:
174 case NV_CRASHCAT_MEM_APERTURE_FBGPA:
175 {
176 ptr = crashcatEngineMapBufferDescriptor(pCrashCatEng, pBufDesc);
177 NV_CHECK_OR_RETURN(LEVEL_ERROR, ptr != NULL, NULL);
178 break;
179 }
180 case NV_CRASHCAT_MEM_APERTURE_DMEM:
181 case NV_CRASHCAT_MEM_APERTURE_EMEM:
182 {
183 ptr = portMemAllocNonPaged(pBufDesc->size);
184 NV_CHECK_OR_RETURN(LEVEL_ERROR, ptr != NULL, NULL);
185 break;
186 }
187 default:
188 NV_PRINTF(LEVEL_WARNING,
189 "Unknown CrashCat aperture ID 0x%02x (offset = 0x%" NvU64_fmtx
190 ", size = 0x%" NvU64_fmtx ")\n",
191 pBufDesc->aperture, pBufDesc->physOffset, pBufDesc->size);
192 break;
193 }
194
195 return ptr;
196 }
197
_crashcatEngineUnmapBufferDescriptor(CrashCatEngine * pCrashCatEng,CrashCatBufferDescriptor * pBufDesc)198 static void _crashcatEngineUnmapBufferDescriptor
199 (
200 CrashCatEngine *pCrashCatEng,
201 CrashCatBufferDescriptor *pBufDesc
202 )
203 {
204 switch (pBufDesc->aperture)
205 {
206 case NV_CRASHCAT_MEM_APERTURE_SYSGPA:
207 case NV_CRASHCAT_MEM_APERTURE_FBGPA:
208 crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
209 break;
210 case NV_CRASHCAT_MEM_APERTURE_DMEM:
211 case NV_CRASHCAT_MEM_APERTURE_EMEM:
212 portMemFree(pBufDesc->pMapping);
213 break;
214 default:
215 NV_PRINTF(LEVEL_WARNING,
216 "Unknown CrashCat aperture ID 0x%02x (offset = 0x%" NvU64_fmtx
217 ", size = 0x%" NvU64_fmtx ")\n",
218 pBufDesc->aperture, pBufDesc->physOffset, pBufDesc->size);
219 break;
220 }
221 }
222
crashcatEngineRegisterCrashBuffer_IMPL(CrashCatEngine * pCrashCatEng,NV_CRASHCAT_MEM_APERTURE aperture,NvU64 offset,NvU64 size,void * pEngPriv)223 NV_STATUS crashcatEngineRegisterCrashBuffer_IMPL
224 (
225 CrashCatEngine *pCrashCatEng,
226 NV_CRASHCAT_MEM_APERTURE aperture,
227 NvU64 offset,
228 NvU64 size,
229 void *pEngPriv
230 )
231 {
232 NV_CHECK_OR_RETURN(LEVEL_INFO, (aperture == NV_CRASHCAT_MEM_APERTURE_SYSGPA) ||
233 (aperture == NV_CRASHCAT_MEM_APERTURE_FBGPA),
234 NV_ERR_INVALID_ARGUMENT);
235 NV_CHECK_OR_RETURN(LEVEL_INFO, size > 0, NV_ERR_INVALID_ARGUMENT);
236 NV_CHECK_OR_RETURN(LEVEL_INFO, pEngPriv != NULL, NV_ERR_INVALID_ARGUMENT);
237
238 // Create a crashcat buffer descriptor and register in the registeredCrashBuffers
239 CrashCatBufferDescriptor *pBufDesc = _crashcatEngineCreateBufferDescriptor(pCrashCatEng,
240 aperture,
241 offset, size,
242 pEngPriv);
243 if (pBufDesc == NULL)
244 return NV_ERR_NO_MEMORY;
245
246 pBufDesc->bRegistered = NV_TRUE;
247
248 NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
249 if (!mapInsertExisting(&pCrashCatEng->registeredCrashBuffers, key, pBufDesc))
250 {
251 _crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
252 return NV_ERR_INSERT_DUPLICATE_NAME;
253 }
254
255 return NV_OK;
256 }
257
crashcatEngineUnregisterCrashBuffer_IMPL(CrashCatEngine * pCrashCatEng,NV_CRASHCAT_MEM_APERTURE aperture,NvU64 offset,NvU64 size)258 void crashcatEngineUnregisterCrashBuffer_IMPL
259 (
260 CrashCatEngine *pCrashCatEng,
261 NV_CRASHCAT_MEM_APERTURE aperture,
262 NvU64 offset,
263 NvU64 size
264 )
265 {
266 NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
267 CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->registeredCrashBuffers, key);
268 if (pBufDesc == NULL)
269 return;
270
271 NV_ASSERT_CHECKED(pBufDesc->size == size);
272
273 //
274 // CrashCat should be unloaded from the engine before unregistering the crash buffer.
275 // Unload will unmap all buffers.
276 //
277 NV_ASSERT_CHECKED(pBufDesc->pMapping == NULL);
278
279 mapRemove(&pCrashCatEng->registeredCrashBuffers, pBufDesc);
280 _crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
281 }
282
crashcatEngineMapCrashBuffer_IMPL(CrashCatEngine * pCrashCatEng,NV_CRASHCAT_MEM_APERTURE aperture,NvU64 offset,NvU64 size)283 void *crashcatEngineMapCrashBuffer_IMPL
284 (
285 CrashCatEngine *pCrashCatEng,
286 NV_CRASHCAT_MEM_APERTURE aperture,
287 NvU64 offset,
288 NvU64 size
289 )
290 {
291 NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
292 CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->registeredCrashBuffers, key);
293
294 // Sysmem buffers always need to be pre-registered
295 if ((aperture != NV_CRASHCAT_MEM_APERTURE_SYSGPA) && (pBufDesc == NULL))
296 pBufDesc = _crashcatEngineCreateBufferDescriptor(pCrashCatEng, aperture,
297 offset, size, NULL);
298
299 NV_CHECK_OR_RETURN(LEVEL_ERROR, pBufDesc != NULL, NULL);
300 NV_ASSERT_CHECKED(pBufDesc->size == size);
301
302 pBufDesc->pMapping = _crashcatEngineMapBufferDescriptor(pCrashCatEng, pBufDesc);
303
304 if ((pBufDesc->pMapping == NULL) ||
305 !mapInsertExisting(&pCrashCatEng->mappedCrashBuffers, (NvU64)pBufDesc->pMapping, pBufDesc))
306 {
307 if (pBufDesc->pMapping != NULL)
308 {
309 _crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
310 pBufDesc->pMapping = NULL;
311 }
312
313 //
314 // If this wasn't a registered buffer descriptor, it was created above, so destroy it
315 // before returning.
316 //
317 if (!pBufDesc->bRegistered)
318 _crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
319
320 return NULL;
321 }
322
323 return pBufDesc->pMapping;
324 }
325
crashcatEngineUnmapCrashBuffer_IMPL(CrashCatEngine * pCrashCatEng,void * ptr)326 void crashcatEngineUnmapCrashBuffer_IMPL
327 (
328 CrashCatEngine *pCrashCatEng,
329 void *ptr
330 )
331 {
332 CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->mappedCrashBuffers, (NvU64)ptr);
333 if (pBufDesc == NULL)
334 return;
335
336 NV_ASSERT_CHECKED(ptr == pBufDesc->pMapping);
337
338 mapRemove(&pCrashCatEng->mappedCrashBuffers, pBufDesc);
339 _crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
340 pBufDesc->pMapping = NULL;
341
342 // If this was not a registered buffer, destroy the buffered descriptor now
343 if (!pBufDesc->bRegistered)
344 _crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
345 }
346
crashcatEngineSyncCrashBuffer_IMPL(CrashCatEngine * pCrashCatEng,void * ptr,NvU32 offset,NvU32 size)347 void crashcatEngineSyncCrashBuffer_IMPL
348 (
349 CrashCatEngine *pCrashCatEng,
350 void *ptr,
351 NvU32 offset,
352 NvU32 size
353 )
354 {
355 CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->mappedCrashBuffers, (NvU64)ptr);
356
357 NV_ASSERT_OR_RETURN_VOID(pBufDesc != NULL);
358
359 // Direct-map buffers don't require any sync
360 if ((pBufDesc->aperture == NV_CRASHCAT_MEM_APERTURE_SYSGPA) ||
361 (pBufDesc->aperture == NV_CRASHCAT_MEM_APERTURE_FBGPA))
362 return;
363
364 crashcatEngineSyncBufferDescriptor(pCrashCatEng, pBufDesc, offset, size);
365 }
366