ASoC: SOF: sof-audio: Modify logic for enabling/disabling topology cores
In the current code, we enable a widget core when it is set up and disable it when it is freed. This is problematic with IPC4 because widget free is essentially a NOP and all widgets are freed in the firmware when the pipeline is deleted. This results in a crash during pipeline deletion when one of it's widgets is scheduled to run on a secondary core and is powered off when widget is freed. So, change the logic to enable all cores needed by all the modules in a pipeline when the pipeline widget is set up and disable them after the pipeline widget is freed. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Link: https://lore.kernel.org/r/20231124135743.24674-3-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
0376b995bb
commit
31ed8da1c8
1 changed files with 41 additions and 24 deletions
|
@ -46,6 +46,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
|
||||||
struct snd_sof_widget *swidget)
|
struct snd_sof_widget *swidget)
|
||||||
{
|
{
|
||||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||||
|
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||||
struct snd_sof_widget *pipe_widget;
|
struct snd_sof_widget *pipe_widget;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -87,15 +88,22 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* disable widget core. continue to route setup status and complete flag
|
* decrement ref count for cores associated with all modules in the pipeline and clear
|
||||||
* even if this fails and return the appropriate error
|
* the complete flag
|
||||||
*/
|
*/
|
||||||
ret = snd_sof_dsp_core_put(sdev, swidget->core);
|
if (swidget->id == snd_soc_dapm_scheduler) {
|
||||||
if (ret < 0) {
|
int i;
|
||||||
dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n",
|
|
||||||
swidget->core, swidget->widget->name);
|
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
|
||||||
if (!err)
|
ret = snd_sof_dsp_core_put(sdev, i);
|
||||||
err = ret;
|
if (ret < 0) {
|
||||||
|
dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n",
|
||||||
|
i, swidget->widget->name);
|
||||||
|
if (!err)
|
||||||
|
err = ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
swidget->spipe->complete = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -108,10 +116,6 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
|
||||||
err = ret;
|
err = ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear pipeline complete */
|
|
||||||
if (swidget->id == snd_soc_dapm_scheduler)
|
|
||||||
swidget->spipe->complete = 0;
|
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
|
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
|
||||||
|
|
||||||
|
@ -134,8 +138,10 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
|
||||||
struct snd_sof_widget *swidget)
|
struct snd_sof_widget *swidget)
|
||||||
{
|
{
|
||||||
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
|
||||||
|
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||||
bool use_count_decremented = false;
|
bool use_count_decremented = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* skip if there is no private data */
|
/* skip if there is no private data */
|
||||||
if (!swidget->private)
|
if (!swidget->private)
|
||||||
|
@ -166,19 +172,23 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
|
||||||
goto use_count_dec;
|
goto use_count_dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* enable widget core */
|
/* update ref count for cores associated with all modules in the pipeline */
|
||||||
ret = snd_sof_dsp_core_get(sdev, swidget->core);
|
if (swidget->id == snd_soc_dapm_scheduler) {
|
||||||
if (ret < 0) {
|
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
|
||||||
dev_err(sdev->dev, "error: failed to enable target core for widget %s\n",
|
ret = snd_sof_dsp_core_get(sdev, i);
|
||||||
swidget->widget->name);
|
if (ret < 0) {
|
||||||
goto pipe_widget_free;
|
dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n",
|
||||||
|
i, swidget->widget->name);
|
||||||
|
goto pipe_widget_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup widget in the DSP */
|
/* setup widget in the DSP */
|
||||||
if (tplg_ops && tplg_ops->widget_setup) {
|
if (tplg_ops && tplg_ops->widget_setup) {
|
||||||
ret = tplg_ops->widget_setup(sdev, swidget);
|
ret = tplg_ops->widget_setup(sdev, swidget);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto core_put;
|
goto pipe_widget_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send config for DAI components */
|
/* send config for DAI components */
|
||||||
|
@ -208,15 +218,22 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
widget_free:
|
widget_free:
|
||||||
/* widget use_count and core ref_count will both be decremented by sof_widget_free() */
|
/* widget use_count will be decremented by sof_widget_free() */
|
||||||
sof_widget_free_unlocked(sdev, swidget);
|
sof_widget_free_unlocked(sdev, swidget);
|
||||||
use_count_decremented = true;
|
use_count_decremented = true;
|
||||||
core_put:
|
|
||||||
if (!use_count_decremented)
|
|
||||||
snd_sof_dsp_core_put(sdev, swidget->core);
|
|
||||||
pipe_widget_free:
|
pipe_widget_free:
|
||||||
if (swidget->id != snd_soc_dapm_scheduler)
|
if (swidget->id != snd_soc_dapm_scheduler) {
|
||||||
sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
|
sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
|
||||||
|
} else {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* decrement ref count for all cores that were updated previously */
|
||||||
|
for_each_set_bit(j, &spipe->core_mask, sdev->num_cores) {
|
||||||
|
if (j >= i)
|
||||||
|
break;
|
||||||
|
snd_sof_dsp_core_put(sdev, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
use_count_dec:
|
use_count_dec:
|
||||||
if (!use_count_decremented)
|
if (!use_count_decremented)
|
||||||
swidget->use_count--;
|
swidget->use_count--;
|
||||||
|
|
Loading…
Add table
Reference in a new issue