[PATCH v1 25/27] drm/panthor: Tolerate access-window loss during HW waits
From: Karunika Choo
Date: Tue Sep 22 2026 - 17:14:15 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.
Skip firmware-event processing when GPU access is unavailable.
Signed-off-by: Karunika Choo <karunika.choo@xxxxxxx>
---
v1:
- extend access-window loss handling to fw boot wait.
drivers/gpu/drm/panthor/panthor_aw.c | 8 ++++++++
drivers/gpu/drm/panthor/panthor_aw.h | 2 ++
drivers/gpu/drm/panthor/panthor_fw.c | 5 +++--
drivers/gpu/drm/panthor/panthor_gpu.c | 4 +++-
drivers/gpu/drm/panthor/panthor_pwr.c | 27 +++++++++++++++++++------
drivers/gpu/drm/panthor/panthor_sched.c | 5 +++++
6 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/panthor/panthor_aw.c b/drivers/gpu/drm/panthor/panthor_aw.c
index 4fcfb3ad05073..9ebb23eadfec5 100644
--- a/drivers/gpu/drm/panthor/panthor_aw.c
+++ b/drivers/gpu/drm/panthor/panthor_aw.c
@@ -573,3 +573,11 @@ int panthor_aw_ensure_gpu_access(struct panthor_device *ptdev)
goto again;
}
+
+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 7a46a1e18093a..1da613fa330a0 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_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 1449d9a66302e..b4c234f3d3ea4 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -1140,9 +1140,10 @@ static int panthor_fw_start(struct panthor_device *ptdev)
gpu_write(fw->iomem, MCU_CONTROL, MCU_CONTROL_AUTO);
if (!wait_event_timeout(ptdev->fw->req_waitqueue,
- ptdev->fw->booted,
+ (ptdev->fw->booted ||
+ !panthor_aw_has_gpu_access(ptdev)),
msecs_to_jiffies(1000))) {
- if (!ptdev->fw->booted &&
+ if (!ptdev->fw->booted && panthor_aw_has_gpu_access(ptdev) &&
!(gpu_read(fw->irq.iomem, INT_STAT) & JOB_INT_GLOBAL_IF))
timedout = true;
}
diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index e6e970e9b59d3..25fe7c77f8763 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_gpu.h"
#include "panthor_gpu_regs.h"
@@ -376,7 +377,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
msecs_to_jiffies(100))) {
scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
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 cc2e01595f23b..2a0feb0b39ece 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_gpu_regs.h"
#include "panthor_hw.h"
@@ -122,7 +123,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;
}
@@ -266,9 +268,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);
@@ -330,9 +337,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;
@@ -387,9 +398,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;
@@ -519,7 +534,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 ac6aee554820e..6d801329514e0 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -1887,6 +1887,9 @@ void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events)
guard(spinlock)(&ptdev->scheduler->events_lock);
+ if (!panthor_aw_has_gpu_access(ptdev))
+ return;
+
if (events & JOB_INT_GLOBAL_IF) {
sched_process_global_irq_locked(ptdev);
events &= ~JOB_INT_GLOBAL_IF;
@@ -2060,6 +2063,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