[PATCH v6 1/2] drm/tyr: add TyrIrq threaded IRQ wrapper
From: Laura Nao
Date: Thu Aug 27 2026 - 04:06:35 EST
Introduce a generic TyrIrq threaded IRQ wrapper along with the
TyrIrqTrait trait describing the operations required to handle a
Tyr interrupt source.
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/irq.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
2 files changed, 116 insertions(+)
diff --git a/drivers/gpu/drm/tyr/irq.rs b/drivers/gpu/drm/tyr/irq.rs
new file mode 100644
index 000000000000..e6a739532daa
--- /dev/null
+++ b/drivers/gpu/drm/tyr/irq.rs
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Threaded IRQ wrapper shared by all Tyr interrupt sources.
+#![allow(dead_code)]
+use core::marker::PhantomPinned;
+
+use kernel::{
+ device::Bound,
+ irq::{
+ Flags,
+ IrqReturn,
+ ThreadedHandler,
+ ThreadedIrqReturn,
+ ThreadedRegistration, //
+ },
+ platform,
+ prelude::*, //
+};
+
+/// Trait describing the operations required to service a Tyr interrupt source.
+pub(crate) trait TyrIrqTrait: Sync {
+ /// Returns the masked interrupt status.
+ fn read_status(&self) -> u32;
+
+ /// Clears all bits in the mask register, disabling the interrupt sources.
+ fn clear_mask(&self);
+
+ /// Sets the mask register to re-enable the interrupt sources.
+ fn reenable_mask(&self);
+
+ /// Returns the raw interrupt status, regardless of the current mask.
+ fn read_raw_status(&self) -> u32;
+
+ /// Clears the given bits in the interrupt status register.
+ fn clear_status(&self, status: u32);
+
+ /// Returns the bitmask of interrupt sources handled by this instance.
+ fn mask(&self) -> u32;
+
+ /// Handles the given pending, unmasked interrupt bits.
+ fn handle(&self, status: u32);
+}
+
+/// A threaded IRQ wrapper shared by all Tyr interrupt sources.
+#[pin_data]
+pub(crate) struct TyrIrq<T: TyrIrqTrait> {
+ /// The interrupt source.
+ irq: T,
+ #[pin]
+ _pin: PhantomPinned,
+}
+
+impl<T: TyrIrqTrait> TyrIrq<T> {
+ /// Requests a threaded IRQ registration for `irq`, using `name` to look up the interrupt.
+ ///
+ /// # Safety
+ ///
+ /// Callers must not `mem::forget()` the resulting registration or otherwise prevent its
+ /// [`Drop`] implementation from running.
+ pub(crate) unsafe fn request<'a>(
+ pdev: &'a platform::Device<Bound>,
+ name: &'static CStr,
+ irq: T,
+ ) -> Result<impl PinInit<ThreadedRegistration<'a, Self>, Error> + 'a>
+ where
+ T: 'a,
+ {
+ let handler = try_pin_init!(Self {
+ irq,
+ _pin: PhantomPinned,
+ });
+
+ // SAFETY: The caller guarantees the resulting registration will not be leaked.
+ let registration =
+ unsafe { pdev.request_threaded_irq_by_name(Flags::SHARED, name, name, handler) };
+
+ // Clear the status and unmask once the handler has been
+ // successfully registered.
+ Ok(registration.pin_chain(|reg| {
+ let irq = ®.handler().irq;
+ irq.clear_status(irq.mask());
+ irq.reenable_mask();
+ Ok(())
+ }))
+ }
+}
+
+impl<T: TyrIrqTrait> ThreadedHandler for TyrIrq<T> {
+ fn handle(&self) -> ThreadedIrqReturn {
+ let masked_status = self.irq.read_status();
+
+ if masked_status == 0 {
+ return ThreadedIrqReturn::None;
+ }
+ self.irq.clear_mask();
+ ThreadedIrqReturn::WakeThread
+ }
+
+ fn handle_threaded(&self) -> IrqReturn {
+ let mut ret = IrqReturn::None;
+
+ loop {
+ let raw_status = self.irq.read_raw_status() & self.irq.mask();
+ if raw_status == 0 {
+ break;
+ }
+ self.irq.clear_status(raw_status);
+ self.irq.handle(raw_status);
+ ret = IrqReturn::Handled;
+ }
+
+ self.irq.reenable_mask();
+ ret
+ }
+}
diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs
index e7ec450bdc9c..31205e3bf0e7 100644
--- a/drivers/gpu/drm/tyr/tyr.rs
+++ b/drivers/gpu/drm/tyr/tyr.rs
@@ -12,6 +12,7 @@
mod fw;
mod gem;
mod gpu;
+mod irq;
mod mmu;
mod regs;
mod slot;
--
2.39.5