[PATCH 1/3] gpu: nova-core: add formatted tracing
Zhi Wang <[email protected]>
| Newsgroups | dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <cdb03b9b0262ef59f3dd93ee3c7bfaa38312ddc4.1785907106.git.zhiw@nvidia.com> |
Provide formatted trace events for general driver, FSP, GSP and vGPU messages. Add a shared event class and a formatting helper that avoids formatting disabled events and uses a fixed-size stack buffer. Signed-off-by: Zhi Wang <[email protected]> --- drivers/gpu/Makefile | 4 +- drivers/gpu/nova-core/nova_core.rs | 1 + drivers/gpu/nova-core/trace.c | 5 + drivers/gpu/nova-core/trace.h | 52 +++++++++ drivers/gpu/nova-core/trace.rs | 162 +++++++++++++++++++++++++++++ rust/bindings/bindings_helper.h | 4 + 6 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/nova-core/trace.c create mode 100644 drivers/gpu/nova-core/trace.h create mode 100644 drivers/gpu/nova-core/trace.rs diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile index e372fc02139f..d26e7dea9e66 100644 --- a/drivers/gpu/Makefile +++ b/drivers/gpu/Makefile @@ -14,7 +14,9 @@ obj-$(CONFIG_TRACE_GPU_MEM) += trace/ # system supports cross-crate dependencies natively. obj-$(CONFIG_NOVA_CORE) += nova-core.o -nova-core-y := nova-core/nova_core.o nova-core/nova_core_exports.o +nova-core-y := nova-core/nova_core.o \ + nova-core/trace.o \ + nova-core/nova_core_exports.o obj-$(CONFIG_DRM_NOVA) += nova-drm.o nova-drm-y := drm/nova/nova.o diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs index 35a8b1214b0e..85ee5067ef56 100644 --- a/drivers/gpu/nova-core/nova_core.rs +++ b/drivers/gpu/nova-core/nova_core.rs @@ -22,6 +22,7 @@ mod num; mod regs; mod sbuffer; +mod trace; mod vbios; mod vgpu; diff --git a/drivers/gpu/nova-core/trace.c b/drivers/gpu/nova-core/trace.c new file mode 100644 index 000000000000..c72cb0f65b47 --- /dev/null +++ b/drivers/gpu/nova-core/trace.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define CREATE_TRACE_POINTS +#define CREATE_RUST_TRACE_POINTS +#include "trace.h" diff --git a/drivers/gpu/nova-core/trace.h b/drivers/gpu/nova-core/trace.h new file mode 100644 index 000000000000..a8e5181ba302 --- /dev/null +++ b/drivers/gpu/nova-core/trace.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM nova_core + +#if !defined(_NOVA_CORE_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _NOVA_CORE_TRACE_H_ + +#include <linux/tracepoint.h> + +DECLARE_EVENT_CLASS(nova_core_trace_class, + TP_PROTO(const char *dev, const char *message, size_t message_len), + TP_ARGS(dev, message, message_len), + TP_STRUCT__entry( + __string(dev, dev) + __string_len(message, message, message_len) + ), + TP_fast_assign( + __assign_str(dev); + __assign_str(message); + ), + TP_printk("%s %s", __get_str(dev), __get_str(message)) +); + +DEFINE_EVENT(nova_core_trace_class, nova_core_trace_driver, + TP_PROTO(const char *dev, const char *message, size_t message_len), + TP_ARGS(dev, message, message_len) +); + +DEFINE_EVENT(nova_core_trace_class, nova_core_trace_fsp, + TP_PROTO(const char *dev, const char *message, size_t message_len), + TP_ARGS(dev, message, message_len) +); + +DEFINE_EVENT(nova_core_trace_class, nova_core_trace_gsp, + TP_PROTO(const char *dev, const char *message, size_t message_len), + TP_ARGS(dev, message, message_len) +); + +DEFINE_EVENT(nova_core_trace_class, nova_core_trace_vgpu, + TP_PROTO(const char *dev, const char *message, size_t message_len), + TP_ARGS(dev, message, message_len) +); + +#endif /* _NOVA_CORE_TRACE_H_ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/gpu/nova-core +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> diff --git a/drivers/gpu/nova-core/trace.rs b/drivers/gpu/nova-core/trace.rs new file mode 100644 index 000000000000..893479b3fcb5 --- /dev/null +++ b/drivers/gpu/nova-core/trace.rs @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Nova tracepoint helpers. + +use kernel::{ + ffi::c_char, + fmt::{ + self, + Write, // + }, + str::{ + CStr, + CStrExt, + Formatter, // + }, // +}; + +const MESSAGE_MAX: usize = 512; + +// To add another formatted Nova Core trace event: +// +// 1. Define it from `nova_core_trace_class` in `trace.h`. +// 2. Declare its Rust entry point with `declare_nova_core_trace!` below. +// 3. Add a public frontend macro that passes its event name to +// `nova_core_trace_impl!`, following the examples at the end of this file. +pub(crate) mod raw { + use super::c_char; + + macro_rules! declare_nova_core_trace { + ($event:ident) => { + kernel::tracepoint::declare_trace! { + /// # Safety + /// + /// `dev` must point to a valid NUL-terminated string, and + /// `message` must point to `message_len` readable bytes for + /// this call. + pub(crate) unsafe fn $event( + dev: *const c_char, + message: *const c_char, + message_len: usize, + ); + } + }; + } + + declare_nova_core_trace!(nova_core_trace_driver); + declare_nova_core_trace!(nova_core_trace_fsp); + declare_nova_core_trace!(nova_core_trace_gsp); + declare_nova_core_trace!(nova_core_trace_vgpu); +} + +/// Formats and emits a Nova Core text trace event. +/// +/// # Safety +/// +/// `trace` must synchronously consume `dev`, `message`, and `message_len` +/// according to the `nova_core_trace_class` event prototype. +#[expect(dead_code)] +pub(crate) unsafe fn nova_core_trace_fmt( + dev: &CStr, + args: fmt::Arguments<'_>, + trace: unsafe fn(*const c_char, *const c_char, usize), +) { + let mut message = [0u8; MESSAGE_MAX]; + let message_len = { + let mut formatter = Formatter::new(&mut message); + + let _ = formatter.write_fmt(args); + formatter.bytes_written().min(MESSAGE_MAX) + }; + + // SAFETY: The caller guarantees that `trace` synchronously consumes its + // arguments. The device name is NUL-terminated, and `message` contains + // `message_len` initialized bytes. + unsafe { + trace( + dev.as_char_ptr(), + message.as_ptr().cast::<c_char>(), + message_len, + ) + } +} + +#[expect(unused_macros)] +macro_rules! nova_core_trace_impl { + ($event:ident, $dev:expr, $($arg:tt)*) => {{ + #[cfg(CONFIG_TRACEPOINTS)] + let should_trace = { + // SAFETY: `$event` names a real C tracepoint static key. + unsafe { + kernel::macros::paste! { + kernel::jump_label::static_branch_unlikely!( + kernel::bindings::[<__tracepoint_ $event>], + kernel::bindings::tracepoint, + key + ) + } + } + }; + + #[cfg(not(CONFIG_TRACEPOINTS))] + let should_trace = false; + + if should_trace { + match ($dev, kernel::prelude::fmt!($($arg)*)) { + (dev, args) => { + // SAFETY: `$event` has the event-class prototype required + // by `nova_core_trace_fmt`. + unsafe { + $crate::trace::nova_core_trace_fmt( + dev.as_ref().name(), + args, + $crate::trace::raw::$event, + ) + } + } + } + } + }}; +} + +// Frontend macros expand in their caller's module and invoke this helper by +// path, so the re-export must be visible from the parent module. +#[expect(unused_imports)] +pub(super) use nova_core_trace_impl; + +#[expect(unused_macros)] +macro_rules! nova_core_trace_driver { + ($dev:expr, $($arg:tt)*) => { + $crate::trace::nova_core_trace_impl!(nova_core_trace_driver, $dev, $($arg)*) + }; +} + +#[expect(unused_macros)] +macro_rules! nova_core_trace_fsp { + ($dev:expr, $($arg:tt)*) => { + $crate::trace::nova_core_trace_impl!(nova_core_trace_fsp, $dev, $($arg)*) + }; +} + +#[expect(unused_macros)] +macro_rules! nova_core_trace_gsp { + ($dev:expr, $($arg:tt)*) => { + $crate::trace::nova_core_trace_impl!(nova_core_trace_gsp, $dev, $($arg)*) + }; +} + +#[expect(unused_macros)] +macro_rules! nova_core_trace_vgpu { + ($dev:expr, $($arg:tt)*) => { + $crate::trace::nova_core_trace_impl!(nova_core_trace_vgpu, $dev, $($arg)*) + }; +} + +#[expect(unused_imports)] +pub(crate) use nova_core_trace_driver; +#[expect(unused_imports)] +pub(crate) use nova_core_trace_fsp; +#[expect(unused_imports)] +pub(crate) use nova_core_trace_gsp; +#[expect(unused_imports)] +pub(crate) use nova_core_trace_vgpu; diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 1124785e210b..d1e0a60e370f 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -165,3 +165,7 @@ const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DI #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" #endif + +#if IS_ENABLED(CONFIG_NOVA_CORE) +#include "../../drivers/gpu/nova-core/trace.h" +#endif -- 2.53.0