[PATCH] platform/x86: gpd pocket fan: Cancel work before releasing GPIOs
From: Myeonghun Pak
Date: Sat Oct 17 2026 - 23:34:03 EST
The fan worker changes the direction of both GPIOs and schedules its
next run. Its managed cancellation action is registered before the GPIOs
are acquired, so devres releases the GPIOs before cancelling the work. A
running worker can therefore change a GPIO after the driver has released
it.
Register the work cancellation action after both GPIO acquisitions. This
makes devres cancel and drain the worker before releasing either GPIO.
No work has been queued yet if GPIO acquisition or action registration
fails.
This issue was identified as part of our ongoing research while
reviewing kernel code.
Fixes: b82a7b018b93 ("platform/x86: gpd pocket fan: Clean-up by using managed work init")
Co-developed-by: Ijae Kim <ae878000@xxxxxxxxx>
Signed-off-by: Ijae Kim <ae878000@xxxxxxxxx>
Signed-off-by: Myeonghun Pak <mhun512@xxxxxxxxx>
---
Compile-tested with Clang, W=1. No hardware runtime testing.
Based on mainline 0fcb05b72344f40806cbe810de8872f1698bf053.
diff --git a/drivers/platform/x86/gpd-pocket-fan.c b/drivers/platform/x86/gpd-pocket-fan.c
index c923673..ced9379 100644
--- a/drivers/platform/x86/gpd-pocket-fan.c
+++ b/drivers/platform/x86/gpd-pocket-fan.c
@@ -153,10 +153,6 @@ static int gpd_pocket_fan_probe(struct platform_device *pdev)
return -ENOMEM;
fan->dev = &pdev->dev;
- ret = devm_delayed_work_autocancel(&pdev->dev, &fan->work,
- gpd_pocket_fan_worker);
- if (ret)
- return ret;
/* Note this returns a "weak" reference which we don't need to free */
fan->dts0 = thermal_zone_get_zone_by_name("soc_dts0");
@@ -175,6 +171,11 @@ static int gpd_pocket_fan_probe(struct platform_device *pdev)
if (IS_ERR(fan->gpio1))
return PTR_ERR(fan->gpio1);
+ ret = devm_delayed_work_autocancel(&pdev->dev, &fan->work,
+ gpd_pocket_fan_worker);
+ if (ret)
+ return ret;
+
gpd_pocket_fan_force_update(fan);
platform_set_drvdata(pdev, fan);