From 82d64fb0fd39b532263f060a8ec86e47e9ab305b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 21 Mar 2022 19:21:04 -0500 Subject: [PATCH 1/2] soundwire: bus_type: reset pointers on remove and shutdown Some information is not cleared on driver remove, which can lead to kernel oopses when removing codec drivers, e.g. with the following sequence. /sbin/modprobe -r snd_soc_sof_sdw /sbin/modprobe -r snd_soc_rt711 This was not detected earlier in Intel tests since the tests first remove the parent PCI device and shuts down the bus. This patch fixes the kernel oopses - however the users will still see a set of 'probed timed out' errors since a driver can no longer be found for a physical device. The issue with the ops pointer has been there forever, but the Fixes tag below should be more than enough for actual SoundWire uses. BugLink: https://github.com/thesofproject/linux/issues/3531 Fixes: 2140b66b5d3ec ("soundwire: bus: fix race condition with probe_complete signaling") Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus_type.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 893296f3fe395e..0b48fdf1b8e5b3 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -109,6 +109,8 @@ static int sdw_drv_probe(struct device *dev) ret = drv->probe(slave, id); if (ret) { + slave->ops = NULL; + name = drv->name; if (!name) name = drv->driver.name; @@ -152,6 +154,9 @@ static int sdw_drv_remove(struct device *dev) struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); int ret = 0; + slave->ops = NULL; + slave->probed = false; + if (drv->remove) ret = drv->remove(slave); @@ -165,6 +170,9 @@ static void sdw_drv_shutdown(struct device *dev) struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + slave->ops = NULL; + slave->probed = false; + if (drv->shutdown) drv->shutdown(slave); } From cbd8778ba8c34ea644a367cc5ae8ce3546257959 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Mar 2022 08:19:12 -0500 Subject: [PATCH 2/2] ASoC: SOF: topology: cleanup dailinks on widget unload We set the cpu_dai capture_ or playback_widget on widget_ready but never clear them, which leads to failures when unloading/reloading a topology in modprobe/rmmnod tests BugLink: https://github.com/thesofproject/linux/issues/3535 Fixes: 311ce4fe7637 ("ASoC: SOF: Add support for loading topologies") Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 30b46d20ceeb7f..d5e3564ec9f856 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1065,6 +1065,46 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, return 0; } +static void sof_disconnect_dai_widget(struct snd_soc_component *scomp, + struct snd_soc_dapm_widget *w) +{ + struct snd_soc_card *card = scomp->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *cpu_dai; + int i; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + if (!w->sname || !rtd->dai_link->stream_name) + continue; + + /* does stream match DAI link ? */ + if (strcmp(w->sname, rtd->dai_link->stream_name)) + continue; + + switch (w->id) { + case snd_soc_dapm_dai_out: + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + if (cpu_dai->capture_widget == w) { + cpu_dai->capture_widget = NULL; + break; + } + } + break; + case snd_soc_dapm_dai_in: + for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + if (cpu_dai->playback_widget == w) { + cpu_dai->playback_widget = NULL; + break; + } + } + break; + default: + break; + } + } +} + /* bind PCM ID to host component ID */ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int dir) @@ -1383,6 +1423,9 @@ static int sof_widget_unload(struct snd_soc_component *scomp, if (dai) list_del(&dai->list); + + sof_disconnect_dai_widget(scomp, widget); + break; default: break;