[PATCH] power: supply: bq256xx: drain usb_work before freeing the charger
Fan Wu <[email protected]> Tue, 4 Aug 2026 14:55:11 +0000
| Newsgroups | org.kernel.vger.stable,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <[email protected]> |
The USB-PHY notifier queues usb_work, whose handler calls
power_supply_changed(bq->charger). The reset devm action only unregisters
the notifier and was registered before the power supplies, so devm frees
bq->charger on unwind before the action runs; a usb_work still queued can
then dereference it.
Register the reset action after the power supplies, so it unregisters
the notifiers and drains usb_work before the supplies are released.
Initialize usb_work and obtain the PHY references before registering
the notifiers, so the worker cannot run before the supplies exist.
Found by static analysis.
Fixes: 32e4978bb920 ("power: supply: bq256xx: Introduce the BQ256XX charger driver")
Cc: [email protected]
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <[email protected]>
---
drivers/power/supply/bq256xx_charger.c | 29 +++++++++++++++--------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c
index 5a6634fde8..43e1da849d 100644
--- a/drivers/power/supply/bq256xx_charger.c
+++ b/drivers/power/supply/bq256xx_charger.c
@@ -896,6 +896,8 @@ static void bq256xx_charger_reset(void *data)
if (!IS_ERR_OR_NULL(bq->usb3_phy))
usb_unregister_notifier(bq->usb3_phy, &bq->usb_nb);
+
+ cancel_work_sync(&bq->usb_work);
}
static int bq256xx_set_charger_property(struct power_supply *psy,
@@ -1721,24 +1723,12 @@ static int bq256xx_probe(struct i2c_client *client)
return ret;
}
- ret = devm_add_action_or_reset(dev, bq256xx_charger_reset, bq);
- if (ret)
- return ret;
+ INIT_WORK(&bq->usb_work, bq256xx_usb_work);
+ bq->usb_nb.notifier_call = bq256xx_usb_notifier;
/* OTG reporting */
bq->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (!IS_ERR_OR_NULL(bq->usb2_phy)) {
- INIT_WORK(&bq->usb_work, bq256xx_usb_work);
- bq->usb_nb.notifier_call = bq256xx_usb_notifier;
- usb_register_notifier(bq->usb2_phy, &bq->usb_nb);
- }
-
bq->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
- if (!IS_ERR_OR_NULL(bq->usb3_phy)) {
- INIT_WORK(&bq->usb_work, bq256xx_usb_work);
- bq->usb_nb.notifier_call = bq256xx_usb_notifier;
- usb_register_notifier(bq->usb3_phy, &bq->usb_nb);
- }
ret = bq256xx_power_supply_init(bq, &psy_cfg, dev);
if (ret) {
@@ -1746,6 +1736,17 @@ static int bq256xx_probe(struct i2c_client *client)
return ret;
}
+ /* Register after the power supplies so devm runs it first. */
+ ret = devm_add_action_or_reset(dev, bq256xx_charger_reset, bq);
+ if (ret)
+ return ret;
+
+ if (!IS_ERR_OR_NULL(bq->usb2_phy))
+ usb_register_notifier(bq->usb2_phy, &bq->usb_nb);
+
+ if (!IS_ERR_OR_NULL(bq->usb3_phy))
+ usb_register_notifier(bq->usb3_phy, &bq->usb_nb);
+
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq, NULL,
bq256xx_irq_handler_thread,
--
2.34.1