ASoC: hdac_hda: fix memleak on module unload
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, commit6bae5ea949
("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:6bae5ea949
("ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers") 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> BugLink: https://github.com/thesofproject/linux/issues/2195 Link: https://lore.kernel.org/r/20200717101950.3885187-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
640f835cd0
commit
c3ec8ac821
|
@ -513,6 +513,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
|
||||||
struct hdac_hda_priv *hda_pvt =
|
struct hdac_hda_priv *hda_pvt =
|
||||||
snd_soc_component_get_drvdata(component);
|
snd_soc_component_get_drvdata(component);
|
||||||
struct hdac_device *hdev = &hda_pvt->codec.core;
|
struct hdac_device *hdev = &hda_pvt->codec.core;
|
||||||
|
struct hda_codec *codec = &hda_pvt->codec;
|
||||||
struct hdac_ext_link *hlink = NULL;
|
struct hdac_ext_link *hlink = NULL;
|
||||||
|
|
||||||
hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
|
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);
|
pm_runtime_disable(&hdev->dev);
|
||||||
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
|
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[] = {
|
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)
|
static int hdac_hda_dev_remove(struct hdac_device *hdev)
|
||||||
{
|
{
|
||||||
struct hdac_hda_priv *hda_pvt;
|
/*
|
||||||
|
* Resources are freed in hdac_hda_codec_remove(). This
|
||||||
hda_pvt = dev_get_drvdata(&hdev->dev);
|
* function is kept to keep hda_codec_driver_remove() happy.
|
||||||
if (hda_pvt && hda_pvt->codec.registered)
|
*/
|
||||||
cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue