Skip to content

Commit

Permalink
extcon: arizona: Fix various races on driver unbind
Browse files Browse the repository at this point in the history
We must free/disable all interrupts and cancel all pending works
before doing further cleanup.

Before this commit arizona_extcon_remove() was doing several
register writes to shut things down before disabling the IRQs
and it was cancelling only 1 of the 3 different works used.

Move all the register-writes shutting things down to after
the disabling of the IRQs and add the 2 missing
cancel_delayed_work_sync() calls.

This fixes various possible races on driver unbind. One of which
would always trigger on devices using the mic-clamp feature for
jack detection. The ARIZONA_MICD_CLAMP_MODE_MASK update was
done before disabling the IRQs, causing:
1. arizona_jackdet() to run
2. detect a jack being inserted (clamp disabled means jack inserted)
3. call arizona_start_mic() which:
3.1 Enables the MICVDD regulator
3.2 takes a pm_runtime_reference

And this was all happening after the ARIZONA_MICD_ENA bit clearing,
which would undo 3.1 and 3.2 because the ARIZONA_MICD_CLAMP_MODE_MASK
update was being done after the ARIZONA_MICD_ENA bit clearing.

So this means that arizona_extcon_remove() would exit with
1. MICVDD enabled and 2. The pm_runtime_reference being unbalanced.

MICVDD still being enabled caused the following oops when the
regulator is released by the devm framework:

[ 2850.745757] ------------[ cut here ]------------
[ 2850.745827] WARNING: CPU: 2 PID: 2098 at drivers/regulator/core.c:2123 _regulator_put.part.0+0x19f/0x1b0
[ 2850.745835] Modules linked in: extcon_arizona ...
...
[ 2850.746909] Call Trace:
[ 2850.746932]  regulator_put+0x2d/0x40
[ 2850.746946]  release_nodes+0x22a/0x260
[ 2850.746984]  __device_release_driver+0x190/0x240
[ 2850.747002]  driver_detach+0xd4/0x120
...
[ 2850.747337] ---[ end trace f455dfd7abd9781f ]---

Note this oops is just one of various theoretically possible races caused
by the wrong ordering inside arizona_extcon_remove(), this fixes the
ordering fixing all possible races, including the reported oops.

Signed-off-by: Hans de Goede <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Acked-by: Charles Keepax <[email protected]>
Tested-by: Charles Keepax <[email protected]>
Acked-by: Chanwoo Choi <[email protected]>
Signed-off-by: Lee Jones <[email protected]>
  • Loading branch information
jwrdegoede authored and Lee Jones committed Mar 18, 2021
1 parent c309a3e commit e5b499f
Showing 1 changed file with 21 additions and 19 deletions.
40 changes: 21 additions & 19 deletions drivers/extcon/extcon-arizona.c
Original file line number Diff line number Diff line change
Expand Up @@ -1760,25 +1760,6 @@ static int arizona_extcon_remove(struct platform_device *pdev)
bool change;
int ret;

ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, 0,
&change);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
ret);
} else if (change) {
regulator_disable(info->micvdd);
pm_runtime_put(info->dev);
}

gpiod_put(info->micd_pol_gpio);

pm_runtime_disable(&pdev->dev);

regmap_update_bits(arizona->regmap,
ARIZONA_MICD_CLAMP_CONTROL,
ARIZONA_MICD_CLAMP_MODE_MASK, 0);

if (info->micd_clamp) {
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
Expand All @@ -1794,10 +1775,31 @@ static int arizona_extcon_remove(struct platform_device *pdev)
arizona_free_irq(arizona, jack_irq_rise, info);
arizona_free_irq(arizona, jack_irq_fall, info);
cancel_delayed_work_sync(&info->hpdet_work);
cancel_delayed_work_sync(&info->micd_detect_work);
cancel_delayed_work_sync(&info->micd_timeout_work);

ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
ARIZONA_MICD_ENA, 0,
&change);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
ret);
} else if (change) {
regulator_disable(info->micvdd);
pm_runtime_put(info->dev);
}

regmap_update_bits(arizona->regmap,
ARIZONA_MICD_CLAMP_CONTROL,
ARIZONA_MICD_CLAMP_MODE_MASK, 0);
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
ARIZONA_JD1_ENA, 0);
arizona_clk32k_disable(arizona);

gpiod_put(info->micd_pol_gpio);

pm_runtime_disable(&pdev->dev);

return 0;
}

Expand Down

0 comments on commit e5b499f

Please sign in to comment.