[RFC PATCH 18/18] drm/panthor: Tolerate access-window loss during HW waits

From: Karunika Choo

Date: Thu May 28 2026 - 11:21:24 EST


The arbiter can close the access window while the driver is waiting for
GPU, power, or firmware acknowledgements. In that case the pending MMIO
wait cannot complete, but it should not be treated as a hardware timeout
or trigger recovery.

Add a helper to report whether the access window still owns GPU access
and use it to suppress timeout handling once access has been revoked.
Also skip deferred scheduler FW event processing when the window is no
longer available.

Signed-off-by: Karunika Choo <karunika.choo@xxxxxxx>
---
drivers/gpu/drm/panthor/panthor_aw.c | 8 ++++++++
drivers/gpu/drm/panthor/panthor_aw.h | 2 ++
drivers/gpu/drm/panthor/panthor_gpu.c | 4 +++-
drivers/gpu/drm/panthor/panthor_pwr.c | 27 +++++++++++++++++++------
drivers/gpu/drm/panthor/panthor_sched.c | 9 ++++++---
5 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_aw.c b/drivers/gpu/drm/panthor/panthor_aw.c
index 7c7637a8a9f1..f23022e2b4cd 100644
--- a/drivers/gpu/drm/panthor/panthor_aw.c
+++ b/drivers/gpu/drm/panthor/panthor_aw.c
@@ -566,3 +566,11 @@ int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev)

return panthor_aw_resume(ptdev);
}
+
+bool panthor_aw_has_gpu_access(struct panthor_device *ptdev)
+{
+ if (!ptdev->aw)
+ return true;
+
+ return (atomic_read(&ptdev->aw->state) == PANTHOR_AW_STATE_GPU_GRANTED);
+}
diff --git a/drivers/gpu/drm/panthor/panthor_aw.h b/drivers/gpu/drm/panthor/panthor_aw.h
index 7a46a1e18093..1da613fa330a 100644
--- a/drivers/gpu/drm/panthor/panthor_aw.h
+++ b/drivers/gpu/drm/panthor/panthor_aw.h
@@ -41,4 +41,6 @@ int panthor_aw_suspend(struct panthor_device *ptdev);

int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev);

+bool panthor_aw_has_gpu_access(struct panthor_device *ptdev);
+
#endif
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index 3c88a25287bf..129bb3779ebd 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -17,6 +17,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_print.h>

+#include "panthor_aw.h"
#include "panthor_device.h"
#include "panthor_device_io.h"
#include "panthor_gpu.h"
@@ -352,7 +353,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
msecs_to_jiffies(100))) {
spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
if ((ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED) != 0 &&
- !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED))
+ !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_CLEAN_CACHES_COMPLETED) &&
+ panthor_aw_has_gpu_access(ptdev))
ret = -ETIMEDOUT;
else
ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c
index b833e4559e45..0c3fa311c1af 100644
--- a/drivers/gpu/drm/panthor/panthor_pwr.c
+++ b/drivers/gpu/drm/panthor/panthor_pwr.c
@@ -10,6 +10,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_print.h>

+#include "panthor_aw.h"
#include "panthor_device.h"
#include "panthor_device_io.h"
#include "panthor_gpu_regs.h"
@@ -118,7 +119,8 @@ static int panthor_pwr_reset(struct panthor_device *ptdev, u32 reset_cmd)
msecs_to_jiffies(PWR_RESET_TIMEOUT_MS))) {
guard(spinlock_irqsave)(&ptdev->pwr->reqs_lock);

- if (reset_pending(ptdev) && !reset_irq_raised(ptdev)) {
+ if (reset_pending(ptdev) && !reset_irq_raised(ptdev) &&
+ panthor_aw_has_gpu_access(ptdev)) {
drm_err(&ptdev->base, "RESET timed out (0x%x)", reset_cmd);
return -ETIMEDOUT;
}
@@ -262,9 +264,14 @@ static int panthor_pwr_domain_transition(struct panthor_device *ptdev, u32 cmd,

panthor_pwr_write_command(ptdev, pwr_cmd, mask);

- ret = gpu_read64_poll_timeout(pwr->iomem, ready_reg, val, (mask & val) == expected_val,
+ ret = gpu_read64_poll_timeout(pwr->iomem, ready_reg, val,
+ ((mask & val) == expected_val ||
+ !panthor_aw_has_gpu_access(ptdev)),
100, timeout_us);
if (ret) {
+ if (!panthor_aw_has_gpu_access(ptdev))
+ return 0;
+
drm_err(&ptdev->base,
"timeout waiting on %s power domain transition, cmd(0x%x), arg(0x%llx)",
get_domain_name(domain), pwr_cmd, mask);
@@ -326,9 +333,13 @@ static int retract_domain(struct panthor_device *ptdev, u32 domain)
* allow-flag will be set with delegated-flag being cleared.
*/
ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val,
- ((delegated_mask | allow_mask) & val) == allow_mask, 10,
- PWR_TRANSITION_TIMEOUT_US);
+ (((delegated_mask | allow_mask) & val) == allow_mask ||
+ !panthor_aw_has_gpu_access(ptdev)),
+ 10, PWR_TRANSITION_TIMEOUT_US);
if (ret) {
+ if (!panthor_aw_has_gpu_access(ptdev))
+ return 0;
+
drm_err(&ptdev->base, "Retracting %s domain timeout, cmd(0x%x)",
get_domain_name(domain), pwr_cmd);
return ret;
@@ -383,9 +394,13 @@ static int delegate_domain(struct panthor_device *ptdev, u32 domain)
* allow-flag will be cleared with delegated-flag being set.
*/
ret = gpu_read64_poll_timeout(pwr->iomem, PWR_STATUS, val,
- ((delegated_mask | allow_mask) & val) == delegated_mask,
+ (((delegated_mask | allow_mask) & val) == delegated_mask ||
+ !panthor_aw_has_gpu_access(ptdev)),
10, PWR_TRANSITION_TIMEOUT_US);
if (ret) {
+ if (!panthor_aw_has_gpu_access(ptdev))
+ return 0;
+
drm_err(&ptdev->base, "Delegating %s domain timeout, cmd(0x%x)",
get_domain_name(domain), pwr_cmd);
return ret;
@@ -512,7 +527,7 @@ void panthor_pwr_l2_power_off(struct panthor_device *ptdev)
const u64 pwr_status = gpu_read64(pwr->iomem, PWR_STATUS);

/* Abort if L2 power off constraints are not satisfied */
- if (!(pwr_status & l2_allow_mask)) {
+ if (!(pwr_status & l2_allow_mask) && panthor_aw_has_gpu_access(ptdev)) {
drm_warn(&ptdev->base, "Power off L2 domain not allowed");
return;
}
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index 5b34032deff8..f4bfb8fab0dd 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -1875,7 +1875,10 @@ static void process_fw_events_work(struct work_struct *work)
u32 events = atomic_xchg(&sched->fw_events, 0);
struct panthor_device *ptdev = sched->ptdev;

- mutex_lock(&sched->lock);
+ guard(mutex)(&sched->lock);
+
+ if (!panthor_aw_has_gpu_access(ptdev))
+ return;

if (events & JOB_INT_GLOBAL_IF) {
sched_process_global_irq_locked(ptdev);
@@ -1888,8 +1891,6 @@ static void process_fw_events_work(struct work_struct *work)
sched_process_csg_irq_locked(ptdev, csg_id);
events &= ~BIT(csg_id);
}
-
- mutex_unlock(&sched->lock);
}

/**
@@ -1983,6 +1984,8 @@ static int csgs_upd_ctx_apply_locked(struct panthor_device *ptdev,
csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id);

ret = panthor_fw_csg_wait_acks(ptdev, csg_id, req_mask, &acked, 100);
+ if (ret && !panthor_aw_has_gpu_access(ptdev))
+ ret = 0;

if (acked & CSG_ENDPOINT_CONFIG)
csg_slot_sync_priority_locked(ptdev, csg_id);
--
2.43.0