From nobody Sat Jul 25 00:42:48 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4BF024DA54F; Tue, 21 Jul 2026 15:15:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784646937; cv=none; b=ltCHxUGSpHAaiyV9VkpXElXts3eZy4w8wU1q+/LvoRdLzCgpMZoQmumq17J1qGcxoYgzzxLCNtblgNDiWvO/59XmeOa9SkcaoFZIaJUJviva5QraXNtRV1H5L/HDbMv/j98gOHqGQEgw5plplngh7RG9clVULJ9P343GcI0NtTs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784646937; c=relaxed/simple; bh=btItQEO2+VGINywKdLiJJbQna1oD70XRrKeHl9goPRc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=b+KObefFuBYEoDLmTYGqm4vHnpYvq69xlD+y9p0tvAhikfcM8Zah50EP1a216EdGXtI/lDL9rLQuqJYsAbCqDNA1JqHNJ88By+/wMfXmvNUlsLXN0sAt/aQUC0S/izz/nxPSINtT0daE0YBKXZE5Wm1h5yxbRc700Zhp5UXF1jY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=NfpHWD+F; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="NfpHWD+F" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784646934; bh=btItQEO2+VGINywKdLiJJbQna1oD70XRrKeHl9goPRc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NfpHWD+FlOEjJKHzwS7KUGObW6P4FLggJIApYuU0k5c51VUWvSC1sHXD3+pzdNaks VimB4z3BmE8MGx01iVVQRxgGYci6o9nwToWtoq6dOBaSyYb6rZd5LAepbyRjneUKmV GaqK48BE910nTNh2XPVtm8UvdRTv6kciMvz+cgwVoZDZxswNLRz4VKacCApGCIPtdq dxzV5ZvOuVlDhK78KO/BryVkWr1reXyz4ZDDujdeQN4rhmy7wnL4zWSTKlMb1dqaH6 on9U7DJtNICoYWJrkuK9cc5jQW4BDPqKdIiaSJ+WyZOdMb3FasI2z5+Rnd+xSJwuKf h1fwe977UPE1w== Received: from laura.lan (unknown [100.64.0.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laura.nao) by bali.collaboradmins.com (Postfix) with ESMTPSA id 9F74317E062C; Tue, 21 Jul 2026 17:15:33 +0200 (CEST) From: Laura Nao To: daniel.almeida@collabora.com, aliceryhl@google.com, dakr@kernel.org, airlied@gmail.com, simona@ffwll.ch, ojeda@kernel.org Cc: boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, a.hindborg@kernel.org, tmgross@umich.edu, tamird@kernel.org, acourbot@nvidia.com, work@onurozkan.dev, deborah.brouwer@collabora.com, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, kernel@collabora.com, Beata Michalska Subject: [PATCH 1/2] drm/tyr: add Wait type for GPU events Date: Tue, 21 Jul 2026 17:14:22 +0200 Message-Id: <20260721151423.444175-2-laura.nao@collabora.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260721151423.444175-1-laura.nao@collabora.com> References: <20260721151423.444175-1-laura.nao@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Deborah Brouwer Add a Wait convenience type wrapping a CondVar and Mutex for sleeping until a condition is met or a timeout expires. The helper centralizes a common wait pattern: check the completion predicate before sleeping, wait interruptibly with a timeout, retry on spurious or unrelated wakeups, and perform a final predicate check before returning ETIMEDOUT. This will be used for CSF firmware responses and other GPU-driven events. Also add a new_wait! macro so each Wait instance gets a call-site-specific lockdep class key for its internal mutex. Co-developed-by: Daniel Almeida Signed-off-by: Daniel Almeida Co-developed-by: Beata Michalska Signed-off-by: Beata Michalska Signed-off-by: Deborah Brouwer --- drivers/gpu/drm/tyr/tyr.rs | 1 + drivers/gpu/drm/tyr/wait.rs | 126 ++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 drivers/gpu/drm/tyr/wait.rs diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs index e7ec450bdc9c..3f6fe5fbeb0f 100644 --- a/drivers/gpu/drm/tyr/tyr.rs +++ b/drivers/gpu/drm/tyr/tyr.rs @@ -16,6 +16,7 @@ mod regs; mod slot; mod vm; +mod wait; =20 kernel::module_platform_driver! { type: TyrPlatformDriver, diff --git a/drivers/gpu/drm/tyr/wait.rs b/drivers/gpu/drm/tyr/wait.rs new file mode 100644 index 000000000000..2a4d691c443c --- /dev/null +++ b/drivers/gpu/drm/tyr/wait.rs @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT + +//! Code to wait on GPU events. +#![allow(dead_code)] + +use kernel::{ + new_condvar, + prelude::*, + sync::{ + lock::{ + mutex::MutexBackend, + Lock, // + }, + Arc, + CondVar, + CondVarTimeoutResult, + Mutex, // + }, + time::msecs_to_jiffies, // +}; + +/// Creates a new [`Wait`] instance with a call-site-specific lockdep clas= s key. +/// +/// Always prefer this macro over [`Wait::new_with_lock`] when the [`Wait`= ] instance has +/// unique locking behaviour that could otherwise trigger false-positive l= ockdep +/// warnings. +#[macro_export] +macro_rules! new_wait { + () =3D> {{ + let lock =3D new_mutex!(()); + $crate::wait::Wait::new_with_lock(lock) + }}; +} + +/// A convenience type to wait for GPU events. +/// +/// Wraps a [`CondVar`] and [`Mutex`] pair. The mutex synchronizes predica= te checks +/// with wait/wake operations; the condvar provides the sleep/wake mechani= sm. +#[pin_data] +pub(crate) struct Wait { + /// The actual wait/signal mechanism. + #[pin] + cond: CondVar, + /// Synchronizes waiters with notifications. + #[pin] + lock: Mutex<()>, +} + +impl Wait { + /// Creates a new [`Wait`] with a caller-supplied lock instance. + /// + /// Use [`new_wait!`] instead of calling this directly; the macro ensu= res a + /// per-call-site lockdep class key is registered. + pub(crate) fn new_with_lock(lock: impl PinInit>= ) -> Result> { + Arc::pin_init( + pin_init!(Self { + cond <- new_condvar!(), + lock <- lock, + }), + GFP_KERNEL, + ) + } + + /// Waits until a GPU event condition is met or the timeout elapses. + /// + /// Calls `on_woken` before sleeping and after each wakeup. If `on_wok= en` + /// returns [`WaitResult::Retry`], the wait continues; [`WaitResult::D= one`] + /// returns success. + /// + /// `on_woken` is called while the internal wait lock is held, so it m= ust be + /// cheap and must not call back into code that can notify this wait o= bject. + /// + /// Returns [`ETIMEDOUT`] if the deadline is reached without the condi= tion + /// becoming true, or [`ERESTARTSYS`] if interrupted by a signal. + pub(crate) fn wait_interruptible_timeout(&self, timeout_ms: u32, mu= t on_woken: F) -> Result + where + F: FnMut() -> Result, + { + let mut guard =3D self.lock.lock(); + let mut remaining_time =3D msecs_to_jiffies(timeout_ms); + + loop { + // Check the condition before sleeping to avoid missing a wake= up + // that arrived between the caller's last check and acquiring = the + // lock here. + if let WaitResult::Done =3D on_woken()? { + return Ok(()); + } + + match self + .cond + .wait_interruptible_timeout(&mut guard, remaining_time) + { + CondVarTimeoutResult::Woken { jiffies } =3D> match on_woke= n()? { + WaitResult::Done =3D> return Ok(()), + WaitResult::Retry =3D> remaining_time =3D jiffies, + }, + CondVarTimeoutResult::Timeout =3D> { + // One final check before giving up. + if let WaitResult::Done =3D on_woken()? { + return Ok(()); + } + return Err(ETIMEDOUT); + } + CondVarTimeoutResult::Signal { .. } =3D> return Err(ERESTA= RTSYS), + } + } + } + + /// Wakes all waiters. + /// + /// Takes the internal lock so notifications are serialized against wa= iters + /// checking the condition and entering the sleep state. + pub(crate) fn notify_all(&self) { + let _guard =3D self.lock.lock(); + self.cond.notify_all(); + } +} + +/// The result of a wait operation. +pub(crate) enum WaitResult { + /// The condition was met. + Done, + /// The wakeup was spurious or for an unrelated event; retry. + Retry, +} --=20 2.39.5 From nobody Sat Jul 25 00:42:48 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 665D14D9916; Tue, 21 Jul 2026 15:15:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784646939; cv=none; b=dI7FcsEGkfIUKQDxpny5oR4fJOOn4hhLZELA9Ap4JGg2Q5/00hRgqYNUduHIJKTICzSxEUQjgVBjVQKr4Rt1gqu+rwfzpvzt/JHzDtXxX6wzcIrYmce8PqKaoT7yNu8Qw0RkDt9Fn1wewspw76eLSgBx4jJUOnmlGTZS4xejCF0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784646939; c=relaxed/simple; bh=Bm2sDgGGdf93DGpkU5R0geZJmOBMRfW4uCRvCqoKcOk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=T2U7g+EFOYJO69ugQFenzJNp3WYsVUN8iXO2EljKQhEA7khUqr05uGg6Sy2OoXu5DQotn533Oy6VR3pYjWpNY/SmGSuQmXsBFX8utzlUl3gyUXEo6hp6ejysma0nHcaFi8nRaionC/HseOlXMxaQNzKK1sIuGyN6PK2ITPa+DnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=OW8ofhD+; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="OW8ofhD+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1784646935; bh=Bm2sDgGGdf93DGpkU5R0geZJmOBMRfW4uCRvCqoKcOk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OW8ofhD+7zPldXdMKoPwIRCf1AgKP5NHavOOfAT5COpMLadJgFqhc3ro6vEBxC4H3 5q8lfc+SHEWZ/MPZFwhLFESpkMV3Stocac/JZnLHKj6hj9+ooXQpF5E3PhpnXH1C3o D8uTJB97SZIL6TAZaiiIed5eM/My+fRoMNHkjoLR7d3K3/TeBC+ZUzVdlys78iCy93 rZ8KtIK/XL2kNlxAm0C7wDcUHBovThA2I0W1OJFfm1SXlNpfRttNS9Qx0g19A8lhwH EOmYxRf8rU1+EveYhKZ40kpXz3ZxHT2kJNjT4894utKpe88prVOQpxDo41I8Et5w5l qivftjQSC4niQ== Received: from laura.lan (unknown [100.64.0.215]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: laura.nao) by bali.collaboradmins.com (Postfix) with ESMTPSA id AFC9917E08A2; Tue, 21 Jul 2026 17:15:34 +0200 (CEST) From: Laura Nao To: daniel.almeida@collabora.com, aliceryhl@google.com, dakr@kernel.org, airlied@gmail.com, simona@ffwll.ch, ojeda@kernel.org Cc: boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, a.hindborg@kernel.org, tmgross@umich.edu, tamird@kernel.org, acourbot@nvidia.com, work@onurozkan.dev, deborah.brouwer@collabora.com, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, kernel@collabora.com, Laura Nao Subject: [PATCH 2/2] drm/tyr: add Job IRQ handling Date: Tue, 21 Jul 2026 17:14:23 +0200 Message-Id: <20260721151423.444175-3-laura.nao@collabora.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260721151423.444175-1-laura.nao@collabora.com> References: <20260721151423.444175-1-laura.nao@collabora.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a threaded IRQ wrapper for Tyr interrupt sources and use it to handle the firmware Job IRQ. The Job IRQ reports requests from the CSF firmware, including global interface requests and CSG attention bits. Add a Job IRQ handler that masks the interrupt in the primary IRQ handler, processes pending raw status in the threaded handler, clears handled bits, and reenables the mask before returning. Co-developed-by: Daniel Almeida Signed-off-by: Daniel Almeida Co-developed-by: Deborah Brouwer Signed-off-by: Deborah Brouwer Signed-off-by: Laura Nao --- drivers/gpu/drm/tyr/driver.rs | 75 ++++++++++++++++++++++++ drivers/gpu/drm/tyr/fw.rs | 4 ++ drivers/gpu/drm/tyr/fw/irq.rs | 104 ++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 drivers/gpu/drm/tyr/fw/irq.rs diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs index 46ba91af9aca..6ee6f5e578b7 100644 --- a/drivers/gpu/drm/tyr/driver.rs +++ b/drivers/gpu/drm/tyr/driver.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 or MIT =20 +use core::marker::PhantomPinned; + use kernel::{ clk::{ Clk, @@ -21,6 +23,13 @@ poll, Io, // }, + irq::{ + Flags, + IrqReturn, + ThreadedHandler, + ThreadedIrqReturn, + ThreadedRegistration, // + }, new_mutex, of, platform, @@ -238,3 +247,69 @@ struct Regulators { _mali: Regulator, _sram: Regulator, } + +pub(crate) trait TyrIrqTrait: Sync { + fn read_status(&self) -> u32; + fn clear_mask(&self); + fn reenable_mask(&self); + fn read_raw_status(&self) -> u32; + fn clear_status(&self, status: u32); + fn mask(&self) -> u32; + fn handle(&self, status: u32); +} + +#[pin_data] +pub(crate) struct TyrIrq { + irq: T, + #[pin] + _pin: PhantomPinned, +} + +impl TyrIrq { + pub(crate) fn request<'a>( + pdev: &'a platform::Device, + name: &'static CStr, + irq: T, + ) -> Result, Error> + 'a> + where + T: 'a, + { + let handler =3D try_pin_init!(Self { + irq, + _pin: PhantomPinned, + }); + + // SAFETY: The resulting `PinInit` is not leaked, it is consumed b= y the caller to + // initialize a pinned `ThreadedRegistration`. + Ok(unsafe { pdev.request_threaded_irq_by_name(Flags::SHARED, name,= name, handler) }) + } +} + +impl ThreadedHandler for TyrIrq { + fn handle(&self) -> ThreadedIrqReturn { + let masked_status =3D self.irq.read_status(); + + if masked_status =3D=3D 0 { + return ThreadedIrqReturn::None; + } + self.irq.clear_mask(); + ThreadedIrqReturn::WakeThread + } + + fn handle_threaded(&self) -> IrqReturn { + let mut ret =3D IrqReturn::None; + + loop { + let raw_status =3D self.irq.read_raw_status() & self.irq.mask(= ); + if raw_status =3D=3D 0 { + break; + } + self.irq.handle(raw_status); + self.irq.clear_status(raw_status); + ret =3D IrqReturn::Handled; + } + + self.irq.reenable_mask(); + ret + } +} diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs index 554808a792aa..4188dc4232f5 100644 --- a/drivers/gpu/drm/tyr/fw.rs +++ b/drivers/gpu/drm/tyr/fw.rs @@ -66,8 +66,12 @@ vm::Vm, // }; =20 +pub(crate) mod irq; mod parser; =20 +/// Maximum number of CSG interfaces supported by hardware. +const MAX_CSG: usize =3D 16; + impl_flags!( #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)] pub(super) struct SectionFlags(u32); diff --git a/drivers/gpu/drm/tyr/fw/irq.rs b/drivers/gpu/drm/tyr/fw/irq.rs new file mode 100644 index 000000000000..4084904d53f6 --- /dev/null +++ b/drivers/gpu/drm/tyr/fw/irq.rs @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 or MIT + +//! IRQ handling for the Job IRQ. +//! +//! The Job IRQ signals events from the MCU, including global interface ac= knowledgements. +#![allow(dead_code)] + +use core::sync::atomic::{ + AtomicBool, + Ordering, // +}; + +use kernel::{ + c_str, + device::Bound, // + io::Io, + irq::ThreadedRegistration, + platform, + prelude::*, + sync::Arc, // +}; + +use crate::{ + driver::{ + IoMem, + TyrIrq, + TyrIrqTrait, // + }, + regs::job_control::{ + JOB_IRQ_CLEAR, + JOB_IRQ_MASK, + JOB_IRQ_RAWSTAT, + JOB_IRQ_STATUS, // + }, + wait::Wait, // +}; + +const CSG_IRQ_MASK: u32 =3D (1u32 << super::MAX_CSG) - 1; + +pub(crate) struct JobIrq<'bound> { + iomem: Arc>, + fw_ready: Arc, + ready_wait: Arc, +} + +pub(crate) fn job_irq_init<'bound>( + pdev: &'bound platform::Device, + iomem: Arc>, + fw_ready: Arc, + ready_wait: Arc, +) -> Result>>, Error> + 'bound> { + iomem.write_reg( + JOB_IRQ_MASK::zeroed() + .with_const_csg::() + .with_glb(true), + ); + let job_irq =3D JobIrq { + iomem: iomem.clone(), + fw_ready, + ready_wait, + }; + + TyrIrq::request(pdev, c_str!("job"), job_irq) +} + +impl TyrIrqTrait for JobIrq<'_> { + fn read_status(&self) -> u32 { + self.iomem.read(JOB_IRQ_STATUS).into_raw() + } + + fn clear_mask(&self) { + self.iomem.write_reg(JOB_IRQ_MASK::zeroed()); + } + + fn reenable_mask(&self) { + self.iomem.write_reg( + JOB_IRQ_MASK::zeroed() + .with_const_csg::() + .with_glb(true), + ); + } + + fn read_raw_status(&self) -> u32 { + self.iomem.read(JOB_IRQ_RAWSTAT).into_raw() + } + + fn clear_status(&self, status: u32) { + self.iomem.write_reg(JOB_IRQ_CLEAR::from_raw(status)); + } + + fn mask(&self) -> u32 { + JOB_IRQ_MASK::zeroed() + .with_const_csg::() + .with_glb(true) + .into_raw() + } + + fn handle(&self, status: u32) { + if JOB_IRQ_RAWSTAT::from_raw(status).glb() { + self.fw_ready.store(true, Ordering::Release); + self.ready_wait.notify_all(); + } + } +} --=20 2.39.5