[PATCH] ASoC: SOF: fix runtime pm usage mismatch after probe errors

Kai Vehmanen kai.vehmanen at linux.intel.com
Wed Feb 10 11:52:37 CET 2021


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: Kai Vehmanen <kai.vehmanen at linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at intel.com>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski at intel.com>
---
 sound/soc/sof/core.c        | 10 ++++++++++
 sound/soc/sof/sof-pci-dev.c |  3 ++-
 sound/soc/sof/sof-priv.h    |  2 ++
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index 8d13eb13fe08..6d8f7d9fd192 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -246,6 +246,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
 	if (plat_data->sof_probe_complete)
 		plat_data->sof_probe_complete(sdev->dev);
 
+	sdev->probe_completed = true;
+
 	return 0;
 
 fw_trace_err:
@@ -340,6 +342,14 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
 }
 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)
 {
 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 388772f9c4d2..84990cc8aa7d 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -447,7 +447,8 @@ static void sof_pci_remove(struct pci_dev *pci)
 	snd_sof_device_remove(&pci->dev);
 
 	/* 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);
 
 	/* release pci regions and disable device */
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 682c4b6d01ef..ad0d7ba2708c 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -389,6 +389,7 @@ struct snd_sof_dev {
 
 	/* work queue in case the probe is implemented in two steps */
 	struct work_struct probe_work;
+	bool probe_completed;
 
 	/* DSP HW differentiation */
 	struct snd_sof_pdata *pdata;
@@ -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_remove(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_resume(struct device *dev);

base-commit: d40dac7ae8c0f213ac1da7896c35ddc2c58419ab
-- 
2.29.2



More information about the Alsa-devel mailing list