* [PATCH v4 0/3] drm/tyr: GPU reset infrastructure
@ 2026-08-13 10:42 Onur Özkan
2026-08-13 10:42 ` [PATCH v4 1/3] rust: workqueue: impl Send and Sync for OwnedQueue Onur Özkan
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Onur Özkan @ 2026-08-13 10:42 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, dri-devel
Cc: dakr, aliceryhl, daniel.almeida, airlied, simona, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, Onur Özkan
Add support for scheduling GPU resets on a dedicated workqueue. Track
the reset state to avoid queueing another reset while one is already
pending or in progress.
Use an SRCU based gate with mutex-protected reader admission to block
hardware accesses while reset work runs and wait for current users
before resetting.
Stop new reset requests during teardown and drain any queued or running
reset work before releasing the device resources.
This is the initial reset infrastructure only. It is not wired to a reset
source yet as those will follow in separate work.
Based on 'commit 53441a9cae3c ("drm/tyr: program CSF global interface")'
from tyr-for-upstream with the following patch series on the ML:
- rust: workqueue: add cancel_sync support [1]
- rust: add SRCU abstraction [2]
- rust: workqueue: add ScopedQueue for lifetime bound items [3]
- Creation of workqueues in Rust [4]
TODOs:
- On reset failure, we don't do anything for now. We should unplug
the GPU (that's what Panthor does) but we don't have the infrastructure
for that yet [5].
- In schedule(), similar to panthor_device_schedule_reset(), we should
have a PM check but similar to the note above, we don't have the
infrastructure for that yet.
Changes since v3:
- Dropped Resettable, ActiveHwState, pre/post-reset hooks and typestate.
- Removed ResetState::Enqueueing and teardown spinning.
- Replaced fail-fast try_access() and epoch tracking with a blocking
hardware-access gate.
- Used b4 for the prerequisites.
Changes since v2:
- Replaced Work::disable_sync with Work::cancel_sync.
- Used type state pattern for reset stages.
- Using ScopedQueue with device lifetime instead of a static workqueue.
- Removed SRCU patch from this series.
Changes since v1:
- Removed OrderedQueue and using Alice's workqueue implementation [1]
instead.
- Added Resettable trait with pre_reset and post_reset hooks to be
implemented by reset-managed hardwares.
- Added SRCU abstraction and used it to synchronize the reset work and
hardware access.
v1: https://lore.kernel.org/rust-for-linux/20260313091646.16938-1-work@onurozkan.dev
v2: https://lore.kernel.org/rust-for-linux/20260416171728.205141-1-work@onurozkan.dev
Link: https://lore.kernel.org/all/20260617131731.145337-1-work@onurozkan.dev [1]
Link: https://lore.kernel.org/all/20260613065348.96750-1-work@onurozkan.dev [2]
Link: https://lore.kernel.org/all/20260617144645.253444-1-work@onurozkan.dev [3]
Link: https://lore.kernel.org/all/20260312-create-workqueue-v4-0-ea39c351c38f@google.com [4]
Link: https://gitlab.freedesktop.org/panfrost/linux/-/work_items/29#note_3391826 [5]
Link: https://gitlab.freedesktop.org/panfrost/linux/-/issues/28
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
Onur Özkan (3):
rust: workqueue: impl Send and Sync for OwnedQueue
drm/tyr: clear stale IRQ state before soft reset
drm/tyr: add GPU reset infrastructure
drivers/gpu/drm/tyr/driver.rs | 39 ++----
drivers/gpu/drm/tyr/reset.rs | 260 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/tyr/reset/hw_gate.rs | 79 +++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
rust/kernel/workqueue/mod.rs | 8 ++
5 files changed, 362 insertions(+), 25 deletions(-)
---
base-commit: 53441a9cae3c4be552fa8aefa6e61b0f1bceb8a5
change-id: 20260813-tyr-reset-impl-93e951f996b4
prerequisite-message-id: <20260312-create-workqueue-v4-0-ea39c351c38f@google.com>
prerequisite-patch-id: f5e24f7b3717f2ab0445b5395c7f12b554861d78
prerequisite-patch-id: 0bf6ae4abcef7090d0e48921d6ec627a59dc6a7a
prerequisite-patch-id: f2bd17b7ba9f4626ddec56fec8e108872ddc6af1
prerequisite-message-id: <20260617144645.253444-1-work@onurozkan.dev>
prerequisite-patch-id: 5b966d09cfd455dd09fb0911d174b123efa02a16
prerequisite-message-id: <20260613065348.96750-1-work@onurozkan.dev>
prerequisite-patch-id: 9e1efee190d212ba1b01cd0acb5a4357e0b4da42
prerequisite-patch-id: 26aba035f4d1e212fa6ea7078095febefff5c5ba
prerequisite-patch-id: ffa25d5aadec4c04589af2bdd59a9c022f0fc9b0
prerequisite-patch-id: c2e05a4ac9d665d331952b291a622df6be673e41
prerequisite-patch-id: c14a4bd8a68b045356d61f7fa94690bd037ad08b
prerequisite-message-id: <20260617131731.145337-1-work@onurozkan.dev>
prerequisite-patch-id: b40e7a218c4e0467933e83c45b09eb78c7ebace2
Best regards,
--
Onur Özkan <work@onurozkan.dev>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/3] rust: workqueue: impl Send and Sync for OwnedQueue
2026-08-13 10:42 [PATCH v4 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
@ 2026-08-13 10:42 ` Onur Özkan
2026-08-13 10:42 ` [PATCH v4 2/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
2026-08-13 10:42 ` [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure Onur Özkan
2 siblings, 0 replies; 6+ messages in thread
From: Onur Özkan @ 2026-08-13 10:42 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, dri-devel
Cc: dakr, aliceryhl, daniel.almeida, airlied, simona, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, Onur Özkan
Allows OwnedQueue to be used across thread boundaries which is needed
from the tyr reset implementation.
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
rust/kernel/workqueue/mod.rs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/rust/kernel/workqueue/mod.rs b/rust/kernel/workqueue/mod.rs
index 933032fc4a85..d766cd9b9175 100644
--- a/rust/kernel/workqueue/mod.rs
+++ b/rust/kernel/workqueue/mod.rs
@@ -383,6 +383,14 @@ pub struct OwnedQueue {
queue: NonNull<Queue>,
}
+// SAFETY: `OwnedQueue` has exclusive ownership of the workqueue and accesses to workqueues
+// are thread safe as documented by the `Send` implementation for `Queue`.
+unsafe impl Send for OwnedQueue {}
+
+// SAFETY: Shared access to an `OwnedQueue` only provides shared access to its `Queue` which
+// is thread safe as documented by the `Sync` implementation for `Queue`.
+unsafe impl Sync for OwnedQueue {}
+
impl Deref for OwnedQueue {
type Target = Queue;
fn deref(&self) -> &Queue {
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 2/3] drm/tyr: clear stale IRQ state before soft reset
2026-08-13 10:42 [PATCH v4 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-13 10:42 ` [PATCH v4 1/3] rust: workqueue: impl Send and Sync for OwnedQueue Onur Özkan
@ 2026-08-13 10:42 ` Onur Özkan
2026-08-13 10:42 ` [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure Onur Özkan
2 siblings, 0 replies; 6+ messages in thread
From: Onur Özkan @ 2026-08-13 10:42 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, dri-devel
Cc: dakr, aliceryhl, daniel.almeida, airlied, simona, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, Onur Özkan,
Boris Brezillon
Previous reset may leave the reset completed IRQ set which can make the
poll return too early.
Clear the IRQ first so the driver waits for the current reset to
complete.
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
drivers/gpu/drm/tyr/driver.rs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index c5063b2be94d..90d6cd988cd2 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -86,6 +86,9 @@ pub(crate) struct TyrDrmRegistrationData<'bound> {
}
fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
+ // Clear any stale reset IRQ state before issuing a new soft reset.
+ iomem.write_reg(GPU_IRQ_CLEAR::zeroed().with_reset_completed(true));
+
iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
poll::read_poll_timeout(
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure
2026-08-13 10:42 [PATCH v4 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-13 10:42 ` [PATCH v4 1/3] rust: workqueue: impl Send and Sync for OwnedQueue Onur Özkan
2026-08-13 10:42 ` [PATCH v4 2/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
@ 2026-08-13 10:42 ` Onur Özkan
2026-08-13 23:25 ` Daniel Almeida
2 siblings, 1 reply; 6+ messages in thread
From: Onur Özkan @ 2026-08-13 10:42 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, dri-devel
Cc: dakr, aliceryhl, daniel.almeida, airlied, simona, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, Onur Özkan
Add support for scheduling GPU resets on a dedicated workqueue. Track
the reset state to avoid queueing another reset while one is already
pending or in progress.
Use an SRCU based gate with mutex-protected reader admission to block
hardware accesses while reset work runs and wait for current users
before resetting.
Stop new reset requests during teardown and drain any queued or running
reset work before releasing the device resources.
This is the initial reset infrastructure only. It is not wired to a reset
source yet as those will follow in separate work.
Link: https://gitlab.freedesktop.org/panfrost/linux/-/work_items/28
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
drivers/gpu/drm/tyr/driver.rs | 42 ++----
drivers/gpu/drm/tyr/reset.rs | 260 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/tyr/reset/hw_gate.rs | 79 +++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
4 files changed, 354 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 90d6cd988cd2..bd613ab7e05c 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -8,7 +8,6 @@
device::{
Bound,
Core,
- Device,
DeviceContext, //
},
dma::{
@@ -17,13 +16,9 @@
},
drm,
drm::ioctl,
- io::{
- poll,
- Io, //
- },
new_mutex,
of,
- platform,
+ platform, //
prelude::*,
regulator,
regulator::Regulator,
@@ -33,7 +28,6 @@
Arc,
Mutex, //
},
- time,
types::ForLt, //
};
@@ -41,10 +35,10 @@
file::TyrDrmFileData,
fw::Firmware,
gem::BoData,
- gpu,
gpu::GpuInfo,
mmu::Mmu,
- regs::gpu_control::*, //
+ regs::gpu_control::*,
+ reset, //
};
pub(crate) type IoMem<'a> = kernel::io::mem::IoMem<'a, SZ_2M>;
@@ -67,6 +61,11 @@ pub(crate) struct TyrDrmRegistrationData<'bound> {
/// Parent platform device.
pub(crate) pdev: &'bound platform::Device<Bound>,
+ // `ResetHandle::drop()` drains queued/running works and this must happen
+ // before clocks/regulators are dropped. So keep this field before them to
+ // ensure the correct drop order.
+ pub(crate) reset: reset::ResetHandle<'bound>,
+
/// Firmware sections.
pub(crate) fw: Arc<Firmware<'bound>>,
@@ -85,23 +84,6 @@ pub(crate) struct TyrDrmRegistrationData<'bound> {
pub(crate) gpu_info: GpuInfo,
}
-fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
- // Clear any stale reset IRQ state before issuing a new soft reset.
- iomem.write_reg(GPU_IRQ_CLEAR::zeroed().with_reset_completed(true));
-
- iomem.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
-
- poll::read_poll_timeout(
- || Ok(iomem.read(GPU_IRQ_RAWSTAT)),
- |status| status.reset_completed(),
- time::Delta::from_millis(1),
- time::Delta::from_millis(100),
- )
- .inspect_err(|_| dev_err!(dev, "GPU reset failed."))?;
-
- Ok(())
-}
-
kernel::of_device_table!(
OF_TABLE,
MODULE_OF_TABLE,
@@ -136,8 +118,7 @@ fn probe<'bound>(
let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?, GFP_KERNEL)?;
- issue_soft_reset(pdev.as_ref(), &iomem)?;
- gpu::l2_power_on(pdev.as_ref(), &iomem)?;
+ reset::run_reset(pdev.as_ref(), &iomem)?;
let gpu_info = GpuInfo::new(&iomem);
gpu_info.log(pdev.as_ref());
@@ -152,6 +133,10 @@ fn probe<'bound>(
let unreg_dev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, Ok(()))?;
+ // SAFETY: `ResetHandle` is stored in registration data created with `new_with_lt`
+ // and is dropped before the borrowed device and MMIO references expire.
+ let reset = unsafe { reset::ResetHandle::new(pdev, iomem.as_arc_borrow())? };
+
let mmu = Mmu::new(iomem.as_arc_borrow(), &gpu_info)?;
let firmware = Firmware::new(
@@ -167,6 +152,7 @@ fn probe<'bound>(
let reg_data = try_pin_init!(TyrDrmRegistrationData {
pdev,
+ reset,
fw: firmware,
clks <- new_mutex!(Clocks {
core: core_clk,
diff --git a/drivers/gpu/drm/tyr/reset.rs b/drivers/gpu/drm/tyr/reset.rs
new file mode 100644
index 000000000000..a0eabf8ac6d0
--- /dev/null
+++ b/drivers/gpu/drm/tyr/reset.rs
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Provides asynchronous reset handling for the Tyr DRM driver via [`ResetHandle`].
+//!
+//! [`ResetHandle::schedule`] runs reset work on a dedicated ordered
+//! [`ScopedQueue`] and avoids duplicate pending reset requests.
+//!
+//! # High-level Execution Flow
+//!
+//! ```text
+//! +------+ schedule() +---------+ reset_work() +------------+
+//! | Idle |------------->| Pending |--------------->| InProgress |
+//! +------+ +---------+ +------------+
+//! ^ |
+//! | work complete |
+//! +---------------------------------------------+
+//!
+//! Teardown transitions any state to ShuttingDown, then drains pending and
+//! running work.
+//! ```
+
+mod hw_gate;
+
+use hw_gate::HwGate;
+
+use kernel::{
+ device::{
+ Bound,
+ Device, //
+ },
+ io::{
+ poll,
+ Io, //
+ },
+ platform,
+ prelude::*,
+ sync::{
+ atomic::{
+ Atomic,
+ AtomicType,
+ Full,
+ Release, //
+ },
+ Arc,
+ ArcBorrow, //
+ },
+ time,
+ workqueue::{
+ self,
+ ScopedQueue,
+ Work, //
+ },
+};
+
+use crate::{
+ driver::IoMem,
+ gpu,
+ regs::gpu_control::*, //
+};
+
+/// Lifecycle state of the reset worker.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[repr(i32)]
+enum ResetState {
+ /// Hardware is available and no reset request exists.
+ Idle = 0,
+ /// Reset work item is queued and waiting to be claimed by the worker.
+ Pending = 1,
+ /// Worker has claimed the request and is resetting hardware.
+ InProgress = 2,
+ /// Teardown has started and no new reset request may start.
+ ShuttingDown = 3,
+}
+
+// SAFETY: `ResetState` and `i32` have the same size and alignment, and are
+// round-trip transmutable.
+unsafe impl AtomicType for ResetState {
+ type Repr = i32;
+}
+
+/// Internal reset orchestrator that owns the state, [`HwGate`], and work item.
+#[pin_data]
+struct Controller<'bound> {
+ /// Parent platform device.
+ pdev: &'bound platform::Device<Bound>,
+ /// Mapped register space needed for reset operations.
+ iomem: Arc<IoMem<'bound>>,
+ /// State shared by reset schedulers and the worker.
+ state: Atomic<ResetState>,
+ /// Drains reset-sensitive hardware accesses before a reset.
+ #[pin]
+ hw: HwGate,
+ /// Work item backing async reset processing.
+ #[pin]
+ work: Work<Controller<'bound>>,
+}
+
+kernel::impl_has_work! {
+ impl{'bound} HasWork<Controller<'bound>> for Controller<'bound> { self.work }
+}
+
+impl<'bound> workqueue::WorkItem for Controller<'bound> {
+ type Pointer = Arc<Self>;
+
+ fn run(this: Arc<Self>) {
+ this.reset_work();
+ }
+}
+
+impl<'bound> Controller<'bound> {
+ /// Creates an [`Arc<Controller>`] ready for use.
+ fn new(
+ pdev: &'bound platform::Device<Bound>,
+ iomem: ArcBorrow<'_, IoMem<'bound>>,
+ ) -> Result<Arc<Self>> {
+ Arc::pin_init(
+ try_pin_init!(Self {
+ pdev,
+ iomem: iomem.into(),
+ state: Atomic::new(ResetState::Idle),
+ hw <- HwGate::new(),
+ work <- kernel::new_work!("tyr::reset"),
+ }),
+ GFP_KERNEL,
+ )
+ }
+
+ /// Attempts to transition the reset state from `from` to `to`.
+ #[inline]
+ fn try_transition(&self, from: ResetState, to: ResetState) -> bool {
+ self.state.cmpxchg(from, to, Full).is_ok()
+ }
+
+ /// Processes one scheduled reset request.
+ ///
+ /// If the pending reset cannot be claimed, the worker returns immediately.
+ ///
+ /// It first claims [`ResetState::Pending`], then waits for earlier hardware
+ /// accesses to complete before issuing the reset and returning the worker
+ /// state to [`ResetState::Idle`].
+ ///
+ /// Panthor reference:
+ /// - drivers/gpu/drm/panthor/panthor_device.c::panthor_device_reset_work()
+ fn reset_work(self: &Arc<Self>) {
+ if !self.try_transition(ResetState::Pending, ResetState::InProgress) {
+ return;
+ }
+
+ dev_info!(self.pdev, "Starting GPU reset.\n");
+
+ // Wait for current hardware accesses to finish before resetting.
+ let reset_guard = self.hw.close();
+ let reset_result = run_reset(self.pdev.as_ref(), &self.iomem);
+ drop(reset_guard);
+
+ if let Err(e) = reset_result {
+ dev_err!(self.pdev, "GPU reset failed: {:?}\n", e);
+
+ // TODO: Unplug the GPU.
+ // There is no API for unplugging the GPU and this is unreachable
+ // for now since there are no hardware users for reset API.
+ } else {
+ dev_info!(self.pdev, "GPU reset completed.\n");
+ }
+
+ let _ = self.try_transition(ResetState::InProgress, ResetState::Idle);
+ }
+}
+
+/// User-facing handle for scheduling resets.
+///
+/// Dropping the handle drains any queued or in-flight reset work before the
+/// [`ScopedQueue`] and the clock and regulator resources are released.
+pub(crate) struct ResetHandle<'bound> {
+ controller: Arc<Controller<'bound>>,
+ wq: ScopedQueue<'bound>,
+}
+
+impl<'bound> ResetHandle<'bound> {
+ /// Creates [`ResetHandle`].
+ ///
+ /// # Safety
+ ///
+ /// The returned handle must not be leaked or otherwise prevented from
+ /// running [`Drop`], since it owns work that may borrow from `'bound`.
+ pub(crate) unsafe fn new(
+ pdev: &'bound platform::Device<Bound>,
+ iomem: ArcBorrow<'_, IoMem<'bound>>,
+ ) -> Result<Self> {
+ Ok(Self {
+ controller: Controller::new(pdev, iomem)?,
+ // SAFETY: The caller guarantees the handle is dropped.
+ wq: unsafe { ScopedQueue::new(c"tyr-reset-wq")? },
+ })
+ }
+
+ /// Schedules a GPU reset on the dedicated workqueue.
+ ///
+ /// If a reset is already pending or in progress the call is a no-op.
+ #[expect(dead_code)]
+ pub(crate) fn schedule(&self) {
+ // TODO: Similar to `panthor_device_schedule_reset()` in Panthor, add a
+ // power management check once Tyr supports it.
+
+ if self
+ .controller
+ .try_transition(ResetState::Idle, ResetState::Pending)
+ {
+ let _ = self.wq.enqueue(self.controller.clone());
+ }
+ }
+}
+
+impl<'bound> Drop for ResetHandle<'bound> {
+ fn drop(&mut self) {
+ // Stop new reset requests before draining queued/running work.
+ self.controller
+ .state
+ .store(ResetState::ShuttingDown, Release);
+
+ // Not required for safety because `wq` will drain on drop, but keep
+ // cancellation of `controller.work` explicit before fields are dropped.
+ let _ = self.controller.work.cancel_sync();
+ }
+}
+
+/// Issues a soft reset command and waits for reset-complete IRQ status.
+fn issue_soft_reset<'bound>(dev: &'bound Device<Bound>, io: &IoMem<'bound>) -> Result {
+ // Clear any stale reset-complete IRQ state before issuing a new soft reset.
+ io.write_reg(GPU_IRQ_CLEAR::zeroed().with_reset_completed(true));
+
+ io.write_reg(GPU_COMMAND::reset(ResetMode::SoftReset));
+
+ poll::read_poll_timeout(
+ || Ok(io.read(GPU_IRQ_RAWSTAT)),
+ |status| status.reset_completed(),
+ time::Delta::from_millis(1),
+ time::Delta::from_millis(100),
+ )
+ .inspect_err(|_| dev_err!(dev, "GPU reset timed out."))?;
+
+ Ok(())
+}
+
+/// Runs one synchronous GPU reset pass.
+///
+/// Its visibility is `pub(super)` only so the probe path can run an
+/// initial reset; it is not part of this module's public API.
+///
+/// On success, the GPU is left in a state suitable for reinitialization.
+///
+/// The sequence is as follows:
+/// - Trigger a GPU soft reset.
+/// - Wait for the reset-complete IRQ status.
+/// - Power L2 back on.
+pub(super) fn run_reset<'bound>(dev: &'bound Device<Bound>, iomem: &IoMem<'bound>) -> Result {
+ issue_soft_reset(dev, iomem)?;
+ gpu::l2_power_on(dev, iomem)?;
+ Ok(())
+}
diff --git a/drivers/gpu/drm/tyr/reset/hw_gate.rs b/drivers/gpu/drm/tyr/reset/hw_gate.rs
new file mode 100644
index 000000000000..9c5708fb911d
--- /dev/null
+++ b/drivers/gpu/drm/tyr/reset/hw_gate.rs
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0 or MIT
+
+//! Hardware-access gate for the GPU reset cycle.
+//!
+//! [`HwGate`] uses a mutex and [`Srcu`] to coordinate reset-sensitive hardware
+//! access with reset. Readers hold the mutex while entering SRCU, then release
+//! it before accessing hardware. The reset worker holds the mutex while waiting
+//! for admitted readers and resetting hardware.
+
+use kernel::{
+ prelude::*,
+ sync::{
+ new_mutex,
+ srcu,
+ Mutex,
+ MutexGuard,
+ Srcu, //
+ },
+};
+
+/// A gate that coordinates hardware access with the reset worker.
+#[pin_data]
+pub(super) struct HwGate {
+ /// Admits readers and is held exclusively while the reset worker owns the
+ /// hardware.
+ #[pin]
+ gate_lock: Mutex<()>,
+ /// Drains readers that entered before the reset worker acquired `gate_lock`.
+ #[pin]
+ srcu: Srcu,
+}
+
+impl HwGate {
+ /// Creates an open hardware-access gate.
+ pub(super) fn new() -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {
+ gate_lock <- new_mutex!(()),
+ srcu <- kernel::new_srcu!(),
+ })
+ }
+
+ /// Enters a reset-sensitive hardware-access section.
+ #[expect(dead_code)]
+ fn read(&self) -> HwReadGuard<'_> {
+ let gate_lock = self.gate_lock.lock();
+ let srcu = self.srcu.read_lock();
+ drop(gate_lock);
+
+ HwReadGuard { _srcu: srcu }
+ }
+
+ /// Stops new readers and drains admitted readers for the reset worker.
+ ///
+ /// Callers must serialize write-side access. The reset controller's state
+ /// machine provides that serialization.
+ pub(super) fn close(&self) -> HwWriteGuard<'_> {
+ let gate_lock = self.gate_lock.lock();
+
+ // Holding `gate_lock` prevents new readers from entering SRCU. Readers
+ // admitted before us are enrolled, so wait for their read-side work.
+ self.srcu.synchronize();
+
+ HwWriteGuard {
+ _gate_lock: gate_lock,
+ }
+ }
+}
+
+/// Read section that keeps the reset worker off the hardware while held.
+#[must_use = "the gate is released when the guard is dropped"]
+struct HwReadGuard<'a> {
+ _srcu: srcu::Guard<'a>,
+}
+
+/// Closed [`HwGate`] held by the reset worker. Reopens on drop.
+#[must_use = "the gate stays closed until the guard is dropped"]
+pub(super) struct HwWriteGuard<'a> {
+ _gate_lock: MutexGuard<'a, ()>,
+}
diff --git a/drivers/gpu/drm/tyr/tyr.rs b/drivers/gpu/drm/tyr/tyr.rs
index 3f6fe5fbeb0f..63873628c843 100644
--- a/drivers/gpu/drm/tyr/tyr.rs
+++ b/drivers/gpu/drm/tyr/tyr.rs
@@ -14,6 +14,7 @@
mod gpu;
mod mmu;
mod regs;
+mod reset;
mod slot;
mod vm;
mod wait;
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure
2026-08-13 10:42 ` [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure Onur Özkan
@ 2026-08-13 23:25 ` Daniel Almeida
2026-08-14 11:20 ` Onur Özkan
0 siblings, 1 reply; 6+ messages in thread
From: Daniel Almeida @ 2026-08-13 23:25 UTC (permalink / raw)
To: Onur Özkan
Cc: linux-kernel, rust-for-linux, dri-devel, dakr, aliceryhl, airlied,
simona, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross
Hi Onur,
Can we move the iomem to the HwGate and get rid of its Arc? This way we
ensure that all hardware access must consider the possibility of an ongoing
reset by having each component that needs hardware access hold an Arc<HwGate>
instead. Perhaps we can even broaden this to "hardware must be powered on" at
some point in the future.
Otherwise, this looks good to me. Let's wait for Alice too.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure
2026-08-13 23:25 ` Daniel Almeida
@ 2026-08-14 11:20 ` Onur Özkan
0 siblings, 0 replies; 6+ messages in thread
From: Onur Özkan @ 2026-08-14 11:20 UTC (permalink / raw)
To: Daniel Almeida
Cc: linux-kernel, rust-for-linux, dri-devel, dakr, aliceryhl, airlied,
simona, ojeda, boqun, gary, bjorn3_gh, lossin, a.hindborg,
tmgross
On Thu, 13 Aug 2026 20:25:15 -0300
Daniel Almeida <daniel.almeida@collabora.com> wrote:
> Hi Onur,
>
> Can we move the iomem to the HwGate and get rid of its Arc? This way we
> ensure that all hardware access must consider the possibility of an ongoing
> reset by having each component that needs hardware access hold an Arc<HwGate>
> instead. Perhaps we can even broaden this to "hardware must be powered on" at
> some point in the future.
Sounds good to me, will do that in v5.
Regards,
Onur
>
> Otherwise, this looks good to me. Let's wait for Alice too.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-14 11:20 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-13 10:42 [PATCH v4 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-13 10:42 ` [PATCH v4 1/3] rust: workqueue: impl Send and Sync for OwnedQueue Onur Özkan
2026-08-13 10:42 ` [PATCH v4 2/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
2026-08-13 10:42 ` [PATCH v4 3/3] drm/tyr: add GPU reset infrastructure Onur Özkan
2026-08-13 23:25 ` Daniel Almeida
2026-08-14 11:20 ` Onur Özkan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox