Commit 271d9373 authored by Kai Vehmanen's avatar Kai Vehmanen Committed by Mark Brown

ASoC: SOF: fix runtime pm usage mismatch after probe errors

With current delayed probe implementation, sof_probe_complete is not
called in case of errors. And as this function is responsible for
decrementing runtime pm usage counter, this will result in following
problem:

 - probe driver in conditions where probe will fail (to force
   the condition on Intel SOF systems, set
   "snd_sof_intel_hda_common.codec_mask=0")
 - unload driver (runtime-pm usage_count is leaked)
 - fix the issue by installing missing fw, modifying module parameters,
   etc actions
 - try to load driver again -> success, probe ok
 -> device never enters runtime suspend

Fix the issue by storing result of delayed probe to a state variable and
providing new snd_sof_device_probe_completed() to be queried from SOF
PCI/ACPI/OF drivers.

If probe never completed successfully, runtime PM was not set up and
thus at remove(), we should not increment usage count anymore.
Signed-off-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@intel.com>
Reviewed-by: default avatarGuennadi Liakhovetski <guennadi.liakhovetski@intel.com>
Link: https://lore.kernel.org/r/20210210105237.2179273-1-kai.vehmanen@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent b6eabd24
...@@ -246,6 +246,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -246,6 +246,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
if (plat_data->sof_probe_complete) if (plat_data->sof_probe_complete)
plat_data->sof_probe_complete(sdev->dev); plat_data->sof_probe_complete(sdev->dev);
sdev->probe_completed = true;
return 0; return 0;
fw_trace_err: fw_trace_err:
...@@ -340,6 +342,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) ...@@ -340,6 +342,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
} }
EXPORT_SYMBOL(snd_sof_device_probe); EXPORT_SYMBOL(snd_sof_device_probe);
bool snd_sof_device_probe_completed(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
return sdev->probe_completed;
}
EXPORT_SYMBOL(snd_sof_device_probe_completed);
int snd_sof_device_remove(struct device *dev) int snd_sof_device_remove(struct device *dev)
{ {
struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct snd_sof_dev *sdev = dev_get_drvdata(dev);
......
...@@ -447,7 +447,8 @@ static void sof_pci_remove(struct pci_dev *pci) ...@@ -447,7 +447,8 @@ static void sof_pci_remove(struct pci_dev *pci)
snd_sof_device_remove(&pci->dev); snd_sof_device_remove(&pci->dev);
/* follow recommendation in pci-driver.c to increment usage counter */ /* follow recommendation in pci-driver.c to increment usage counter */
if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) if (snd_sof_device_probe_completed(&pci->dev) &&
!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME))
pm_runtime_get_noresume(&pci->dev); pm_runtime_get_noresume(&pci->dev);
/* release pci regions and disable device */ /* release pci regions and disable device */
......
...@@ -389,6 +389,7 @@ struct snd_sof_dev { ...@@ -389,6 +389,7 @@ struct snd_sof_dev {
/* work queue in case the probe is implemented in two steps */ /* work queue in case the probe is implemented in two steps */
struct work_struct probe_work; struct work_struct probe_work;
bool probe_completed;
/* DSP HW differentiation */ /* DSP HW differentiation */
struct snd_sof_pdata *pdata; struct snd_sof_pdata *pdata;
...@@ -464,6 +465,7 @@ struct snd_sof_dev { ...@@ -464,6 +465,7 @@ struct snd_sof_dev {
int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data); int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data);
int snd_sof_device_remove(struct device *dev); int snd_sof_device_remove(struct device *dev);
int snd_sof_device_shutdown(struct device *dev); int snd_sof_device_shutdown(struct device *dev);
bool snd_sof_device_probe_completed(struct device *dev);
int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_suspend(struct device *dev);
int snd_sof_runtime_resume(struct device *dev); int snd_sof_runtime_resume(struct device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment