* [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings
@ 2026-09-07 20:16 Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 01/16] drm/panfrost: Move shrinker initialization and unplug one level down Adrián Larumbe
` (15 more replies)
0 siblings, 16 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
This patch series began as an assortment of small fixes for some issues
uncovered by Claude. Over time, it has evolved to include many other
fixes for further problems revealed by Sashiko in successive revisions,
and also refactorings and improvements suggested by maintainer
discussions.
A subset of patches submitted in previous revisions was already merged
after they had been reviewed, to avoid this series growing to unmanageable
extents.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
Changes in v8:
- Applied fixes for issues brought up by Sashiko.
- Rolled back some additions from v7: job stopping, IRQ consolidation.
- Applied RPM fixes before moving most driver init code into panfrost_device.c
- Brought back v6 patch that enables MMU IRQs before device is registered.
- Simplified perfcnt reset handling procedure, so that no retry is done in the kernel.
- Link to v7: https://patch.msgid.link/20260828-claude-fixes-v7-0-72a13b2c125d@collabora.com
Changes in v7:
- Again fixed some minor issues reported by Sashiko.
- Made sure the new debugfs reset knob works even when runtime PM isn't enabled.
- Added new patch that handles job termination at driver teardown time.
- Link to v6: https://patch.msgid.link/20260826-claude-fixes-v6-0-78119af409e7@collabora.com
Changes in v6:
- Grafted trivial already-reviwed patches from previous revisions into
their own series so that they could be merged into drm-misc-next.
- Added commits with multiple refactorings, code rearrangements and simplifications.
- Addressed all issues brought up by reviwers and Sashiko in the previous revision.
- Link to v5: https://patch.msgid.link/20260811-claude-fixes-v5-0-3d692c9e98c2@collabora.com
Changes in v5:
- Addressed more issues uncovered by Sashiko.
- Discarded two patches to avoid dealing with too many pre-existing issues at once.
- Biggest change is the re-arrangement of the start sequence, made to look like Panthor.
- Link to v4: https://patch.msgid.link/20260729-claude-fixes-v4-0-01968f2ec77a@collabora.com
Changes in v4:
- Fixed errors and issues uncovered by Sashiko in the previous revision.
- Changed the way RPM checks whether the device is initialised when resuming.
- Simplified perfcnt treatment of potential resets.
- Link to v3: https://patch.msgid.link/20260724-claude-fixes-v3-0-542af61abd0f@collabora.com
Changes in v3:
- Applied some minor suggestions for the first couple of patches in the series.
- Moved shrinker initialisation into gem initialisation.
- Fixed RPM bugs by moving all clock and power initialisation into RPM resume.
- Added patch for reset sequence fixes and also a userspace knob to trigger it.
- Reworked perfcnt fix by having the reset sequence restore its initial state.
- Link to v2: https://patch.msgid.link/20260604-claude-fixes-v2-0-57c6bd4c1655@collabora.com
Changes in v2:
- Fixed race conditions introduced by the previous revision, in the RPM and
HWPerf commits specifically. These can be consulted at [1]
- Don't attempt to suspend the device unconditionally at the end of
probe(), and do it through autosuspend instead.
- Broke the RPM patch into one that fixes PM refcnt proper and another one
for MMU enablement at device init time.
- Moved perfcnt GPU disable helper into its own commmit. Same for
transplating shrinker initialisation and unplug.
- Added 'Fixes' and 'Reported-by' tags to all the relevant commits
- [1] https://sashiko.dev/#/patchset/20260526-claude-fixes-v1-0-16e92eaa4949%40collabora.com
- Link to v1: https://patch.msgid.link/20260526-claude-fixes-v1-0-16e92eaa4949@collabora.com
To: Boris Brezillon <boris.brezillon@collabora.com>
To: Rob Herring <robh@kernel.org>
To: Steven Price <steven.price@arm.com>
To: Adrián Larumbe <adrian.larumbe@collabora.com>
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: Maxime Ripard <mripard@kernel.org>
To: Thomas Zimmermann <tzimmermann@suse.de>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
To: Faith Ekstrand <faith.ekstrand@collabora.com>
To: "Marty E. Plummer" <hanetzer@startmail.com>
To: Tomeu Vizoso <tomeu@tomeuvizoso.net>
To: Eric Anholt <eric@anholt.net>
To: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
To: Robin Murphy <robin.murphy@arm.com>
To: Philipp Zabel <p.zabel@pengutronix.de>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-kernel@vger.kernel.org
Cc: Neil Armstrong <neil.armstrong@linaro.org>
---
Adrián Larumbe (16):
drm/panfrost: Move shrinker initialization and unplug one level down
drm/panfrost: Move lock and modparam initialisations into their subsystems
drm/panfrost: Move debugfs initialisation to relevant subsystems
drm/panfrost: Skip NULL checks for clock enable/disabling
drm/panfrost: Consolidate device clock management and reset
drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove
drm/panfrost: Explicitly enable MMU interrupts at device init
drm/panfrost: Move all DRM device initialisation into device_init()
drm/panfrost: Add warning messages to fatal error conditions
drm/panfrost: Add debugfs knob for manually triggering a GPU reset
drm/panfrost: Move perfcnt GPU disable sequence into a helper
drm/panfrost: Skip cache flush/invalidate when enabling perfcnt
drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems
drm/panfrost: Introduce a reset lock
drm/panfrost: Fix races between perfcnt and reset sequence
drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field
drivers/gpu/drm/panfrost/panfrost_device.c | 220 ++++++++++++++-------
drivers/gpu/drm/panfrost/panfrost_device.h | 5 +
drivers/gpu/drm/panfrost/panfrost_drv.c | 198 +------------------
drivers/gpu/drm/panfrost/panfrost_drv.h | 9 -
drivers/gpu/drm/panfrost/panfrost_gem.c | 64 ++++--
drivers/gpu/drm/panfrost/panfrost_gem.h | 10 +-
drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c | 9 +-
drivers/gpu/drm/panfrost/panfrost_gpu.c | 2 +
drivers/gpu/drm/panfrost/panfrost_job.c | 101 ++++++++++
drivers/gpu/drm/panfrost/panfrost_job.h | 4 +
drivers/gpu/drm/panfrost/panfrost_mmu.c | 14 +-
drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 236 ++++++++++++++---------
drivers/gpu/drm/panfrost/panfrost_perfcnt.h | 1 +
include/uapi/drm/panfrost_drm.h | 8 +-
14 files changed, 497 insertions(+), 384 deletions(-)
---
base-commit: 3ab04dcce43cd4fdaed94f08f4e6289be4921ea4
change-id: 20260523-claude-fixes-82b03a134a8c
Best regards,
--
Adrián Larumbe <adrian.larumbe@collabora.com>
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v8 01/16] drm/panfrost: Move shrinker initialization and unplug one level down
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 02/16] drm/panfrost: Move lock and modparam initialisations into their subsystems Adrián Larumbe
` (14 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Since the moment we call drm_dev_register() the device should be in a
position to accept jobs, so it's best if the shrinker is already
initialized by then.
On top of that, make shrinker functions take an panfrost_device pointer
like other functions in the same sequence and rename them accordingly.
Essentially mimic the init/fini behaviour in Panthor.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 8 +++++++-
drivers/gpu/drm/panfrost/panfrost_drv.c | 6 ------
drivers/gpu/drm/panfrost/panfrost_gem.c | 26 ++++++++++++++----------
drivers/gpu/drm/panfrost/panfrost_gem.h | 7 ++++---
drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c | 8 ++------
5 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 485349faf251..05c40d5a20b5 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -280,9 +280,14 @@ int panfrost_device_init(struct panfrost_device *pfdev)
if (err)
goto out_job;
- panfrost_gem_init(pfdev);
+ err = panfrost_gem_init(pfdev);
+ if (err)
+ goto out_perfcnt;
return 0;
+
+out_perfcnt:
+ panfrost_perfcnt_fini(pfdev);
out_job:
panfrost_jm_fini(pfdev);
out_mmu:
@@ -304,6 +309,7 @@ int panfrost_device_init(struct panfrost_device *pfdev)
void panfrost_device_fini(struct panfrost_device *pfdev)
{
+ panfrost_gem_fini(pfdev);
panfrost_perfcnt_fini(pfdev);
panfrost_jm_fini(pfdev);
panfrost_mmu_fini(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 96a66d673ba6..9882a3ede75f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -1003,14 +1003,9 @@ static int panfrost_probe(struct platform_device *pdev)
if (err < 0)
goto err_out1;
- err = panfrost_gem_shrinker_init(&pfdev->base);
- if (err)
- goto err_out2;
return 0;
-err_out2:
- drm_dev_unregister(&pfdev->base);
err_out1:
pm_runtime_disable(pfdev->base.dev);
panfrost_device_fini(pfdev);
@@ -1024,7 +1019,6 @@ static void panfrost_remove(struct platform_device *pdev)
struct panfrost_device *pfdev = platform_get_drvdata(pdev);
drm_dev_unregister(&pfdev->base);
- panfrost_gem_shrinker_cleanup(&pfdev->base);
pm_runtime_get_sync(pfdev->base.dev);
pm_runtime_disable(pfdev->base.dev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 3a7fce428898..f39c0f50ed4f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -15,20 +15,24 @@
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
-void panfrost_gem_init(struct panfrost_device *pfdev)
+int panfrost_gem_init(struct panfrost_device *pfdev)
{
- int err;
+ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && panfrost_transparent_hugepage) {
+ int err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
+
+ if (drm_gem_get_huge_mnt(&pfdev->base))
+ drm_info(&pfdev->base, "Using Transparent Hugepage\n");
+ else if (err)
+ drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
+ err);
+ }
- if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
- !panfrost_transparent_hugepage)
- return;
+ return panfrost_gem_shrinker_init(pfdev);
+}
- err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
- if (drm_gem_get_huge_mnt(&pfdev->base))
- drm_info(&pfdev->base, "Using Transparent Hugepage\n");
- else if (err)
- drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
- err);
+void panfrost_gem_fini(struct panfrost_device *pfdev)
+{
+ panfrost_gem_shrinker_fini(pfdev);
}
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 79d4377019e9..5c823cdbd980 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -129,7 +129,8 @@ drm_mm_node_to_panfrost_mapping(struct drm_mm_node *node)
return container_of(node, struct panfrost_gem_mapping, mmnode);
}
-void panfrost_gem_init(struct panfrost_device *pfdev);
+int panfrost_gem_init(struct panfrost_device *pfdev);
+void panfrost_gem_fini(struct panfrost_device *pfdev);
struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size);
@@ -154,8 +155,8 @@ panfrost_gem_mapping_get(struct panfrost_gem_object *bo,
void panfrost_gem_mapping_put(struct panfrost_gem_mapping *mapping);
void panfrost_gem_teardown_mappings_locked(struct panfrost_gem_object *bo);
-int panfrost_gem_shrinker_init(struct drm_device *dev);
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev);
+int panfrost_gem_shrinker_init(struct panfrost_device *pfdev);
+void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev);
void panfrost_gem_set_label(struct drm_gem_object *obj, const char *label);
int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index 2fe967a90bcb..fefae87535d6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -95,10 +95,8 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
*
* This function registers and sets up the panfrost shrinker.
*/
-int panfrost_gem_shrinker_init(struct drm_device *dev)
+int panfrost_gem_shrinker_init(struct panfrost_device *pfdev)
{
- struct panfrost_device *pfdev = to_panfrost_device(dev);
-
pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
if (!pfdev->shrinker)
return -ENOMEM;
@@ -118,10 +116,8 @@ int panfrost_gem_shrinker_init(struct drm_device *dev)
*
* This function unregisters the panfrost shrinker.
*/
-void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
+void panfrost_gem_shrinker_fini(struct panfrost_device *pfdev)
{
- struct panfrost_device *pfdev = to_panfrost_device(dev);
-
if (pfdev->shrinker)
shrinker_free(pfdev->shrinker);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 02/16] drm/panfrost: Move lock and modparam initialisations into their subsystems
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 01/16] drm/panfrost: Move shrinker initialization and unplug one level down Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems Adrián Larumbe
` (13 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
The device init function feels a bit cluttered with things that should be
done in the specific subsystems where those locks and lists are being
used. Same goes for module parameters, it's best to limit them to the
subsystems where they're relevant.
Then we can also discard panfrost_drv.h since the transparent_huge_page
doesn't need to be accessed elsewhere. We can also simplify the
creation of a mount point, because drm_gem_get_huge_mnt() would never
return NULL if drm_gem_huge_mnt_create() returns 0 when kernel is built
with support for transparent huge pages.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 7 -------
drivers/gpu/drm/panfrost/panfrost_drv.c | 10 ----------
drivers/gpu/drm/panfrost/panfrost_drv.h | 9 ---------
drivers/gpu/drm/panfrost/panfrost_gem.c | 19 +++++++++++++------
drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c | 3 +++
drivers/gpu/drm/panfrost/panfrost_gpu.c | 2 ++
drivers/gpu/drm/panfrost/panfrost_job.c | 1 +
drivers/gpu/drm/panfrost/panfrost_mmu.c | 3 +++
8 files changed, 22 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 05c40d5a20b5..c1a2e93a2b9b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -216,13 +216,6 @@ int panfrost_device_init(struct panfrost_device *pfdev)
{
int err;
- mutex_init(&pfdev->sched_lock);
- INIT_LIST_HEAD(&pfdev->as_lru_list);
-
- spin_lock_init(&pfdev->as_lock);
-
- spin_lock_init(&pfdev->cycle_counter.lock);
-
#ifdef CONFIG_DEBUG_FS
mutex_init(&pfdev->debugfs.gems_lock);
INIT_LIST_HEAD(&pfdev->debugfs.gems_list);
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 9882a3ede75f..59af79a534fa 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -21,7 +21,6 @@
#include <drm/drm_utils.h>
#include "panfrost_device.h"
-#include "panfrost_drv.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
#include "panfrost_job.h"
@@ -955,12 +954,6 @@ static const struct drm_driver panfrost_drm_driver = {
#endif
};
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-bool panfrost_transparent_hugepage = true;
-module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
-MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
-#endif
-
static int panfrost_probe(struct platform_device *pdev)
{
struct panfrost_device *pfdev;
@@ -979,9 +972,6 @@ static int panfrost_probe(struct platform_device *pdev)
pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
- mutex_init(&pfdev->shrinker_lock);
- INIT_LIST_HEAD(&pfdev->shrinker_list);
-
err = panfrost_device_init(pfdev);
if (err) {
if (err != -EPROBE_DEFER)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.h b/drivers/gpu/drm/panfrost/panfrost_drv.h
deleted file mode 100644
index a2277ec61aab..000000000000
--- a/drivers/gpu/drm/panfrost/panfrost_drv.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 or MIT */
-/* Copyright 2025 Amazon.com, Inc. or its affiliates */
-
-#ifndef __PANFROST_DRV_H__
-#define __PANFROST_DRV_H__
-
-extern bool panfrost_transparent_hugepage;
-
-#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index f39c0f50ed4f..383ac8cd5645 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -11,20 +11,27 @@
#include <drm/panfrost_drm.h>
#include <drm/drm_print.h>
#include "panfrost_device.h"
-#include "panfrost_drv.h"
#include "panfrost_gem.h"
#include "panfrost_mmu.h"
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static bool panfrost_transparent_hugepage = true;
+module_param_named(transparent_hugepage, panfrost_transparent_hugepage, bool, 0400);
+MODULE_PARM_DESC(transparent_hugepage, "Use a dedicated tmpfs mount point with Transparent Hugepage enabled (true = default)");
+#else
+#define panfrost_transparent_hugepage false
+#endif
+
int panfrost_gem_init(struct panfrost_device *pfdev)
{
- if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && panfrost_transparent_hugepage) {
+ if (panfrost_transparent_hugepage) {
int err = drm_gem_huge_mnt_create(&pfdev->base, "within_size");
- if (drm_gem_get_huge_mnt(&pfdev->base))
+ if (err)
+ drm_warn(&pfdev->base,
+ "Can't use Transparent Hugepage (%d)\n", err);
+ else
drm_info(&pfdev->base, "Using Transparent Hugepage\n");
- else if (err)
- drm_warn(&pfdev->base, "Can't use Transparent Hugepage (%d)\n",
- err);
}
return panfrost_gem_shrinker_init(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
index fefae87535d6..72cd7a165e6d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
@@ -97,6 +97,9 @@ panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
*/
int panfrost_gem_shrinker_init(struct panfrost_device *pfdev)
{
+ mutex_init(&pfdev->shrinker_lock);
+ INIT_LIST_HEAD(&pfdev->shrinker_list);
+
pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");
if (!pfdev->shrinker)
return -ENOMEM;
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index 7d555e63e21a..8a15ccce08e9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -516,6 +516,8 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
{
int err;
+ spin_lock_init(&pfdev->cycle_counter.lock);
+
err = panfrost_gpu_soft_reset(pfdev);
if (err)
return err;
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index d59b4863b8ad..476c936b54e6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -874,6 +874,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
spin_lock_init(&js->job_lock);
+ mutex_init(&pfdev->sched_lock);
js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
if (js->irq < 0)
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 4a3162c3b659..5c393ed6e310 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -955,6 +955,9 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
{
int err;
+ INIT_LIST_HEAD(&pfdev->as_lru_list);
+ spin_lock_init(&pfdev->as_lock);
+
pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "mmu");
if (pfdev->mmu_irq < 0)
return pfdev->mmu_irq;
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 01/16] drm/panfrost: Move shrinker initialization and unplug one level down Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 02/16] drm/panfrost: Move lock and modparam initialisations into their subsystems Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:28 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 04/16] drm/panfrost: Skip NULL checks for clock enable/disabling Adrián Larumbe
` (12 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Because debugfs knobs are a device interface, and also the different knobs
deal with specific subsystems, it's best to move their initialisations away
from panfrost_drv.c and into the subsystem they provide information about.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 8 ++
drivers/gpu/drm/panfrost/panfrost_device.h | 4 +
drivers/gpu/drm/panfrost/panfrost_drv.c | 129 +----------------------------
drivers/gpu/drm/panfrost/panfrost_gem.c | 29 ++++++-
drivers/gpu/drm/panfrost/panfrost_gem.h | 3 +-
drivers/gpu/drm/panfrost/panfrost_job.c | 99 ++++++++++++++++++++++
drivers/gpu/drm/panfrost/panfrost_job.h | 4 +
7 files changed, 144 insertions(+), 132 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index c1a2e93a2b9b..5bf528f41278 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -561,3 +561,11 @@ EXPORT_GPL_DEV_PM_OPS(panfrost_pm_ops) = {
RUNTIME_PM_OPS(panfrost_device_runtime_suspend, panfrost_device_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(panfrost_device_suspend, panfrost_device_resume)
};
+
+#ifdef CONFIG_DEBUG_FS
+void panfrost_device_debugfs_init(struct drm_minor *minor)
+{
+ panfrost_gem_debugfs_init(minor);
+ panfrost_sched_debugfs_init(minor);
+}
+#endif // CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index 1fe1554f2652..a0b9a2145fc9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -341,4 +341,8 @@ panfrost_device_schedule_reset(struct panfrost_device *pfdev)
queue_work(pfdev->reset.wq, &pfdev->reset.work);
}
+#ifdef CONFIG_DEBUG_FS
+void panfrost_device_debugfs_init(struct drm_minor *minor);
+#endif // CONFIG_DEBUG_FS
+
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 59af79a534fa..55fc22e8d4d4 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -792,133 +792,6 @@ static const struct file_operations panfrost_drm_driver_fops = {
.show_fdinfo = drm_show_fdinfo,
};
-#ifdef CONFIG_DEBUG_FS
-static int panthor_gems_show(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = m->private;
- struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
-
- panfrost_gem_debugfs_print_bos(pfdev, m);
-
- return 0;
-}
-
-static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
- struct seq_file *m)
-{
- struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
- const char *prio = "UNKNOWN";
-
- static const char * const prios[] = {
- [DRM_SCHED_PRIORITY_HIGH] = "HIGH",
- [DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
- [DRM_SCHED_PRIORITY_LOW] = "LOW",
- };
-
- if (jm_ctx->slot_entity[0].priority !=
- jm_ctx->slot_entity[1].priority)
- drm_warn(ddev, "Slot priorities should be the same in a single context");
-
- if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
- prio = prios[jm_ctx->slot_entity[0].priority];
-
- seq_printf(m, " JM context %u: priority %s\n", handle, prio);
-}
-
-static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
- struct seq_file *m)
-{
- struct panfrost_jm_ctx *jm_ctx;
- unsigned long i;
-
- xa_lock(&pfile->jm_ctxs);
- xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
- jm_ctx = panfrost_jm_ctx_get(jm_ctx);
- xa_unlock(&pfile->jm_ctxs);
- show_panfrost_jm_ctx(jm_ctx, i, m);
- panfrost_jm_ctx_put(jm_ctx);
- xa_lock(&pfile->jm_ctxs);
- }
- xa_unlock(&pfile->jm_ctxs);
-
- return 0;
-}
-
-static struct drm_info_list panthor_debugfs_list[] = {
- {"gems",
- panthor_gems_show, 0, NULL},
-};
-
-static int panthor_gems_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(panthor_debugfs_list,
- ARRAY_SIZE(panthor_debugfs_list),
- minor->debugfs_root, minor);
-
- return 0;
-}
-
-static int show_each_file(struct seq_file *m, void *arg)
-{
- struct drm_info_node *node = (struct drm_info_node *)m->private;
- struct drm_device *ddev = node->minor->dev;
- int (*show)(struct panfrost_file_priv *, struct seq_file *) =
- node->info_ent->data;
- struct drm_file *file;
- int ret;
-
- ret = mutex_lock_interruptible(&ddev->filelist_mutex);
- if (ret)
- return ret;
-
- list_for_each_entry(file, &ddev->filelist, lhead) {
- struct task_struct *task;
- struct panfrost_file_priv *pfile = file->driver_priv;
- struct pid *pid;
-
- /*
- * Although we have a valid reference on file->pid, that does
- * not guarantee that the task_struct who called get_pid() is
- * still alive (e.g. get_pid(current) => fork() => exit()).
- * Therefore, we need to protect this ->comm access using RCU.
- */
- rcu_read_lock();
- pid = rcu_dereference(file->pid);
- task = pid_task(pid, PIDTYPE_TGID);
- seq_printf(m, "client_id %8llu pid %8d command %s:\n",
- file->client_id, pid_nr(pid),
- task ? task->comm : "<unknown>");
- rcu_read_unlock();
-
- ret = show(pfile, m);
- if (ret < 0)
- break;
-
- seq_puts(m, "\n");
- }
-
- mutex_unlock(&ddev->filelist_mutex);
- return ret;
-}
-
-static struct drm_info_list panfrost_sched_debugfs_list[] = {
- { "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
-};
-
-static void panfrost_sched_debugfs_init(struct drm_minor *minor)
-{
- drm_debugfs_create_files(panfrost_sched_debugfs_list,
- ARRAY_SIZE(panfrost_sched_debugfs_list),
- minor->debugfs_root, minor);
-}
-
-static void panfrost_debugfs_init(struct drm_minor *minor)
-{
- panthor_gems_debugfs_init(minor);
- panfrost_sched_debugfs_init(minor);
-}
-#endif
-
/*
* Panfrost driver version:
* - 1.0 - initial interface
@@ -950,7 +823,7 @@ static const struct drm_driver panfrost_drm_driver = {
.gem_prime_import = panfrost_gem_prime_import,
.gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table,
#ifdef CONFIG_DEBUG_FS
- .debugfs_init = panfrost_debugfs_init,
+ .debugfs_init = panfrost_device_debugfs_init,
#endif
};
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
index 383ac8cd5645..518f24549b9d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
@@ -9,6 +9,7 @@
#include <linux/dma-mapping.h>
#include <drm/panfrost_drm.h>
+#include <drm/drm_debugfs.h>
#include <drm/drm_print.h>
#include "panfrost_device.h"
#include "panfrost_gem.h"
@@ -735,8 +736,8 @@ static void panfrost_gem_debugfs_bo_print(struct panfrost_gem_object *bo,
totals->reclaimable += resident_size;
}
-void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
- struct seq_file *m)
+static void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
+ struct seq_file *m)
{
struct gem_size_totals totals = {0};
struct panfrost_gem_object *bo;
@@ -756,4 +757,28 @@ void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
totals.size, totals.resident, totals.reclaimable);
}
+
+static int panfrost_gems_show(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
+
+ panfrost_gem_debugfs_print_bos(pfdev, m);
+
+ return 0;
+}
+
+static struct drm_info_list panfrost_debugfs_list[] = {
+ {"gems",
+ panfrost_gems_show, 0, NULL},
+};
+
+int panfrost_gem_debugfs_init(struct drm_minor *minor)
+{
+ drm_debugfs_create_files(panfrost_debugfs_list,
+ ARRAY_SIZE(panfrost_debugfs_list),
+ minor->debugfs_root, minor);
+
+ return 0;
+}
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h
index 5c823cdbd980..3008afcf4bff 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gem.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gem.h
@@ -164,8 +164,7 @@ int panfrost_gem_sync(struct drm_gem_object *obj, u32 type,
void panfrost_gem_internal_set_label(struct drm_gem_object *obj, const char *label);
#ifdef CONFIG_DEBUG_FS
-void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
- struct seq_file *m);
+int panfrost_gem_debugfs_init(struct drm_minor *minor);
#endif
#endif /* __PANFROST_GEM_H__ */
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index 476c936b54e6..00fb36c577df 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -8,6 +8,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma-resv.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_print.h>
#include <drm/gpu_scheduler.h>
#include <drm/panfrost_drm.h>
@@ -1138,3 +1140,100 @@ int panfrost_jm_ctx_destroy(struct drm_file *file, u32 handle)
panfrost_jm_ctx_put(jm_ctx);
return 0;
}
+
+#ifdef CONFIG_DEBUG_FS
+static void show_panfrost_jm_ctx(struct panfrost_jm_ctx *jm_ctx, u32 handle,
+ struct seq_file *m)
+{
+ struct drm_device *ddev = ((struct drm_info_node *)m->private)->minor->dev;
+ const char *prio = "UNKNOWN";
+
+ static const char * const prios[] = {
+ [DRM_SCHED_PRIORITY_HIGH] = "HIGH",
+ [DRM_SCHED_PRIORITY_NORMAL] = "NORMAL",
+ [DRM_SCHED_PRIORITY_LOW] = "LOW",
+ };
+
+ if (jm_ctx->slot_entity[0].priority !=
+ jm_ctx->slot_entity[1].priority)
+ drm_warn(ddev, "Slot priorities should be the same in a single context");
+
+ if (jm_ctx->slot_entity[0].priority < ARRAY_SIZE(prios))
+ prio = prios[jm_ctx->slot_entity[0].priority];
+
+ seq_printf(m, " JM context %u: priority %s\n", handle, prio);
+}
+
+static int show_file_jm_ctxs(struct panfrost_file_priv *pfile,
+ struct seq_file *m)
+{
+ struct panfrost_jm_ctx *jm_ctx;
+ unsigned long i;
+
+ xa_lock(&pfile->jm_ctxs);
+ xa_for_each(&pfile->jm_ctxs, i, jm_ctx) {
+ jm_ctx = panfrost_jm_ctx_get(jm_ctx);
+ xa_unlock(&pfile->jm_ctxs);
+ show_panfrost_jm_ctx(jm_ctx, i, m);
+ panfrost_jm_ctx_put(jm_ctx);
+ xa_lock(&pfile->jm_ctxs);
+ }
+ xa_unlock(&pfile->jm_ctxs);
+
+ return 0;
+}
+
+static int show_each_file(struct seq_file *m, void *arg)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *ddev = node->minor->dev;
+ int (*show)(struct panfrost_file_priv *, struct seq_file *) =
+ node->info_ent->data;
+ struct drm_file *file;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ddev->filelist_mutex);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(file, &ddev->filelist, lhead) {
+ struct task_struct *task;
+ struct panfrost_file_priv *pfile = file->driver_priv;
+ struct pid *pid;
+
+ /*
+ * Although we have a valid reference on file->pid, that does
+ * not guarantee that the task_struct who called get_pid() is
+ * still alive (e.g. get_pid(current) => fork() => exit()).
+ * Therefore, we need to protect this ->comm access using RCU.
+ */
+ rcu_read_lock();
+ pid = rcu_dereference(file->pid);
+ task = pid_task(pid, PIDTYPE_TGID);
+ seq_printf(m, "client_id %8llu pid %8d command %s:\n",
+ file->client_id, pid_nr(pid),
+ task ? task->comm : "<unknown>");
+ rcu_read_unlock();
+
+ ret = show(pfile, m);
+ if (ret < 0)
+ break;
+
+ seq_puts(m, "\n");
+ }
+
+ mutex_unlock(&ddev->filelist_mutex);
+ return ret;
+}
+
+static struct drm_info_list panfrost_sched_debugfs_list[] = {
+ { "sched_ctxs", show_each_file, 0, show_file_jm_ctxs },
+};
+
+void panfrost_sched_debugfs_init(struct drm_minor *minor)
+{
+ drm_debugfs_create_files(panfrost_sched_debugfs_list,
+ ARRAY_SIZE(panfrost_sched_debugfs_list),
+ minor->debugfs_root, minor);
+}
+#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h
index c3f57e41a571..3e3b9717838f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.h
+++ b/drivers/gpu/drm/panfrost/panfrost_job.h
@@ -74,4 +74,8 @@ int panfrost_job_get_slot(struct panfrost_job *job);
int panfrost_job_push(struct panfrost_job *job);
void panfrost_job_put(struct panfrost_job *job);
+#ifdef CONFIG_DEBUG_FS
+void panfrost_sched_debugfs_init(struct drm_minor *minor);
+#endif
+
#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 04/16] drm/panfrost: Skip NULL checks for clock enable/disabling
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (2 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset Adrián Larumbe
` (11 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
The clk_* API can deal with NULL clock objects, so we can do away with NULL
checks in client code.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 5bf528f41278..b3a53504bd01 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -510,11 +510,9 @@ static int panfrost_device_resume(struct device *dev)
if (ret)
goto err_clk;
- if (pfdev->bus_clock) {
- ret = clk_enable(pfdev->bus_clock);
- if (ret)
- goto err_bus_clk;
- }
+ ret = clk_enable(pfdev->bus_clock);
+ if (ret)
+ goto err_bus_clk;
}
ret = pm_runtime_force_resume(dev);
@@ -524,7 +522,7 @@ static int panfrost_device_resume(struct device *dev)
return 0;
err_resume:
- if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS) && pfdev->bus_clock)
+ if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
clk_disable(pfdev->bus_clock);
err_bus_clk:
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
@@ -545,9 +543,7 @@ static int panfrost_device_suspend(struct device *dev)
return ret;
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
- if (pfdev->bus_clock)
- clk_disable(pfdev->bus_clock);
-
+ clk_disable(pfdev->bus_clock);
clk_disable(pfdev->clock);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (3 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 04/16] drm/panfrost: Skip NULL checks for clock enable/disabling Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:31 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove Adrián Larumbe
` (10 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Gather all clock enables and disables into a single function to avoid
repetitions between driver init/fini and device resume/suspend, since
these clocks are always handled in bulk.
Also do clk (un)prepares and dis/enables at the same time, since the
clk_prepare_* family of functions can simply increase the refcnt of
an already prepared clock.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 110 +++++++++++++----------------
1 file changed, 51 insertions(+), 59 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index b3a53504bd01..48135e412b6c 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -34,10 +34,43 @@ static void panfrost_reset_fini(struct panfrost_device *pfdev)
reset_control_assert(pfdev->rstc);
}
-static int panfrost_clk_init(struct panfrost_device *pfdev)
+static int panfrost_clk_enable(struct panfrost_device *pfdev)
{
int err;
+
+ err = clk_prepare_enable(pfdev->clock);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(pfdev->bus_clock);
+ if (err)
+ goto disable_clock;
+
+ err = clk_prepare_enable(pfdev->bus_ace_clock);
+ if (err)
+ goto disable_bus_clock;
+
+ return 0;
+
+disable_bus_clock:
+ clk_disable_unprepare(pfdev->bus_clock);
+disable_clock:
+ clk_disable_unprepare(pfdev->clock);
+
+ return err;
+}
+
+static void panfrost_clk_disable(struct panfrost_device *pfdev)
+{
+ clk_disable_unprepare(pfdev->bus_ace_clock);
+ clk_disable_unprepare(pfdev->bus_clock);
+ clk_disable_unprepare(pfdev->clock);
+}
+
+static int panfrost_clk_init(struct panfrost_device *pfdev)
+{
unsigned long rate;
+ int err;
pfdev->clock = devm_clk_get(pfdev->base.dev, NULL);
if (IS_ERR(pfdev->clock)) {
@@ -48,53 +81,31 @@ static int panfrost_clk_init(struct panfrost_device *pfdev)
rate = clk_get_rate(pfdev->clock);
dev_info(pfdev->base.dev, "clock rate = %lu\n", rate);
- err = clk_prepare_enable(pfdev->clock);
- if (err)
- return err;
-
pfdev->bus_clock = devm_clk_get_optional(pfdev->base.dev, "bus");
if (IS_ERR(pfdev->bus_clock)) {
- dev_err(pfdev->base.dev, "get bus_clock failed %ld\n",
- PTR_ERR(pfdev->bus_clock));
err = PTR_ERR(pfdev->bus_clock);
- goto disable_clock;
+ dev_err(pfdev->base.dev, "get bus_clock failed %d\n", err);
+ return err;
}
if (pfdev->bus_clock) {
rate = clk_get_rate(pfdev->bus_clock);
dev_info(pfdev->base.dev, "bus_clock rate = %lu\n", rate);
-
- err = clk_prepare_enable(pfdev->bus_clock);
- if (err)
- goto disable_clock;
}
pfdev->bus_ace_clock = devm_clk_get_optional(pfdev->base.dev, "bus_ace");
if (IS_ERR(pfdev->bus_ace_clock)) {
err = PTR_ERR(pfdev->bus_ace_clock);
dev_err(pfdev->base.dev, "get bus_ace_clock failed %d\n", err);
- goto disable_bus_clock;
+ return err;
}
- err = clk_prepare_enable(pfdev->bus_ace_clock);
- if (err)
- goto disable_bus_clock;
-
- return 0;
-
-disable_bus_clock:
- clk_disable_unprepare(pfdev->bus_clock);
-disable_clock:
- clk_disable_unprepare(pfdev->clock);
-
- return err;
+ return panfrost_clk_enable(pfdev);
}
static void panfrost_clk_fini(struct panfrost_device *pfdev)
{
- clk_disable_unprepare(pfdev->bus_ace_clock);
- clk_disable_unprepare(pfdev->bus_clock);
- clk_disable_unprepare(pfdev->clock);
+ panfrost_clk_disable(pfdev);
}
static int panfrost_regulator_init(struct panfrost_device *pfdev)
@@ -436,34 +447,17 @@ static int panfrost_device_runtime_resume(struct device *dev)
if (ret)
return ret;
- ret = clk_enable(pfdev->clock);
- if (ret)
- goto err_clk;
-
- ret = clk_enable(pfdev->bus_clock);
- if (ret)
- goto err_bus_clk;
-
- ret = clk_enable(pfdev->bus_ace_clock);
- if (ret)
- goto err_bus_ace_clk;
+ ret = panfrost_clk_enable(pfdev);
+ if (ret) {
+ reset_control_assert(pfdev->rstc);
+ return ret;
+ }
}
panfrost_device_reset(pfdev, true);
panfrost_devfreq_resume(pfdev);
return 0;
-
-err_bus_ace_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- clk_disable(pfdev->bus_clock);
-err_bus_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- clk_disable(pfdev->clock);
-err_clk:
- if (pfdev->comp->pm_features & BIT(GPU_PM_RT))
- reset_control_assert(pfdev->rstc);
- return ret;
}
static int panfrost_device_runtime_suspend(struct device *dev)
@@ -480,9 +474,7 @@ static int panfrost_device_runtime_suspend(struct device *dev)
panfrost_gpu_power_off(pfdev);
if (pfdev->comp->pm_features & BIT(GPU_PM_RT)) {
- clk_disable(pfdev->bus_ace_clock);
- clk_disable(pfdev->bus_clock);
- clk_disable(pfdev->clock);
+ panfrost_clk_disable(pfdev);
reset_control_assert(pfdev->rstc);
}
@@ -506,11 +498,11 @@ static int panfrost_device_resume(struct device *dev)
}
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
- ret = clk_enable(pfdev->clock);
+ ret = clk_prepare_enable(pfdev->clock);
if (ret)
goto err_clk;
- ret = clk_enable(pfdev->bus_clock);
+ ret = clk_prepare_enable(pfdev->bus_clock);
if (ret)
goto err_bus_clk;
}
@@ -523,10 +515,10 @@ static int panfrost_device_resume(struct device *dev)
err_resume:
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
- clk_disable(pfdev->bus_clock);
+ clk_disable_unprepare(pfdev->bus_clock);
err_bus_clk:
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS))
- clk_disable(pfdev->clock);
+ clk_disable_unprepare(pfdev->clock);
err_clk:
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
dev_pm_opp_set_opp(dev, NULL);
@@ -543,8 +535,8 @@ static int panfrost_device_suspend(struct device *dev)
return ret;
if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
- clk_disable(pfdev->bus_clock);
- clk_disable(pfdev->clock);
+ clk_disable_unprepare(pfdev->bus_clock);
+ clk_disable_unprepare(pfdev->clock);
}
if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (4 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:29 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init Adrián Larumbe
` (9 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
During device probe(), failure to do a PM get() will leave the usage_count
set to 0, which is the value assigned at device creation time. That means
when the autosuspend delay expires, runtime suspend callback won't be
invoked, so the device will remain powered on forever.
On top of that, failure to call PM put() during device unplug means
Panfrost device's PM usage_count increases monotonically for every new
module reload.
The outcome of both of the above meant that:
- Devfreq OPP transition notifications would be printed all the time,
even when no jobs are being submitted. This quickly fills the kernel
ring buffer with junk.
- Because MMU interrupts are only enabled when the device is reset,
the very first job targeting the tiler heap BO after device probe()
would always time out, since the driver's PM runtime resume callback
would not be invoked.
To fix the above:
- Manually adjust the PM refcnt at device probe and removal time.
- Ensure pm_runtime_dont_use_autosuspend is called in the wind-down path.
- Call pm_runtime_put_autosuspend() when device is ready to accept jobs
- Move pm_runtime_set_suspended() before panfrost_device_fini() so that
resource unwinding happens in the opposite order as initialisation.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Fixes: 635430797d3f ("drm/panfrost: Rework runtime PM initialization")
Fixes: 876b15d2c88d ("drm/panfrost: Fix module unload")
---
drivers/gpu/drm/panfrost/panfrost_drv.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 55fc22e8d4d4..a3eff77add55 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -854,6 +854,7 @@ static int panfrost_probe(struct platform_device *pdev)
pm_runtime_set_active(pfdev->base.dev);
pm_runtime_mark_last_busy(pfdev->base.dev);
+ pm_runtime_get_noresume(pfdev->base.dev);
pm_runtime_enable(pfdev->base.dev);
pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
pm_runtime_use_autosuspend(pfdev->base.dev);
@@ -866,13 +867,16 @@ static int panfrost_probe(struct platform_device *pdev)
if (err < 0)
goto err_out1;
+ pm_runtime_put_autosuspend(pfdev->base.dev);
return 0;
err_out1:
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
pm_runtime_disable(pfdev->base.dev);
- panfrost_device_fini(pfdev);
+ pm_runtime_put_noidle(pfdev->base.dev);
pm_runtime_set_suspended(pfdev->base.dev);
+ panfrost_device_fini(pfdev);
err_out0:
return err;
}
@@ -884,9 +888,11 @@ static void panfrost_remove(struct platform_device *pdev)
drm_dev_unregister(&pfdev->base);
pm_runtime_get_sync(pfdev->base.dev);
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
+ pm_runtime_put_noidle(pfdev->base.dev);
pm_runtime_disable(pfdev->base.dev);
- panfrost_device_fini(pfdev);
pm_runtime_set_suspended(pfdev->base.dev);
+ panfrost_device_fini(pfdev);
}
static ssize_t profiling_show(struct device *dev,
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (5 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:31 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 08/16] drm/panfrost: Move all DRM device initialisation into device_init() Adrián Larumbe
` (8 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Because the device must be in a position to accept jobs between the time
drm_dev_register() is called and autosuspend first kicks in, there's a very
narrow window inbetween during which jobs targeting the tiler buffer
object would time out, since the device's PM status is 'Active', but no MMU
interrupts were enabled at device initialisation time.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Fixes: 73e467f60acd ("drm/panfrost: Consolidate reset handling")
---
drivers/gpu/drm/panfrost/panfrost_mmu.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 5c393ed6e310..faa62643caf1 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -336,6 +336,12 @@ void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu
WARN_ON(atomic_read(&mmu->as_count) < 0);
}
+static void panfrost_mmu_enable_interrupts(struct panfrost_device *pfdev)
+{
+ mmu_write(pfdev, MMU_INT_CLEAR, ~0);
+ mmu_write(pfdev, MMU_INT_MASK, ~0);
+}
+
void panfrost_mmu_reset(struct panfrost_device *pfdev)
{
struct panfrost_mmu *mmu, *mmu_tmp;
@@ -355,8 +361,7 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
spin_unlock(&pfdev->as_lock);
- mmu_write(pfdev, MMU_INT_CLEAR, ~0);
- mmu_write(pfdev, MMU_INT_MASK, ~0);
+ panfrost_mmu_enable_interrupts(pfdev);
}
static size_t get_pgsize(u64 addr, size_t size, size_t *count)
@@ -973,6 +978,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
return err;
}
+ panfrost_mmu_enable_interrupts(pfdev);
+
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 08/16] drm/panfrost: Move all DRM device initialisation into device_init()
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (6 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 09/16] drm/panfrost: Add warning messages to fatal error conditions Adrián Larumbe
` (7 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Ideally the probe() function will do as little as possible, and all device
initialisation and registration should happen inside the panfrost device
subsystem, just like it's done in Panthor. This also simplifies resource
unwinding in the error path.
Do the same thing for DRM driver remove, as in, sweep most of the action
into panfrost_device_fini(), just like we did for device probe.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 37 +++++++++++++++++++++++
drivers/gpu/drm/panfrost/panfrost_drv.c | 47 +-----------------------------
2 files changed, 38 insertions(+), 46 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index 48135e412b6c..be4443e41d9a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -8,6 +8,7 @@
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <drm/drm_drv.h>
#include "panfrost_device.h"
#include "panfrost_devfreq.h"
@@ -227,6 +228,12 @@ int panfrost_device_init(struct panfrost_device *pfdev)
{
int err;
+ pfdev->comp = of_device_get_match_data(pfdev->base.dev);
+ if (!pfdev->comp)
+ return -ENODEV;
+
+ pfdev->coherent = device_get_dma_attr(pfdev->base.dev) == DEV_DMA_COHERENT;
+
#ifdef CONFIG_DEBUG_FS
mutex_init(&pfdev->debugfs.gems_lock);
INIT_LIST_HEAD(&pfdev->debugfs.gems_list);
@@ -288,8 +295,31 @@ int panfrost_device_init(struct panfrost_device *pfdev)
if (err)
goto out_perfcnt;
+ pm_runtime_set_active(pfdev->base.dev);
+ pm_runtime_mark_last_busy(pfdev->base.dev);
+ pm_runtime_get_noresume(pfdev->base.dev);
+ pm_runtime_enable(pfdev->base.dev);
+ pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
+ pm_runtime_use_autosuspend(pfdev->base.dev);
+
+ /*
+ * Register the DRM device with the core and the connectors with
+ * sysfs
+ */
+ err = drm_dev_register(&pfdev->base, 0);
+ if (err < 0)
+ goto err_disable_rpm;
+
+ pm_runtime_put_autosuspend(pfdev->base.dev);
+
return 0;
+err_disable_rpm:
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
+ pm_runtime_disable(pfdev->base.dev);
+ pm_runtime_put_noidle(pfdev->base.dev);
+ pm_runtime_set_suspended(pfdev->base.dev);
+ panfrost_gem_fini(pfdev);
out_perfcnt:
panfrost_perfcnt_fini(pfdev);
out_job:
@@ -313,6 +343,13 @@ int panfrost_device_init(struct panfrost_device *pfdev)
void panfrost_device_fini(struct panfrost_device *pfdev)
{
+ pm_runtime_get_sync(pfdev->base.dev);
+
+ pm_runtime_dont_use_autosuspend(pfdev->base.dev);
+ pm_runtime_disable(pfdev->base.dev);
+ pm_runtime_put_noidle(pfdev->base.dev);
+ pm_runtime_set_suspended(pfdev->base.dev);
+
panfrost_gem_fini(pfdev);
panfrost_perfcnt_fini(pfdev);
panfrost_jm_fini(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index a3eff77add55..f77780c72a1a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -830,7 +830,6 @@ static const struct drm_driver panfrost_drm_driver = {
static int panfrost_probe(struct platform_device *pdev)
{
struct panfrost_device *pfdev;
- int err;
pfdev = devm_drm_dev_alloc(&pdev->dev, &panfrost_drm_driver,
struct panfrost_device, base);
@@ -839,46 +838,7 @@ static int panfrost_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pfdev);
- pfdev->comp = of_device_get_match_data(&pdev->dev);
- if (!pfdev->comp)
- return -ENODEV;
-
- pfdev->coherent = device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT;
-
- err = panfrost_device_init(pfdev);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Fatal error during GPU init\n");
- goto err_out0;
- }
-
- pm_runtime_set_active(pfdev->base.dev);
- pm_runtime_mark_last_busy(pfdev->base.dev);
- pm_runtime_get_noresume(pfdev->base.dev);
- pm_runtime_enable(pfdev->base.dev);
- pm_runtime_set_autosuspend_delay(pfdev->base.dev, 50); /* ~3 frames */
- pm_runtime_use_autosuspend(pfdev->base.dev);
-
- /*
- * Register the DRM device with the core and the connectors with
- * sysfs
- */
- err = drm_dev_register(&pfdev->base, 0);
- if (err < 0)
- goto err_out1;
-
- pm_runtime_put_autosuspend(pfdev->base.dev);
-
- return 0;
-
-err_out1:
- pm_runtime_dont_use_autosuspend(pfdev->base.dev);
- pm_runtime_disable(pfdev->base.dev);
- pm_runtime_put_noidle(pfdev->base.dev);
- pm_runtime_set_suspended(pfdev->base.dev);
- panfrost_device_fini(pfdev);
-err_out0:
- return err;
+ return panfrost_device_init(pfdev);
}
static void panfrost_remove(struct platform_device *pdev)
@@ -887,11 +847,6 @@ static void panfrost_remove(struct platform_device *pdev)
drm_dev_unregister(&pfdev->base);
- pm_runtime_get_sync(pfdev->base.dev);
- pm_runtime_dont_use_autosuspend(pfdev->base.dev);
- pm_runtime_put_noidle(pfdev->base.dev);
- pm_runtime_disable(pfdev->base.dev);
- pm_runtime_set_suspended(pfdev->base.dev);
panfrost_device_fini(pfdev);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 09/16] drm/panfrost: Add warning messages to fatal error conditions
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (7 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 08/16] drm/panfrost: Move all DRM device initialisation into device_init() Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset Adrián Larumbe
` (6 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Rather than just failing silently, let's warn the user of device remove not
being able to take an PM reference or the PM suspend path still reporting
inflight jobs. Neither situation should ever happen.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index be4443e41d9a..f0fae6fa1e24 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -9,6 +9,7 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_drv.h>
+#include <drm/drm_print.h>
#include "panfrost_device.h"
#include "panfrost_devfreq.h"
@@ -343,7 +344,7 @@ int panfrost_device_init(struct panfrost_device *pfdev)
void panfrost_device_fini(struct panfrost_device *pfdev)
{
- pm_runtime_get_sync(pfdev->base.dev);
+ drm_WARN_ON(&pfdev->base, pm_runtime_get_sync(pfdev->base.dev) < 0);
pm_runtime_dont_use_autosuspend(pfdev->base.dev);
pm_runtime_disable(pfdev->base.dev);
@@ -501,7 +502,7 @@ static int panfrost_device_runtime_suspend(struct device *dev)
{
struct panfrost_device *pfdev = dev_get_drvdata(dev);
- if (!panfrost_jm_is_idle(pfdev))
+ if (drm_WARN_ON(&pfdev->base, !panfrost_jm_is_idle(pfdev)))
return -EBUSY;
panfrost_devfreq_suspend(pfdev);
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (8 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 09/16] drm/panfrost: Add warning messages to fatal error conditions Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:28 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 11/16] drm/panfrost: Move perfcnt GPU disable sequence into a helper Adrián Larumbe
` (5 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
This will be of great help when testing potential races between the GPU
reset sequence and other parts of the code accessing HW registers.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 37 ++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index f0fae6fa1e24..f171abe26f80 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -2,6 +2,7 @@
/* Copyright 2018 Marty E. Plummer <hanetzer@startmail.com> */
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
+#include <linux/debugfs.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
@@ -589,9 +590,45 @@ EXPORT_GPL_DEV_PM_OPS(panfrost_pm_ops) = {
};
#ifdef CONFIG_DEBUG_FS
+static int reset_get(void *data, u64 *val)
+{
+ struct panfrost_device *pfdev =
+ container_of(data, struct panfrost_device, base);
+
+ *val = atomic_read(&pfdev->reset.pending);
+ return 0;
+}
+
+static int reset_set(void *data, u64 val)
+{
+ struct panfrost_device *pfdev =
+ container_of(data, struct panfrost_device, base);
+ int ret = pm_runtime_get_if_active(pfdev->base.dev);
+
+ if (ret) {
+ panfrost_device_schedule_reset(pfdev);
+ flush_work(&pfdev->reset.work);
+ if (ret > 0)
+ pm_runtime_put(pfdev->base.dev);
+ }
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(panfrost_reset_debugfs_fops,
+ reset_get, reset_set,
+ "0x%08llx\n");
+
+static void panfrost_reset_debugfs_init(struct drm_minor *minor)
+{
+ debugfs_create_file("reset", 0600, minor->debugfs_root,
+ minor->dev, &panfrost_reset_debugfs_fops);
+}
+
void panfrost_device_debugfs_init(struct drm_minor *minor)
{
panfrost_gem_debugfs_init(minor);
panfrost_sched_debugfs_init(minor);
+ panfrost_reset_debugfs_init(minor);
}
#endif // CONFIG_DEBUG_FS
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 11/16] drm/panfrost: Move perfcnt GPU disable sequence into a helper
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (9 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 12/16] drm/panfrost: Skip cache flush/invalidate when enabling perfcnt Adrián Larumbe
` (4 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Just for the sake of avoiding repetition.
Reviewed-by: Steven Price <steven.price@arm.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 31 ++++++++++++-----------------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index 7020c0192e18..f71534e741b6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -35,6 +35,16 @@ struct panfrost_perfcnt {
struct completion dump_comp;
};
+static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
+{
+ gpu_write(pfdev, GPU_PERFCNT_CFG,
+ GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
+ gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+}
+
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
{
complete(&pfdev->perfcnt->dump_comp);
@@ -193,12 +203,7 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
if (user != perfcnt->user)
return -EINVAL;
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0x0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
+ panfrost_perfcnt_hw_disable(pfdev);
perfcnt->user = NULL;
drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
@@ -327,12 +332,7 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
perfcnt->bosize = size;
/* Start with everything disabled. */
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+ panfrost_perfcnt_hw_disable(pfdev);
init_completion(&perfcnt->dump_comp);
mutex_init(&perfcnt->lock);
@@ -344,10 +344,5 @@ int panfrost_perfcnt_init(struct panfrost_device *pfdev)
void panfrost_perfcnt_fini(struct panfrost_device *pfdev)
{
/* Disable everything before leaving. */
- gpu_write(pfdev, GPU_PERFCNT_CFG,
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_OFF));
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0);
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+ panfrost_perfcnt_hw_disable(pfdev);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 12/16] drm/panfrost: Skip cache flush/invalidate when enabling perfcnt
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (10 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 11/16] drm/panfrost: Move perfcnt GPU disable sequence into a helper Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems Adrián Larumbe
` (3 subsequent siblings)
15 siblings, 0 replies; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
The GPU cache flush/invalidate operation is unnecessary. First off, the
GPU doesn't read off the perfcnt sample buffer, only writes into it, so
an invalidate doesn't make a difference. Then flushing GPU caches after
each sample has been written is enough for the CPU to see updated values.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index f71534e741b6..ffc77121070e 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -124,21 +124,10 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
panfrost_gem_internal_set_label(&bo->base, "Perfcnt sample buffer");
/*
- * Invalidate the cache and clear the counters to start from a fresh
- * state.
+ * Clear the counters to start from a fresh state.
*/
- reinit_completion(&pfdev->perfcnt->dump_comp);
- gpu_write(pfdev, GPU_INT_CLEAR,
- GPU_IRQ_CLEAN_CACHES_COMPLETED |
- GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_INV_CACHES);
- ret = wait_for_completion_timeout(&pfdev->perfcnt->dump_comp,
- msecs_to_jiffies(1000));
- if (!ret) {
- ret = -ETIMEDOUT;
- goto err_vunmap;
- }
ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
if (ret < 0)
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (11 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 12/16] drm/panfrost: Skip cache flush/invalidate when enabling perfcnt Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:35 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 14/16] drm/panfrost: Introduce a reset lock Adrián Larumbe
` (2 subsequent siblings)
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
If the GPU and CPU are fully coherent, then there's no need to flush the
GPU caches after a perfcnt sample is made available.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index ffc77121070e..b3f71d7fd82a 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -52,7 +52,10 @@ void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
{
- gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
+ if (pfdev->features.selected_coherency != COHERENCY_ACE)
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
+ else
+ complete(&pfdev->perfcnt->dump_comp);
}
static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 14/16] drm/panfrost: Introduce a reset lock
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (12 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:38 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field Adrián Larumbe
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
So as to avoid accessing HW register while a reset is ongoing, a read/write
semaphore that envelopes the reset sequence will help driver entry points
avoid racing with it. For now, the only such racy entry point is the ioctl
that returns the current GPU timestmap.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 2 ++
drivers/gpu/drm/panfrost/panfrost_device.h | 1 +
drivers/gpu/drm/panfrost/panfrost_drv.c | 9 ++++++---
drivers/gpu/drm/panfrost/panfrost_job.c | 1 +
4 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index f171abe26f80..e90efcff5ce7 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -466,6 +466,8 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
{
+ guard(rwsem_write)(&pfdev->reset.lock);
+
panfrost_gpu_soft_reset(pfdev);
panfrost_gpu_power_on(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index a0b9a2145fc9..63452febb1cf 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -165,6 +165,7 @@ struct panfrost_device {
struct {
struct workqueue_struct *wq;
struct work_struct work;
+ struct rw_semaphore lock;
atomic_t pending;
} reset;
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index f77780c72a1a..571a26b84126 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -41,9 +41,12 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
if (ret)
return ret;
- panfrost_cycle_counter_get(pfdev);
- *arg = panfrost_timestamp_read(pfdev);
- panfrost_cycle_counter_put(pfdev);
+ /* We should not read timestamp register while the GPU is being reset */
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ panfrost_cycle_counter_get(pfdev);
+ *arg = panfrost_timestamp_read(pfdev);
+ panfrost_cycle_counter_put(pfdev);
+ }
pm_runtime_put(pfdev->base.dev);
return 0;
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index 00fb36c577df..c2b1f1087e21 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -877,6 +877,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
spin_lock_init(&js->job_lock);
mutex_init(&pfdev->sched_lock);
+ init_rwsem(&pfdev->reset.lock);
js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
if (js->irq < 0)
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (13 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 14/16] drm/panfrost: Introduce a reset lock Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:36 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field Adrián Larumbe
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Formerly, the reset sequence would race with panfrost_mmu_as_put()
when tearing down a perfcnt session. On top of that, poking GPU
registers to program a perfcnt session or obtaining a dump might lead to
undefined behaviour when done at the same time a reset was ongoing.
Use the reset r/w semaphore to govern access to the hardware at reset
time. On top of that, expand the DRM uAPI for the perfcnt DUMP operation
so that userspace can be made aware of a reset having happened, because
that means counters will go back to 0 and can no longer be accumulated
to values previously kept in user space.
The new perfcnt-aware reset sequence also takes care to reestablish
perfcnt to its original configuration if there was an enabled session,
or else flags the current session as dead if that failed.
Fixes: 73e467f60acd ("drm/panfrost: Consolidate reset handling")
Fixes: 7786fd108777 ("drm/panfrost: Expose performance counters through unstable ioctls")
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 2 +
drivers/gpu/drm/panfrost/panfrost_perfcnt.c | 195 +++++++++++++++++++---------
drivers/gpu/drm/panfrost/panfrost_perfcnt.h | 1 +
include/uapi/drm/panfrost_drm.h | 8 +-
4 files changed, 145 insertions(+), 61 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index e90efcff5ce7..690598342a86 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -476,6 +476,8 @@ void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
panfrost_jm_reset_interrupts(pfdev);
if (enable_job_int)
panfrost_jm_enable_interrupts(pfdev);
+
+ panfrost_perfcnt_reset(pfdev);
}
static int panfrost_device_runtime_resume(struct device *dev)
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
index b3f71d7fd82a..fef01000deb6 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
@@ -11,6 +11,7 @@
#include <drm/drm_file.h>
#include <drm/drm_gem_shmem_helper.h>
#include <drm/panfrost_drm.h>
+#include <drm/drm_print.h>
#include "panfrost_device.h"
#include "panfrost_features.h"
@@ -28,11 +29,15 @@
struct panfrost_perfcnt {
struct panfrost_gem_mapping *mapping;
+ unsigned int counterset;
size_t bosize;
void *buf;
struct panfrost_file_priv *user;
struct mutex lock;
struct completion dump_comp;
+ bool reset_happened;
+ bool dump_finished;
+ bool owns_as_ref;
};
static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
@@ -47,36 +52,110 @@ static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
{
+ pfdev->perfcnt->dump_finished = true;
complete(&pfdev->perfcnt->dump_comp);
}
void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
{
- if (pfdev->features.selected_coherency != COHERENCY_ACE)
+ if (pfdev->features.selected_coherency != COHERENCY_ACE) {
gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
- else
+ } else {
+ pfdev->perfcnt->dump_finished = true;
complete(&pfdev->perfcnt->dump_comp);
+ }
+}
+
+static int panfrost_perfcnt_hw_enable(struct panfrost_device *pfdev)
+{
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+ u32 cfg, as;
+ int ret;
+
+ ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
+ if (ret < 0)
+ return ret;
+
+ as = ret;
+ cfg = GPU_PERFCNT_CFG_AS(as) |
+ GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
+
+ /*
+ * Bifrost GPUs have 2 set of counters, but we're only interested by
+ * the first one for now.
+ */
+ if (panfrost_model_is_bifrost(pfdev))
+ cfg |= GPU_PERFCNT_CFG_SETSEL(perfcnt->counterset);
+
+ gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
+ gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
+ gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
+
+ /*
+ * Due to PRLAM-8186 we need to disable the Tiler before we enable HW
+ * counters.
+ */
+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
+ else
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+
+ gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
+
+ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
+ gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+
+ return 0;
}
-static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
+static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev, u32 *state)
{
- u64 gpuva;
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+ u64 gpuva = perfcnt->mapping->mmnode.start << PAGE_SHIFT;
int ret;
- reinit_completion(&pfdev->perfcnt->dump_comp);
- gpuva = pfdev->perfcnt->mapping->mmnode.start << PAGE_SHIFT;
- gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
- gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
- gpu_write(pfdev, GPU_INT_CLEAR,
- GPU_IRQ_CLEAN_CACHES_COMPLETED |
- GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ if (!perfcnt->owns_as_ref) {
+ *state = PANFROST_PERFCNT_SESSION_DEAD;
+ return -EIO;
+ }
+
+ if (perfcnt->reset_happened) {
+ *state = PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
+ perfcnt->reset_happened = false;
+ }
+
+ perfcnt->dump_finished = false;
+
+ reinit_completion(&pfdev->perfcnt->dump_comp);
+
+ gpu_write(pfdev, GPU_PERFCNT_BASE_LO, lower_32_bits(gpuva));
+ gpu_write(pfdev, GPU_PERFCNT_BASE_HI, upper_32_bits(gpuva));
+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_CLEAN_CACHES_COMPLETED |
+ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_SAMPLE);
+ }
+
+ /*
+ * Here we release the reset semaphore because perfcnt should not get in the way
+ * of a HW reset. Besides, a legitimate reset might be issued during the wait.
+ */
ret = wait_for_completion_interruptible_timeout(&pfdev->perfcnt->dump_comp,
msecs_to_jiffies(1000));
- if (!ret)
- ret = -ETIMEDOUT;
- else if (ret > 0)
- ret = 0;
+
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ /* Either sample finished or reset happened */
+ if (ret > 0) {
+ ret = perfcnt->dump_finished ? 0 :
+ perfcnt->owns_as_ref ? -EAGAIN : -EIO;
+ if (perfcnt->reset_happened)
+ *state |= PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
+ if (!perfcnt->owns_as_ref)
+ *state |= PANFROST_PERFCNT_SESSION_DEAD;
+ } else if (!ret) {
+ ret = -ETIMEDOUT;
+ }
+ }
return ret;
}
@@ -87,9 +166,8 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
{
struct panfrost_file_priv *user = file_priv->driver_priv;
struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
- struct iosys_map map;
struct drm_gem_shmem_object *bo;
- u32 cfg, as;
+ struct iosys_map map;
int ret;
if (user == perfcnt->user)
@@ -122,54 +200,31 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
ret = drm_gem_vmap(&bo->base, &map);
if (ret)
goto err_put_mapping;
+
perfcnt->buf = map.vaddr;
+ perfcnt->counterset = counterset;
panfrost_gem_internal_set_label(&bo->base, "Perfcnt sample buffer");
- /*
- * Clear the counters to start from a fresh state.
- */
- gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
- gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
-
- ret = panfrost_mmu_as_get(pfdev, perfcnt->mapping->mmu);
- if (ret < 0)
- goto err_vunmap;
-
- as = ret;
- cfg = GPU_PERFCNT_CFG_AS(as) |
- GPU_PERFCNT_CFG_MODE(GPU_PERFCNT_CFG_MODE_MANUAL);
-
- /*
- * Bifrost GPUs have 2 set of counters, but we're only interested by
- * the first one for now.
- */
- if (panfrost_model_is_bifrost(pfdev))
- cfg |= GPU_PERFCNT_CFG_SETSEL(counterset);
-
- gpu_write(pfdev, GPU_PRFCNT_JM_EN, 0xffffffff);
- gpu_write(pfdev, GPU_PRFCNT_SHADER_EN, 0xffffffff);
- gpu_write(pfdev, GPU_PRFCNT_MMU_L2_EN, 0xffffffff);
-
- /*
- * Due to PRLAM-8186 we need to disable the Tiler before we enable HW
- * counters.
- */
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0);
- else
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ /*
+ * Clear the counters to start from a fresh state.
+ */
+ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
+ gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
- gpu_write(pfdev, GPU_PERFCNT_CFG, cfg);
+ ret = panfrost_perfcnt_hw_enable(pfdev);
+ if (ret)
+ goto err_vunmap;
- if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8186))
- gpu_write(pfdev, GPU_PRFCNT_TILER_EN, 0xffffffff);
+ perfcnt->reset_happened = false;
+ perfcnt->owns_as_ref = true;
+ perfcnt->user = user;
+ }
/* The BO ref is retained by the mapping. */
drm_gem_object_put(&bo->base);
- perfcnt->user = user;
-
return 0;
err_vunmap:
@@ -195,13 +250,16 @@ static int panfrost_perfcnt_disable_locked(struct panfrost_device *pfdev,
if (user != perfcnt->user)
return -EINVAL;
- panfrost_perfcnt_hw_disable(pfdev);
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ panfrost_perfcnt_hw_disable(pfdev);
+ if (perfcnt->owns_as_ref)
+ panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
+ perfcnt->user = NULL;
+ }
- perfcnt->user = NULL;
drm_gem_vunmap(&perfcnt->mapping->obj->base.base, &map);
perfcnt->buf = NULL;
panfrost_gem_close(&perfcnt->mapping->obj->base.base, file_priv);
- panfrost_mmu_as_put(pfdev, perfcnt->mapping->mmu);
panfrost_gem_mapping_put(perfcnt->mapping);
perfcnt->mapping = NULL;
pm_runtime_put_autosuspend(pfdev->base.dev);
@@ -255,7 +313,7 @@ int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
goto out;
}
- ret = panfrost_perfcnt_dump_locked(pfdev);
+ ret = panfrost_perfcnt_dump_locked(pfdev, &req->state);
if (ret)
goto out;
@@ -338,3 +396,20 @@ void panfrost_perfcnt_fini(struct panfrost_device *pfdev)
/* Disable everything before leaving. */
panfrost_perfcnt_hw_disable(pfdev);
}
+
+void panfrost_perfcnt_reset(struct panfrost_device *pfdev)
+{
+ struct panfrost_perfcnt *perfcnt = pfdev->perfcnt;
+
+ if (drm_WARN_ON(&pfdev->base, !perfcnt))
+ return;
+
+ lockdep_assert_held(&pfdev->reset.lock);
+
+ if (!perfcnt->user)
+ return;
+
+ perfcnt->owns_as_ref = !panfrost_perfcnt_hw_enable(pfdev);
+ perfcnt->reset_happened = true;
+ complete(&perfcnt->dump_comp);
+}
diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.h b/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
index 8bbcf5f5fb33..8b9bc704b634 100644
--- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
+++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.h
@@ -14,5 +14,6 @@ int panfrost_ioctl_perfcnt_enable(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void panfrost_perfcnt_reset(struct panfrost_device *pfdev);
#endif
diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h
index 50d5337f35ef..b2c46fa0811b 100644
--- a/include/uapi/drm/panfrost_drm.h
+++ b/include/uapi/drm/panfrost_drm.h
@@ -47,7 +47,7 @@ extern "C" {
* them for anything but debugging purpose.
*/
#define DRM_IOCTL_PANFROST_PERFCNT_ENABLE DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_ENABLE, struct drm_panfrost_perfcnt_enable)
-#define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump)
+#define DRM_IOCTL_PANFROST_PERFCNT_DUMP DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_PERFCNT_DUMP, struct drm_panfrost_perfcnt_dump)
#define PANFROST_JD_REQ_FS (1 << 0)
#define PANFROST_JD_REQ_CYCLE_COUNT (1 << 1)
@@ -270,8 +270,14 @@ struct drm_panfrost_perfcnt_enable {
__u32 counterset;
};
+/* Perfcnt dump state as influenced by a HW reset */
+#define PANFROST_PERFCNT_SESSION_DEAD (1 << 0)
+#define PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET (1 << 1)
+
struct drm_panfrost_perfcnt_dump {
__u64 buf_ptr;
+ __u32 state;
+ __u32 pad;
};
/* madvise provides a way to tell the kernel in case a buffers contents
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
` (14 preceding siblings ...)
2026-09-07 20:16 ` [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence Adrián Larumbe
@ 2026-09-07 20:16 ` Adrián Larumbe
2026-09-07 20:33 ` sashiko-bot
15 siblings, 1 reply; 26+ messages in thread
From: Adrián Larumbe @ 2026-09-07 20:16 UTC (permalink / raw)
To: Boris Brezillon, Rob Herring, Steven Price, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Faith Ekstrand, Marty E. Plummer, Tomeu Vizoso, Eric Anholt,
Alyssa Rosenzweig, Robin Murphy, Philipp Zabel
Cc: dri-devel, linux-kernel, Collabora Kernel Team,
Adrián Larumbe, Neil Armstrong
Expose expanded PERFCNT_DUMP IOCTL interface to user mode.
Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_drv.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 571a26b84126..de9b1c115181 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -808,6 +808,7 @@ static const struct file_operations panfrost_drm_driver_fops = {
* - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO,
* PANFROST_IOCTL_QUERY_BO_INFO and
* DRM_PANFROST_PARAM_SELECTED_COHERENCY
+ * - 1.7 - adds PERFCNT_DUMP req state field
*/
static const struct drm_driver panfrost_drm_driver = {
.driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ,
@@ -820,7 +821,7 @@ static const struct drm_driver panfrost_drm_driver = {
.name = "panfrost",
.desc = "panfrost DRM",
.major = 1,
- .minor = 6,
+ .minor = 7,
.gem_create_object = panfrost_gem_create_object,
.gem_prime_import = panfrost_gem_prime_import,
--
2.55.0
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems
2026-09-07 20:16 ` [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems Adrián Larumbe
@ 2026-09-07 20:28 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:28 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-after-free of BO label string in debugfs due to incorrect cleanup ordering
--
commit a176b75fb18c68d91dd9610fff6763a62e825a4f
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Move debugfs initialisation to relevant subsystems
This commit moves the initialization of debugfs knobs out of panfrost_drv.c
and into the specific subsystems they provide information about, such as gem
and sched.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c
> index 383ac8cd56456..518f24549b9de 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gem.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
[ ... ]
> @@ -756,4 +757,28 @@ void panfrost_gem_debugfs_print_bos(struct panfrost_device *pfdev,
> seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
> totals.size, totals.resident, totals.reclaimable);
> }
> +
> +static int panfrost_gems_show(struct seq_file *m, void *data)
> +{
> + struct drm_info_node *node = m->private;
> + struct panfrost_device *pfdev = to_panfrost_device(node->minor->dev);
> +
> + panfrost_gem_debugfs_print_bos(pfdev, m);
[Severity: High]
This is a pre-existing issue, but does this debugfs read path have a race
condition with BO destruction that could lead to a use-after-free?
When reading the gems debugfs file, panfrost_gem_debugfs_print_bos() holds
the gems_lock and iterates over BOs. If it reads a positive refcount for a
BO, and immediately after that the last reference to the BO is dropped by
another thread, panfrost_gem_free_object() in
drivers/gpu/drm/panfrost/panfrost_gem.c is called.
In panfrost_gem_free_object(), the cleanup order frees the label string
before removing the BO from the debugfs list:
panfrost_gem_free_object()
...
kfree_const(bo->label.str);
panfrost_gem_debugfs_bo_rm(bo);
mutex_destroy(&bo->label.lock);
Because the string is freed before the BO is removed from the debugfs list
and before synchronization on the list lock occurs in
panfrost_gem_debugfs_bo_rm(), the debugfs printing thread could dereference
the freed bo->label.str.
Should panfrost_gem_debugfs_bo_rm(bo) be called before freeing the string
and destroying the lock to prevent this?
> +
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=3
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset
2026-09-07 20:16 ` [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset Adrián Larumbe
@ 2026-09-07 20:28 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:28 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Incorrect error handling of pm_runtime_get_if_active() leads to unsafe hardware access when runtime PM is disabled.
--
commit 8d990169095e4c032a10ab3f7f2aa29eb0345717
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Add debugfs knob for manually triggering a GPU reset
This commit introduces a new debugfs file to manually schedule a GPU reset.
It is intended to help test potential race conditions between the reset
sequence and other hardware register accesses.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
> index f0fae6fa1e248..f171abe26f80d 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.c
[ ... ]
> +static int reset_set(void *data, u64 val)
> +{
> + struct panfrost_device *pfdev =
> + container_of(data, struct panfrost_device, base);
> + int ret = pm_runtime_get_if_active(pfdev->base.dev);
> +
> + if (ret) {
[Severity: High]
Can this cause a kernel panic if runtime PM is disabled?
pm_runtime_get_if_active() returns a negative error code (like -EINVAL)
when runtime PM is disabled, such as during system suspend. Because this
condition checks if (ret) instead of if (ret > 0), a negative error return
evaluates to true.
This would cause panfrost_device_schedule_reset() to execute and flush the
work queue while the device is potentially powered down, which may lead to
unclocked register accesses and a synchronous external abort (bus fault).
Should this condition be if (ret > 0) to ensure the device is genuinely
active before proceeding with the hardware reset?
> + panfrost_device_schedule_reset(pfdev);
> + flush_work(&pfdev->reset.work);
> + if (ret > 0)
> + pm_runtime_put(pfdev->base.dev);
> + }
> +
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=10
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove
2026-09-07 20:16 ` [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove Adrián Larumbe
@ 2026-09-07 20:29 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:29 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Ignoring the return value of pm_runtime_get_sync() can lead to unclocked register accesses and system crashes.
- [High] Driver teardown races with in-flight GPU jobs, leading to unhandled hardware faults.
--
commit 75e6d8fc2d8a39088a19c0381af15b43a9a4c041
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove
During device probe(), failure to do a PM get() will leave the usage_count
set to 0, which is the value assigned at device creation time. That means
when the autosuspend delay expires, runtime suspend callback won't be
invoked, so the device will remain powered on forever.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
> index 55fc22e8d4d4e..a3eff77add557 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_drv.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
[ ... ]
> @@ -884,9 +888,11 @@ static void panfrost_remove(struct platform_device *pdev)
> drm_dev_unregister(&pfdev->base);
>
> pm_runtime_get_sync(pfdev->base.dev);
> + pm_runtime_dont_use_autosuspend(pfdev->base.dev);
> + pm_runtime_put_noidle(pfdev->base.dev);
> pm_runtime_disable(pfdev->base.dev);
> - panfrost_device_fini(pfdev);
> pm_runtime_set_suspended(pfdev->base.dev);
> + panfrost_device_fini(pfdev);
[Severity: High]
This is a pre-existing issue, but does panfrost_device_fini() ignore the
return value of pm_runtime_get_sync() and risk system crashes?
Looking at panfrost_device.c:panfrost_device_fini(), it issues a warning but
unconditionally proceeds with hardware teardown:
drm_WARN_ON(&pfdev->base, pm_runtime_get_sync(pfdev->base.dev) < 0);
...
panfrost_jm_fini(pfdev);
panfrost_mmu_fini(pfdev);
panfrost_gpu_fini(pfdev);
If pm_runtime_get_sync() fails (e.g., due to regulator or clock failure),
the device remains physically suspended with clocks disabled.
Can unconditionally writing to MMIO registers in panfrost_jm_fini(),
panfrost_mmu_fini(), and panfrost_gpu_fini() with clocks off cause a bus
fault or kernel panic?
[Severity: High]
This is a pre-existing issue, but does panfrost_device_fini() tear down
hardware while GPU jobs might still be executing?
During device unbind, the driver does not appear to wait for actively
executing jobs on the physical GPU hardware to complete or abort. It proceeds
to unmap pagetables and power off the GPU:
panfrost_jm_fini(pfdev);
panfrost_mmu_fini(pfdev);
panfrost_gpu_fini(pfdev);
Can pulling the memory and clocks out from under a running GPU job during a
hot-unplug or unbind cause catastrophic hardware faults or kernel panics?
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=6
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset
2026-09-07 20:16 ` [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset Adrián Larumbe
@ 2026-09-07 20:31 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:31 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incomplete refactoring of clock management in system PM callbacks, contradicting the commit message
--
commit ade848b25069fa976d1163310dd16ab781b653aa
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Consolidate device clock management and reset
This commit introduces helpers to consolidate clock management and avoid
repetition across different power states. It updates the driver init, fini,
and runtime PM paths to prepare/enable and disable/unprepare clocks together.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
> index b3a53504bd016..48135e412b6c9 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.c
[ ... ]
> @@ -506,11 +498,11 @@ static int panfrost_device_resume(struct device *dev)
> }
>
> if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
> - ret = clk_enable(pfdev->clock);
> + ret = clk_prepare_enable(pfdev->clock);
> if (ret)
> goto err_clk;
>
> - ret = clk_enable(pfdev->bus_clock);
> + ret = clk_prepare_enable(pfdev->bus_clock);
> if (ret)
> goto err_bus_clk;
> }
[Severity: Medium]
The commit message mentions gathering all clock enables and disables into a
single function to avoid repetitions between driver init/fini and device
resume/suspend. Does this system resume path intentionally bypass the newly
added panfrost_clk_enable() function?
By calling clk_prepare_enable() directly, it appears to miss the refactoring
goal and omits bus_ace_clock for platforms using GPU_PM_CLK_DIS.
[ ... ]
> @@ -543,8 +535,8 @@ static int panfrost_device_suspend(struct device *dev)
> return ret;
>
> if (pfdev->comp->pm_features & BIT(GPU_PM_CLK_DIS)) {
> - clk_disable(pfdev->bus_clock);
> - clk_disable(pfdev->clock);
> + clk_disable_unprepare(pfdev->bus_clock);
> + clk_disable_unprepare(pfdev->clock);
> }
>
> if (pfdev->comp->pm_features & BIT(GPU_PM_VREG_OFF))
[Severity: Medium]
Similarly, should this section use the new panfrost_clk_disable() helper
instead of open-coding the clk_disable_unprepare() calls?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=5
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init
2026-09-07 20:16 ` [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init Adrián Larumbe
@ 2026-09-07 20:31 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:31 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] The driver is vulnerable to an asynchronous bus fault (system crash) during driver removal when IRQs are shared. The GPU is powered off before the devm-managed IRQs are freed, but the `is_suspended` flags are not set, allowing the IRQ handlers to read from unpowered registers.
- [High] Hardware register MMU_INT_MASK suffers from a TOCTOU race with the IRQ thread, which can leave interrupts enabled when the device is suspended.
- [High] Incorrect ordering of hardware state update leaves Address Space (AS) interrupts permanently masked after recovering from a page fault.
--
commit edb0f05f6a41299dfda9d57b9f1f096e6d1d4aca
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
Subject: drm/panfrost: Explicitly enable MMU interrupts at device init
This patch addresses an issue where jobs targeting the tiler buffer object
could time out between device registration and the first autosuspend. It
fixes this by explicitly enabling MMU interrupts at device initialization.
Fixes: 73e467f60acd ("drm/panfrost: Consolidate reset handling")
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
[ ... ]
> @@ -973,6 +978,8 @@ int panfrost_mmu_init(struct panfrost_device *pfdev)
> return err;
> }
>
> + panfrost_mmu_enable_interrupts(pfdev);
> +
[Severity: High]
This is a pre-existing issue, but while reviewing the interrupt handling
code, does the driver have a vulnerability to an asynchronous bus fault
during driver removal when IRQs are shared?
In drivers/gpu/drm/panfrost/panfrost_device.c, panfrost_remove() calls
pm_runtime_set_suspended():
static void panfrost_remove(struct platform_device *pdev)
{
// ...
pm_runtime_disable(pfdev->base.dev);
pm_runtime_set_suspended(pfdev->base.dev);
panfrost_device_fini(pfdev);
}
This bypasses the panfrost_device_runtime_suspend() callback that normally
sets PANFROST_COMP_BIT_MMU. Then panfrost_device_fini() powers off the GPU.
Because PANFROST_COMP_BIT_MMU is not set, if an interrupt arrives on the
shared line before devm cleanup frees the IRQ:
drivers/gpu/drm/panfrost/panfrost_mmu.c:panfrost_mmu_irq_handler()
if (test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended))
return IRQ_NONE;
if (!mmu_read(pfdev, MMU_INT_STAT))
return IRQ_NONE;
The handler will bypass the is_suspended check and read MMU_INT_STAT from
the powered-off GPU, potentially causing an SError or system crash.
[Severity: High]
This is also a pre-existing issue, but does MMU_INT_MASK suffer from a
TOCTOU race with the IRQ thread that can leave interrupts enabled when the
device is suspended?
In panfrost_mmu_irq_handler_thread(), the thread checks the suspended state
outside the lock:
/* Enable interrupts only if we're not about to get suspended */
if (!test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) {
spin_lock(&pfdev->as_lock);
mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
spin_unlock(&pfdev->as_lock);
}
If preempted immediately after this evaluates to true, another CPU running
panfrost_mmu_suspend_irq() can set the is_suspended bit, write 0 to
MMU_INT_MASK, and block on synchronize_irq():
set_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
mmu_write(pfdev, MMU_INT_MASK, 0);
synchronize_irq(pfdev->mmu_irq);
When the thread resumes, it locks, writes ~pfdev->as_faulty_mask to unmask
the interrupts, and exits. This allows synchronize_irq() to return, but
leaves the interrupts erroneously unmasked in hardware during suspend.
[Severity: High]
This is another pre-existing issue, but does the hardware state update
ordering in panfrost_mmu_as_get() leave Address Space (AS) interrupts
permanently masked after recovering from a page fault?
When clearing a faulty AS, the code writes to MMU_INT_MASK before clearing
the faulty AS's bit in as_faulty_mask:
mmu_write(pfdev, MMU_INT_CLEAR, mask);
mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
pfdev->as_faulty_mask &= ~mask;
panfrost_mmu_enable(pfdev, mmu);
The inverted mask writes a 0 for this AS, keeping it disabled in the
hardware register. Software state is updated immediately afterward, but
the hardware register is never re-written to reflect the unmasked state.
This could cause future GPU jobs on this AS to hang and timeout without
raising an interrupt.
> return 0;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=7
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field
2026-09-07 20:16 ` [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field Adrián Larumbe
@ 2026-09-07 20:33 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:33 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The newly added `pad` field in `struct drm_panfrost_perfcnt_dump` is not validated for being zero, breaking future extendability.
- [Medium] The `state` output field in `struct drm_panfrost_perfcnt_dump` is not initialized to zero before being returned to userspace on the success path.
--
commit 206ab1a1901fc21e7df0dcb1254dbaded4f7ae19
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field
Expose expanded PERFCNT_DUMP IOCTL interface to user mode.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
> index 571a26b841269..de9b1c115181b 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_drv.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
> @@ -808,6 +808,7 @@ static const struct file_operations panfrost_drm_driver_fops = {
> * - 1.6 - adds PANFROST_BO_MAP_WB, PANFROST_IOCTL_SYNC_BO,
> * PANFROST_IOCTL_QUERY_BO_INFO and
> * DRM_PANFROST_PARAM_SELECTED_COHERENCY
> + * - 1.7 - adds PERFCNT_DUMP req state field
[Severity: Medium]
Since this exposes the new PERFCNT_DUMP fields to userspace, does the IOCTL
handler need to validate that the new padding field is zero?
In the newly expanded struct drm_panfrost_perfcnt_dump, a pad field was added:
include/uapi/drm/panfrost_drm.h:
struct drm_panfrost_perfcnt_dump {
__u64 buf_ptr;
__u32 state;
__u32 pad;
};
But in panfrost_ioctl_perfcnt_dump(), it doesn't appear this field is checked:
drivers/gpu/drm/panfrost/panfrost_perfcnt.c:panfrost_ioctl_perfcnt_dump() {
...
ret = panfrost_unstable_ioctl_check();
if (ret)
return ret;
mutex_lock(&perfcnt->lock);
...
}
If userspace leaves this uninitialized, the kernel currently accepts non-zero
values, which might prevent safely repurposing the pad field for new features
in the future.
[Severity: Medium]
Also regarding the new state field, is req->state guaranteed to be initialized
to zero before being returned to userspace?
Looking at panfrost_ioctl_perfcnt_dump(), the state field is passed directly:
drivers/gpu/drm/panfrost/panfrost_perfcnt.c:panfrost_ioctl_perfcnt_dump() {
...
ret = panfrost_perfcnt_dump_locked(pfdev, &req->state);
if (ret)
goto out;
...
}
And in panfrost_perfcnt_dump_locked(), *state is only conditionally modified
or OR'd:
drivers/gpu/drm/panfrost/panfrost_perfcnt.c:panfrost_perfcnt_dump_locked() {
...
if (perfcnt->reset_happened) {
*state = PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
perfcnt->reset_happened = false;
}
...
/* Either sample finished or reset happened */
if (ret > 0) {
...
if (perfcnt->reset_happened)
*state |= PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
if (!perfcnt->owns_as_ref)
*state |= PANFROST_PERFCNT_SESSION_DEAD;
}
...
}
If a userspace program calls the IOCTL with uninitialized memory for req->state,
and the happy path is taken where neither condition hits, does this leave the
state field uninitialized on success, returning the user's garbage data back
to them and potentially causing them to falsely detect a GPU reset or dead
session?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=16
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems
2026-09-07 20:16 ` [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems Adrián Larumbe
@ 2026-09-07 20:35 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:35 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Use-After-Free in IRQ handler during device teardown due to shared interrupt firing after subsystem deinitialization.
--
commit 4af8baef18e17c6d5fb401654ac07ca6918a16ae
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems
This commit skips flushing the GPU caches after a performance counter sample
is made available if the GPU and CPU are fully coherent. It directly signals
the completion instead.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> index ffc77121070e2..b3f71d7fd82a9 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> @@ -52,7 +52,10 @@ void panfrost_perfcnt_clean_cache_done(struct panfrost_device *pfdev)
>
> void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
> {
> - gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
> + if (pfdev->features.selected_coherency != COHERENCY_ACE)
> + gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
> + else
> + complete(&pfdev->perfcnt->dump_comp);
[Severity: High]
This is a pre-existing issue, but can this dereference of pfdev->perfcnt lead
to a use-after-free during device teardown?
Looking at panfrost_gpu_init() in drivers/gpu/drm/panfrost/panfrost_gpu.c,
the shared GPU IRQ is requested before panfrost_perfcnt_init() allocates
pfdev->perfcnt. During driver teardown (panfrost_device_fini()), devres
cleans up allocations in reverse order. This means pfdev->perfcnt is freed
while the shared IRQ remains registered.
If an external interrupt fires on the shared IRQ line during this window,
panfrost_gpu_irq_handler() could see the GPU_IRQ_PERFCNT_SAMPLE_COMPLETED
bit set (e.g., if reading GPU_INT_STAT from unclocked hardware returns
0xFFFFFFFF).
The handler would then call panfrost_perfcnt_sample_done(), which accesses
the already freed pfdev->perfcnt pointer here.
Should the GPU IRQ be explicitly disabled or unregistered before perfcnt is
deinitialized?
> }
>
> static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=13
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence
2026-09-07 20:16 ` [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence Adrián Larumbe
@ 2026-09-07 20:36 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:36 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] State Loss: The `reset_happened` flag is cleared prematurely on error paths
- [Medium] API Flaw: Uninitialized userspace memory leaked back as flags and unvalidated padding
- [Low] Cleanup Rule Violation: Mixing goto-based error handling and scoped_guard in the same function
Pre-existing issues:
- [High] Race Condition / GPU Fault: Pending asynchronous GPU sample operation is not cancelled when wait is interrupted
--
commit 9121f328e8a02b83046e96373b7d6c617fd603c1
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Fix races between perfcnt and reset sequence
This commit uses the reset read/write semaphore to manage access to hardware
during reset time. It expands the DRM uAPI for the perfcnt dump operation so
userspace can be aware of hardware resets. It also attempts to reestablish
the perfcnt configuration if a session was enabled during a reset.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> --- a/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_perfcnt.c
> @@ -47,11 +52,15 @@ static void panfrost_perfcnt_hw_disable(struct panfrost_device *pfdev)
> void panfrost_perfcnt_sample_done(struct panfrost_device *pfdev)
> {
> - if (pfdev->features.selected_coherency != COHERENCY_ACE)
> + if (pfdev->features.selected_coherency != COHERENCY_ACE) {
> gpu_write(pfdev, GPU_CMD, GPU_CMD_CLEAN_CACHES);
> - else
> + } else {
> + pfdev->perfcnt->dump_finished = true;
> complete(&pfdev->perfcnt->dump_comp);
> + }
> }
[Severity: High]
This is a pre-existing issue, but does this IRQ handler complete the dump_comp
unconditionally without verifying if it corresponds to the currently active
dump request?
If the wait in panfrost_perfcnt_dump_locked() is interrupted by a signal, the
hardware GPU_CMD_PERFCNT_SAMPLE command could still be running. If userspace
immediately closes the file descriptor, the GEM object and MMU mappings could
be freed while the GPU is still actively writing to memory, potentially
causing a GPU page fault.
[ ... ]
> @@ -60,25 +105,43 @@ static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
> -static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev)
> +static int panfrost_perfcnt_dump_locked(struct panfrost_device *pfdev, u32 *state)
> {
> + scoped_guard(rwsem_read, &pfdev->reset.lock) {
> + if (!perfcnt->owns_as_ref) {
> + *state = PANFROST_PERFCNT_SESSION_DEAD;
> + return -EIO;
> + }
> +
> + if (perfcnt->reset_happened) {
> + *state = PANFROST_PERFCNT_SESSION_INTERRUPTED_BY_RESET;
> + perfcnt->reset_happened = false;
> + }
[Severity: High]
If wait_for_completion_interruptible_timeout() gets interrupted (e.g., by a
signal) or times out, it will return an error like -ERESTARTSYS. Since
perfcnt->reset_happened is cleared here at the start of the function, won't
the reset condition be permanently lost?
If the ioctl is retried by VFS or userspace, userspace might incorrectly
accumulate counter values across a GPU reset without knowing it happened.
[ ... ]
> @@ -122,54 +200,31 @@ static int panfrost_perfcnt_enable_locked(struct panfrost_device *pfdev,
> ret = drm_gem_vmap(&bo->base, &map);
> if (ret)
> goto err_put_mapping;
> +
> perfcnt->buf = map.vaddr;
> + perfcnt->counterset = counterset;
>
> panfrost_gem_internal_set_label(&bo->base, "Perfcnt sample buffer");
>
> + scoped_guard(rwsem_read, &pfdev->reset.lock) {
> + /*
> + * Clear the counters to start from a fresh state.
> + */
> + gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_PERFCNT_SAMPLE_COMPLETED);
> + gpu_write(pfdev, GPU_CMD, GPU_CMD_PERFCNT_CLEAR);
>
> + ret = panfrost_perfcnt_hw_enable(pfdev);
> + if (ret)
> + goto err_vunmap;
[Severity: Low]
Does this goto statement jump out of the scoped_guard() block directly into
legacy error handling labels?
The subsystem coding guidelines specify that goto-based cleanup and
scoped_guard() / __free() shouldn't be mixed in the same function to avoid
confusing ownership semantics.
[ ... ]
> @@ -255,7 +313,7 @@ int panfrost_ioctl_perfcnt_dump(struct drm_device *dev, void *data,
> goto out;
> }
>
> - ret = panfrost_perfcnt_dump_locked(pfdev);
> + ret = panfrost_perfcnt_dump_locked(pfdev, &req->state);
[Severity: Medium]
Since DRM_IOCTL_PANFROST_PERFCNT_DUMP uses DRM_IOWR, is it possible that
req->state and req->pad contain uninitialized user stack memory here?
It appears req->state is passed directly into panfrost_perfcnt_dump_locked()
where it is conditionally updated using a bitwise OR, without ever being
unconditionally zero-initialized first. Also, req->pad doesn't seem to be
validated to be zero, which could complicate extending this struct in the
future.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=15
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v8 14/16] drm/panfrost: Introduce a reset lock
2026-09-07 20:16 ` [PATCH v8 14/16] drm/panfrost: Introduce a reset lock Adrián Larumbe
@ 2026-09-07 20:38 ` sashiko-bot
0 siblings, 0 replies; 26+ messages in thread
From: sashiko-bot @ 2026-09-07 20:38 UTC (permalink / raw)
To: Adrián Larumbe; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Scheduler teardown races with pending reset work in panfrost_jm_fini().
- [High] panfrost_reset() drops PM references prematurely, allowing concurrent autosuspend to power off the GPU before reset.
--
commit 41ac0c5362c3dc2a1e03fb9d2659c68f74cd414d
Author: Adrián Larumbe <adrian.larumbe@collabora.com>
drm/panfrost: Introduce a reset lock
This commit adds a read/write semaphore to the panfrost device reset structure.
It protects hardware register access during an ongoing reset sequence,
specifically preventing the timestamp query ioctl from racing with the reset
process.
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
> index f171abe26f80d..e90efcff5ce7e 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.c
> @@ -466,6 +466,8 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
>
> void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
> {
> + guard(rwsem_write)(&pfdev->reset.lock);
> +
> panfrost_gpu_soft_reset(pfdev);
>
> panfrost_gpu_power_on(pfdev);
[Severity: High]
This isn't a bug introduced by this patch, but looking at how
panfrost_device_reset() is called from panfrost_reset() in
drivers/gpu/drm/panfrost/panfrost_job.c, is there a race with GPU
autosuspend?
In panfrost_reset(), the PM references for stuck jobs are dropped right
before calling panfrost_device_reset():
pm_runtime_put_noidle(pfdev->base.dev);
panfrost_devfreq_record_idle(&pfdev->pfdevfreq);
...
/* Proceed with reset now. */
panfrost_device_reset(pfdev, false);
If an autosuspend timer expires in this small window, could
panfrost_device_runtime_suspend() execute and power off the GPU? If so,
the subsequent register accesses inside panfrost_device_reset() (like writing
to GPU_INT_MASK in panfrost_gpu_soft_reset()) might hit powered-off hardware,
potentially causing a bus fault.
[ ... ]
> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
> index 00fb36c577df7..c2b1f1087e21e 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_job.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_job.c
> @@ -877,6 +877,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
> INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
> spin_lock_init(&js->job_lock);
> mutex_init(&pfdev->sched_lock);
> + init_rwsem(&pfdev->reset.lock);
>
> js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), "job");
> if (js->irq < 0)
[Severity: High]
This is a pre-existing issue, but while we are setting up the reset worker
and its locks here, does the teardown order in panfrost_jm_fini() race with
the reset work?
Looking at panfrost_jm_fini() in drivers/gpu/drm/panfrost/panfrost_job.c, it
destroys the schedulers before cancelling the pending reset work:
for (j = 0; j < NUM_JOB_SLOTS; j++) {
drm_sched_fini(&js->queue[j].sched);
}
cancel_work_sync(&pfdev->reset.work);
If a user triggers a GPU reset via debugfs or a delayed reset work is queued
just as the module is unloaded, could panfrost_reset_work() execute
concurrently? Since panfrost_reset() calls drm_sched_stop() and
drm_sched_start() on the torn-down schedulers, this sequence could lead to
accessing freed scheduler memory.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260907-claude-fixes-v8-0-c2bcb5e82184@collabora.com?part=14
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2026-09-07 20:38 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 20:16 [PATCH v8 00/16] Collection of fixes for Panfrost: Perfcnt, RPM, refactorings Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 01/16] drm/panfrost: Move shrinker initialization and unplug one level down Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 02/16] drm/panfrost: Move lock and modparam initialisations into their subsystems Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 03/16] drm/panfrost: Move debugfs initialisation to relevant subsystems Adrián Larumbe
2026-09-07 20:28 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 04/16] drm/panfrost: Skip NULL checks for clock enable/disabling Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 05/16] drm/panfrost: Consolidate device clock management and reset Adrián Larumbe
2026-09-07 20:31 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 06/16] drm/panfrost: Fix PM refcnt and autosuspend issues at device probe/remove Adrián Larumbe
2026-09-07 20:29 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 07/16] drm/panfrost: Explicitly enable MMU interrupts at device init Adrián Larumbe
2026-09-07 20:31 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 08/16] drm/panfrost: Move all DRM device initialisation into device_init() Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 09/16] drm/panfrost: Add warning messages to fatal error conditions Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 10/16] drm/panfrost: Add debugfs knob for manually triggering a GPU reset Adrián Larumbe
2026-09-07 20:28 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 11/16] drm/panfrost: Move perfcnt GPU disable sequence into a helper Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 12/16] drm/panfrost: Skip cache flush/invalidate when enabling perfcnt Adrián Larumbe
2026-09-07 20:16 ` [PATCH v8 13/16] drm/panfrost: Avoid cache flush after perfcnt sample in fully coherent systems Adrián Larumbe
2026-09-07 20:35 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 14/16] drm/panfrost: Introduce a reset lock Adrián Larumbe
2026-09-07 20:38 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 15/16] drm/panfrost: Fix races between perfcnt and reset sequence Adrián Larumbe
2026-09-07 20:36 ` sashiko-bot
2026-09-07 20:16 ` [PATCH v8 16/16] drm/panfrost: Bump driver minor to reflect new DUMP IOCTL req field Adrián Larumbe
2026-09-07 20:33 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox