Message ID | 20211030182813.116672-4-hdegoede@redhat.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | power-suppy/i2c/extcon: Add support for cht-wc PMIC without USB-PD support | expand |
Hi, On Sat, Oct 30, 2021 at 08:28:03PM +0200, Hans de Goede wrote: > Before this commit the driver was registering its interrupt handler before > it registered the power_supply, causing bq->charger to potentially be NULL > when the interrupt handler runs, triggering a NULL pointer exception in > the interrupt handler: > > [ 21.213531] BUG: kernel NULL pointer dereference, address: 0000000000000680 > ... > [ 21.213573] Hardware name: Xiaomi Inc Mipad2/Mipad, BIOS MIPad-P4.X64.0043.R03.1603071414 03/07/2016 > [ 21.213576] RIP: 0010:__lock_acquire+0x5c5/0x1de0 > ... > [ 21.213629] Call Trace: > [ 21.213636] ? disable_irq_nosync+0x10/0x10 > [ 21.213644] ? __mutex_unlock_slowpath+0x35/0x260 > [ 21.213655] lock_acquire+0xb5/0x2b0 > [ 21.213661] ? power_supply_changed+0x23/0x90 > [ 21.213670] ? disable_irq_nosync+0x10/0x10 > [ 21.213676] _raw_spin_lock_irqsave+0x48/0x60 > [ 21.213682] ? power_supply_changed+0x23/0x90 > [ 21.213687] power_supply_changed+0x23/0x90 > [ 21.213697] __bq25890_handle_irq+0x5e/0xe0 [bq25890_charger] > [ 21.213709] bq25890_irq_handler_thread+0x26/0x40 [bq25890_charger] > [ 21.213718] irq_thread_fn+0x20/0x60 > ... > > Fix this by moving the power_supply_register() call to above the > request_threaded_irq() call. > > Note this fix includes making the following 2 (necessary) changes: > > 1. Switch to the devm version of power_supply_register() to avoid the > need to make the error-handling in probe() more complicated. > > 2. Rename the "irq_fail" label to "err_unregister_usb_notifier" since > the old name no longer makes sense after this fix. > > Signed-off-by: Hans de Goede <hdegoede@redhat.com> > --- Thanks, queued. -- Sebastian > drivers/power/supply/bq25890_charger.c | 23 +++++++++++------------ > 1 file changed, 11 insertions(+), 12 deletions(-) > > diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c > index 945c3257ca93..491d36a3811a 100644 > --- a/drivers/power/supply/bq25890_charger.c > +++ b/drivers/power/supply/bq25890_charger.c > @@ -734,8 +734,9 @@ static int bq25890_power_supply_init(struct bq25890_device *bq) > psy_cfg.supplied_to = bq25890_charger_supplied_to; > psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); > > - bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc, > - &psy_cfg); > + bq->charger = devm_power_supply_register(bq->dev, > + &bq25890_power_supply_desc, > + &psy_cfg); > > return PTR_ERR_OR_ZERO(bq->charger); > } > @@ -985,22 +986,22 @@ static int bq25890_probe(struct i2c_client *client, > usb_register_notifier(bq->usb_phy, &bq->usb_nb); > } > > + ret = bq25890_power_supply_init(bq); > + if (ret < 0) { > + dev_err(dev, "Failed to register power supply\n"); > + goto err_unregister_usb_notifier; > + } > + > ret = devm_request_threaded_irq(dev, client->irq, NULL, > bq25890_irq_handler_thread, > IRQF_TRIGGER_FALLING | IRQF_ONESHOT, > BQ25890_IRQ_PIN, bq); > if (ret) > - goto irq_fail; > - > - ret = bq25890_power_supply_init(bq); > - if (ret < 0) { > - dev_err(dev, "Failed to register power supply\n"); > - goto irq_fail; > - } > + goto err_unregister_usb_notifier; > > return 0; > > -irq_fail: > +err_unregister_usb_notifier: > if (!IS_ERR_OR_NULL(bq->usb_phy)) > usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); > > @@ -1011,8 +1012,6 @@ static int bq25890_remove(struct i2c_client *client) > { > struct bq25890_device *bq = i2c_get_clientdata(client); > > - power_supply_unregister(bq->charger); > - > if (!IS_ERR_OR_NULL(bq->usb_phy)) > usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); > > -- > 2.31.1 >
diff --git a/drivers/power/supply/bq25890_charger.c b/drivers/power/supply/bq25890_charger.c index 945c3257ca93..491d36a3811a 100644 --- a/drivers/power/supply/bq25890_charger.c +++ b/drivers/power/supply/bq25890_charger.c @@ -734,8 +734,9 @@ static int bq25890_power_supply_init(struct bq25890_device *bq) psy_cfg.supplied_to = bq25890_charger_supplied_to; psy_cfg.num_supplicants = ARRAY_SIZE(bq25890_charger_supplied_to); - bq->charger = power_supply_register(bq->dev, &bq25890_power_supply_desc, - &psy_cfg); + bq->charger = devm_power_supply_register(bq->dev, + &bq25890_power_supply_desc, + &psy_cfg); return PTR_ERR_OR_ZERO(bq->charger); } @@ -985,22 +986,22 @@ static int bq25890_probe(struct i2c_client *client, usb_register_notifier(bq->usb_phy, &bq->usb_nb); } + ret = bq25890_power_supply_init(bq); + if (ret < 0) { + dev_err(dev, "Failed to register power supply\n"); + goto err_unregister_usb_notifier; + } + ret = devm_request_threaded_irq(dev, client->irq, NULL, bq25890_irq_handler_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, BQ25890_IRQ_PIN, bq); if (ret) - goto irq_fail; - - ret = bq25890_power_supply_init(bq); - if (ret < 0) { - dev_err(dev, "Failed to register power supply\n"); - goto irq_fail; - } + goto err_unregister_usb_notifier; return 0; -irq_fail: +err_unregister_usb_notifier: if (!IS_ERR_OR_NULL(bq->usb_phy)) usb_unregister_notifier(bq->usb_phy, &bq->usb_nb); @@ -1011,8 +1012,6 @@ static int bq25890_remove(struct i2c_client *client) { struct bq25890_device *bq = i2c_get_clientdata(client); - power_supply_unregister(bq->charger); - if (!IS_ERR_OR_NULL(bq->usb_phy)) usb_unregister_notifier(bq->usb_phy, &bq->usb_nb);
Before this commit the driver was registering its interrupt handler before it registered the power_supply, causing bq->charger to potentially be NULL when the interrupt handler runs, triggering a NULL pointer exception in the interrupt handler: [ 21.213531] BUG: kernel NULL pointer dereference, address: 0000000000000680 ... [ 21.213573] Hardware name: Xiaomi Inc Mipad2/Mipad, BIOS MIPad-P4.X64.0043.R03.1603071414 03/07/2016 [ 21.213576] RIP: 0010:__lock_acquire+0x5c5/0x1de0 ... [ 21.213629] Call Trace: [ 21.213636] ? disable_irq_nosync+0x10/0x10 [ 21.213644] ? __mutex_unlock_slowpath+0x35/0x260 [ 21.213655] lock_acquire+0xb5/0x2b0 [ 21.213661] ? power_supply_changed+0x23/0x90 [ 21.213670] ? disable_irq_nosync+0x10/0x10 [ 21.213676] _raw_spin_lock_irqsave+0x48/0x60 [ 21.213682] ? power_supply_changed+0x23/0x90 [ 21.213687] power_supply_changed+0x23/0x90 [ 21.213697] __bq25890_handle_irq+0x5e/0xe0 [bq25890_charger] [ 21.213709] bq25890_irq_handler_thread+0x26/0x40 [bq25890_charger] [ 21.213718] irq_thread_fn+0x20/0x60 ... Fix this by moving the power_supply_register() call to above the request_threaded_irq() call. Note this fix includes making the following 2 (necessary) changes: 1. Switch to the devm version of power_supply_register() to avoid the need to make the error-handling in probe() more complicated. 2. Rename the "irq_fail" label to "err_unregister_usb_notifier" since the old name no longer makes sense after this fix. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/power/supply/bq25890_charger.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)