* [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal
@ 2026-11-02 16:53 Tristan Madani
2026-11-02 16:53 ` [PATCH v6 1/4] ASoC: rt5668: cancel delayed works on component removal Tristan Madani
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Tristan Madani @ 2026-11-02 16:53 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Charles Keepax, Oder Chiou, Bard Liao, Jaroslav Kysela,
Takashi Iwai, Jorge Eduardo Candelaria, Margarita Olaya Cabrera,
Misael Lopez Cruz, patches, linux-sound, linux-kernel, stable,
tristan
From: Tristan Madani <tristan@talencesecurity.com>
Several ASoC codec drivers schedule delayed works for jack detection
and microphone polling but do not cancel them on component removal,
leaving handlers that can run against freed memory.
This series adds proper teardown ordering in four codec drivers:
rt5668, rt5659, twl6040, and wm8994.
Changes since v5:
- Patch 4/4 (wm8994): add comments clarifying why mic_work is
cancelled twice (before and after jackdet_bootstrap), per
Charles Keepax review. No functional change.
- Patches 1-3/4: no changes.
Changes since v4:
- Patch 1/4 (rt5668): correct Fixes tag from nonexistent
e13da14e8543 to d59fb2856223. No code changes.
- Patches 2-4/4: no changes.
Changes since v3:
- rt5668 (1/4): track IRQ acquisition with irq_acquired flag.
- Patches 2-4/4: no code changes.
Changes since v2:
- rt5668 (1/4): also cancel jd_check_work, disable IRQ first.
- twl6040 (3/4): swap ordering -- free_irq() first.
- rt5659/wm8994: no code changes.
Changes since v1:
- Unified series per Mark Brown request.
- rt5659: guard cancel with jack_detect_work_inited flag.
- wm8994: cancel mic_work before and after jackdet_bootstrap.
Tristan Madani (4):
ASoC: rt5668: cancel delayed works on component removal
ASoC: rt5659: cancel jack_detect_work on component removal
ASoC: twl6040: cancel headset jack work on component removal
ASoC: wm8994: drain delayed works on remove and probe error
sound/soc/codecs/rt5659.c | 20 +++++++++++++++++++-
sound/soc/codecs/rt5659.h | 3 +++
sound/soc/codecs/rt5668.c | 20 +++++++++++++++++++-
sound/soc/codecs/twl6040.c | 1 +
sound/soc/codecs/wm8994.c | 16 ++++++++++++++++
5 files changed, 58 insertions(+), 2 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 1/4] ASoC: rt5668: cancel delayed works on component removal
2026-11-02 16:53 [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
@ 2026-11-02 16:53 ` Tristan Madani
2026-11-02 16:53 ` [PATCH v6 2/4] ASoC: rt5659: cancel jack_detect_work " Tristan Madani
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-11-02 16:53 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Charles Keepax, Oder Chiou, Bard Liao, Jaroslav Kysela,
Takashi Iwai, Jorge Eduardo Candelaria, Margarita Olaya Cabrera,
Misael Lopez Cruz, patches, linux-sound, linux-kernel, stable,
tristan
From: Tristan Madani <tristan@talencesecurity.com>
rt5668_remove() does not disable the IRQ or cancel the pending
jack_detect_work and jd_check_work delayed works. If the component is
unbound while work is pending, the handlers access freed memory.
Track IRQ acquisition in rt5668_i2c_probe() via an irq_acquired flag.
In rt5668_remove(), disable the IRQ (if acquired) and cancel both
delayed works before resetting the codec. Re-enable the IRQ in
rt5668_probe() when a sound card rebinds to prevent permanent IRQ
silencing across card unbind/rebind cycles.
Fixes: d59fb2856223 ("ASoC: rt5668: add rt5668B codec driver")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
sound/soc/codecs/rt5668.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index cd6245d6b91af..29d70802a046a 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -62,6 +62,9 @@ struct rt5668_priv {
int pll_out;
int jack_type;
+
+ bool irq_acquired;
+ bool irq_disabled;
};
static const struct reg_default rt5668_reg[] = {
@@ -2216,12 +2219,26 @@ static int rt5668_probe(struct snd_soc_component *component)
rt5668->component = component;
+ if (rt5668->irq_disabled) {
+ enable_irq(to_i2c_client(component->dev)->irq);
+ rt5668->irq_disabled = false;
+ }
+
return 0;
}
static void rt5668_remove(struct snd_soc_component *component)
{
struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component);
+ struct i2c_client *i2c = to_i2c_client(component->dev);
+
+ if (rt5668->irq_acquired) {
+ disable_irq(i2c->irq);
+ rt5668->irq_disabled = true;
+ }
+
+ cancel_delayed_work_sync(&rt5668->jack_detect_work);
+ cancel_delayed_work_sync(&rt5668->jd_check_work);
rt5668_reset(rt5668->regmap);
}
@@ -2555,7 +2572,8 @@ static int rt5668_i2c_probe(struct i2c_client *i2c)
| IRQF_ONESHOT, "rt5668", rt5668);
if (ret)
dev_err(&i2c->dev, "Failed to request IRQ: %d\n", ret);
-
+ else
+ rt5668->irq_acquired = true;
}
return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668,
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 2/4] ASoC: rt5659: cancel jack_detect_work on component removal
2026-11-02 16:53 [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
2026-11-02 16:53 ` [PATCH v6 1/4] ASoC: rt5668: cancel delayed works on component removal Tristan Madani
@ 2026-11-02 16:53 ` Tristan Madani
2026-11-02 16:53 ` [PATCH v6 3/4] ASoC: twl6040: cancel headset jack work " Tristan Madani
2026-11-02 16:53 ` [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
3 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-11-02 16:53 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Charles Keepax, Oder Chiou, Bard Liao, Jaroslav Kysela,
Takashi Iwai, Jorge Eduardo Candelaria, Margarita Olaya Cabrera,
Misael Lopez Cruz, patches, linux-sound, linux-kernel, stable,
tristan
From: Tristan Madani <tristan@talencesecurity.com>
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 <tristan@talencesecurity.com>
---
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 af8051fa69f89..68f7d5673e190 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);
}
@@ -4283,6 +4297,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);
@@ -4292,6 +4307,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:
@@ -4302,7 +4318,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 [flat|nested] 6+ messages in thread
* [PATCH v6 3/4] ASoC: twl6040: cancel headset jack work on component removal
2026-11-02 16:53 [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
2026-11-02 16:53 ` [PATCH v6 1/4] ASoC: rt5668: cancel delayed works on component removal Tristan Madani
2026-11-02 16:53 ` [PATCH v6 2/4] ASoC: rt5659: cancel jack_detect_work " Tristan Madani
@ 2026-11-02 16:53 ` Tristan Madani
2026-11-02 16:53 ` [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
3 siblings, 0 replies; 6+ messages in thread
From: Tristan Madani @ 2026-11-02 16:53 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Charles Keepax, Oder Chiou, Bard Liao, Jaroslav Kysela,
Takashi Iwai, Jorge Eduardo Candelaria, Margarita Olaya Cabrera,
Misael Lopez Cruz, patches, linux-sound, linux-kernel, stable,
tristan
From: Tristan Madani <tristan@talencesecurity.com>
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.
Free the IRQ first so that the threaded handler cannot schedule new
work, then cancel any residual queued work synchronously. This
ordering prevents the race where the handler fires between a cancel
and the free_irq, re-arming the work after it was drained.
Fixes: a2d2362edf9f ("ASoC: twl6040: Add jack support for headset and handset")
Cc: stable@vger.kernel.org
Signed-off-by: Tristan Madani <tristan@talencesecurity.com>
---
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..826bde1a9ba46 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1136,6 +1136,7 @@ static void twl6040_remove(struct snd_soc_component *component)
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
free_irq(priv->plug_irq, component);
+ cancel_delayed_work_sync(&priv->hs_jack.work);
}
static const struct snd_soc_component_driver soc_component_dev_twl6040 = {
--
2.47.3
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error
2026-11-02 16:53 [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
` (2 preceding siblings ...)
2026-11-02 16:53 ` [PATCH v6 3/4] ASoC: twl6040: cancel headset jack work " Tristan Madani
@ 2026-11-02 16:53 ` Tristan Madani
2026-11-02 16:59 ` Charles Keepax
3 siblings, 1 reply; 6+ messages in thread
From: Tristan Madani @ 2026-11-02 16:53 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood
Cc: Charles Keepax, Oder Chiou, Bard Liao, Jaroslav Kysela,
Takashi Iwai, Jorge Eduardo Candelaria, Margarita Olaya Cabrera,
Misael Lopez Cruz, patches, linux-sound, linux-kernel, stable,
tristan
From: Tristan Madani <tristan@talencesecurity.com>
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 <tristan@talencesecurity.com>
---
Changes in v6:
- Add comments clarifying why mic_work is cancelled twice, per
Charles Keepax review. No functional change.
sound/soc/codecs/wm8994.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 6b91e02f130b3..6a790479c8a7e 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4595,6 +4595,14 @@ 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);
+ /* Catch mic_work re-armed by jackdet_bootstrap running concurrently. */
+ 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;
}
@@ -4636,6 +4644,14 @@ 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);
+ /* Catch mic_work re-armed by jackdet_bootstrap running concurrently. */
+ 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 [flat|nested] 6+ messages in thread
* Re: [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error
2026-11-02 16:53 ` [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
@ 2026-11-02 16:59 ` Charles Keepax
0 siblings, 0 replies; 6+ messages in thread
From: Charles Keepax @ 2026-11-02 16:59 UTC (permalink / raw)
To: Tristan Madani
Cc: Mark Brown, Liam Girdwood, Oder Chiou, Bard Liao,
Jaroslav Kysela, Takashi Iwai, Jorge Eduardo Candelaria,
Margarita Olaya Cabrera, Misael Lopez Cruz, patches, linux-sound,
linux-kernel, stable, tristan
On Mon, Nov 02, 2026 at 04:53:40PM +0000, Tristan Madani wrote:
> From: Tristan Madani <tristan@talencesecurity.com>
>
> 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 <tristan@talencesecurity.com>
> ---
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Thanks,
Charles
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-02 17:01 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-02 16:53 [PATCH v6 0/4] ASoC: cancel pending delayed works on codec removal Tristan Madani
2026-11-02 16:53 ` [PATCH v6 1/4] ASoC: rt5668: cancel delayed works on component removal Tristan Madani
2026-11-02 16:53 ` [PATCH v6 2/4] ASoC: rt5659: cancel jack_detect_work " Tristan Madani
2026-11-02 16:53 ` [PATCH v6 3/4] ASoC: twl6040: cancel headset jack work " Tristan Madani
2026-11-02 16:53 ` [PATCH v6 4/4] ASoC: wm8994: drain delayed works on remove and probe error Tristan Madani
2026-11-02 16:59 ` Charles Keepax
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®