Skip to content

Commit 214c953

Browse files
ttabiDanilo Krummrich
authored andcommitted
drm/nouveau: expose GSP-RM logging buffers via debugfs
The LOGINIT, LOGINTR, LOGRM, and LOGPMU buffers are circular buffers that have printf-like logs from GSP-RM and PMU encoded in them. LOGINIT, LOGINTR, and LOGRM are allocated by Nouveau and their DMA addresses are passed to GSP-RM during initialization. The buffers are required for GSP-RM to initialize properly. LOGPMU is also allocated by Nouveau, but its contents are updated when Nouveau receives an NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT RPC from GSP-RM. Nouveau then copies the RPC to the buffer. The messages are encoded as an array of variable-length structures that contain the parameters to an NV_PRINTF call. The format string and parameter count are stored in a special ELF image that contains only logging strings. This image is not currently shipped with the Nvidia driver. There are two methods to extract the logs. OpenRM tries to load the logging ELF, and if present, parses the log buffers in real time and outputs the strings to the kernel console. Alternatively, and this is the method used by this patch, the buffers can be exposed to user space, and a user-space tool (along with the logging ELF image) can parse the buffer and dump the logs. This method has the advantage that it allows the buffers to be parsed even when the logging ELF file is not available to the user. However, it has the disadvantage the debugfs entries need to remain until the driver is unloaded. The buffers are exposed via debugfs. If GSP-RM fails to initialize, then Nouveau immediately shuts down the GSP interface. This would normally also deallocate the logging buffers, thereby preventing the user from capturing the debug logs. To avoid this, introduce the keep-gsp-logging command line parameter. If specified, and if at least one logging buffer has content, then Nouveau will migrate these buffers into new debugfs entries that are retained until the driver unloads. An end-user can capture the logs using the following commands: cp /sys/kernel/debug/nouveau/<path>/loginit loginit cp /sys/kernel/debug/nouveau/<path>/logrm logrm cp /sys/kernel/debug/nouveau/<path>/logintr logintr cp /sys/kernel/debug/nouveau/<path>/logpmu logpmu where (for a PCI device) <path> is the PCI ID of the GPU (e.g. 0000:65:00.0). Since LOGPMU is not needed for normal GSP-RM operation, it is only created if debugfs is available. Otherwise, the NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT RPCs are ignored. A simple way to test the buffer migration feature is to have nvkm_gsp_init() return an error code. Tested-by: Ben Skeggs <[email protected]> Signed-off-by: Timur Tabi <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 7c995e2 commit 214c953

File tree

4 files changed

+528
-1
lines changed

4 files changed

+528
-1
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. */
3+
4+
#ifndef __NVIF_LOG_H__
5+
#define __NVIF_LOG_H__
6+
7+
#ifdef CONFIG_DEBUG_FS
8+
9+
/**
10+
* nvif_log - structure for tracking logging buffers
11+
* @entry: an entry in a list of struct nvif_logs
12+
* @shutdown: pointer to function to call to clean up
13+
*
14+
* Structure used to track logging buffers so that they can be cleaned up
15+
* when the module exits.
16+
*
17+
* The @shutdown function is called when the module exits. It should free all
18+
* backing resources, such as logging buffers.
19+
*/
20+
struct nvif_log {
21+
struct list_head entry;
22+
void (*shutdown)(struct nvif_log *log);
23+
};
24+
25+
/**
26+
* nvif_logs - linked list of nvif_log objects
27+
*/
28+
struct nvif_logs {
29+
struct list_head head;
30+
};
31+
32+
#define NVIF_LOGS_DECLARE(logs) \
33+
struct nvif_logs logs = { LIST_HEAD_INIT(logs.head) }
34+
35+
static inline void nvif_log_shutdown(struct nvif_logs *logs)
36+
{
37+
if (!list_empty(&logs->head)) {
38+
struct nvif_log *log, *n;
39+
40+
list_for_each_entry_safe(log, n, &logs->head, entry) {
41+
/* shutdown() should also delete the log entry */
42+
log->shutdown(log);
43+
}
44+
}
45+
}
46+
47+
extern struct nvif_logs gsp_logs;
48+
49+
#endif
50+
51+
#endif

drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <core/falcon.h>
66
#include <core/firmware.h>
77

8+
#include <linux/debugfs.h>
9+
810
#define GSP_PAGE_SHIFT 12
911
#define GSP_PAGE_SIZE BIT(GSP_PAGE_SHIFT)
1012

@@ -220,6 +222,24 @@ struct nvkm_gsp {
220222

221223
/* The size of the registry RPC */
222224
size_t registry_rpc_size;
225+
226+
#ifdef CONFIG_DEBUG_FS
227+
/*
228+
* Logging buffers in debugfs. The wrapper objects need to remain
229+
* in memory until the dentry is deleted.
230+
*/
231+
struct {
232+
struct dentry *parent;
233+
struct dentry *init;
234+
struct dentry *rm;
235+
struct dentry *intr;
236+
struct dentry *pmu;
237+
} debugfs;
238+
struct debugfs_blob_wrapper blob_init;
239+
struct debugfs_blob_wrapper blob_intr;
240+
struct debugfs_blob_wrapper blob_rm;
241+
struct debugfs_blob_wrapper blob_pmu;
242+
#endif
223243
};
224244

225245
static inline bool

drivers/gpu/drm/nouveau/nouveau_drm.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/vga_switcheroo.h>
3131
#include <linux/mmu_notifier.h>
3232
#include <linux/dynamic_debug.h>
33+
#include <linux/debugfs.h>
3334

3435
#include <drm/clients/drm_client_setup.h>
3536
#include <drm/drm_drv.h>
@@ -47,6 +48,7 @@
4748
#include <nvif/fifo.h>
4849
#include <nvif/push006c.h>
4950
#include <nvif/user.h>
51+
#include <nvif/log.h>
5052

5153
#include <nvif/class.h>
5254
#include <nvif/cl0002.h>
@@ -115,6 +117,16 @@ static struct drm_driver driver_platform;
115117

116118
#ifdef CONFIG_DEBUG_FS
117119
struct dentry *nouveau_debugfs_root;
120+
121+
/**
122+
* gsp_logs - list of nvif_log GSP-RM logging buffers
123+
*
124+
* Head pointer to a a list of nvif_log buffers that is created for each GPU
125+
* upon GSP shutdown if the "keep_gsp_logging" command-line parameter is
126+
* specified. This is used to track the alternative debugfs entries for the
127+
* GSP-RM logs.
128+
*/
129+
NVIF_LOGS_DECLARE(gsp_logs);
118130
#endif
119131

120132
static u64
@@ -1482,6 +1494,10 @@ nouveau_drm_exit(void)
14821494
if (IS_ENABLED(CONFIG_DRM_NOUVEAU_SVM))
14831495
mmu_notifier_synchronize();
14841496

1497+
#ifdef CONFIG_DEBUG_FS
1498+
nvif_log_shutdown(&gsp_logs);
1499+
#endif
1500+
14851501
nouveau_module_debugfs_fini();
14861502
}
14871503

0 commit comments

Comments
 (0)