Skip to content

Commit 7e6fb67

Browse files
jwrdegoedesre
authored andcommitted
power: supply: bq25890: Fix usb-notifier probe and remove races
There are 2 races surrounding the usb-notifier: 1. The notifier, and thus usb_work, may run before the bq->charger power_supply class device is registered. But usb_work may call power_supply_changed() which relies on the psy device being registered. 2. usb_work may be pending/running at remove() time, so it needs to be cancelled on remove after unregistering the usb-notifier. Fix 1. by moving usb-notifier registration to after the power_supply registration. Fix 2. by adding a cancel_work_sync() call directly after the usb-notifier unregistration. Reviewed-by: Marek Vasut <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Sebastian Reichel <[email protected]>
1 parent a7aaa80 commit 7e6fb67

File tree

1 file changed

+12
-18
lines changed

1 file changed

+12
-18
lines changed

drivers/power/supply/bq25890_charger.c

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,40 +1391,34 @@ static int bq25890_probe(struct i2c_client *client)
13911391
if (ret)
13921392
return ret;
13931393

1394-
if (!IS_ERR_OR_NULL(bq->usb_phy)) {
1395-
INIT_WORK(&bq->usb_work, bq25890_usb_work);
1396-
bq->usb_nb.notifier_call = bq25890_usb_notifier;
1397-
usb_register_notifier(bq->usb_phy, &bq->usb_nb);
1398-
}
1399-
14001394
ret = bq25890_power_supply_init(bq);
1401-
if (ret < 0) {
1402-
dev_err(dev, "Failed to register power supply\n");
1403-
goto err_unregister_usb_notifier;
1404-
}
1395+
if (ret < 0)
1396+
return dev_err_probe(dev, ret, "registering power supply\n");
14051397

14061398
ret = devm_request_threaded_irq(dev, client->irq, NULL,
14071399
bq25890_irq_handler_thread,
14081400
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
14091401
BQ25890_IRQ_PIN, bq);
14101402
if (ret)
1411-
goto err_unregister_usb_notifier;
1412-
1413-
return 0;
1403+
return ret;
14141404

1415-
err_unregister_usb_notifier:
1416-
if (!IS_ERR_OR_NULL(bq->usb_phy))
1417-
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
1405+
if (!IS_ERR_OR_NULL(bq->usb_phy)) {
1406+
INIT_WORK(&bq->usb_work, bq25890_usb_work);
1407+
bq->usb_nb.notifier_call = bq25890_usb_notifier;
1408+
usb_register_notifier(bq->usb_phy, &bq->usb_nb);
1409+
}
14181410

1419-
return ret;
1411+
return 0;
14201412
}
14211413

14221414
static void bq25890_remove(struct i2c_client *client)
14231415
{
14241416
struct bq25890_device *bq = i2c_get_clientdata(client);
14251417

1426-
if (!IS_ERR_OR_NULL(bq->usb_phy))
1418+
if (!IS_ERR_OR_NULL(bq->usb_phy)) {
14271419
usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
1420+
cancel_work_sync(&bq->usb_work);
1421+
}
14281422

14291423
if (!bq->skip_reset) {
14301424
/* reset all registers to default values */

0 commit comments

Comments
 (0)