Files
open-gpu-kernel-modules/src/nvidia/src/libraries/crashcat/crashcat_engine.c
Maneet Singh f59818b751 535.113.01
2023-09-21 10:43:43 -07:00

366 lines
12 KiB
C

/*
* SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define NVOC_CRASHCAT_ENGINE_H_PRIVATE_ACCESS_ALLOWED
#include "crashcat/crashcat_engine.h"
#include "crashcat/crashcat_queue.h"
#include "crashcat/crashcat_wayfinder.h"
#include "utils/nvassert.h"
#include "nv-crashcat-decoder.h"
static NV_INLINE NvU64 _crashcatEngineComputeDescriptorKey(NV_CRASHCAT_MEM_APERTURE, NvU64);
static CrashCatBufferDescriptor *_crashcatEngineCreateBufferDescriptor(CrashCatEngine *,
NV_CRASHCAT_MEM_APERTURE,
NvU64, NvU64, void *);
static NV_INLINE void _crashcatEngineDestroyBufferDescriptor(CrashCatEngine *,
CrashCatBufferDescriptor *);
static void *_crashcatEngineMapBufferDescriptor(CrashCatEngine *, CrashCatBufferDescriptor *);
static void _crashcatEngineUnmapBufferDescriptor(CrashCatEngine *, CrashCatBufferDescriptor *);
NV_STATUS crashcatEngineLoadWayfinder_IMPL(CrashCatEngine *pCrashCatEng)
{
NvU32 wfl0Offset = crashcatEngineGetWFL0Offset(pCrashCatEng);
NvU32 wfl0 = crashcatEnginePriRead(pCrashCatEng, wfl0Offset);
// Has the L0 wayfinder been populated yet?
if (!crashcatWayfinderL0Valid(wfl0))
return NV_WARN_NOTHING_TO_DO;
NV_CHECK_OK_OR_RETURN(LEVEL_ERROR,
objCreate(&pCrashCatEng->pWayfinder, pCrashCatEng, CrashCatWayfinder,
crashcatWayfinderL0Version(wfl0), // halspec args
wfl0)); // constructor args
return NV_OK;
}
CrashCatReport *crashcatEngineGetNextCrashReport_IMPL(CrashCatEngine *pCrashCatEng)
{
// Don't attempt to probe for reports if CrashCat is not configured
if (!crashcatEngineConfigured(pCrashCatEng))
return NULL;
// No reports if there's no wayfinder yet
if ((pCrashCatEng->pWayfinder == NULL) &&
(crashcatEngineLoadWayfinder(pCrashCatEng) != NV_OK))
return NULL;
CrashCatQueue *pQueue = crashcatWayfinderGetReportQueue_HAL(pCrashCatEng->pWayfinder);
if (pQueue != NULL)
return crashcatQueueConsumeNextReport_HAL(pQueue);
return NULL;
}
NV_STATUS crashcatEngineConstruct_IMPL
(
CrashCatEngine *pCrashCatEng
)
{
mapInitIntrusive(&pCrashCatEng->registeredCrashBuffers);
mapInitIntrusive(&pCrashCatEng->mappedCrashBuffers);
return NV_OK;
}
void crashcatEngineDestruct_IMPL
(
CrashCatEngine *pCrashCatEng
)
{
crashcatEngineUnload(pCrashCatEng);
// All buffers should be unmapped and unregistered before the destructor is called
NV_ASSERT(mapCount(&pCrashCatEng->mappedCrashBuffers) == 0);
NV_ASSERT(mapCount(&pCrashCatEng->registeredCrashBuffers) == 0);
mapDestroy(&pCrashCatEng->mappedCrashBuffers);
mapDestroy(&pCrashCatEng->registeredCrashBuffers);
}
void crashcatEngineUnload_IMPL
(
CrashCatEngine *pCrashCatEng
)
{
objDelete(pCrashCatEng->pWayfinder);
}
// Non-NVOC wrapper to handle variadic arguments
void crashcatEnginePrintf(CrashCatEngine *pCrashCatEng, NvBool bReportStart, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
// Dispatches virtual function with va_list
crashcatEngineVprintf(pCrashCatEng, bReportStart, fmt, args);
va_end(args);
}
static NV_INLINE NvU64 _crashcatEngineComputeDescriptorKey
(
NV_CRASHCAT_MEM_APERTURE aperture,
NvU64 offset
)
{
// Offset should be at least 8-byte aligned so that the aperture bits can be stuffed
NV_ASSERT_CHECKED((offset & (sizeof(NvU64) - 1)) == 0);
return (offset | (NvU64)aperture);
}
static CrashCatBufferDescriptor *_crashcatEngineCreateBufferDescriptor
(
CrashCatEngine *pCrashCatEng,
NV_CRASHCAT_MEM_APERTURE aperture,
NvU64 offset,
NvU64 size,
void *pEngPriv
)
{
CrashCatBufferDescriptor *pBufDesc = portMemAllocNonPaged(sizeof(*pBufDesc));
if (pBufDesc == NULL)
return NULL;
portMemSet(pBufDesc, 0, sizeof(*pBufDesc));
pBufDesc->bRegistered = NV_FALSE;
pBufDesc->aperture = aperture;
pBufDesc->physOffset = offset;
pBufDesc->size = size;
pBufDesc->pEngPriv = pEngPriv;
return pBufDesc;
}
static NV_INLINE void _crashcatEngineDestroyBufferDescriptor
(
CrashCatEngine *pCrashCatEng,
CrashCatBufferDescriptor *pBufDesc
)
{
portMemFree(pBufDesc);
}
static void *_crashcatEngineMapBufferDescriptor
(
CrashCatEngine *pCrashCatEng,
CrashCatBufferDescriptor *pBufDesc
)
{
void *ptr = NULL;
switch (pBufDesc->aperture)
{
case NV_CRASHCAT_MEM_APERTURE_SYSGPA:
case NV_CRASHCAT_MEM_APERTURE_FBGPA:
{
ptr = crashcatEngineMapBufferDescriptor(pCrashCatEng, pBufDesc);
NV_CHECK_OR_RETURN(LEVEL_ERROR, ptr != NULL, NULL);
break;
}
case NV_CRASHCAT_MEM_APERTURE_DMEM:
case NV_CRASHCAT_MEM_APERTURE_EMEM:
{
ptr = portMemAllocNonPaged(pBufDesc->size);
NV_CHECK_OR_RETURN(LEVEL_ERROR, ptr != NULL, NULL);
break;
}
default:
NV_PRINTF(LEVEL_WARNING,
"Unknown CrashCat aperture ID 0x%02x (offset = 0x%" NvU64_fmtx
", size = 0x%" NvU64_fmtx ")\n",
pBufDesc->aperture, pBufDesc->physOffset, pBufDesc->size);
break;
}
return ptr;
}
static void _crashcatEngineUnmapBufferDescriptor
(
CrashCatEngine *pCrashCatEng,
CrashCatBufferDescriptor *pBufDesc
)
{
switch (pBufDesc->aperture)
{
case NV_CRASHCAT_MEM_APERTURE_SYSGPA:
case NV_CRASHCAT_MEM_APERTURE_FBGPA:
crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
break;
case NV_CRASHCAT_MEM_APERTURE_DMEM:
case NV_CRASHCAT_MEM_APERTURE_EMEM:
portMemFree(pBufDesc->pMapping);
break;
default:
NV_PRINTF(LEVEL_WARNING,
"Unknown CrashCat aperture ID 0x%02x (offset = 0x%" NvU64_fmtx
", size = 0x%" NvU64_fmtx ")\n",
pBufDesc->aperture, pBufDesc->physOffset, pBufDesc->size);
break;
}
}
NV_STATUS crashcatEngineRegisterCrashBuffer_IMPL
(
CrashCatEngine *pCrashCatEng,
NV_CRASHCAT_MEM_APERTURE aperture,
NvU64 offset,
NvU64 size,
void *pEngPriv
)
{
NV_CHECK_OR_RETURN(LEVEL_INFO, (aperture == NV_CRASHCAT_MEM_APERTURE_SYSGPA) ||
(aperture == NV_CRASHCAT_MEM_APERTURE_FBGPA),
NV_ERR_INVALID_ARGUMENT);
NV_CHECK_OR_RETURN(LEVEL_INFO, size > 0, NV_ERR_INVALID_ARGUMENT);
NV_CHECK_OR_RETURN(LEVEL_INFO, pEngPriv != NULL, NV_ERR_INVALID_ARGUMENT);
// Create a crashcat buffer descriptor and register in the registeredCrashBuffers
CrashCatBufferDescriptor *pBufDesc = _crashcatEngineCreateBufferDescriptor(pCrashCatEng,
aperture,
offset, size,
pEngPriv);
if (pBufDesc == NULL)
return NV_ERR_NO_MEMORY;
pBufDesc->bRegistered = NV_TRUE;
NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
if (!mapInsertExisting(&pCrashCatEng->registeredCrashBuffers, key, pBufDesc))
{
_crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
return NV_ERR_INSERT_DUPLICATE_NAME;
}
return NV_OK;
}
void crashcatEngineUnregisterCrashBuffer_IMPL
(
CrashCatEngine *pCrashCatEng,
NV_CRASHCAT_MEM_APERTURE aperture,
NvU64 offset,
NvU64 size
)
{
NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->registeredCrashBuffers, key);
if (pBufDesc == NULL)
return;
NV_ASSERT_CHECKED(pBufDesc->size == size);
//
// CrashCat should be unloaded from the engine before unregistering the crash buffer.
// Unload will unmap all buffers.
//
NV_ASSERT_CHECKED(pBufDesc->pMapping == NULL);
mapRemove(&pCrashCatEng->registeredCrashBuffers, pBufDesc);
_crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
}
void *crashcatEngineMapCrashBuffer_IMPL
(
CrashCatEngine *pCrashCatEng,
NV_CRASHCAT_MEM_APERTURE aperture,
NvU64 offset,
NvU64 size
)
{
NvU64 key = _crashcatEngineComputeDescriptorKey(aperture, offset);
CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->registeredCrashBuffers, key);
// Sysmem buffers always need to be pre-registered
if ((aperture != NV_CRASHCAT_MEM_APERTURE_SYSGPA) && (pBufDesc == NULL))
pBufDesc = _crashcatEngineCreateBufferDescriptor(pCrashCatEng, aperture,
offset, size, NULL);
NV_CHECK_OR_RETURN(LEVEL_ERROR, pBufDesc != NULL, NULL);
NV_ASSERT_CHECKED(pBufDesc->size == size);
pBufDesc->pMapping = _crashcatEngineMapBufferDescriptor(pCrashCatEng, pBufDesc);
if ((pBufDesc->pMapping == NULL) ||
!mapInsertExisting(&pCrashCatEng->mappedCrashBuffers, (NvU64)pBufDesc->pMapping, pBufDesc))
{
if (pBufDesc->pMapping != NULL)
{
_crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
pBufDesc->pMapping = NULL;
}
//
// If this wasn't a registered buffer descriptor, it was created above, so destroy it
// before returning.
//
if (!pBufDesc->bRegistered)
_crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
return NULL;
}
return pBufDesc->pMapping;
}
void crashcatEngineUnmapCrashBuffer_IMPL
(
CrashCatEngine *pCrashCatEng,
void *ptr
)
{
CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->mappedCrashBuffers, (NvU64)ptr);
if (pBufDesc == NULL)
return;
NV_ASSERT_CHECKED(ptr == pBufDesc->pMapping);
mapRemove(&pCrashCatEng->mappedCrashBuffers, pBufDesc);
_crashcatEngineUnmapBufferDescriptor(pCrashCatEng, pBufDesc);
pBufDesc->pMapping = NULL;
// If this was not a registered buffer, destroy the buffered descriptor now
if (!pBufDesc->bRegistered)
_crashcatEngineDestroyBufferDescriptor(pCrashCatEng, pBufDesc);
}
void crashcatEngineSyncCrashBuffer_IMPL
(
CrashCatEngine *pCrashCatEng,
void *ptr,
NvU32 offset,
NvU32 size
)
{
CrashCatBufferDescriptor *pBufDesc = mapFind(&pCrashCatEng->mappedCrashBuffers, (NvU64)ptr);
NV_ASSERT_OR_RETURN_VOID(pBufDesc != NULL);
// Direct-map buffers don't require any sync
if ((pBufDesc->aperture == NV_CRASHCAT_MEM_APERTURE_SYSGPA) ||
(pBufDesc->aperture == NV_CRASHCAT_MEM_APERTURE_FBGPA))
return;
crashcatEngineSyncBufferDescriptor(pCrashCatEng, pBufDesc, offset, size);
}