The hdac_hda remove implementation fails to free the hda codec resources, leading to memleaks at module unload. This gap has been there from the start, commit 6bae5ea94989 ("ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers").
Instead of duplicating the cleanup logic, use the common snd_hda_codec_cleanup_for_unbind() to free the resources. Remove existing code in hdac_hda to cleanup "codec.jackpoll_work" and call to snd_hdac_regmap_exit(), as these are already done in snd_hda_codec_cleanup_for_unbind().
The cleanup is done in ASoC component remove() callback and not in the HDAC bus hdev_detach(). This is done to ensure the codec specific cleanup routines are run before the parent card is freed.
Fixes: 6bae5ea94989 ("ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers") BugLink: https://github.com/thesofproject/linux/issues/2195 Signed-off-by: Kai Vehmanen kai.vehmanen@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- sound/soc/codecs/hdac_hda.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 72bd779bf942..74574b9180a5 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -513,6 +513,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) struct hdac_hda_priv *hda_pvt = snd_soc_component_get_drvdata(component); struct hdac_device *hdev = &hda_pvt->codec.core; + struct hda_codec *codec = &hda_pvt->codec; struct hdac_ext_link *hlink = NULL;
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); @@ -524,7 +525,10 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) pm_runtime_disable(&hdev->dev); snd_hdac_ext_bus_link_put(hdev->bus, hlink);
- snd_hdac_regmap_exit(hdev); + if (codec->patch_ops.free) + codec->patch_ops.free(codec); + + snd_hda_codec_cleanup_for_unbind(codec); }
static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { @@ -608,12 +612,10 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
static int hdac_hda_dev_remove(struct hdac_device *hdev) { - struct hdac_hda_priv *hda_pvt; - - hda_pvt = dev_get_drvdata(&hdev->dev); - if (hda_pvt && hda_pvt->codec.registered) - cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work); - + /* + * Resources are freed in hdac_hda_codec_remove(). This + * function is kept to keep hda_codec_driver_remove() happy. + */ return 0; }