* [PATCH v6 0/3] drm/tyr: GPU reset infrastructure
@ 2026-08-19 18:45 Onur Özkan
2026-08-19 18:45 ` [PATCH v6 1/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Onur Özkan @ 2026-08-19 18:45 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: add SRCU abstraction [1]
- rust: workqueue: add cancel_sync support [2]
TODOs:
- On reset failure, we don't do anything for now. We should unplug
the GPU.
- 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 v5:
- Use ScopedWork instead of a separately allocated Controller and its
open-coded cancellation.
- Rename reset-internal lifetimes.
- use dev_dbg!() instead of dev_info!().
- Use Danilo's workqueue series [2] which already includes OwnedQueue
Send + Sync, ScopedQueue and ScopedWork.
Link: https://lore.kernel.org/all/20260613065348.96750-1-work@onurozkan.dev [1]
Link: https://lore.kernel.org/all/20260807165252.3849875-1-dakr@kernel.org [2]
Link: https://lore.kernel.org/all/20260708114358.957305-1-work@onurozkan.dev
Link: https://gitlab.freedesktop.org/panfrost/linux/-/issues/28
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
Onur Özkan (3):
drm/tyr: clear stale IRQ state before soft reset
drm/tyr: add GPU reset infrastructure
drm/tyr: put iomem behind the hardware gate
drivers/gpu/drm/tyr/driver.rs | 65 ++++-----
drivers/gpu/drm/tyr/fw.rs | 16 +-
drivers/gpu/drm/tyr/mmu.rs | 9 +-
drivers/gpu/drm/tyr/mmu/address_space.rs | 49 +++----
drivers/gpu/drm/tyr/reset.rs | 242 +++++++++++++++++++++++++++++++
drivers/gpu/drm/tyr/reset/hw_gate.rs | 102 +++++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
7 files changed, 406 insertions(+), 78 deletions(-)
---
base-commit: 53441a9cae3c4be552fa8aefa6e61b0f1bceb8a5
change-id: 20260813-tyr-reset-impl-93e951f996b4
prerequisite-message-id: <20260807165252.3849875-1-dakr@kernel.org>
prerequisite-patch-id: 4275f7d6e3cf96d61221d47f2398ebfb896db0c7
prerequisite-patch-id: f5e24f7b3717f2ab0445b5395c7f12b554861d78
prerequisite-patch-id: 0bf6ae4abcef7090d0e48921d6ec627a59dc6a7a
prerequisite-patch-id: 8dc24064e858240a6bb5411a261a987a7eae3fad
prerequisite-patch-id: eefbd4a72ed6da0083e20811882738cc3b05604f
prerequisite-patch-id: 7502236d334b13c547a8b47f0be9bf7171b5ca6b
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
--
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v6 1/3] drm/tyr: clear stale IRQ state before soft reset
2026-08-19 18:45 [PATCH v6 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
@ 2026-08-19 18:45 ` Onur Özkan
2026-08-19 18:45 ` [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure Onur Özkan
2026-08-19 18:45 ` [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate Onur Özkan
2 siblings, 0 replies; 13+ messages in thread
From: Onur Özkan @ 2026-08-19 18:45 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] 13+ messages in thread
* [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-19 18:45 [PATCH v6 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-19 18:45 ` [PATCH v6 1/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
@ 2026-08-19 18:45 ` Onur Özkan
2026-08-21 15:31 ` Daniel Almeida
2026-08-19 18:45 ` [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate Onur Özkan
2 siblings, 1 reply; 13+ messages in thread
From: Onur Özkan @ 2026-08-19 18:45 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 | 41 ++----
drivers/gpu/drm/tyr/reset.rs | 249 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/tyr/reset/hw_gate.rs | 80 +++++++++++
drivers/gpu/drm/tyr/tyr.rs | 1 +
4 files changed, 343 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 90d6cd988cd2..52b1f16fa405 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,12 @@ 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.
+ #[pin]
+ pub(crate) reset: reset::ResetHandle<'bound>,
+
/// Firmware sections.
pub(crate) fw: Arc<Firmware<'bound>>,
@@ -85,23 +85,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 +119,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());
@@ -167,6 +149,9 @@ fn probe<'bound>(
let reg_data = try_pin_init!(TyrDrmRegistrationData {
pdev,
+ // SAFETY: `Registration` is stored in the platform driver data and
+ // not leaked, so `ResetHandle` is dropped before borrowed data expires.
+ reset <- unsafe { reset::ResetHandle::new(pdev, iomem.as_arc_borrow())? },
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..a41158c7ea21
--- /dev/null
+++ b/drivers/gpu/drm/tyr/reset.rs
@@ -0,0 +1,249 @@
+// 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::{
+ ScopedQueue,
+ ScopedWork,
+ ScopedWorkItem,
+ ScopedWorkRef, //
+ },
+};
+
+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<'ctrl> {
+ /// Parent platform device.
+ pdev: &'ctrl platform::Device<Bound>,
+ /// Mapped register space needed for reset operations.
+ iomem: Arc<IoMem<'ctrl>>,
+ /// State shared by reset schedulers and the worker.
+ state: Atomic<ResetState>,
+ /// Drains reset-sensitive hardware accesses before a reset.
+ #[pin]
+ hw: HwGate,
+}
+
+impl<'ctrl> ScopedWorkItem for Controller<'ctrl> {
+ fn run(work: &ScopedWorkRef<Self>) {
+ work.reset_work();
+ }
+}
+
+impl<'ctrl> Controller<'ctrl> {
+ /// Creates a reset controller.
+ fn new(
+ pdev: &'ctrl platform::Device<Bound>,
+ iomem: Arc<IoMem<'ctrl>>,
+ ) -> impl PinInit<Self, Error> {
+ try_pin_init!(Self {
+ pdev,
+ iomem,
+ state: Atomic::new(ResetState::Idle),
+ hw <- HwGate::new(),
+ })
+ }
+
+ /// 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) {
+ if !self.try_transition(ResetState::Pending, ResetState::InProgress) {
+ return;
+ }
+
+ dev_dbg!(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_dbg!(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.
+#[pin_data(PinnedDrop)]
+pub(crate) struct ResetHandle<'reset> {
+ #[pin]
+ controller: ScopedWork<Controller<'reset>>,
+ wq: ScopedQueue<'reset>,
+}
+
+impl<'reset> ResetHandle<'reset> {
+ /// Creates [`ResetHandle`].
+ ///
+ /// # Safety
+ ///
+ /// The returned handle must not be leaked or otherwise prevented from
+ /// running [`Drop`], since it owns work that may borrow from `'reset`.
+ pub(crate) unsafe fn new(
+ pdev: &'reset platform::Device<Bound>,
+ iomem: ArcBorrow<'_, IoMem<'reset>>,
+ ) -> Result<impl PinInit<Self, Error>> {
+ let iomem = iomem.into();
+
+ Ok(try_pin_init!(Self {
+ controller <- kernel::new_scoped_work!("tyr::reset", 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(&'reset 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);
+ }
+ }
+}
+
+#[pinned_drop]
+impl<'reset> PinnedDrop for ResetHandle<'reset> {
+ fn drop(self: Pin<&mut Self>) {
+ // Stop new reset requests before draining queued/running work.
+ self.controller
+ .state
+ .store(ResetState::ShuttingDown, Release);
+ }
+}
+
+/// Issues a soft reset command and waits for reset-complete IRQ status.
+fn issue_soft_reset(dev: &Device<Bound>, io: &IoMem<'_>) -> 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(dev: &Device<Bound>, iomem: &IoMem<'_>) -> 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..54754f9fc05f
--- /dev/null
+++ b/drivers/gpu/drm/tyr/reset/hw_gate.rs
@@ -0,0 +1,80 @@
+// 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, //
+ },
+};
+
+/// Synchronizes GPU hardware access with reset.
+#[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 access(&self) -> HwAccessGuard<'_> {
+ let gate_lock = self.gate_lock.lock();
+ let srcu = self.srcu.read_lock();
+ drop(gate_lock);
+
+ HwAccessGuard { _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) -> HwClosedGuard<'_> {
+ 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();
+
+ HwClosedGuard {
+ _gate_lock: gate_lock,
+ }
+ }
+}
+
+/// Shared hardware access that blocks reset until dropped.
+#[must_use = "the gate is released when the guard is dropped"]
+struct HwAccessGuard<'a> {
+ _srcu: srcu::Guard<'a>,
+}
+
+/// Exclusive hardware access for the reset worker that blocks new hardware
+/// accesses until dropped.
+#[must_use = "the gate stays closed until the guard is dropped"]
+pub(super) struct HwClosedGuard<'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] 13+ messages in thread
* [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate
2026-08-19 18:45 [PATCH v6 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-19 18:45 ` [PATCH v6 1/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
2026-08-19 18:45 ` [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure Onur Özkan
@ 2026-08-19 18:45 ` Onur Özkan
2026-08-24 17:05 ` Daniel Almeida
2 siblings, 1 reply; 13+ messages in thread
From: Onur Özkan @ 2026-08-19 18:45 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
Move iomem mapping into HwGate and pass Arc<HwGate> to components that
access hardware. Callers obtain HwAccessGuard before accessing the iomem
so the reset worker waits for ongoing accesses.
Suggested-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
drivers/gpu/drm/tyr/driver.rs | 35 +++++++++++------------
drivers/gpu/drm/tyr/fw.rs | 16 ++++++-----
drivers/gpu/drm/tyr/mmu.rs | 9 ++----
drivers/gpu/drm/tyr/mmu/address_space.rs | 49 ++++++++++++++++----------------
drivers/gpu/drm/tyr/reset.rs | 33 +++++++++------------
drivers/gpu/drm/tyr/reset/hw_gate.rs | 40 ++++++++++++++++++++------
6 files changed, 96 insertions(+), 86 deletions(-)
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 52b1f16fa405..c326192f8af2 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -76,9 +76,6 @@ pub(crate) struct TyrDrmRegistrationData<'bound> {
#[pin]
regulators: Mutex<Regulators>,
- /// GPU MMIO register mapping.
- pub(crate) iomem: Arc<IoMem<'bound>>,
-
/// Some information on the GPU.
///
/// This is mainly queried by userspace, i.e.: Mesa.
@@ -117,12 +114,19 @@ fn probe<'bound>(
let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
- let iomem = Arc::new(request.iomap_sized::<SZ_2M>()?, GFP_KERNEL)?;
+ let hw = Arc::pin_init(
+ reset::HwGate::new(request.iomap_sized::<SZ_2M>()?),
+ GFP_KERNEL,
+ )?;
- reset::run_reset(pdev.as_ref(), &iomem)?;
+ reset::run_reset(pdev.as_ref(), &hw)?;
- let gpu_info = GpuInfo::new(&iomem);
- gpu_info.log(pdev.as_ref());
+ let gpu_info = {
+ let hw_guard = hw.access();
+ let gpu_info = GpuInfo::new(hw_guard.iomem());
+ gpu_info.log(pdev.as_ref());
+ gpu_info
+ };
let pa_bits = MMU_FEATURES::from_raw(gpu_info.mmu_features)
.pa_bits()
@@ -134,24 +138,18 @@ fn probe<'bound>(
let unreg_dev = drm::UnregisteredDevice::<TyrDrmDriver>::new(pdev, Ok(()))?;
- let mmu = Mmu::new(iomem.as_arc_borrow(), &gpu_info)?;
+ let mmu = Mmu::new(hw.clone(), &gpu_info)?;
- let firmware = Firmware::new(
- pdev,
- iomem.clone(),
- &unreg_dev,
- mmu.as_arc_borrow(),
- &gpu_info,
- )?;
+ let firmware = Firmware::new(pdev, hw.clone(), &unreg_dev, mmu.as_arc_borrow(), &gpu_info)?;
firmware.boot()?;
firmware.enable_global_interface(&gpu_info, &core_clk)?;
let reg_data = try_pin_init!(TyrDrmRegistrationData {
pdev,
- // SAFETY: `Registration` is stored in the platform driver data and
- // not leaked, so `ResetHandle` is dropped before borrowed data expires.
- reset <- unsafe { reset::ResetHandle::new(pdev, iomem.as_arc_borrow())? },
+ // SAFETY: `ResetHandle` is stored in registration data created with `new_with_lt`
+ // and is dropped before the borrowed device and MMIO references expire.
+ reset <- unsafe { reset::ResetHandle::new(pdev, hw.clone())? },
fw: firmware,
clks <- new_mutex!(Clocks {
core: core_clk,
@@ -162,7 +160,6 @@ fn probe<'bound>(
_mali: mali_regulator,
_sram: sram_regulator,
}),
- iomem,
gpu_info,
});
diff --git a/drivers/gpu/drm/tyr/fw.rs b/drivers/gpu/drm/tyr/fw.rs
index 651bbe77f10b..e1522ab14e8d 100644
--- a/drivers/gpu/drm/tyr/fw.rs
+++ b/drivers/gpu/drm/tyr/fw.rs
@@ -41,7 +41,6 @@
use crate::{
driver::{
- IoMem,
TyrDrmDevice, //
},
fw::{
@@ -65,6 +64,7 @@
MCU_CONTROL,
MCU_STATUS, //
},
+ reset::HwGate,
vm::Vm, //
};
@@ -148,8 +148,8 @@ pub(crate) struct Firmware<'bound> {
/// Platform device reference (needed to access the MCU JOB_IRQ registers).
_pdev: ARef<platform::Device>,
- /// Iomem need to access registers.
- iomem: Arc<IoMem<'bound>>,
+ /// Shared gate that coordinates hardware access with GPU reset.
+ hw: Arc<HwGate<'bound>>,
/// MCU VM.
vm: Arc<Vm<'bound>>,
@@ -221,7 +221,7 @@ fn load(
/// Load firmware and map sections into MCU VM.
pub(crate) fn new(
pdev: &'bound platform::Device<Bound>,
- iomem: Arc<IoMem<'bound>>,
+ hw: Arc<HwGate<'bound>>,
ddev: &TyrDrmDevice<Uninit>,
mmu: ArcBorrow<'_, Mmu<'bound>>,
gpu_info: &GpuInfo,
@@ -262,7 +262,7 @@ pub(crate) fn new(
let firmware = Arc::pin_init(
try_pin_init!(Firmware {
_pdev: pdev.into(),
- iomem,
+ hw,
vm,
sections,
global_iface <- new_mutex!(GlobalInterface::new()?),
@@ -288,7 +288,8 @@ pub(crate) fn shared_section<'a>(&'a self) -> Result<&'a Section<'bound>> {
}
pub(crate) fn boot(&self) -> Result {
- let io = &self.iomem;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
io.write_reg(MCU_CONTROL::zeroed().with_req(McuControlMode::Auto));
if let Err(e) = poll::read_poll_timeout(
@@ -307,8 +308,9 @@ pub(crate) fn boot(&self) -> Result {
/// Enable the global interface.
pub(crate) fn enable_global_interface(&self, gpu_info: &GpuInfo, core_clk: &Clk) -> Result {
let shared_section = self.shared_section()?;
+ let hw_guard = self.hw.access();
self.global_iface
.lock()
- .enable(&self.iomem, shared_section, gpu_info, core_clk)
+ .enable(hw_guard.iomem(), shared_section, gpu_info, core_clk)
}
}
diff --git a/drivers/gpu/drm/tyr/mmu.rs b/drivers/gpu/drm/tyr/mmu.rs
index cb5908c80e3d..8df6d2ef3c74 100644
--- a/drivers/gpu/drm/tyr/mmu.rs
+++ b/drivers/gpu/drm/tyr/mmu.rs
@@ -26,7 +26,6 @@
};
use crate::{
- driver::IoMem,
gpu::GpuInfo,
mmu::address_space::{
AddressSpaceManager,
@@ -36,6 +35,7 @@
gpu_control::AS_PRESENT,
MAX_AS, //
},
+ reset::HwGate,
slot::SlotManager, //
};
@@ -67,14 +67,11 @@ pub(crate) struct Mmu<'bound> {
impl<'bound> Mmu<'bound> {
/// Create an MMU component for this device.
- pub(crate) fn new(
- iomem: ArcBorrow<'_, IoMem<'bound>>,
- gpu_info: &GpuInfo,
- ) -> Result<Arc<Mmu<'bound>>> {
+ pub(crate) fn new(hw: Arc<HwGate<'bound>>, gpu_info: &GpuInfo) -> Result<Arc<Mmu<'bound>>> {
let present = AS_PRESENT::from_raw(gpu_info.as_present).present().get();
let slot_count = present.count_ones().try_into()?;
- let as_manager = AddressSpaceManager::new(iomem, present)?;
+ let as_manager = AddressSpaceManager::new(hw, present)?;
let mmu_init = try_pin_init!(Self{
as_manager <- new_mutex!(SlotManager::new(as_manager, slot_count)?),
});
diff --git a/drivers/gpu/drm/tyr/mmu/address_space.rs b/drivers/gpu/drm/tyr/mmu/address_space.rs
index d5274220eb3c..7ce2902e6300 100644
--- a/drivers/gpu/drm/tyr/mmu/address_space.rs
+++ b/drivers/gpu/drm/tyr/mmu/address_space.rs
@@ -42,7 +42,6 @@
};
use crate::{
- driver::IoMem,
mmu::{
AsSlotManager,
Mmu, //
@@ -52,6 +51,7 @@
mmu_control::mmu_as_control::*,
MAX_AS, //
},
+ reset::HwGate,
slot::{
Seat,
SlotOperations, //
@@ -201,8 +201,8 @@ fn as_config(&self) -> Result<AddressSpaceConfig> {
///
/// [`SlotOperations`]: crate::slot::SlotOperations
pub(crate) struct AddressSpaceManager<'bound> {
- /// Memory-mapped I/O region for GPU register access.
- iomem: Arc<IoMem<'bound>>,
+ /// Shared gate that coordinates hardware access with GPU reset.
+ hw: Arc<HwGate<'bound>>,
/// Bitmask of available address space slots from GPU_AS_PRESENT register.
as_present: u32,
@@ -229,16 +229,13 @@ fn evict(&mut self, slot_idx: usize, _slot_data: &Self::SlotData) -> Result {
impl<'bound> AddressSpaceManager<'bound> {
/// Creates a new address space manager.
///
- /// Initializes the manager with references to the platform device and
- /// I/O memory region, along with the bitmask of available AS slots.
+ /// Initializes the manager with the hardware-access gate and the bitmask
+ /// of available AS slots.
pub(super) fn new(
- iomem: ArcBorrow<'_, IoMem<'bound>>,
+ hw: Arc<HwGate<'bound>>,
as_present: u32,
) -> Result<AddressSpaceManager<'bound>> {
- Ok(Self {
- iomem: iomem.into(),
- as_present,
- })
+ Ok(Self { hw, as_present })
}
/// Validates that an AS slot number is within range and present in hardware.
@@ -269,7 +266,8 @@ fn validate_as_slot(&self, as_nr: usize) -> Result {
///
/// Returns an error if polling times out after 10ms or if register access fails.
fn as_wait_ready(&self, as_nr: usize) -> Result {
- let io = &*self.iomem;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
let op = || {
let status_reg = STATUS::try_at(as_nr).ok_or(EINVAL)?;
Ok(io.read(status_reg))
@@ -283,9 +281,10 @@ fn as_wait_ready(&self, as_nr: usize) -> Result {
/// Sends a command to an AS slot.
///
/// Returns an error if waiting for ready times out or if register write fails.
- fn as_send_cmd(&mut self, as_nr: usize, cmd: MmuCommand) -> Result {
+ fn as_send_cmd(&self, as_nr: usize, cmd: MmuCommand) -> Result {
self.as_wait_ready(as_nr)?;
- let io = &*self.iomem;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
let command_reg = COMMAND::try_at(as_nr).ok_or(EINVAL)?;
io.write(command_reg, COMMAND::zeroed().with_command(cmd));
Ok(())
@@ -294,7 +293,7 @@ fn as_send_cmd(&mut self, as_nr: usize, cmd: MmuCommand) -> Result {
/// Sends a command to an AS slot and waits for completion.
///
/// Returns an error if sending the command fails or if waiting for completion times out.
- fn as_send_cmd_and_wait(&mut self, as_nr: usize, cmd: MmuCommand) -> Result {
+ fn as_send_cmd_and_wait(&self, as_nr: usize, cmd: MmuCommand) -> Result {
self.as_send_cmd(as_nr, cmd)?;
self.as_wait_ready(as_nr)?;
Ok(())
@@ -303,10 +302,10 @@ fn as_send_cmd_and_wait(&mut self, as_nr: usize, cmd: MmuCommand) -> Result {
/// Enables an AS slot with the provided configuration.
///
/// Returns an error if the slot is invalid or if register writes/commands fail.
- fn as_enable(&mut self, as_nr: usize, as_config: &AddressSpaceConfig) -> Result {
+ fn as_enable(&self, as_nr: usize, as_config: &AddressSpaceConfig) -> Result {
self.validate_as_slot(as_nr)?;
-
- let io = &*self.iomem;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
let transtab = as_config.transtab;
io.write(
@@ -346,14 +345,14 @@ fn as_enable(&mut self, as_nr: usize, as_config: &AddressSpaceConfig) -> Result
/// Disables an AS slot and clears its configuration.
///
/// Returns an error if the slot is invalid or if register writes/commands fail.
- fn as_disable(&mut self, as_nr: usize) -> Result {
+ fn as_disable(&self, as_nr: usize) -> Result {
self.validate_as_slot(as_nr)?;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
// Flush AS before disabling
self.as_send_cmd_and_wait(as_nr, MmuCommand::FlushMem)?;
- let io = &*self.iomem;
-
io.write(
TRANSTAB_LO::try_at(as_nr).ok_or(EINVAL)?,
TRANSTAB_LO::from_raw(0),
@@ -397,8 +396,10 @@ fn as_disable(&mut self, as_nr: usize) -> Result {
/// power-of-two region aligned to its size.
///
/// Returns an error if the slot is invalid or if register writes/commands fail.
- fn as_start_update(&mut self, as_nr: usize, region: &Range<u64>) -> Result {
+ fn as_start_update(&self, as_nr: usize, region: &Range<u64>) -> Result {
self.validate_as_slot(as_nr)?;
+ let hw_guard = self.hw.access();
+ let io = hw_guard.iomem();
// The lock operates on full 64-byte cache lines of translation table entries.
// Since each translation table entry (TTE) is 8 bytes, a cache line has 8 TTEs.
@@ -436,8 +437,6 @@ fn as_start_update(&mut self, as_nr: usize, region: &Range<u64>) -> Result {
// because log2(32 KiB) = 15.
let lockaddr_size = lock_region_log2 - 1;
- let io = &*self.iomem;
-
let lockaddr_val = LOCKADDR::zeroed()
.try_with_size(lockaddr_size)?
.try_with_base(lockaddr_base)?
@@ -458,7 +457,7 @@ fn as_start_update(&mut self, as_nr: usize, region: &Range<u64>) -> Result {
/// Completes an atomic translation table update.
///
/// Returns an error if the slot is invalid or if the flush command fails.
- fn as_end_update(&mut self, as_nr: usize) -> Result {
+ fn as_end_update(&self, as_nr: usize) -> Result {
self.validate_as_slot(as_nr)?;
self.as_send_cmd_and_wait(as_nr, MmuCommand::FlushPt)?;
Ok(())
@@ -467,7 +466,7 @@ fn as_end_update(&mut self, as_nr: usize) -> Result {
/// Flushes the translation table cache for an AS slot.
///
/// Returns an error if the slot is invalid or if the flush command fails.
- fn as_flush(&mut self, as_nr: usize) -> Result {
+ fn as_flush(&self, as_nr: usize) -> Result {
self.validate_as_slot(as_nr)?;
self.as_send_cmd(as_nr, MmuCommand::FlushPt)
}
diff --git a/drivers/gpu/drm/tyr/reset.rs b/drivers/gpu/drm/tyr/reset.rs
index a41158c7ea21..1abcd25877d3 100644
--- a/drivers/gpu/drm/tyr/reset.rs
+++ b/drivers/gpu/drm/tyr/reset.rs
@@ -21,7 +21,7 @@
mod hw_gate;
-use hw_gate::HwGate;
+pub(crate) use hw_gate::HwGate;
use kernel::{
device::{
@@ -41,8 +41,7 @@
Full,
Release, //
},
- Arc,
- ArcBorrow, //
+ Arc, //
},
time,
workqueue::{
@@ -84,13 +83,10 @@ unsafe impl AtomicType for ResetState {
struct Controller<'ctrl> {
/// Parent platform device.
pdev: &'ctrl platform::Device<Bound>,
- /// Mapped register space needed for reset operations.
- iomem: Arc<IoMem<'ctrl>>,
/// State shared by reset schedulers and the worker.
state: Atomic<ResetState>,
- /// Drains reset-sensitive hardware accesses before a reset.
- #[pin]
- hw: HwGate,
+ /// Shared gate that coordinates hardware access with GPU reset.
+ hw: Arc<HwGate<'ctrl>>,
}
impl<'ctrl> ScopedWorkItem for Controller<'ctrl> {
@@ -103,13 +99,12 @@ impl<'ctrl> Controller<'ctrl> {
/// Creates a reset controller.
fn new(
pdev: &'ctrl platform::Device<Bound>,
- iomem: Arc<IoMem<'ctrl>>,
+ hw: Arc<HwGate<'ctrl>>,
) -> impl PinInit<Self, Error> {
try_pin_init!(Self {
pdev,
- iomem,
state: Atomic::new(ResetState::Idle),
- hw <- HwGate::new(),
+ hw,
})
}
@@ -136,10 +131,7 @@ fn reset_work(&self) {
dev_dbg!(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);
+ let reset_result = run_reset(self.pdev.as_ref(), &self.hw);
if let Err(e) = reset_result {
dev_err!(self.pdev, "GPU reset failed: {:?}\n", e);
@@ -175,12 +167,10 @@ impl<'reset> ResetHandle<'reset> {
/// running [`Drop`], since it owns work that may borrow from `'reset`.
pub(crate) unsafe fn new(
pdev: &'reset platform::Device<Bound>,
- iomem: ArcBorrow<'_, IoMem<'reset>>,
+ hw: Arc<HwGate<'reset>>,
) -> Result<impl PinInit<Self, Error>> {
- let iomem = iomem.into();
-
Ok(try_pin_init!(Self {
- controller <- kernel::new_scoped_work!("tyr::reset", Controller::new(pdev, iomem)),
+ controller <- kernel::new_scoped_work!("tyr::reset", Controller::new(pdev, hw)),
// SAFETY: The caller guarantees the handle is dropped.
wq: unsafe { ScopedQueue::new(c"tyr-reset-wq")? },
}))
@@ -242,7 +232,10 @@ fn issue_soft_reset(dev: &Device<Bound>, io: &IoMem<'_>) -> Result {
/// - Trigger a GPU soft reset.
/// - Wait for the reset-complete IRQ status.
/// - Power L2 back on.
-pub(super) fn run_reset(dev: &Device<Bound>, iomem: &IoMem<'_>) -> Result {
+pub(super) fn run_reset(dev: &Device<Bound>, hw: &HwGate<'_>) -> Result {
+ let hw_guard = hw.close();
+ let iomem = hw_guard.iomem();
+
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
index 54754f9fc05f..b7db2abf47ea 100644
--- a/drivers/gpu/drm/tyr/reset/hw_gate.rs
+++ b/drivers/gpu/drm/tyr/reset/hw_gate.rs
@@ -18,9 +18,13 @@
},
};
+use crate::driver::IoMem;
+
/// Synchronizes GPU hardware access with reset.
#[pin_data]
-pub(super) struct HwGate {
+pub(crate) struct HwGate<'hw> {
+ /// GPU MMIO register mapping.
+ iomem: IoMem<'hw>,
/// Admits readers and is held exclusively while the reset worker owns the
/// hardware.
#[pin]
@@ -30,30 +34,33 @@ pub(super) struct HwGate {
srcu: Srcu,
}
-impl HwGate {
+impl<'hw> HwGate<'hw> {
/// Creates an open hardware-access gate.
- pub(super) fn new() -> impl PinInit<Self, Error> {
+ pub(crate) fn new(iomem: IoMem<'hw>) -> impl PinInit<Self, Error> {
try_pin_init!(Self {
+ iomem,
gate_lock <- new_mutex!(()),
srcu <- kernel::new_srcu!(),
})
}
/// Enters a reset-sensitive hardware-access section.
- #[expect(dead_code)]
- fn access(&self) -> HwAccessGuard<'_> {
+ pub(crate) fn access(&self) -> HwAccessGuard<'_, 'hw> {
let gate_lock = self.gate_lock.lock();
let srcu = self.srcu.read_lock();
drop(gate_lock);
- HwAccessGuard { _srcu: srcu }
+ HwAccessGuard {
+ gate: self,
+ _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) -> HwClosedGuard<'_> {
+ pub(super) fn close(&self) -> HwClosedGuard<'_, 'hw> {
let gate_lock = self.gate_lock.lock();
// Holding `gate_lock` prevents new readers from entering SRCU. Readers
@@ -61,6 +68,7 @@ pub(super) fn close(&self) -> HwClosedGuard<'_> {
self.srcu.synchronize();
HwClosedGuard {
+ gate: self,
_gate_lock: gate_lock,
}
}
@@ -68,13 +76,27 @@ pub(super) fn close(&self) -> HwClosedGuard<'_> {
/// Shared hardware access that blocks reset until dropped.
#[must_use = "the gate is released when the guard is dropped"]
-struct HwAccessGuard<'a> {
+pub(crate) struct HwAccessGuard<'a, 'hw> {
+ gate: &'a HwGate<'hw>,
_srcu: srcu::Guard<'a>,
}
+impl<'a, 'hw> HwAccessGuard<'a, 'hw> {
+ pub(crate) fn iomem(&self) -> &IoMem<'hw> {
+ &self.gate.iomem
+ }
+}
+
/// Exclusive hardware access for the reset worker that blocks new hardware
/// accesses until dropped.
#[must_use = "the gate stays closed until the guard is dropped"]
-pub(super) struct HwClosedGuard<'a> {
+pub(super) struct HwClosedGuard<'a, 'hw> {
+ gate: &'a HwGate<'hw>,
_gate_lock: MutexGuard<'a, ()>,
}
+
+impl<'a, 'hw> HwClosedGuard<'a, 'hw> {
+ pub(super) fn iomem(&self) -> &IoMem<'hw> {
+ &self.gate.iomem
+ }
+}
--
2.51.2
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-19 18:45 ` [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure Onur Özkan
@ 2026-08-21 15:31 ` Daniel Almeida
2026-08-21 15:58 ` Onur Özkan
0 siblings, 1 reply; 13+ messages in thread
From: Daniel Almeida @ 2026-08-21 15:31 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,
> On 19 Aug 2026, at 15:45, Onur Özkan <work@onurozkan.dev> wrote:
>
> 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>
I’d use dev_info instead, I don’t think a reset belongs in dev_dbg.
Otherwise, this looks good to go from my POV.
Tested-by: Daniel Almeida <daniel.almeida@collabora.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 15:31 ` Daniel Almeida
@ 2026-08-21 15:58 ` Onur Özkan
2026-08-21 16:12 ` Danilo Krummrich
2026-08-21 16:39 ` Daniel Almeida
0 siblings, 2 replies; 13+ messages in thread
From: Onur Özkan @ 2026-08-21 15:58 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 Fri, 21 Aug 2026 12:31:03 -0300
Daniel Almeida <daniel.almeida@collabora.com> wrote:
> Hi Onur,
>
> > On 19 Aug 2026, at 15:45, Onur Özkan <work@onurozkan.dev> wrote:
> >
> > 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>
>
> I’d use dev_info instead, I don’t think a reset belongs in dev_dbg.
It was dev_dbg initially, Danillo said otherwise and I changed it. I have no
strong feeling on both.
Does it deserve a new version to switch back into dev_dbg again? I think we can
easily switch that when pulling this series.
>
> Otherwise, this looks good to go from my POV.
>
> Tested-by: Daniel Almeida <daniel.almeida@collabora.com>
> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Thanks for testing and reviewing it.
Best,
Onur
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 15:58 ` Onur Özkan
@ 2026-08-21 16:12 ` Danilo Krummrich
2026-08-21 16:39 ` Daniel Almeida
1 sibling, 0 replies; 13+ messages in thread
From: Danilo Krummrich @ 2026-08-21 16:12 UTC (permalink / raw)
To: Onur Özkan
Cc: Daniel Almeida, linux-kernel, rust-for-linux, dri-devel,
aliceryhl, airlied, simona, ojeda, boqun, gary, bjorn3_gh, lossin,
a.hindborg, tmgross
On Fri Aug 21, 2026 at 5:58 PM CEST, Onur Özkan wrote:
> On Fri, 21 Aug 2026 12:31:03 -0300
> Daniel Almeida <daniel.almeida@collabora.com> wrote:
>> I’d use dev_info instead, I don’t think a reset belongs in dev_dbg.
>
> It was dev_dbg initially, Danillo said otherwise and I changed it. I have no
> strong feeling on both.
Why do you think it is useful to print "Starting GPU reset." and "GPU reset
completed." with dev_info()? How does this help users or help with debugging?
In general, if drivers work properly they should remain silent. A successful
reset means it worked properly. What you rather want to print, likely with
dev_warn() or dev_err(), is what caused the GPU reset to be performed in the
first place.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 15:58 ` Onur Özkan
2026-08-21 16:12 ` Danilo Krummrich
@ 2026-08-21 16:39 ` Daniel Almeida
2026-08-21 16:42 ` Onur Özkan
2026-08-21 17:01 ` Danilo Krummrich
1 sibling, 2 replies; 13+ messages in thread
From: Daniel Almeida @ 2026-08-21 16:39 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
> On 21 Aug 2026, at 12:58, Onur Özkan <work@onurozkan.dev> wrote:
>
> On Fri, 21 Aug 2026 12:31:03 -0300
> Daniel Almeida <daniel.almeida@collabora.com> wrote:
>
>> Hi Onur,
>>
>>> On 19 Aug 2026, at 15:45, Onur Özkan <work@onurozkan.dev> wrote:
>>>
>>> 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>
>>
>> I’d use dev_info instead, I don’t think a reset belongs in dev_dbg.
>
> It was dev_dbg initially, Danillo said otherwise and I changed it. I have no
> strong feeling on both.
>
You mean it was dev_info initially?
> Does it deserve a new version to switch back into dev_dbg again? I think we can
> easily switch that when pulling this series.
My point is that resetting the GPU should not be a “debug” trace, but rather something
that should hit dmesg unconditionally. Of all things that are printed on a driver, a
“hey the GPU is being reset because something crashed” is something that should
always show up IMHO.
I don’t think you need to send a new version though, let’s wait for more feedback
as well.
— Daniel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 16:39 ` Daniel Almeida
@ 2026-08-21 16:42 ` Onur Özkan
2026-08-21 17:01 ` Danilo Krummrich
1 sibling, 0 replies; 13+ messages in thread
From: Onur Özkan @ 2026-08-21 16:42 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 Fri, 21 Aug 2026 13:39:45 -0300
Daniel Almeida <daniel.almeida@collabora.com> wrote:
>
>
> > On 21 Aug 2026, at 12:58, Onur Özkan <work@onurozkan.dev> wrote:
> >
> > On Fri, 21 Aug 2026 12:31:03 -0300
> > Daniel Almeida <daniel.almeida@collabora.com> wrote:
> >
> >> Hi Onur,
> >>
> >>> On 19 Aug 2026, at 15:45, Onur Özkan <work@onurozkan.dev> wrote:
> >>>
> >>> 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>
> >>
> >> I’d use dev_info instead, I don’t think a reset belongs in dev_dbg.
> >
> > It was dev_dbg initially, Danillo said otherwise and I changed it. I have no
> > strong feeling on both.
> >
>
> You mean it was dev_info initially?
Yeah, I wrote it incorrectly.
>
> > Does it deserve a new version to switch back into dev_dbg again? I think we can
> > easily switch that when pulling this series.
>
> My point is that resetting the GPU should not be a “debug” trace, but rather something
> that should hit dmesg unconditionally. Of all things that are printed on a driver, a
> “hey the GPU is being reset because something crashed” is something that should
> always show up IMHO.
>
> I don’t think you need to send a new version though, let’s wait for more feedback
> as well.
>
Okay.
- Onur
>
> — Daniel
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 16:39 ` Daniel Almeida
2026-08-21 16:42 ` Onur Özkan
@ 2026-08-21 17:01 ` Danilo Krummrich
2026-08-21 17:23 ` Daniel Almeida
1 sibling, 1 reply; 13+ messages in thread
From: Danilo Krummrich @ 2026-08-21 17:01 UTC (permalink / raw)
To: Daniel Almeida
Cc: Onur Özkan, linux-kernel, rust-for-linux, dri-devel,
aliceryhl, airlied, simona, ojeda, boqun, gary, bjorn3_gh, lossin,
a.hindborg, tmgross
On Fri Aug 21, 2026 at 6:39 PM CEST, Daniel Almeida wrote:
> My point is that resetting the GPU should not be a “debug” trace, but rather
> something that should hit dmesg unconditionally. Of all things that are
> printed on a driver, a “hey the GPU is being reset because something crashed”
> is something that should always show up IMHO.
Please see my reply in [1]. If something crashed, please feel free to add a
dev_warn() or dev_err() print about the exact error condition. But please do not
add dev_info() prints about things that were successful and just bloat dmesg.
In this specific case you want the caller of ResetHandle::schedule() to print
about *why* the reset work was scheduled. You also already have a dev_err()
print when the GPU reset failed. So, at this point you're good already.
Additional prints about when exactly the reset work starts and when it completes
is stuff for dev_dbg().
[1] https://lore.kernel.org/all/DKUR5TGKTJT1.3VR0LSG4WWXJJ@kernel.org/
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 17:01 ` Danilo Krummrich
@ 2026-08-21 17:23 ` Daniel Almeida
2026-08-21 18:53 ` Danilo Krummrich
0 siblings, 1 reply; 13+ messages in thread
From: Daniel Almeida @ 2026-08-21 17:23 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Onur Özkan, linux-kernel, rust-for-linux, dri-devel,
aliceryhl, airlied, simona, ojeda, boqun, gary, bjorn3_gh, lossin,
a.hindborg, tmgross
> Why do you think it is useful to print "Starting GPU reset." and "GPU reset
> completed." with dev_info()? How does this help users or help with debugging?
>
> In general, if drivers work properly they should remain silent. A successful
> reset means it worked properly. What you rather want to print, likely with
> dev_warn() or dev_err(), is what caused the GPU reset to be performed in the
> first place.
I agree, no argument from me there. The problem is, when the GPU is resetting,
things are far from "working". In fact, things went so bad somewhere that it
brought the device down for everybody, and the system is taking steps to (try
to) bring it up again.
As a user, I very much appreciated this when games went down, it made me think
that the problem was important enough to report, and also likely explained why,
in that particular hardware, things didn't really work 100% well afterwards,
which prompted me to reboot the machine.
Two outcomes could have come from that, a) filing a bug on the game itself, and
b) telling the kernel guys that their reset code wasn't really working 100%
well either.
I do agree that "Starting GPU reset" is frivolous, but at least a message
saying that a reset took place, either sucessfully or not, is better than
silence. In fact, isn't this exactly what AMDGPU does? [2].
[2]: https://elixir.bootlin.com/linux/v7.2/source/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c#L5094
> On 21 Aug 2026, at 14:01, Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Fri Aug 21, 2026 at 6:39 PM CEST, Daniel Almeida wrote:
>> My point is that resetting the GPU should not be a “debug” trace, but rather
>> something that should hit dmesg unconditionally. Of all things that are
>> printed on a driver, a “hey the GPU is being reset because something crashed”
>> is something that should always show up IMHO.
>
> Please see my reply in [1]. If something crashed, please feel free to add a
> dev_warn() or dev_err() print about the exact error condition. But please do not
> add dev_info() prints about things that were successful and just bloat dmesg.
>
> In this specific case you want the caller of ResetHandle::schedule() to print
> about *why* the reset work was scheduled. You also already have a dev_err()
> print when the GPU reset failed. So, at this point you're good already.
I guess that also works, so long as it says that the GPU is resetting? i.e.:
it’s not only a fault or something, but also a message saying “this fault” (or
whatever it was) is causing a reset.
>
> Additional prints about when exactly the reset work starts and when it completes
> is stuff for dev_dbg().
>
> [1] https://lore.kernel.org/all/DKUR5TGKTJT1.3VR0LSG4WWXJJ@kernel.org/
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure
2026-08-21 17:23 ` Daniel Almeida
@ 2026-08-21 18:53 ` Danilo Krummrich
0 siblings, 0 replies; 13+ messages in thread
From: Danilo Krummrich @ 2026-08-21 18:53 UTC (permalink / raw)
To: Daniel Almeida
Cc: Onur Özkan, linux-kernel, rust-for-linux, dri-devel,
aliceryhl, airlied, simona, ojeda, boqun, gary, bjorn3_gh, lossin,
a.hindborg, tmgross
On Fri Aug 21, 2026 at 7:23 PM CEST, Daniel Almeida wrote:
> I agree, no argument from me there. The problem is, when the GPU is resetting,
> things are far from "working". In fact, things went so bad somewhere that it
> brought the device down for everybody, and the system is taking steps to (try
> to) bring it up again.
>
> As a user, I very much appreciated this when games went down, it made me think
> that the problem was important enough to report, and also likely explained why,
> in that particular hardware, things didn't really work 100% well afterwards,
> which prompted me to reboot the machine.
>
> Two outcomes could have come from that, a) filing a bug on the game itself, and
> b) telling the kernel guys that their reset code wasn't really working 100%
> well either.
>
> I do agree that "Starting GPU reset" is frivolous, but at least a message
> saying that a reset took place, either sucessfully or not, is better than
> silence.
I had a brief look at panthor, and it seems to me that this reset only ever
happens when the hardware is truely malfunctioning. I.e. it never runs under
"normal" error conditions, right?
In that case, I think it's fine. But I'd still rather print where the error
occurs and about the error / recovery condition. The "Starting GPU reset" one
still doesn't seem overly useful to me.
In general, the reset prints should still hint some additional information that
helps to understand the root cause.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate
2026-08-19 18:45 ` [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate Onur Özkan
@ 2026-08-24 17:05 ` Daniel Almeida
0 siblings, 0 replies; 13+ messages in thread
From: Daniel Almeida @ 2026-08-24 17:05 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,
While testing this patch, I came across the following splat:
[ 12.648287] WARNING: possible circular locking dependency detected
[ 12.648826] 7.1.0-rc5-g991a312b28c2 #1 Not tainted
[ 12.649245] ------------------------------------------------------
[ 12.649782] modprobe/167 is trying to acquire lock:
[ 12.650208] ffff0001f1713c80 (drivers/gpu/drm/tyr/reset/hw_gate.rs:42){+.+.}-{4:4}, at: rust_helper_mutex_lock+0x14/0x20
[ 12.651169]
[ 12.651169] but task is already holding lock:
[ 12.651677] ffff0001f1713cc0 (drivers/gpu/drm/tyr/reset/hw_gate.rs:43){.+.+}-{0:0}, at: srcu_lock_acquire+0x4/0x40
[ 12.652588]
[ 12.652588] which lock already depends on the new lock.
[ 12.652588]
[ 12.653299]
[ 12.653299] the existing dependency chain (in reverse order) is:
[ 12.653948]
[ 12.653948] -> #1 (drivers/gpu/drm/tyr/reset/hw_gate.rs:43){.+.+}-{0:0}:
[ 12.654664] srcu_lock_sync+0x30/0x3c
[ 12.655035] __synchronize_srcu+0x58/0x180
[ 12.655441] synchronize_srcu+0x20c/0x28c
[ 12.655838] _RNvNtCs8XoewxZdfnt_3tyr5reset9run_reset+0x3c/0x1d4 [tyr]
[ 12.656469] _RNvXNtCs8XoewxZdfnt_3tyr6driverNtB2_17TyrPlatformDriverNtNtCsbuTvttuFvbr_6kernel8platform6Driver5probe+0x254/0x470 [tyr]
[ 12.657573] _RNvMs0_NtCsbuTvttuFvbr_6kernel8platformINtB5_7AdapterNtNtCs8XoewxZdfnt_3tyr6driver17TyrPlatformDriverE14probe_callbackBT_+0x44/0x10c [tyr]
[ 12.658812] platform_probe+0x68/0xa4
[ 12.659182] really_probe+0x198/0x42c
[ 12.659551] __driver_probe_device+0xc8/0x190
[ 12.659979] driver_probe_device+0x40/0x240
[ 12.660392] __driver_attach+0xf8/0x294
[ 12.660775] bus_for_each_dev+0xec/0x144
[ 12.661168] driver_attach+0x24/0x30
[ 12.661528] bus_add_driver+0x158/0x2a8
[ 12.661910] driver_register+0x68/0x100
[ 12.662293] __platform_driver_register+0x24/0x30
[ 12.662752] init_module+0x70/0xfc4 [tyr]
[ 12.663157] do_one_initcall+0x114/0x4b4
[ 12.663551] do_init_module+0x54/0x220
[ 12.663927] load_module+0x1754/0x1984
[ 12.664302] __arm64_sys_init_module+0x184/0x23c
[ 12.664755] invoke_syscall+0x48/0xf8
[ 12.665125] el0_svc_common+0x90/0xdc
[ 12.665494] do_el0_svc+0x1c/0x28
[ 12.665833] el0_svc+0x54/0x258
[ 12.666159] el0t_64_sync_handler+0x78/0x12c
[ 12.666582] el0t_64_sync+0x198/0x19c
[ 12.666948]
[ 12.666948] -> #0 (drivers/gpu/drm/tyr/reset/hw_gate.rs:42){+.+.}-{4:4}:
[ 12.667665] __lock_acquire+0x18b4/0x3208
[ 12.668062] lock_acquire+0x110/0x300
[ 12.668429] __mutex_lock_common+0xec/0x1490
[ 12.668851] mutex_lock_nested+0x2c/0x38
[ 12.669242] rust_helper_mutex_lock+0x14/0x20
[ 12.669671] _RNvMs0_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB5_19AddressSpaceManager13as_wait_ready+0x28/0x108 [tyr]
[ 12.670670] _RNvMs0_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB5_19AddressSpaceManager11as_send_cmd+0x24/0xb0 [tyr]
[ 12.671645] _RNvXs_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB4_19AddressSpaceManagerNtNtB8_4slot14SlotOperations8activate+0x2dc/0x3ac [tyr]
[ 12.672807] _RNvMs0_NtCs8XoewxZdfnt_3tyr2fwNtB5_8Firmware3new+0x12d4/0x184c [tyr]
[ 12.673520] _RNvXNtCs8XoewxZdfnt_3tyr6driverNtB2_17TyrPlatformDriverNtNtCsbuTvttuFvbr_6kernel8platform6Driver5probe+0x368/0x470 [tyr]
[ 12.674622] _RNvMs0_NtCsbuTvttuFvbr_6kernel8platformINtB5_7AdapterNtNtCs8XoewxZdfnt_3tyr6driver17TyrPlatformDriverE14probe_callbackBT_+0x44/0x10c [tyr]
[ 12.675860] platform_probe+0x68/0xa4
[ 12.676228] really_probe+0x198/0x42c
[ 12.676596] __driver_probe_device+0xc8/0x190
[ 12.677024] driver_probe_device+0x40/0x240
[ 12.677437] __driver_attach+0xf8/0x294
[ 12.677818] bus_for_each_dev+0xec/0x144
[ 12.678210] driver_attach+0x24/0x30
[ 12.678570] bus_add_driver+0x158/0x2a8
[ 12.678951] driver_register+0x68/0x100
[ 12.679334] __platform_driver_register+0x24/0x30
[ 12.679792] init_module+0x70/0xfc4 [tyr]
[ 12.680196] do_one_initcall+0x114/0x4b4
[ 12.680589] do_init_module+0x54/0x220
[ 12.680964] load_module+0x1754/0x1984
[ 12.681338] __arm64_sys_init_module+0x184/0x23c
[ 12.681790] invoke_syscall+0x48/0xf8
[ 12.682159] el0_svc_common+0x90/0xdc
[ 12.682529] do_el0_svc+0x1c/0x28
[ 12.682868] el0_svc+0x54/0x258
[ 12.683193] el0t_64_sync_handler+0x78/0x12c
[ 12.683615] el0t_64_sync+0x198/0x19c
[ 12.683982]
[ 12.683982] other info that might help us debug this:
[ 12.683982]
[ 12.684677] Possible unsafe locking scenario:
[ 12.684677]
[ 12.685192] CPU0 CPU1
[ 12.685586] ---- ----
[ 12.685981] rlock(drivers/gpu/drm/tyr/reset/hw_gate.rs:43);
[ 12.686483] lock(drivers/gpu/drm/tyr/reset/hw_gate.rs:42);
[ 12.687196] lock(drivers/gpu/drm/tyr/reset/hw_gate.rs:43);
[ 12.687908] lock(drivers/gpu/drm/tyr/reset/hw_gate.rs:42);
[ 12.688403]
[ 12.688403] *** DEADLOCK ***
[ 12.688403]
[ 12.688917] 3 locks held by modprobe/167:
[ 12.689268] #0: ffff0001f0ee3938 (&dev->mutex){....}-{4:4}, at: __driver_attach+0xec/0x294
[ 12.690004] #1: ffff0001f3573468 (drivers/gpu/drm/tyr/mmu.rs:76){+.+.}-{4:4}, at: rust_helper_mutex_lock+0x14/0x20
[ 12.690921] #2: ffff0001f1713cc0 (drivers/gpu/drm/tyr/reset/hw_gate.rs:43){.+.+}-{0:0}, at: srcu_lock_acquire+0x4/0x40
[ 12.691869]
[ 12.691869] stack backtrace:
[ 12.692250] CPU: 4 UID: 0 PID: 167 Comm: modprobe Not tainted 7.1.0-rc5-g991a312b28c2 #1 PREEMPT
[ 12.692255] Hardware name: Radxa ROCK 5B (DT)
[ 12.692257] Call trace:
[ 12.692258] show_stack+0x18/0x24 (C)
[ 12.692266] dump_stack_lvl+0x40/0x9c
[ 12.692272] dump_stack+0x18/0x24
[ 12.692278] print_circular_bug+0x324/0x32c
[ 12.692283] check_noncircular+0x15c/0x178
[ 12.692287] __lock_acquire+0x18b4/0x3208
[ 12.692291] lock_acquire+0x110/0x300
[ 12.692295] __mutex_lock_common+0xec/0x1490
[ 12.692300] mutex_lock_nested+0x2c/0x38
[ 12.692306] rust_helper_mutex_lock+0x14/0x20
[ 12.692311] _RNvMs0_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB5_19AddressSpaceManager13as_wait_ready+0x28/0x108 [tyr]
[ 12.692323] _RNvMs0_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB5_19AddressSpaceManager11as_send_cmd+0x24/0xb0 [tyr]
[ 12.692334] _RNvXs_NtNtCs8XoewxZdfnt_3tyr3mmu13address_spaceNtB4_19AddressSpaceManagerNtNtB8_4slot14SlotOperations8activate+0x2dc/0x3ac [tyr]
[ 12.692346] _RNvMs0_NtCs8XoewxZdfnt_3tyr2fwNtB5_8Firmware3new+0x12d4/0x184c [tyr]
[ 12.692357] _RNvXNtCs8XoewxZdfnt_3tyr6driverNtB2_17TyrPlatformDriverNtNtCsbuTvttuFvbr_6kernel8platform6Driver5probe+0x368/0x470 [tyr]
[ 12.692368] _RNvMs0_NtCsbuTvttuFvbr_6kernel8platformINtB5_7AdapterNtNtCs8XoewxZdfnt_3tyr6driver17TyrPlatformDriverE14probe_callbackBT_+0x44/0x10c [tyr]
[ 12.692379] platform_probe+0x68/0xa4
[ 12.692385] really_probe+0x198/0x42c
[ 12.692389] __driver_probe_device+0xc8/0x190
[ 12.692393] driver_probe_device+0x40/0x240
[ 12.692398] __driver_attach+0xf8/0x294
[ 12.692402] bus_for_each_dev+0xec/0x144
[ 12.692409] driver_attach+0x24/0x30
[ 12.692413] bus_add_driver+0x158/0x2a8
[ 12.692416] driver_register+0x68/0x100
[ 12.692420] __platform_driver_register+0x24/0x30
[ 12.692426] init_module+0x70/0xfc4 [tyr]
[ 12.692437] do_one_initcall+0x114/0x4b4
[ 12.692443] do_init_module+0x54/0x220
[ 12.692447] load_module+0x1754/0x1984
[ 12.692451] __arm64_sys_init_module+0x184/0x23c
[ 12.692458] invoke_syscall+0x48/0xf8
[ 12.692464] el0_svc_common+0x90/0xdc
[ 12.692470] do_el0_svc+0x1c/0x28
[ 12.692476] el0_svc+0x54/0x258
[ 12.692482] el0t_64_sync_handler+0x78/0x12c
[ 12.692489] el0t_64_sync+0x198/0x19c
I suggest that we take the gate only once per public AS operation, and pass
&IoMem to the lower layers as needed. This has the side effect of making the
whole AS op atomic w.r.t to resets, which does not appear to be the case today,
as we nest calls to access(). Additionally, we can reintroduce the &mut self's
that were removed to make this compile; which I'd prefer. This can probably be
done by cloning the Arc<HwGate>, so it doesn't borrow self, i.e.:
let hw = self.hw.clone();
let guard = hw.access(); // doesn't borrow self
-- Daniel
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-08-24 17:05 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-19 18:45 [PATCH v6 0/3] drm/tyr: GPU reset infrastructure Onur Özkan
2026-08-19 18:45 ` [PATCH v6 1/3] drm/tyr: clear stale IRQ state before soft reset Onur Özkan
2026-08-19 18:45 ` [PATCH v6 2/3] drm/tyr: add GPU reset infrastructure Onur Özkan
2026-08-21 15:31 ` Daniel Almeida
2026-08-21 15:58 ` Onur Özkan
2026-08-21 16:12 ` Danilo Krummrich
2026-08-21 16:39 ` Daniel Almeida
2026-08-21 16:42 ` Onur Özkan
2026-08-21 17:01 ` Danilo Krummrich
2026-08-21 17:23 ` Daniel Almeida
2026-08-21 18:53 ` Danilo Krummrich
2026-08-19 18:45 ` [PATCH v6 3/3] drm/tyr: put iomem behind the hardware gate Onur Özkan
2026-08-24 17:05 ` Daniel Almeida
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox