[PATCH 9/9] drm/tyr: wait for global interface readiness
From: Laura Nao
Date: Tue Sep 15 2026 - 07:06:38 EST
Add a wait helper for global interface readiness using the Job IRQ.
JobIrqEvents signals readiness and wakes waiters when the firmware sets
the GLB bit. After booting the firmware, probe waits until the firmware
reports that the global interface is ready to accept requests.
Register the Job IRQ before booting the firmware so that the initial GLB
event is not missed. Store the JobIrqMaskGuard returned by
job_irq_init() ahead of the ThreadedRegistration in
TyrDrmRegistrationData so the Job IRQ is masked before it is freed.
Co-developed-by: Daniel Almeida <daniel.almeida@xxxxxxxxxxxxx>
Signed-off-by: Daniel Almeida <daniel.almeida@xxxxxxxxxxxxx>
Co-developed-by: Deborah Brouwer <deborah.brouwer@xxxxxxxxxxxxx>
Signed-off-by: Deborah Brouwer <deborah.brouwer@xxxxxxxxxxxxx>
Signed-off-by: Laura Nao <laura.nao@xxxxxxxxxxxxx>
---
drivers/gpu/drm/tyr/driver.rs | 30 +++++++++++++++++++++++++++++-
drivers/gpu/drm/tyr/fw.rs | 23 ++++++++++++++---------
drivers/gpu/drm/tyr/fw/irq.rs | 1 -
3 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 2dcf33ec93ea..138afeecfb3d 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -21,6 +21,7 @@
poll,
Io, //
},
+ irq::ThreadedRegistration,
new_mutex,
of,
platform,
@@ -37,10 +38,18 @@
use crate::{
file::TyrDrmFileData,
- fw::Firmware,
+ fw::{
+ irq::{
+ job_irq_init,
+ JobIrq,
+ JobIrqMaskGuard, //
+ },
+ Firmware, //
+ },
gem::Bo,
gpu,
gpu::GpuInfo,
+ irq::TyrIrq,
mmu::Mmu,
regs::gpu_control::*, //
};
@@ -81,6 +90,12 @@ pub(crate) struct TyrDrmRegistrationData<'drm> {
/// GPU MMIO register mapping.
pub(crate) iomem: Arc<IoMem<'drm>>,
+ /// Masks the Job IRQ on drop. Must be declared before `job_irq` so it is
+ /// dropped first (see [`JobIrqMaskGuard`]).
+ _job_irq_mask: JobIrqMaskGuard<'drm>,
+
+ job_irq: Pin<KBox<ThreadedRegistration<'drm, TyrIrq<JobIrq<'drm>>>>>,
+
/// GPU information read from hardware during probe.
pub(crate) gpu_info: GpuInfo,
}
@@ -158,7 +173,18 @@ fn probe<'bound>(
&gpu_info,
)?;
+ let (_job_irq_mask, job_irq_registration) =
+ // SAFETY: The resulting registration is stored in
+ // `TyrDrmRegistrationData`, which is dropped normally when
+ // the driver is unbound. It is not leaked or forgotten.
+ unsafe { job_irq_init(pdev, iomem.clone(), firmware.events.clone()) }?;
+
+ let job_irq = KBox::pin_init(job_irq_registration, GFP_KERNEL)?;
+
firmware.boot()?;
+ firmware.wait_ready(1000).inspect_err(|e| {
+ dev_err!(pdev, "Error waiting for firmware to be ready: {:?}\n", e);
+ })?;
firmware.enable_global_interface(&gpu_info, &core_clk)?;
let reg_data = pin_init!(TyrDrmRegistrationData {
@@ -174,6 +200,8 @@ fn probe<'bound>(
_sram: sram_regulator,
}),
iomem,
+ _job_irq_mask,
+ job_irq,
gpu_info,
});
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index 1499ffdef51f..3a7a11c5723e 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -36,7 +36,8 @@
ArcBorrow,
Mutex, //
},
- time, //
+ time,
+ time::Msecs, //
};
use crate::{
@@ -68,10 +69,7 @@
MCU_CONTROL,
MCU_STATUS, //
}, //
- job_control::{
- JOB_IRQ_CLEAR,
- JOB_IRQ_RAWSTAT, //
- }, //
+ job_control::JOB_IRQ_CLEAR,
},
vm::Vm, //
};
@@ -179,6 +177,9 @@ pub(crate) struct Firmware<'drm> {
/// The global FW interface.
#[pin]
global_iface: Mutex<FwIfaces<'drm>>,
+
+ /// Firmware events signalled via the Job IRQ.
+ pub(crate) events: Arc<irq::JobIrqEvents>,
}
#[pinned_drop]
@@ -291,6 +292,7 @@ pub(crate) fn new(
vm: vm.clone(),
sections,
global_iface <- new_mutex!(FwIfaces::new()?),
+ events: irq::JobIrqEvents::new()?,
}),
GFP_KERNEL,
)?)
@@ -327,10 +329,8 @@ pub(crate) fn boot(&self) -> Result {
io.write_reg(MCU_CONTROL::zeroed().with_req(McuControlMode::Auto));
if let Err(e) = poll::read_poll_timeout(
- || Ok((io.read(MCU_STATUS), io.read(JOB_IRQ_RAWSTAT))),
- |(mcu_status, irq_rawstat)| {
- mcu_status.value() == McuStatus::Enabled && irq_rawstat.glb()
- },
+ || Ok(io.read(MCU_STATUS)),
+ |status| status.value() == McuStatus::Enabled,
time::Delta::from_millis(1),
time::Delta::from_millis(100),
) {
@@ -393,4 +393,9 @@ pub(crate) fn enable_global_interface(&self, gpu_info: &GpuInfo, core_clk: &Clk)
}
}
}
+
+ /// Waits until the firmware signals readiness via the GLB IRQ bit.
+ pub(crate) fn wait_ready(&self, timeout_ms: Msecs) -> Result {
+ self.events.wait_ready(timeout_ms)
+ }
}
diff --git a/drivers/gpu/drm/tyr/fw/irq.rs b/drivers/gpu/drm/tyr/fw/irq.rs
index 7dd894de18cb..95380cb428ba 100644
--- a/drivers/gpu/drm/tyr/fw/irq.rs
+++ b/drivers/gpu/drm/tyr/fw/irq.rs
@@ -3,7 +3,6 @@
//! IRQ handling for the Job IRQ.
//!
//! The Job IRQ signals events from the MCU, including global interface acknowledgements.
-#![allow(dead_code)]
use kernel::{
device::Bound, //
--
2.39.5