mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
power: supply: bq256xx: drain usb_work before freeing the charger
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: 32e4978bb9 ("power: supply: bq256xx: Introduce the BQ256XX charger driver")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260804145511.103470-1-fanwu01@zju.edu.cn
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
This commit is contained in:
parent
37689bcbc4
commit
2dd6cd8237
|
|
@ -892,6 +892,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,
|
||||
|
|
@ -1717,24 +1719,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) {
|
||||
|
|
@ -1742,6 +1732,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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user