mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
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.
This commit is contained in:
commit
1805a6d269
@ -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)
|
||||
{
|
||||
struct snd_soc_component *scomp = swidget->scomp;
|
||||
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||
struct sof_ipc_pipe_new *pipeline;
|
||||
struct snd_sof_widget *comp_swidget;
|
||||
int ret;
|
||||
@ -545,6 +546,7 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
|
||||
swidget->dynamic_pipeline_widget);
|
||||
|
||||
swidget->core = pipeline->core;
|
||||
spipe->core_mask |= BIT(pipeline->core);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -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 sof_ipc4_pipeline *pipeline;
|
||||
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||
int ret;
|
||||
|
||||
pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
|
||||
@ -670,6 +671,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
|
||||
}
|
||||
|
||||
swidget->core = pipeline->core_id;
|
||||
spipe->core_mask |= BIT(pipeline->core_id);
|
||||
|
||||
if (pipeline->use_chain_dma) {
|
||||
dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
|
||||
@ -797,6 +799,7 @@ err:
|
||||
static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct snd_soc_component *scomp = swidget->scomp;
|
||||
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||
struct sof_ipc4_src *src;
|
||||
int ret;
|
||||
|
||||
@ -819,6 +822,8 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
|
||||
goto err;
|
||||
}
|
||||
|
||||
spipe->core_mask |= BIT(swidget->core);
|
||||
|
||||
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
|
||||
|
||||
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)
|
||||
{
|
||||
struct snd_soc_component *scomp = swidget->scomp;
|
||||
struct sof_ipc4_fw_module *fw_module;
|
||||
struct snd_sof_pipeline *spipe = swidget->spipe;
|
||||
struct sof_ipc4_process *process;
|
||||
void *cfg;
|
||||
int ret;
|
||||
@ -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);
|
||||
|
||||
/* 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;
|
||||
free_base_cfg_ext:
|
||||
kfree(process->base_config_ext);
|
||||
|
@ -46,6 +46,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;
|
||||
@ -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
|
||||
* even if this fails and return the appropriate error
|
||||
* decrement ref count for cores associated with all modules in the pipeline and clear
|
||||
* the complete flag
|
||||
*/
|
||||
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;
|
||||
if (swidget->id == snd_soc_dapm_scheduler) {
|
||||
int i;
|
||||
|
||||
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
|
||||
ret = snd_sof_dsp_core_put(sdev, i);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
@ -134,8 +138,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)
|
||||
@ -166,19 +172,23 @@ 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;
|
||||
/* update ref count for cores associated with all modules in the pipeline */
|
||||
if (swidget->id == snd_soc_dapm_scheduler) {
|
||||
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
|
||||
ret = snd_sof_dsp_core_get(sdev, i);
|
||||
if (ret < 0) {
|
||||
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 */
|
||||
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 */
|
||||
@ -208,15 +218,22 @@ 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;
|
||||
|
||||
/* 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:
|
||||
if (!use_count_decremented)
|
||||
swidget->use_count--;
|
||||
|
@ -480,6 +480,7 @@ struct snd_sof_widget {
|
||||
* @paused_count: Count of number of PCM's that have started and have currently paused this
|
||||
pipeline
|
||||
* @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
|
||||
*/
|
||||
struct snd_sof_pipeline {
|
||||
@ -487,6 +488,7 @@ struct snd_sof_pipeline {
|
||||
int started_count;
|
||||
int paused_count;
|
||||
int complete;
|
||||
unsigned long core_mask;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user