Commit 410e5e55 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Mark Brown

ASoC: SOF: core: release resources on errors in probe_continue

The initial intent of releasing resources in the .remove does not work
well with HDaudio codecs. If the probe_continue() fails in a work
queue, e.g. due to missing firmware or authentication issues, we don't
release any resources, and as a result the kernel oopses during
suspend operations.

The suggested fix is to release all resources during errors in
probe_continue(), and use fw_state to track resource allocation
state, so that .remove does not attempt to release the same
hardware resources twice. PM operations are also modified so that
no action is done if DSP resources have been freed due to
an error at probe.
Reported-by: default avatarTakashi Iwai <tiwai@suse.de>
Co-developed-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Bugzilla:  http://bugzilla.suse.com/show_bug.cgi?id=1161246Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20200124213625.30186-4-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
Cc: stable@vger.kernel.org
parent 37e97e6f
...@@ -244,7 +244,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -244,7 +244,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
return 0; return 0;
#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)
fw_trace_err: fw_trace_err:
snd_sof_free_trace(sdev); snd_sof_free_trace(sdev);
fw_run_err: fw_run_err:
...@@ -255,22 +254,10 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ...@@ -255,22 +254,10 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
snd_sof_free_debug(sdev); snd_sof_free_debug(sdev);
dbg_err: dbg_err:
snd_sof_remove(sdev); snd_sof_remove(sdev);
#else
/* /* all resources freed, update state to match */
* when the probe_continue is handled in a work queue, the sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
* probe does not fail so we don't release resources here. sdev->first_boot = true;
* They will be released with an explicit call to
* snd_sof_device_remove() when the PCI/ACPI device is removed
*/
fw_trace_err:
fw_run_err:
fw_load_err:
ipc_err:
dbg_err:
#endif
return ret; return ret;
} }
...@@ -353,10 +340,12 @@ int snd_sof_device_remove(struct device *dev) ...@@ -353,10 +340,12 @@ int snd_sof_device_remove(struct device *dev)
if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE))
cancel_work_sync(&sdev->probe_work); cancel_work_sync(&sdev->probe_work);
if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED) {
snd_sof_fw_unload(sdev); snd_sof_fw_unload(sdev);
snd_sof_ipc_free(sdev); snd_sof_ipc_free(sdev);
snd_sof_free_debug(sdev); snd_sof_free_debug(sdev);
snd_sof_free_trace(sdev); snd_sof_free_trace(sdev);
}
/* /*
* Unregister machine driver. This will unbind the snd_card which * Unregister machine driver. This will unbind the snd_card which
...@@ -364,12 +353,14 @@ int snd_sof_device_remove(struct device *dev) ...@@ -364,12 +353,14 @@ int snd_sof_device_remove(struct device *dev)
* before freeing the snd_card. * before freeing the snd_card.
*/ */
snd_sof_machine_unregister(sdev, pdata); snd_sof_machine_unregister(sdev, pdata);
/* /*
* Unregistering the machine driver results in unloading the topology. * Unregistering the machine driver results in unloading the topology.
* Some widgets, ex: scheduler, attempt to power down the core they are * Some widgets, ex: scheduler, attempt to power down the core they are
* scheduled on, when they are unloaded. Therefore, the DSP must be * scheduled on, when they are unloaded. Therefore, the DSP must be
* removed only after the topology has been unloaded. * removed only after the topology has been unloaded.
*/ */
if (sdev->fw_state > SOF_FW_BOOT_NOT_STARTED)
snd_sof_remove(sdev); snd_sof_remove(sdev);
/* release firmware */ /* release firmware */
......
...@@ -56,6 +56,10 @@ static int sof_resume(struct device *dev, bool runtime_resume) ...@@ -56,6 +56,10 @@ static int sof_resume(struct device *dev, bool runtime_resume)
if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume) if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume)
return 0; return 0;
/* DSP was never successfully started, nothing to resume */
if (sdev->first_boot)
return 0;
/* /*
* if the runtime_resume flag is set, call the runtime_resume routine * if the runtime_resume flag is set, call the runtime_resume routine
* or else call the system resume routine * or else call the system resume routine
......
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