[PATCH v2 01/17] drm/panthor: Disable reset work before unplug
From: Boris Brezillon
Date: Tue Aug 11 2026 - 06:18:42 EST
Unplug is supposed to be the end of the road, so we need to make sure
reset works won't execute while we're cleaning up everything as part
of the unplug, otherwise it would mess up the internal state.
In order to be able to call disable_work_sync() in the unplug
path, we need to defer the unplug triggered by the reset logic,
otherwise we would deadlock.
Fixes: 5fe909cae118 ("drm/panthor: Add the device logical block")
Signed-off-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxx>
---
drivers/gpu/drm/panthor/panthor_device.c | 21 ++++++++++++++++++++-
drivers/gpu/drm/panthor/panthor_device.h | 3 +++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c
index 0b25abebb803..c41de1b61533 100644
--- a/drivers/gpu/drm/panthor/panthor_device.c
+++ b/drivers/gpu/drm/panthor/panthor_device.c
@@ -91,6 +91,16 @@ void panthor_device_unplug(struct panthor_device *ptdev)
*/
mutex_unlock(&ptdev->unplug.lock);
+ /* Unplug triggered by a device removal might race with the deferred
+ * one queued by the reset work. The function covers this concurrent
+ * unplug situation, but if we can disable the work before its
+ * execution, that's still better.
+ */
+ disable_work(&ptdev->unplug.work);
+
+ /* Make sure we're not interrupted by resets while we're unplugging. */
+ disable_work_sync(&ptdev->reset.work);
+
/* Now, try to cleanly shutdown the GPU before the device resources
* get reclaimed.
*/
@@ -114,6 +124,13 @@ void panthor_device_unplug(struct panthor_device *ptdev)
complete_all(&ptdev->unplug.done);
}
+static void panthor_device_unplug_work(struct work_struct *work)
+{
+ struct panthor_device *ptdev = container_of(work, struct panthor_device, unplug.work);
+
+ panthor_device_unplug(ptdev);
+}
+
static void panthor_device_reset_cleanup(struct drm_device *ddev, void *data)
{
struct panthor_device *ptdev = container_of(ddev, struct panthor_device, base);
@@ -148,8 +165,9 @@ static void panthor_device_reset_work(struct work_struct *work)
drm_dev_exit(cookie);
if (ret) {
- panthor_device_unplug(ptdev);
+ disable_work(&ptdev->reset.work);
drm_err(&ptdev->base, "Failed to boot MCU after reset, making device unusable.");
+ queue_work(ptdev->reset.wq, &ptdev->unplug.work);
}
}
@@ -206,6 +224,7 @@ int panthor_device_init(struct panthor_device *ptdev)
*/
*dummy_page_virt = 1;
+ INIT_WORK(&ptdev->unplug.work, panthor_device_unplug_work);
INIT_WORK(&ptdev->reset.work, panthor_device_reset_work);
disable_work(&ptdev->reset.work);
ptdev->reset.wq = alloc_ordered_workqueue("panthor-reset-wq", 0);
diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h
index 0fda64fbe5f2..ea23dde90fea 100644
--- a/drivers/gpu/drm/panthor/panthor_device.h
+++ b/drivers/gpu/drm/panthor/panthor_device.h
@@ -264,6 +264,9 @@ struct panthor_device {
* operation is done.
*/
struct completion done;
+
+ /** @work: Unplug work. */
+ struct work_struct work;
} unplug;
/** @reset: Reset related fields. */
--
2.55.0