Commit 1805a6d2 authored by Mark Brown's avatar Mark Brown

ASoC: SOF: Extend the enabled DSP core handling

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

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.
parents fba29348 31ed8da1
...@@ -493,6 +493,7 @@ static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget) ...@@ -493,6 +493,7 @@ static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{ {
struct snd_soc_component *scomp = swidget->scomp; struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc_pipe_new *pipeline; struct sof_ipc_pipe_new *pipeline;
struct snd_sof_widget *comp_swidget; struct snd_sof_widget *comp_swidget;
int ret; int ret;
...@@ -545,6 +546,7 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) ...@@ -545,6 +546,7 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
swidget->dynamic_pipeline_widget); swidget->dynamic_pipeline_widget);
swidget->core = pipeline->core; swidget->core = pipeline->core;
spipe->core_mask |= BIT(pipeline->core);
return 0; return 0;
......
...@@ -656,6 +656,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) ...@@ -656,6 +656,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{ {
struct snd_soc_component *scomp = swidget->scomp; struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_pipeline *pipeline; struct sof_ipc4_pipeline *pipeline;
struct snd_sof_pipeline *spipe = swidget->spipe;
int ret; int ret;
pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
...@@ -670,6 +671,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) ...@@ -670,6 +671,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
} }
swidget->core = pipeline->core_id; swidget->core = pipeline->core_id;
spipe->core_mask |= BIT(pipeline->core_id);
if (pipeline->use_chain_dma) { if (pipeline->use_chain_dma) {
dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
...@@ -797,6 +799,7 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) ...@@ -797,6 +799,7 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
{ {
struct snd_soc_component *scomp = swidget->scomp; struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_src *src; struct sof_ipc4_src *src;
int ret; int ret;
...@@ -819,6 +822,8 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) ...@@ -819,6 +822,8 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
goto err; goto err;
} }
spipe->core_mask |= BIT(swidget->core);
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate); dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
...@@ -864,6 +869,7 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget) ...@@ -864,6 +869,7 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
{ {
struct snd_soc_component *scomp = swidget->scomp; struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_fw_module *fw_module; struct sof_ipc4_fw_module *fw_module;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_process *process; struct sof_ipc4_process *process;
void *cfg; void *cfg;
int ret; int ret;
...@@ -920,6 +926,9 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget) ...@@ -920,6 +926,9 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
sof_ipc4_widget_update_kcontrol_module_id(swidget); sof_ipc4_widget_update_kcontrol_module_id(swidget);
/* set pipeline core mask to keep track of the core the module is scheduled to run on */
spipe->core_mask |= BIT(swidget->core);
return 0; return 0;
free_base_cfg_ext: free_base_cfg_ext:
kfree(process->base_config_ext); kfree(process->base_config_ext);
......
...@@ -46,6 +46,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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--;
......
...@@ -480,6 +480,7 @@ struct snd_sof_widget { ...@@ -480,6 +480,7 @@ struct snd_sof_widget {
* @paused_count: Count of number of PCM's that have started and have currently paused this * @paused_count: Count of number of PCM's that have started and have currently paused this
pipeline pipeline
* @complete: flag used to indicate that pipeline set up is complete. * @complete: flag used to indicate that pipeline set up is complete.
* @core_mask: Mask containing target cores for all modules in the pipeline
* @list: List item in sdev pipeline_list * @list: List item in sdev pipeline_list
*/ */
struct snd_sof_pipeline { struct snd_sof_pipeline {
...@@ -487,6 +488,7 @@ struct snd_sof_pipeline { ...@@ -487,6 +488,7 @@ struct snd_sof_pipeline {
int started_count; int started_count;
int paused_count; int paused_count;
int complete; int complete;
unsigned long core_mask;
struct list_head list; struct list_head list;
}; };
......
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