Create read-only debugfs entries for LOGINIT, LOGRM, and LOGINTR, which are the three primary printf logging buffers from GSP-RM. LOGPMU will be added at a later date, as it requires it support for its RPC message first.
This patch uses the `pin_init_scope` feature to create the entries. `pin_init_scope` solves the lifetime issue over the `DEBUGFS_ROOT` reference by delaying its acquisition until the time the entry is actually initialized. Co-developed-by: Alexandre Courbot <[email protected]> Signed-off-by: Alexandre Courbot <[email protected]> Signed-off-by: Timur Tabi <[email protected]> --- drivers/gpu/nova-core/gsp.rs | 49 ++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs index 174feaca0a6b..863a75b93c30 100644 --- a/drivers/gpu/nova-core/gsp.rs +++ b/drivers/gpu/nova-core/gsp.rs @@ -3,6 +3,8 @@ mod boot; use kernel::{ + c_str, + debugfs, device, dma::{ CoherentAllocation, @@ -100,17 +102,24 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> { } } -/// GSP runtime data. -#[pin_data] -pub(crate) struct Gsp { - /// Libos arguments. - pub(crate) libos: CoherentAllocation<LibosMemoryRegionInitArgument>, +/// Log buffers used by GSP-RM for debug logging. +struct LogBuffers { /// Init log buffer. loginit: LogBuffer, /// Interrupts log buffer. logintr: LogBuffer, /// RM log buffer. logrm: LogBuffer, +} + +/// GSP runtime data. +#[pin_data] +pub(crate) struct Gsp { + /// Libos arguments. + pub(crate) libos: CoherentAllocation<LibosMemoryRegionInitArgument>, + /// Log buffers, optionally exposed via debugfs. + #[pin] + logs: debugfs::Scope<LogBuffers>, /// Command queue. pub(crate) cmdq: Cmdq, /// RM arguments. @@ -123,15 +132,17 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error pin_init::pin_init_scope(move || { let dev = pdev.as_ref(); + // Create log buffers before try_pin_init! so they're accessible throughout + let loginit = LogBuffer::new(dev)?; + let logintr = LogBuffer::new(dev)?; + let logrm = LogBuffer::new(dev)?; + Ok(try_pin_init!(Self { libos: CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent( dev, GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(), GFP_KERNEL | __GFP_ZERO, )?, - loginit: LogBuffer::new(dev)?, - logintr: LogBuffer::new(dev)?, - logrm: LogBuffer::new(dev)?, cmdq: Cmdq::new(dev)?, rmargs: CoherentAllocation::<GspArgumentsPadded>::alloc_coherent( dev, @@ -152,6 +163,28 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error dma_write!(rmargs[0].inner = fw::GspArgumentsCached::new(cmdq))?; dma_write!(libos[3] = LibosMemoryRegionInitArgument::new("RMARGS", rmargs))?; }, + logs <- { + let log_buffers = LogBuffers { + loginit, + logintr, + logrm, + }; + + #[allow(static_mut_refs)] + // SAFETY: `DEBUGFS_ROOT` is created before driver registration and cleared + // after driver unregistration, so no probe() can race with its modification. + // PANIC: `DEBUGFS_ROOT` cannot be `None` here. It is set before driver + // registration and cleared after driver unregistration, so it is always + // `Some` for the entire lifetime that probe() can be called. + let log_parent: &debugfs::Dir = unsafe { crate::DEBUGFS_ROOT.as_ref() } + .expect("DEBUGFS_ROOT not initialized"); + + log_parent.scope(log_buffers, dev.name(), |logs, dir| { + dir.read_binary_file(c_str!("loginit"), &logs.loginit.0); + dir.read_binary_file(c_str!("logintr"), &logs.logintr.0); + dir.read_binary_file(c_str!("logrm"), &logs.logrm.0); + }) + }, })) }) } -- 2.52.0
