* [PATCH v2 1/4] ASoC: rt5668: cancel jack_detect_work on component removal
2026-10-29 21:25 [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
@ 2026-10-29 21:25 ` Tristan Madani
2026-10-29 21:25 ` [PATCH v2 2/4] ASoC: rt5659: " Tristan Madani
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-10-29 21:25 UTC (permalink / raw)
To: Mark Brown
Cc: Oder Chiou, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Bard Liao, Misael Lopez Cruz, patches, linux-sound, stable
The rt5668 codec driver initializes two delayed works but only
jd_check_work is cancelled during removal. The jack_detect_work is
never cancelled, which can lead to the work handler accessing freed
memory if the device is unbound while the work is pending.
Add cancel_delayed_work_sync() for jack_detect_work in
rt5668_remove().
Fixes: d59fb28562232 ("ASoC: rt5668: add rt5668B codec driver")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristmd@gmail.com>
---
Changes in v2:
- Resend as part of unified series (no code changes from v1)
sound/soc/codecs/rt5668.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index 4154bad276101..0e6594c327311 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -2223,6 +2223,8 @@ static void rt5668_remove(struct snd_soc_component *component)
{
struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+ cancel_delayed_work_sync(&rt5668->jack_detect_work);
+
rt5668_reset(rt5668->regmap);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 2/4] ASoC: rt5659: cancel jack_detect_work on component removal
2026-10-29 21:25 [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
2026-10-29 21:25 ` [PATCH v2 1/4] ASoC: rt5668: cancel jack_detect_work on component removal Tristan Madani
@ 2026-10-29 21:25 ` Tristan Madani
2026-10-29 21:25 ` [PATCH v2 3/4] ASoC: twl6040: cancel headset jack work " Tristan Madani
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-10-29 21:25 UTC (permalink / raw)
To: Mark Brown
Cc: Oder Chiou, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Bard Liao, Misael Lopez Cruz, patches, linux-sound, stable
rt5659_remove() resets the codec via regmap_write() but does not cancel
the pending jack_detect_work. Since the IRQ is registered with
devm_request_threaded_irq(), it remains active until after the component
remove callback returns. The IRQ handler (rt5659_irq) schedules
jack_detect_work, so a late interrupt can queue work that runs against a
reset codec.
Track successful IRQ acquisition with a flag so that disable_irq()
only quiesces a line this driver actually owns. Guard the
cancel_delayed_work_sync() call with a flag that tracks whether the
work was initialized, since INIT_DELAYED_WORK is only called for
specific jd_src configurations (JD3, JD_HDA_HEADER) and cancelling
an uninitialized work is undefined behavior.
On component remove, disable the IRQ to synchronize with any running
handler and prevent new enqueues, then drain the residual
jack_detect_work synchronously before resetting the hardware. On the
next component probe (card rebind), re-enable the IRQ to restore jack
detection.
Fixes: d3cb2de2479b ("ASoC: rt5659: add rt5659 codec driver")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristmd@gmail.com>
---
Changes in v2:
- Resend as part of unified series (no code changes from prior version)
- Guard cancel with jack_detect_work_inited flag since INIT_DELAYED_WORK
is conditional on jd_src (JD3 or HDA_HEADER only), per Mark Brown
- Track IRQ acquisition to guard disable_irq/enable_irq
sound/soc/codecs/rt5659.c | 20 +++++++++++++++++++-
sound/soc/codecs/rt5659.h | 3 +++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index 3097ee6d4e89f..cdf499fb36d67 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3667,6 +3667,11 @@ static int rt5659_probe(struct snd_soc_component *component)
rt5659->component = component;
+ if (rt5659->irq_disabled) {
+ enable_irq(to_i2c_client(component->dev)->irq);
+ rt5659->irq_disabled = false;
+ }
+
switch (rt5659->pdata.jd_src) {
case RT5659_JD_HDA_HEADER:
break;
@@ -3684,6 +3689,15 @@ static int rt5659_probe(struct snd_soc_component *component)
static void rt5659_remove(struct snd_soc_component *component)
{
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
+ struct i2c_client *i2c = to_i2c_client(component->dev);
+
+ if (rt5659->irq_acquired) {
+ disable_irq(i2c->irq);
+ rt5659->irq_disabled = true;
+ }
+
+ if (rt5659->jack_detect_work_inited)
+ cancel_delayed_work_sync(&rt5659->jack_detect_work);
regmap_write(rt5659->regmap, RT5659_RESET, 0);
}
@@ -4271,6 +4285,7 @@ static int rt5659_i2c_probe(struct i2c_client *i2c)
regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040);
INIT_DELAYED_WORK(&rt5659->jack_detect_work,
rt5659_jack_detect_work);
+ rt5659->jack_detect_work_inited = true;
break;
case RT5659_JD_HDA_HEADER:
regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_3, 0x8000);
@@ -4280,6 +4295,7 @@ static int rt5659_i2c_probe(struct i2c_client *i2c)
regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_1, 0x0040);
INIT_DELAYED_WORK(&rt5659->jack_detect_work,
rt5659_jack_detect_intel_hd_header);
+ rt5659->jack_detect_work_inited = true;
rt5659_intel_hd_header_probe_setup(rt5659);
break;
default:
@@ -4290,7 +4306,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c)
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5659", rt5659);
- if (ret)
+ if (!ret)
+ rt5659->irq_acquired = true;
+ else
dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
/* Enable IRQ output for GPIO1 pin any way */
diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h
index b49fd8baf4e7e..e10b3844501b9 100644
--- a/sound/soc/codecs/rt5659.h
+++ b/sound/soc/codecs/rt5659.h
@@ -1813,6 +1813,9 @@ struct rt5659_priv {
int jack_type;
bool hda_hp_plugged;
bool hda_mic_plugged;
+ bool irq_acquired;
+ bool irq_disabled;
+ bool jack_detect_work_inited;
};
int rt5659_set_jack_detect(struct snd_soc_component *component,
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 3/4] ASoC: twl6040: cancel headset jack work on component removal
2026-10-29 21:25 [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
2026-10-29 21:25 ` [PATCH v2 1/4] ASoC: rt5668: cancel jack_detect_work on component removal Tristan Madani
2026-10-29 21:25 ` [PATCH v2 2/4] ASoC: rt5659: " Tristan Madani
@ 2026-10-29 21:25 ` Tristan Madani
2026-10-29 21:25 ` [PATCH v2 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
2026-10-29 22:34 ` [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-10-29 21:25 UTC (permalink / raw)
To: Mark Brown
Cc: Oder Chiou, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Bard Liao, Misael Lopez Cruz, patches, linux-sound, stable
The twl6040 codec driver initializes a delayed work for headset jack
detection (hs_jack.work) but the component remove callback only frees
the plug IRQ without cancelling the pending work. If the IRQ fires and
schedules the work shortly before removal, it can execute on freed
memory.
Add cancel_delayed_work_sync() in twl6040_remove() before freeing the
IRQ to ensure no stale work remains queued.
Fixes: a2d2362edf9f ("ASoC: twl6040: Add jack support for headset and handset")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristmd@gmail.com>
---
Changes in v2:
- Resend as part of unified series (no code changes from v1)
sound/soc/codecs/twl6040.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 650836f9615fb..43feb660b635b 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1135,6 +1135,7 @@ static void twl6040_remove(struct snd_soc_component *component)
{
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
+ cancel_delayed_work_sync(&priv->hs_jack.work);
free_irq(priv->plug_irq, component);
}
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 4/4] ASoC: wm8994: drain delayed works on remove and probe error
2026-10-29 21:25 [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
` (2 preceding siblings ...)
2026-10-29 21:25 ` [PATCH v2 3/4] ASoC: twl6040: cancel headset jack work " Tristan Madani
@ 2026-10-29 21:25 ` Tristan Madani
2026-10-29 22:34 ` [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-10-29 21:25 UTC (permalink / raw)
To: Mark Brown
Cc: Oder Chiou, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Bard Liao, Misael Lopez Cruz, patches, linux-sound, stable
wm8994_component_probe() schedules several delayed works to handle jack
detection and microphone status polling. If the component is removed or
probe fails after these works are scheduled, they can execute after
resources are freed.
Cancel all pending delayed works in the error and removal paths. Guard
cancel_delayed_work_sync(&wm8994->mic_work) with a type check because
INIT_DELAYED_WORK for mic_work only runs in the WM8994 and WM1811 code
paths.
Cancel mic_work before and after jackdet_bootstrap because the two can
re-arm each other: wm1811_mic_work() can re-arm jackdet_bootstrap
through the DAPM power-up chain (force-enabling MICBIAS2 triggers
clk_sys_event which queues jackdet_bootstrap), and
wm1811_jackdet_bootstrap() detects a jack and ultimately queues
mic_work. The second mic_work cancel catches any re-arm from a
jackdet_bootstrap handler that was in flight during the first cancel.
Fixes: 99af79dff5a6 ("ASoC: wm8994: Ensure we get a notification on startup for jackdet")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristmd@gmail.com>
---
Changes in v2:
- Resend as part of unified series
- Cancel mic_work both before and after jackdet_bootstrap to handle
cyclic re-arming through DAPM power-up chain
sound/soc/codecs/wm8994.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 8bf58a6a8af7c..b9e0df83b9bfe 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4551,6 +4551,13 @@ static int wm8994_component_probe(struct snd_soc_component *component)
wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FIFOS_ERR, component);
wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT, component);
wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_TEMP_WARN, component);
+ if (control->type == WM8994 || control->type == WM1811)
+ cancel_delayed_work_sync(&wm8994->mic_work);
+ cancel_delayed_work_sync(&wm8994->jackdet_bootstrap);
+ if (control->type == WM8994 || control->type == WM1811)
+ cancel_delayed_work_sync(&wm8994->mic_work);
+ cancel_delayed_work_sync(&wm8994->mic_complete_work);
+ cancel_delayed_work_sync(&wm8994->open_circuit_work);
return ret;
}
@@ -4592,6 +4599,13 @@ static void wm8994_component_remove(struct snd_soc_component *component)
free_irq(wm8994->micdet_irq, wm8994);
break;
}
+ if (control->type == WM8994 || control->type == WM1811)
+ cancel_delayed_work_sync(&wm8994->mic_work);
+ cancel_delayed_work_sync(&wm8994->jackdet_bootstrap);
+ if (control->type == WM8994 || control->type == WM1811)
+ cancel_delayed_work_sync(&wm8994->mic_work);
+ cancel_delayed_work_sync(&wm8994->mic_complete_work);
+ cancel_delayed_work_sync(&wm8994->open_circuit_work);
release_firmware(wm8994->mbc);
release_firmware(wm8994->mbc_vss);
release_firmware(wm8994->enh_eq);
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal
2026-10-29 21:25 [PATCH v2 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
` (3 preceding siblings ...)
2026-10-29 21:25 ` [PATCH v2 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
@ 2026-10-29 22:34 ` Mark Brown
4 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2026-10-29 22:34 UTC (permalink / raw)
To: Tristan Madani
Cc: Oder Chiou, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Bard Liao, Misael Lopez Cruz, patches, linux-sound, stable
[-- Attachment #1: Type: text/plain, Size: 398 bytes --]
On Thu, Oct 29, 2026 at 09:25:00PM +0000, Tristan Madani wrote:
> Changes in v2:
> - Resend as unified series per Mark Brown request (previously sent as
> individual patches with inflated version numbers)
I asked you to send a v10 (just prior to you sending v10 of one of the
patches) because my tools have seen that randomly higher version...
I'll fix things up, please don't resend for this.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread