Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: codecs: rt5640: Always disable IRQs from rt5640_cancel_work()

Disable IRQs from rt5640_cancel_work(), this fixes a crash caused by
the IRQ never getting freed when the driver is unbound from the i2c_client
with jack-detection active:

[ 193.138780] rt5640 i2c-rt5640: ASoC: unknown pin LDO2
[ 193.138830] rt5640 i2c-rt5640: ASoC: unknown pin MICBIAS1
[ 193.671218] BUG: kernel NULL pointer dereference, address: 0000000000000078
[ 193.671239] #PF: supervisor read access in kernel mode
[ 193.671248] #PF: error_code(0x0000) - not-present page
...
[ 193.671531] ? asm_exc_page_fault+0x22/0x30
[ 193.671551] ? rt5640_jack_inserted+0x10/0x80 [snd_soc_rt5640]
[ 193.671574] rt5640_detect_headset+0x93/0x130 [snd_soc_rt5640]
[ 193.671596] rt5640_jack_work+0x93/0x355 [snd_soc_rt5640]

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://patch.msgid.link/20241024215612.92147-1-hdegoede@redhat.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Hans de Goede and committed by
Mark Brown
032532f9 db7e59e6

+15 -12
+15 -12
sound/soc/codecs/rt5640.c
··· 2419 2419 return IRQ_HANDLED; 2420 2420 } 2421 2421 2422 - static void rt5640_cancel_work(void *data) 2422 + static void rt5640_disable_irq_and_cancel_work(void *data) 2423 2423 { 2424 2424 struct rt5640_priv *rt5640 = data; 2425 + 2426 + if (rt5640->jd_gpio_irq_requested) { 2427 + free_irq(rt5640->jd_gpio_irq, rt5640); 2428 + rt5640->jd_gpio_irq_requested = false; 2429 + } 2430 + 2431 + if (rt5640->irq_requested) { 2432 + free_irq(rt5640->irq, rt5640); 2433 + rt5640->irq_requested = false; 2434 + } 2425 2435 2426 2436 cancel_delayed_work_sync(&rt5640->jack_work); 2427 2437 cancel_delayed_work_sync(&rt5640->bp_work); ··· 2473 2463 if (!rt5640->jack) 2474 2464 return; 2475 2465 2476 - if (rt5640->jd_gpio_irq_requested) 2477 - free_irq(rt5640->jd_gpio_irq, rt5640); 2478 - 2479 - if (rt5640->irq_requested) 2480 - free_irq(rt5640->irq, rt5640); 2481 - 2482 - rt5640_cancel_work(rt5640); 2466 + rt5640_disable_irq_and_cancel_work(rt5640); 2483 2467 2484 2468 if (rt5640->jack->status & SND_JACK_MICROPHONE) { 2485 2469 rt5640_disable_micbias1_ovcd_irq(component); ··· 2481 2477 snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0); 2482 2478 } 2483 2479 2484 - rt5640->jd_gpio_irq_requested = false; 2485 - rt5640->irq_requested = false; 2486 2480 rt5640->jd_gpio = NULL; 2487 2481 rt5640->jack = NULL; 2488 2482 } ··· 2800 2798 if (rt5640->jack) { 2801 2799 /* disable jack interrupts during system suspend */ 2802 2800 disable_irq(rt5640->irq); 2803 - rt5640_cancel_work(rt5640); 2801 + cancel_delayed_work_sync(&rt5640->jack_work); 2802 + cancel_delayed_work_sync(&rt5640->bp_work); 2804 2803 } 2805 2804 2806 2805 snd_soc_component_force_bias_level(component, SND_SOC_BIAS_OFF); ··· 3035 3032 INIT_DELAYED_WORK(&rt5640->jack_work, rt5640_jack_work); 3036 3033 3037 3034 /* Make sure work is stopped on probe-error / remove */ 3038 - ret = devm_add_action_or_reset(&i2c->dev, rt5640_cancel_work, rt5640); 3035 + ret = devm_add_action_or_reset(&i2c->dev, rt5640_disable_irq_and_cancel_work, rt5640); 3039 3036 if (ret) 3040 3037 return ret; 3041 3038