Skip to content

Commit

Permalink
ASoC: SOF: sof-audio: Modify logic for enabling/disabling topology cores
Browse files Browse the repository at this point in the history
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 because the secondary core one of its widgets is
scheduled to run on could be powered off earlier. 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>
  • Loading branch information
ranj063 committed Nov 14, 2023
1 parent ed2109d commit 9c2666d
Showing 1 changed file with 42 additions and 26 deletions.
68 changes: 42 additions & 26 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
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;
int err = 0;
int ret;
Expand Down Expand Up @@ -85,16 +86,21 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
err = ret;
}

/*
* disable widget core. continue to route setup status and complete flag
* even if this fails and return the appropriate error
*/
ret = snd_sof_dsp_core_put(sdev, swidget->core);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n",
swidget->core, swidget->widget->name);
if (!err)
err = ret;
/* disable cores associated with all modules in the pipeline and clear the complete flag */
if (swidget->id == snd_soc_dapm_scheduler) {
int i;

for (i = 0; i < sdev->num_cores; i++) {
if (!(spipe->core_mask & BIT(i)))
continue;

ret = snd_sof_dsp_core_put(sdev, BIT(i));
dev_err(sdev->dev, "error: failed to disable target core: %d for pipeline %s\n",
BIT(i), swidget->widget->name);
if (!err)
err = ret;
}
swidget->spipe->complete = 0;
}

/*
Expand All @@ -107,10 +113,6 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
err = ret;
}

/* clear pipeline complete */
if (swidget->id == snd_soc_dapm_scheduler)
swidget->spipe->complete = 0;

if (!err)
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);

Expand All @@ -133,8 +135,10 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
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;
int ret;
int i;

/* skip if there is no private data */
if (!swidget->private)
Expand Down Expand Up @@ -165,19 +169,26 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
goto use_count_dec;
}

/* enable widget core */
ret = snd_sof_dsp_core_get(sdev, swidget->core);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to enable target core for widget %s\n",
swidget->widget->name);
goto pipe_widget_free;
/* enabled cores associated with all modules in a pipeline */
if (swidget->id == snd_soc_dapm_scheduler) {
for (i = 0; i < sdev->num_cores; i++) {
if (!(spipe->core_mask & BIT(i)))
continue;

ret = snd_sof_dsp_core_get(sdev, BIT(i));
if (ret < 0) {
dev_err(sdev->dev, "error: failed to enable target core %d for pipeline %s\n",
BIT(i), swidget->widget->name);
goto pipe_widget_free;
}
}
}

/* setup widget in the DSP */
if (tplg_ops && tplg_ops->widget_setup) {
ret = tplg_ops->widget_setup(sdev, swidget);
if (ret < 0)
goto core_put;
goto pipe_widget_free;
}

/* send config for DAI components */
Expand Down Expand Up @@ -207,15 +218,20 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
return 0;

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);
use_count_decremented = true;
core_put:
if (!use_count_decremented)
snd_sof_dsp_core_put(sdev, swidget->core);
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);
} else {
int j;

/* free all enabled cores */
for (j = 0; j < i; j++)
if (spipe->core_mask & BIT(j))
snd_sof_dsp_core_put(sdev, BIT(j));
}
use_count_dec:
if (!use_count_decremented)
swidget->use_count--;
Expand Down

0 comments on commit 9c2666d

Please sign in to comment.