From 1eeb47edaed21260ff23e868d0dd6fb9639494e0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:29:49 -0700 Subject: [PATCH 1/4] ASoC: intel: skylake: add remove() callback for component driver Topology is not unloaded in the core during unregister_component() anymore. So, add the remove() callback that will unload the topology. Signed-off-by: Ranjani Sridharan --- sound/soc/intel/skylake/skl-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 56099db8f86ddf..57031b6d4d45e0 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1462,9 +1462,16 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) return 0; } +static void skl_pcm_remove(struct snd_soc_component *component) +{ + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); +} + static const struct snd_soc_component_driver skl_component = { .name = "pcm", .probe = skl_platform_soc_probe, + .remove = skl_pcm_remove, .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, From 2b72dbfa08c04ef525bc7702f448ddcf49730190 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:31:23 -0700 Subject: [PATCH 2/4] ASoC: core: remove link components before cleaning up card resources When the card is registered by the machine driver, dai link components are probed after the snd_card is created. This is done in snd_soc_bind_card() which calls snd_soc_instantiate_card() to first create the snd_card and then probes the link components by calling soc_probe_link_components(). The snd_card is used by the component driver to add the kcontrols associated with dapm widgets to the card. When the machine driver is unregistered, the snd_card is freed when the card resources are cleaned up. But the snd_card needs to be valid while unloading the topology dapm widgets in order to remove the kcontrols from the card. Since, unloading topology is done when the component driver is removed, the link components should be removed in snd_soc_unbind_card(). This will ensure that the kcontrols are removed before the card resources are cleaned up and the snd_card itself is freed. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6f4842977b8d0d..75f6a8085a766f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2831,10 +2831,21 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { + struct snd_soc_pcm_runtime *rtd; + int order; + if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); + + /* remove all components used by DAI links on this card */ + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + soc_remove_link_components(card, rtd, order); + } + } + soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From 421abb60edd67de97fb0a8cfbb2168c3684f751e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:33:42 -0700 Subject: [PATCH 3/4] ASoC: SOF: remove topology in component driver remove() Topology should be removed when the link components are removed when the machine driver is unregistered. This will prevent the NULL pointer derefernce encountered when removing widget kcontrol's from the sound card. So, remove the topology in the remove() callback for the SOF component driver. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 0cf790225cec29..4f48a8bcc1e175 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -703,6 +703,8 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) From dc3c64b206414532e09981468d05029699b144e9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:35:08 -0700 Subject: [PATCH 4/4] ASoC: SOF: core: make component driver resource-managed Previously, we couldn't make the component driver resource-managed because topology unloading was done by the core when the component driver was unregistered. But this has been fixed to allow topology removal during the component driver remove() callback and there aren't any NULL pointer dereferences anymore. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 4d3d527de7df53..b3b5ce6b04a461 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,9 +355,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) sdev->first_boot = false; /* now register audio DSP platform driver and dai */ - ret = snd_soc_register_component(sdev->dev, &sdev->plat_drv, - sof_ops(sdev)->drv, - sof_ops(sdev)->num_drv); + ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, + sof_ops(sdev)->drv, + sof_ops(sdev)->num_drv); if (ret < 0) { dev_err(sdev->dev, "error: failed to register DSP DAI driver %d\n", ret); @@ -466,16 +466,16 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); - snd_soc_unregister_component(dev); snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); snd_sof_remove(sdev); + /* - * platform_device_unregister() frees the card and its resources. - * So it should be called after unregistering the comp driver - * so that the card is valid while unregistering comp driver. + * Unregister machine driver. This will unbind the snd_card which + * will remove the component driver and unload the topology + * before freeing the snd_card. */ if (!IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach);