[PATCH v2 18/21] ASoC: codecs: rt5677-spi: Free the DSP context on component remove

From: Chancel Liu

Date: Wed Sep 23 2026 - 02:18:17 EST


From: Chancel Liu <chancel.liu@xxxxxxx>

component->dev is the underlying SPI bus device, whose devres lifetime
follows the physical devices probe/remove rather than the ASoC cards
bind/unbind. The rt5677_dsp context allocated in the component probe with
devm_kzalloc(component->dev, ...) therefore leaks on every card
bind/unbind cycle, and the delayed work initialised there is never
cancelled on unbind.

Allocate the context with kzalloc() and add a component .remove callback
that cancels the copy work, destroys the mutex and frees the context.

The exported rt5677_spi_hotword_detected(), called from the rt5677 codec
interrupt path, fetches the context via dev_get_drvdata(&g_spi->dev) and
dereferences it. Freeing the context on remove would let that callback
run concurrently and touch freed memory. Add a dsp_lock that serializes
the fetch/use in rt5677_spi_hotword_detected() against clearing the
drvdata in the remove callback, so once remove has cleared the pointer
the callback either observes NULL and bails out or has already finished.

Signed-off-by: Chancel Liu <chancel.liu@xxxxxxx>
---
sound/soc/codecs/rt5677-spi.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index ebc527115ea5..0b2166082437 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -58,6 +58,8 @@

static struct spi_device *g_spi;
static DEFINE_MUTEX(spi_mutex);
+/* Serializes access to the DSP context against the exported hotword callback */
+static DEFINE_MUTEX(dsp_lock);

struct rt5677_dsp {
struct device *dev;
@@ -380,8 +382,7 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component)
{
struct rt5677_dsp *rt5677_dsp;

- rt5677_dsp = devm_kzalloc(component->dev, sizeof(*rt5677_dsp),
- GFP_KERNEL);
+ rt5677_dsp = kzalloc_obj(*rt5677_dsp);
if (!rt5677_dsp)
return -ENOMEM;
rt5677_dsp->dev = &g_spi->dev;
@@ -392,9 +393,23 @@ static int rt5677_spi_pcm_probe(struct snd_soc_component *component)
return 0;
}

+static void rt5677_spi_pcm_remove(struct snd_soc_component *component)
+{
+ struct rt5677_dsp *rt5677_dsp =
+ snd_soc_component_get_drvdata(component);
+
+ scoped_guard(mutex, &dsp_lock)
+ snd_soc_component_set_drvdata(component, NULL);
+
+ cancel_delayed_work_sync(&rt5677_dsp->copy_work);
+ mutex_destroy(&rt5677_dsp->dma_lock);
+ kfree(rt5677_dsp);
+}
+
static const struct snd_soc_component_driver rt5677_spi_dai_component = {
.name = DRV_NAME,
.probe = rt5677_spi_pcm_probe,
+ .remove = rt5677_spi_pcm_remove,
.open = rt5677_spi_pcm_open,
.close = rt5677_spi_pcm_close,
.hw_params = rt5677_spi_hw_params,
@@ -579,6 +594,8 @@ void rt5677_spi_hotword_detected(void)
if (!g_spi)
return;

+ guard(mutex)(&dsp_lock);
+
rt5677_dsp = dev_get_drvdata(&g_spi->dev);
if (!rt5677_dsp) {
dev_err(&g_spi->dev, "Can't get rt5677_dsp\n");
--
2.50.1