The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v4 0/3] Rework panthor's cache flush and soft reset locking
@ 2026-08-12 14:07 Nicolas Frattaroli
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Nicolas Frattaroli @ 2026-08-12 14:07 UTC (permalink / raw)
  To: Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel, Nicolas Frattaroli

There is a problem in panthor's cache flushing/soft reset code
related to locking.

They take the reqs_lock spinlock with _irqsave, even though the
contended lock is never acquired in a raw interrupt handler. Only a
threaded handler locks it.

A new tracepoint to debug cache flushing duration without initial
locking waits is thrown in for good measure as well, to complement
what's in lock_stat and what the function tracer can already do.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
Changes in v4:
- Replace flush tracepoints with just one tracepoint that has a duration
  and exit status argument
- Link to v3: https://patch.msgid.link/20260811-panthor-cache-flush-fix-v3-0-47d2c1bb1dab@collabora.com

Changes in v3:
- Drop new wait_event macro patch as the existing ones have a memory
  barrier that makes the current use valid
- Rewrite fix patch to use scoped guards, and just get rid of the IRQ
  disabling
- Add separate fix for the outside-of-lock pending_reqs clearing in soft
  reset path
- Move tracepoint patch to before fixes for easier before/after testing
- Link to v2: https://patch.msgid.link/20260730-panthor-cache-flush-fix-v2-0-28790478bfff@collabora.com

Changes in v2:
- Use trace event template for the two tracepoints (ty Steven Rostedt)
- Link to v1: https://patch.msgid.link/20260729-panthor-cache-flush-fix-v1-0-205921ed3c81@collabora.com

---
Nicolas Frattaroli (3):
      drm/panthor: Add tracepoint for cache flushing
      drm/panthor: Revisit reqs_lock handling in flush/reset paths
      drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs

 drivers/gpu/drm/panthor/panthor_gpu.c   | 89 ++++++++++++++++++++-------------
 drivers/gpu/drm/panthor/panthor_trace.h | 38 ++++++++++++++
 2 files changed, 93 insertions(+), 34 deletions(-)
---
base-commit: 96ddbb14986632af742523e68f90d51c138c57f0
change-id: 20260728-panthor-cache-flush-fix-b36cb15f92c3

Best regards,
--  
Nicolas Frattaroli <nicolas.frattaroli@collabora.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing
  2026-08-12 14:07 [PATCH v4 0/3] Rework panthor's cache flush and soft reset locking Nicolas Frattaroli
@ 2026-08-12 14:07 ` Nicolas Frattaroli
  2026-08-12 15:07   ` Boris Brezillon
                     ` (2 more replies)
  2026-08-12 14:07 ` [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths Nicolas Frattaroli
  2026-08-12 14:07 ` [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs Nicolas Frattaroli
  2 siblings, 3 replies; 11+ messages in thread
From: Nicolas Frattaroli @ 2026-08-12 14:07 UTC (permalink / raw)
  To: Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel, Nicolas Frattaroli

Add a new event tracepoint: gpu_cache_flush to be emitted after a GPU
cache flush completes, with duration and return status arguments.

This allows debugging the duration a flush takes irrespective of initial
function entry lock contention, and communicates information about
whether the flush timed out or errored out in other ways, and which
caches were flushed.

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_gpu.c   | 26 +++++++++++++++++++++-
 drivers/gpu/drm/panthor/panthor_trace.h | 38 +++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index c013d6bf9a59..7088371c6d64 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -317,6 +317,21 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
 	return panthor_gpu_power_on(ptdev, L2, 1, 20000);
 }
 
+static inline void panthor_gpu_emit_flush_caches_tp(struct panthor_device *ptdev,
+						    u64 start, u32 l2, u32 lsc,
+						    u32 other, int ret)
+{
+	u32 duration;
+
+	if (!tracepoint_enabled(gpu_cache_flush) || !start)
+		return;
+
+	if (check_sub_overflow(ktime_get_ns(), start, &duration))
+		duration = U32_MAX;
+
+	trace_gpu_cache_flush(ptdev->base.dev, l2, lsc, other, duration, ret);
+}
+
 /**
  * panthor_gpu_flush_caches() - Flush caches
  * @ptdev: Device.
@@ -331,12 +346,17 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 {
 	struct panthor_gpu *gpu = ptdev->gpu;
 	unsigned long flags;
+	u64 start = 0;
 	int ret = 0;
 
 	/* Serialize cache flush operations. */
 	guard(mutex)(&ptdev->gpu->cache_flush_lock);
 
 	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
+
+	if (tracepoint_enabled(gpu_cache_flush))
+		start = ktime_get_ns();
+
 	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
 		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
 		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
@@ -345,8 +365,10 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 	}
 	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
 
-	if (ret)
+	if (ret) {
+		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
 		return ret;
+	}
 
 	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
 				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
@@ -360,6 +382,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
 	}
 
+	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
+
 	if (ret) {
 		panthor_device_schedule_reset(ptdev);
 		drm_err(&ptdev->base, "Flush caches timeout");
diff --git a/drivers/gpu/drm/panthor/panthor_trace.h b/drivers/gpu/drm/panthor/panthor_trace.h
index 6ffeb4fe6599..bd8652549ab4 100644
--- a/drivers/gpu/drm/panthor/panthor_trace.h
+++ b/drivers/gpu/drm/panthor/panthor_trace.h
@@ -76,6 +76,44 @@ TRACE_EVENT(gpu_job_irq,
 		  __entry->events, __entry->duration_ns)
 );
 
+/**
+ * gpu_cache_flush - emitted after cache flush completes
+ * @dev: pointer to the &struct device, for printing the device name
+ * @l2: "l2" flush flags
+ * @lsc: "lsc" flush flags
+ * @other: "other" flush flags
+ * @duration_ns: how long the cache flush operation took, in nanoseconds
+ * @ret: return status, 0 == success, negative errno on error
+ *
+ * Begins measuring after any initial lock contention around the locks needed
+ * for flushing caches, but before the actual cache flush is requested. Stops
+ * measuring and is emitted after flush operation is over.
+ */
+TRACE_EVENT(gpu_cache_flush,
+	    TP_PROTO(const struct device *dev, u32 l2, u32 lsc, u32 other,
+		     u32 duration_ns, int ret),
+	    TP_ARGS(dev, l2, lsc, other, duration_ns, ret),
+	    TP_STRUCT__entry(
+		    __string(dev_name, dev_name(dev))
+		    __field(u32, l2)
+		    __field(u32, lsc)
+		    __field(u32, other)
+		    __field(u32, duration_ns)
+		    __field(int, ret)
+	    ),
+	    TP_fast_assign(
+		    __assign_str(dev_name);
+		    __entry->l2          = l2;
+		    __entry->lsc         = lsc;
+		    __entry->other       = other;
+		    __entry->duration_ns = duration_ns;
+		    __entry->ret         = ret;
+	    ),
+	    TP_printk("%s: l2=0x%x lsc=0x%x other=0x%x duration_ns=%u ret=%d",
+		      __get_str(dev_name), __entry->l2, __entry->lsc,
+		      __entry->other, __entry->duration_ns, __entry->ret)
+);
+
 #endif /* __PANTHOR_TRACE_H__ */
 
 #undef TRACE_INCLUDE_PATH

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths
  2026-08-12 14:07 [PATCH v4 0/3] Rework panthor's cache flush and soft reset locking Nicolas Frattaroli
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
@ 2026-08-12 14:07 ` Nicolas Frattaroli
  2026-08-19 15:37   ` Steven Price
  2026-08-20 11:03   ` Liviu Dudau
  2026-08-12 14:07 ` [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs Nicolas Frattaroli
  2 siblings, 2 replies; 11+ messages in thread
From: Nicolas Frattaroli @ 2026-08-12 14:07 UTC (permalink / raw)
  To: Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel, Nicolas Frattaroli

panthor_gpu_flush_caches() and panthor_gpu_soft_reset() acquire their
reqs_lock spinlock with the IRQ-disabling variants of the spinlocking
functions. This isn't necessary, as the lock is never taken from an
atomic context, as Panthor uses threaded interrupt handlers. The result
of this overly strict locking is that IRQs may be disabled more
frequently and for longer than they should be, resulting in increased
system latency.

Switch the locking to use non-IRQ-disabling scoped_guard statements for
locking. The wait_event_timeout read of pending_reqs outside of the
spinlock is fine as wait_event_timeout is a memory barrier according to
the Linux Memory Model.

Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_gpu.c | 72 ++++++++++++++++-------------------
 1 file changed, 33 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index 7088371c6d64..55e33f145b40 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -345,41 +345,36 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
 			     u32 l2, u32 lsc, u32 other)
 {
 	struct panthor_gpu *gpu = ptdev->gpu;
-	unsigned long flags;
 	u64 start = 0;
 	int ret = 0;
 
 	/* Serialize cache flush operations. */
 	guard(mutex)(&ptdev->gpu->cache_flush_lock);
 
-	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
-
-	if (tracepoint_enabled(gpu_cache_flush))
-		start = ktime_get_ns();
-
-	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
-		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
-		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
-	} else {
-		ret = -EIO;
-	}
-	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
-
-	if (ret) {
-		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
-		return ret;
+	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
+		if (tracepoint_enabled(gpu_cache_flush))
+			start = ktime_get_ns();
+
+		if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
+			ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
+			gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
+		} else {
+			panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc,
+							 other, -EIO);
+			return -EIO;
+		}
 	}
 
 	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
 				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
 				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))
-			ret = -ETIMEDOUT;
-		else
-			ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
-		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
+		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))
+				ret = -ETIMEDOUT;
+			else
+				ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
+		}
 	}
 
 	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
@@ -402,27 +397,26 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
 {
 	struct panthor_gpu *gpu = ptdev->gpu;
 	bool timedout = false;
-	unsigned long flags;
 
-	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
-	if (!drm_WARN_ON(&ptdev->base,
-			 ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
-		ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
-		gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
-		gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
+	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
+		if (!drm_WARN_ON(&ptdev->base,
+				ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
+			ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
+			gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
+			gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
+		}
 	}
-	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
 
 	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
 				!(ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED),
 				msecs_to_jiffies(100))) {
-		spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
-		if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
-		    !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
-			timedout = true;
-		else
-			ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
-		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
+		scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
+			if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
+			!(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
+				timedout = true;
+			else
+				ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
+		}
 	}
 
 	if (timedout) {

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs
  2026-08-12 14:07 [PATCH v4 0/3] Rework panthor's cache flush and soft reset locking Nicolas Frattaroli
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
  2026-08-12 14:07 ` [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths Nicolas Frattaroli
@ 2026-08-12 14:07 ` Nicolas Frattaroli
  2026-08-19 15:37   ` Steven Price
  2026-08-20 11:06   ` Liviu Dudau
  2 siblings, 2 replies; 11+ messages in thread
From: Nicolas Frattaroli @ 2026-08-12 14:07 UTC (permalink / raw)
  To: Boris Brezillon, Steven Price, Liviu Dudau, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
	Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel, Nicolas Frattaroli

panthor_gpu_soft_reset() sets pending_reqs to 0 without taking the
requisite reqs_lock.

Fix this by taking the lock for the duration of the modification.

Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
---
 drivers/gpu/drm/panthor/panthor_gpu.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
index 55e33f145b40..fb2702e1e0a2 100644
--- a/drivers/gpu/drm/panthor/panthor_gpu.c
+++ b/drivers/gpu/drm/panthor/panthor_gpu.c
@@ -424,7 +424,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
 		return -ETIMEDOUT;
 	}
 
-	ptdev->gpu->pending_reqs = 0;
+	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
+		ptdev->gpu->pending_reqs = 0;
+	}
+
 	return 0;
 }
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
@ 2026-08-12 15:07   ` Boris Brezillon
  2026-08-19 15:37   ` Steven Price
  2026-08-20 10:58   ` Liviu Dudau
  2 siblings, 0 replies; 11+ messages in thread
From: Boris Brezillon @ 2026-08-12 15:07 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Steven Price, Liviu Dudau, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Grant Likely,
	Heiko Stuebner, linux-kernel, dri-devel, kernel

On Wed, 12 Aug 2026 16:07:18 +0200
Nicolas Frattaroli <nicolas.frattaroli@collabora.com> wrote:

> Add a new event tracepoint: gpu_cache_flush to be emitted after a GPU
> cache flush completes, with duration and return status arguments.
> 
> This allows debugging the duration a flush takes irrespective of initial
> function entry lock contention, and communicates information about
> whether the flush timed out or errored out in other ways, and which
> caches were flushed.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c   | 26 +++++++++++++++++++++-
>  drivers/gpu/drm/panthor/panthor_trace.h | 38 +++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index c013d6bf9a59..7088371c6d64 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -317,6 +317,21 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
>  	return panthor_gpu_power_on(ptdev, L2, 1, 20000);
>  }
>  
> +static inline void panthor_gpu_emit_flush_caches_tp(struct panthor_device *ptdev,
> +						    u64 start, u32 l2, u32 lsc,
> +						    u32 other, int ret)
> +{
> +	u32 duration;
> +
> +	if (!tracepoint_enabled(gpu_cache_flush) || !start)
> +		return;
> +
> +	if (check_sub_overflow(ktime_get_ns(), start, &duration))
> +		duration = U32_MAX;
> +
> +	trace_gpu_cache_flush(ptdev->base.dev, l2, lsc, other, duration, ret);
> +}
> +
>  /**
>   * panthor_gpu_flush_caches() - Flush caches
>   * @ptdev: Device.
> @@ -331,12 +346,17 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
>  	unsigned long flags;
> +	u64 start = 0;
>  	int ret = 0;
>  
>  	/* Serialize cache flush operations. */
>  	guard(mutex)(&ptdev->gpu->cache_flush_lock);
>  
>  	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> +
> +	if (tracepoint_enabled(gpu_cache_flush))
> +		start = ktime_get_ns();
> +
>  	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
>  		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
>  		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> @@ -345,8 +365,10 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  	}
>  	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  
> -	if (ret)
> +	if (ret) {
> +		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
>  		return ret;
> +	}
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
> @@ -360,6 +382,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  	}
>  
> +	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> +
>  	if (ret) {
>  		panthor_device_schedule_reset(ptdev);
>  		drm_err(&ptdev->base, "Flush caches timeout");
> diff --git a/drivers/gpu/drm/panthor/panthor_trace.h b/drivers/gpu/drm/panthor/panthor_trace.h
> index 6ffeb4fe6599..bd8652549ab4 100644
> --- a/drivers/gpu/drm/panthor/panthor_trace.h
> +++ b/drivers/gpu/drm/panthor/panthor_trace.h
> @@ -76,6 +76,44 @@ TRACE_EVENT(gpu_job_irq,
>  		  __entry->events, __entry->duration_ns)
>  );
>  
> +/**
> + * gpu_cache_flush - emitted after cache flush completes
> + * @dev: pointer to the &struct device, for printing the device name
> + * @l2: "l2" flush flags
> + * @lsc: "lsc" flush flags
> + * @other: "other" flush flags
> + * @duration_ns: how long the cache flush operation took, in nanoseconds
> + * @ret: return status, 0 == success, negative errno on error
> + *
> + * Begins measuring after any initial lock contention around the locks needed
> + * for flushing caches, but before the actual cache flush is requested. Stops
> + * measuring and is emitted after flush operation is over.
> + */
> +TRACE_EVENT(gpu_cache_flush,
> +	    TP_PROTO(const struct device *dev, u32 l2, u32 lsc, u32 other,
> +		     u32 duration_ns, int ret),
> +	    TP_ARGS(dev, l2, lsc, other, duration_ns, ret),
> +	    TP_STRUCT__entry(
> +		    __string(dev_name, dev_name(dev))
> +		    __field(u32, l2)
> +		    __field(u32, lsc)
> +		    __field(u32, other)
> +		    __field(u32, duration_ns)
> +		    __field(int, ret)
> +	    ),
> +	    TP_fast_assign(
> +		    __assign_str(dev_name);
> +		    __entry->l2          = l2;
> +		    __entry->lsc         = lsc;
> +		    __entry->other       = other;
> +		    __entry->duration_ns = duration_ns;
> +		    __entry->ret         = ret;
> +	    ),
> +	    TP_printk("%s: l2=0x%x lsc=0x%x other=0x%x duration_ns=%u ret=%d",
> +		      __get_str(dev_name), __entry->l2, __entry->lsc,
> +		      __entry->other, __entry->duration_ns, __entry->ret)
> +);
> +
>  #endif /* __PANTHOR_TRACE_H__ */
>  
>  #undef TRACE_INCLUDE_PATH
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
  2026-08-12 15:07   ` Boris Brezillon
@ 2026-08-19 15:37   ` Steven Price
  2026-08-20 10:58   ` Liviu Dudau
  2 siblings, 0 replies; 11+ messages in thread
From: Steven Price @ 2026-08-19 15:37 UTC (permalink / raw)
  To: Nicolas Frattaroli, Boris Brezillon, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel

On 12/08/2026 15:07, Nicolas Frattaroli wrote:
> Add a new event tracepoint: gpu_cache_flush to be emitted after a GPU
> cache flush completes, with duration and return status arguments.
> 
> This allows debugging the duration a flush takes irrespective of initial
> function entry lock contention, and communicates information about
> whether the flush timed out or errored out in other ways, and which
> caches were flushed.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Steven Price <steven.price@arm.com>

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c   | 26 +++++++++++++++++++++-
>  drivers/gpu/drm/panthor/panthor_trace.h | 38 +++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index c013d6bf9a59..7088371c6d64 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -317,6 +317,21 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
>  	return panthor_gpu_power_on(ptdev, L2, 1, 20000);
>  }
>  
> +static inline void panthor_gpu_emit_flush_caches_tp(struct panthor_device *ptdev,
> +						    u64 start, u32 l2, u32 lsc,
> +						    u32 other, int ret)
> +{
> +	u32 duration;
> +
> +	if (!tracepoint_enabled(gpu_cache_flush) || !start)
> +		return;
> +
> +	if (check_sub_overflow(ktime_get_ns(), start, &duration))
> +		duration = U32_MAX;
> +
> +	trace_gpu_cache_flush(ptdev->base.dev, l2, lsc, other, duration, ret);
> +}
> +
>  /**
>   * panthor_gpu_flush_caches() - Flush caches
>   * @ptdev: Device.
> @@ -331,12 +346,17 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
>  	unsigned long flags;
> +	u64 start = 0;
>  	int ret = 0;
>  
>  	/* Serialize cache flush operations. */
>  	guard(mutex)(&ptdev->gpu->cache_flush_lock);
>  
>  	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> +
> +	if (tracepoint_enabled(gpu_cache_flush))
> +		start = ktime_get_ns();
> +
>  	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
>  		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
>  		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> @@ -345,8 +365,10 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  	}
>  	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  
> -	if (ret)
> +	if (ret) {
> +		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
>  		return ret;
> +	}
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
> @@ -360,6 +382,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  	}
>  
> +	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> +
>  	if (ret) {
>  		panthor_device_schedule_reset(ptdev);
>  		drm_err(&ptdev->base, "Flush caches timeout");
> diff --git a/drivers/gpu/drm/panthor/panthor_trace.h b/drivers/gpu/drm/panthor/panthor_trace.h
> index 6ffeb4fe6599..bd8652549ab4 100644
> --- a/drivers/gpu/drm/panthor/panthor_trace.h
> +++ b/drivers/gpu/drm/panthor/panthor_trace.h
> @@ -76,6 +76,44 @@ TRACE_EVENT(gpu_job_irq,
>  		  __entry->events, __entry->duration_ns)
>  );
>  
> +/**
> + * gpu_cache_flush - emitted after cache flush completes
> + * @dev: pointer to the &struct device, for printing the device name
> + * @l2: "l2" flush flags
> + * @lsc: "lsc" flush flags
> + * @other: "other" flush flags
> + * @duration_ns: how long the cache flush operation took, in nanoseconds
> + * @ret: return status, 0 == success, negative errno on error
> + *
> + * Begins measuring after any initial lock contention around the locks needed
> + * for flushing caches, but before the actual cache flush is requested. Stops
> + * measuring and is emitted after flush operation is over.
> + */
> +TRACE_EVENT(gpu_cache_flush,
> +	    TP_PROTO(const struct device *dev, u32 l2, u32 lsc, u32 other,
> +		     u32 duration_ns, int ret),
> +	    TP_ARGS(dev, l2, lsc, other, duration_ns, ret),
> +	    TP_STRUCT__entry(
> +		    __string(dev_name, dev_name(dev))
> +		    __field(u32, l2)
> +		    __field(u32, lsc)
> +		    __field(u32, other)
> +		    __field(u32, duration_ns)
> +		    __field(int, ret)
> +	    ),
> +	    TP_fast_assign(
> +		    __assign_str(dev_name);
> +		    __entry->l2          = l2;
> +		    __entry->lsc         = lsc;
> +		    __entry->other       = other;
> +		    __entry->duration_ns = duration_ns;
> +		    __entry->ret         = ret;
> +	    ),
> +	    TP_printk("%s: l2=0x%x lsc=0x%x other=0x%x duration_ns=%u ret=%d",
> +		      __get_str(dev_name), __entry->l2, __entry->lsc,
> +		      __entry->other, __entry->duration_ns, __entry->ret)
> +);
> +
>  #endif /* __PANTHOR_TRACE_H__ */
>  
>  #undef TRACE_INCLUDE_PATH
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths
  2026-08-12 14:07 ` [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths Nicolas Frattaroli
@ 2026-08-19 15:37   ` Steven Price
  2026-08-20 11:03   ` Liviu Dudau
  1 sibling, 0 replies; 11+ messages in thread
From: Steven Price @ 2026-08-19 15:37 UTC (permalink / raw)
  To: Nicolas Frattaroli, Boris Brezillon, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel

On 12/08/2026 15:07, Nicolas Frattaroli wrote:
> panthor_gpu_flush_caches() and panthor_gpu_soft_reset() acquire their
> reqs_lock spinlock with the IRQ-disabling variants of the spinlocking
> functions. This isn't necessary, as the lock is never taken from an
> atomic context, as Panthor uses threaded interrupt handlers. The result
> of this overly strict locking is that IRQs may be disabled more
> frequently and for longer than they should be, resulting in increased
> system latency.
> 
> Switch the locking to use non-IRQ-disabling scoped_guard statements for
> locking. The wait_event_timeout read of pending_reqs outside of the
> spinlock is fine as wait_event_timeout is a memory barrier according to
> the Linux Memory Model.
> 
> Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Steven Price <steven.price@arm.com>

Although one minor formatting nit below.

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c | 72 ++++++++++++++++-------------------
>  1 file changed, 33 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index 7088371c6d64..55e33f145b40 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -345,41 +345,36 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  			     u32 l2, u32 lsc, u32 other)
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
> -	unsigned long flags;
>  	u64 start = 0;
>  	int ret = 0;
>  
>  	/* Serialize cache flush operations. */
>  	guard(mutex)(&ptdev->gpu->cache_flush_lock);
>  
> -	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -
> -	if (tracepoint_enabled(gpu_cache_flush))
> -		start = ktime_get_ns();
> -
> -	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
> -		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
> -		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> -	} else {
> -		ret = -EIO;
> -	}
> -	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> -
> -	if (ret) {
> -		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> -		return ret;
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		if (tracepoint_enabled(gpu_cache_flush))
> +			start = ktime_get_ns();
> +
> +		if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
> +			ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
> +			gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> +		} else {
> +			panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc,
> +							 other, -EIO);
> +			return -EIO;
> +		}
>  	}
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
>  				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))
> -			ret = -ETIMEDOUT;
> -		else
> -			ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
> -		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> +		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))

NIT: This isn't aligned correctly with the if() above any more.

To be honest what we really need here is a helper for this sequence as
there's basically the same code again in panthor_gpu_soft_reset() below.

> +				ret = -ETIMEDOUT;
> +			else
> +				ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
> +		}
>  	}
>  
>  	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> @@ -402,27 +397,26 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
>  	bool timedout = false;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -	if (!drm_WARN_ON(&ptdev->base,
> -			 ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
> -		ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
> -		gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
> -		gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		if (!drm_WARN_ON(&ptdev->base,
> +				ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
> +			ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
> +			gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
> +			gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
> +		}
>  	}
> -	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED),
>  				msecs_to_jiffies(100))) {
> -		spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -		if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
> -		    !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
> -			timedout = true;
> -		else
> -			ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
> -		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> +		scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +			if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
> +			!(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))

NIT: Same issue here.

Thanks,
Steve

> +				timedout = true;
> +			else
> +				ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
> +		}
>  	}
>  
>  	if (timedout) {
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs
  2026-08-12 14:07 ` [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs Nicolas Frattaroli
@ 2026-08-19 15:37   ` Steven Price
  2026-08-20 11:06   ` Liviu Dudau
  1 sibling, 0 replies; 11+ messages in thread
From: Steven Price @ 2026-08-19 15:37 UTC (permalink / raw)
  To: Nicolas Frattaroli, Boris Brezillon, Liviu Dudau,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Grant Likely, Heiko Stuebner
  Cc: linux-kernel, dri-devel, kernel

On 12/08/2026 15:07, Nicolas Frattaroli wrote:
> panthor_gpu_soft_reset() sets pending_reqs to 0 without taking the
> requisite reqs_lock.
> 
> Fix this by taking the lock for the duration of the modification.
> 
> Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Steven Price <steven.price@arm.com>

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index 55e33f145b40..fb2702e1e0a2 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -424,7 +424,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
>  		return -ETIMEDOUT;
>  	}
>  
> -	ptdev->gpu->pending_reqs = 0;
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		ptdev->gpu->pending_reqs = 0;
> +	}
> +
>  	return 0;
>  }
>  
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing
  2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
  2026-08-12 15:07   ` Boris Brezillon
  2026-08-19 15:37   ` Steven Price
@ 2026-08-20 10:58   ` Liviu Dudau
  2 siblings, 0 replies; 11+ messages in thread
From: Liviu Dudau @ 2026-08-20 10:58 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Boris Brezillon, Steven Price, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Grant Likely,
	Heiko Stuebner, linux-kernel, dri-devel, kernel

On Wed, Aug 12, 2026 at 04:07:18PM +0200, Nicolas Frattaroli wrote:
> Add a new event tracepoint: gpu_cache_flush to be emitted after a GPU
> cache flush completes, with duration and return status arguments.
> 
> This allows debugging the duration a flush takes irrespective of initial
> function entry lock contention, and communicates information about
> whether the flush timed out or errored out in other ways, and which
> caches were flushed.
> 
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>

Best regards,
Liviu

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c   | 26 +++++++++++++++++++++-
>  drivers/gpu/drm/panthor/panthor_trace.h | 38 +++++++++++++++++++++++++++++++++
>  2 files changed, 63 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index c013d6bf9a59..7088371c6d64 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -317,6 +317,21 @@ int panthor_gpu_l2_power_on(struct panthor_device *ptdev)
>  	return panthor_gpu_power_on(ptdev, L2, 1, 20000);
>  }
>  
> +static inline void panthor_gpu_emit_flush_caches_tp(struct panthor_device *ptdev,
> +						    u64 start, u32 l2, u32 lsc,
> +						    u32 other, int ret)
> +{
> +	u32 duration;
> +
> +	if (!tracepoint_enabled(gpu_cache_flush) || !start)
> +		return;
> +
> +	if (check_sub_overflow(ktime_get_ns(), start, &duration))
> +		duration = U32_MAX;
> +
> +	trace_gpu_cache_flush(ptdev->base.dev, l2, lsc, other, duration, ret);
> +}
> +
>  /**
>   * panthor_gpu_flush_caches() - Flush caches
>   * @ptdev: Device.
> @@ -331,12 +346,17 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
>  	unsigned long flags;
> +	u64 start = 0;
>  	int ret = 0;
>  
>  	/* Serialize cache flush operations. */
>  	guard(mutex)(&ptdev->gpu->cache_flush_lock);
>  
>  	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> +
> +	if (tracepoint_enabled(gpu_cache_flush))
> +		start = ktime_get_ns();
> +
>  	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
>  		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
>  		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> @@ -345,8 +365,10 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  	}
>  	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  
> -	if (ret)
> +	if (ret) {
> +		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
>  		return ret;
> +	}
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
> @@ -360,6 +382,8 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  	}
>  
> +	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> +
>  	if (ret) {
>  		panthor_device_schedule_reset(ptdev);
>  		drm_err(&ptdev->base, "Flush caches timeout");
> diff --git a/drivers/gpu/drm/panthor/panthor_trace.h b/drivers/gpu/drm/panthor/panthor_trace.h
> index 6ffeb4fe6599..bd8652549ab4 100644
> --- a/drivers/gpu/drm/panthor/panthor_trace.h
> +++ b/drivers/gpu/drm/panthor/panthor_trace.h
> @@ -76,6 +76,44 @@ TRACE_EVENT(gpu_job_irq,
>  		  __entry->events, __entry->duration_ns)
>  );
>  
> +/**
> + * gpu_cache_flush - emitted after cache flush completes
> + * @dev: pointer to the &struct device, for printing the device name
> + * @l2: "l2" flush flags
> + * @lsc: "lsc" flush flags
> + * @other: "other" flush flags
> + * @duration_ns: how long the cache flush operation took, in nanoseconds
> + * @ret: return status, 0 == success, negative errno on error
> + *
> + * Begins measuring after any initial lock contention around the locks needed
> + * for flushing caches, but before the actual cache flush is requested. Stops
> + * measuring and is emitted after flush operation is over.
> + */
> +TRACE_EVENT(gpu_cache_flush,
> +	    TP_PROTO(const struct device *dev, u32 l2, u32 lsc, u32 other,
> +		     u32 duration_ns, int ret),
> +	    TP_ARGS(dev, l2, lsc, other, duration_ns, ret),
> +	    TP_STRUCT__entry(
> +		    __string(dev_name, dev_name(dev))
> +		    __field(u32, l2)
> +		    __field(u32, lsc)
> +		    __field(u32, other)
> +		    __field(u32, duration_ns)
> +		    __field(int, ret)
> +	    ),
> +	    TP_fast_assign(
> +		    __assign_str(dev_name);
> +		    __entry->l2          = l2;
> +		    __entry->lsc         = lsc;
> +		    __entry->other       = other;
> +		    __entry->duration_ns = duration_ns;
> +		    __entry->ret         = ret;
> +	    ),
> +	    TP_printk("%s: l2=0x%x lsc=0x%x other=0x%x duration_ns=%u ret=%d",
> +		      __get_str(dev_name), __entry->l2, __entry->lsc,
> +		      __entry->other, __entry->duration_ns, __entry->ret)
> +);
> +
>  #endif /* __PANTHOR_TRACE_H__ */
>  
>  #undef TRACE_INCLUDE_PATH
> 
> -- 
> 2.55.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths
  2026-08-12 14:07 ` [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths Nicolas Frattaroli
  2026-08-19 15:37   ` Steven Price
@ 2026-08-20 11:03   ` Liviu Dudau
  1 sibling, 0 replies; 11+ messages in thread
From: Liviu Dudau @ 2026-08-20 11:03 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Boris Brezillon, Steven Price, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Grant Likely,
	Heiko Stuebner, linux-kernel, dri-devel, kernel

On Wed, Aug 12, 2026 at 04:07:19PM +0200, Nicolas Frattaroli wrote:
> panthor_gpu_flush_caches() and panthor_gpu_soft_reset() acquire their
> reqs_lock spinlock with the IRQ-disabling variants of the spinlocking
> functions. This isn't necessary, as the lock is never taken from an
> atomic context, as Panthor uses threaded interrupt handlers. The result
> of this overly strict locking is that IRQs may be disabled more
> frequently and for longer than they should be, resulting in increased
> system latency.
> 
> Switch the locking to use non-IRQ-disabling scoped_guard statements for
> locking. The wait_event_timeout read of pending_reqs outside of the
> spinlock is fine as wait_event_timeout is a memory barrier according to
> the Linux Memory Model.
> 
> Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>

Best regards,
Liviu

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c | 72 ++++++++++++++++-------------------
>  1 file changed, 33 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index 7088371c6d64..55e33f145b40 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -345,41 +345,36 @@ int panthor_gpu_flush_caches(struct panthor_device *ptdev,
>  			     u32 l2, u32 lsc, u32 other)
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
> -	unsigned long flags;
>  	u64 start = 0;
>  	int ret = 0;
>  
>  	/* Serialize cache flush operations. */
>  	guard(mutex)(&ptdev->gpu->cache_flush_lock);
>  
> -	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -
> -	if (tracepoint_enabled(gpu_cache_flush))
> -		start = ktime_get_ns();
> -
> -	if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
> -		ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
> -		gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> -	} else {
> -		ret = -EIO;
> -	}
> -	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> -
> -	if (ret) {
> -		panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> -		return ret;
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		if (tracepoint_enabled(gpu_cache_flush))
> +			start = ktime_get_ns();
> +
> +		if (!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED)) {
> +			ptdev->gpu->pending_reqs |= GPU_IRQ_CLEAN_CACHES_COMPLETED;
> +			gpu_write(gpu->iomem, GPU_CMD, GPU_FLUSH_CACHES(l2, lsc, other));
> +		} else {
> +			panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc,
> +							 other, -EIO);
> +			return -EIO;
> +		}
>  	}
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_CLEAN_CACHES_COMPLETED),
>  				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))
> -			ret = -ETIMEDOUT;
> -		else
> -			ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
> -		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> +		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))
> +				ret = -ETIMEDOUT;
> +			else
> +				ptdev->gpu->pending_reqs &= ~GPU_IRQ_CLEAN_CACHES_COMPLETED;
> +		}
>  	}
>  
>  	panthor_gpu_emit_flush_caches_tp(ptdev, start, l2, lsc, other, ret);
> @@ -402,27 +397,26 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
>  {
>  	struct panthor_gpu *gpu = ptdev->gpu;
>  	bool timedout = false;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -	if (!drm_WARN_ON(&ptdev->base,
> -			 ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
> -		ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
> -		gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
> -		gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		if (!drm_WARN_ON(&ptdev->base,
> +				ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED)) {
> +			ptdev->gpu->pending_reqs |= GPU_IRQ_RESET_COMPLETED;
> +			gpu_write(gpu->irq.iomem, INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
> +			gpu_write(gpu->iomem, GPU_CMD, GPU_SOFT_RESET);
> +		}
>  	}
> -	spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
>  
>  	if (!wait_event_timeout(ptdev->gpu->reqs_acked,
>  				!(ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED),
>  				msecs_to_jiffies(100))) {
> -		spin_lock_irqsave(&ptdev->gpu->reqs_lock, flags);
> -		if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
> -		    !(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
> -			timedout = true;
> -		else
> -			ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
> -		spin_unlock_irqrestore(&ptdev->gpu->reqs_lock, flags);
> +		scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +			if ((ptdev->gpu->pending_reqs & GPU_IRQ_RESET_COMPLETED) != 0 &&
> +			!(gpu_read(gpu->irq.iomem, INT_RAWSTAT) & GPU_IRQ_RESET_COMPLETED))
> +				timedout = true;
> +			else
> +				ptdev->gpu->pending_reqs &= ~GPU_IRQ_RESET_COMPLETED;
> +		}
>  	}
>  
>  	if (timedout) {
> 
> -- 
> 2.55.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs
  2026-08-12 14:07 ` [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs Nicolas Frattaroli
  2026-08-19 15:37   ` Steven Price
@ 2026-08-20 11:06   ` Liviu Dudau
  1 sibling, 0 replies; 11+ messages in thread
From: Liviu Dudau @ 2026-08-20 11:06 UTC (permalink / raw)
  To: Nicolas Frattaroli
  Cc: Boris Brezillon, Steven Price, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Grant Likely,
	Heiko Stuebner, linux-kernel, dri-devel, kernel

On Wed, Aug 12, 2026 at 04:07:20PM +0200, Nicolas Frattaroli wrote:
> panthor_gpu_soft_reset() sets pending_reqs to 0 without taking the
> requisite reqs_lock.
> 
> Fix this by taking the lock for the duration of the modification.
> 
> Fixes: 5cd894e258c4 ("drm/panthor: Add the GPU logical block")
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>

Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>

Best regards,
Liviu

> ---
>  drivers/gpu/drm/panthor/panthor_gpu.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c
> index 55e33f145b40..fb2702e1e0a2 100644
> --- a/drivers/gpu/drm/panthor/panthor_gpu.c
> +++ b/drivers/gpu/drm/panthor/panthor_gpu.c
> @@ -424,7 +424,10 @@ int panthor_gpu_soft_reset(struct panthor_device *ptdev)
>  		return -ETIMEDOUT;
>  	}
>  
> -	ptdev->gpu->pending_reqs = 0;
> +	scoped_guard(spinlock, &ptdev->gpu->reqs_lock) {
> +		ptdev->gpu->pending_reqs = 0;
> +	}
> +
>  	return 0;
>  }
>  
> 
> -- 
> 2.55.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-08-20 11:06 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 14:07 [PATCH v4 0/3] Rework panthor's cache flush and soft reset locking Nicolas Frattaroli
2026-08-12 14:07 ` [PATCH v4 1/3] drm/panthor: Add tracepoint for cache flushing Nicolas Frattaroli
2026-08-12 15:07   ` Boris Brezillon
2026-08-19 15:37   ` Steven Price
2026-08-20 10:58   ` Liviu Dudau
2026-08-12 14:07 ` [PATCH v4 2/3] drm/panthor: Revisit reqs_lock handling in flush/reset paths Nicolas Frattaroli
2026-08-19 15:37   ` Steven Price
2026-08-20 11:03   ` Liviu Dudau
2026-08-12 14:07 ` [PATCH v4 3/3] drm/panthor: Take reqs_lock in soft_reset for clearing pending_reqs Nicolas Frattaroli
2026-08-19 15:37   ` Steven Price
2026-08-20 11:06   ` Liviu Dudau

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox