Unverified Commit 1805a6d2 authored by Mark Brown's avatar Mark Brown
Browse files

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;

+9 −0
Original line number Diff line number Diff line
@@ -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 @@ 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)
{
	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);
+41 −24
Original line number Diff line number Diff line
@@ -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,16 +88,23 @@ 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 (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, "error: failed to disable target core: %d for widget %s\n",
			swidget->core, swidget->widget->name);
				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;
	}

	/*
	 * free the scheduler widget (same as pipe_widget) associated with the current swidget.
@@ -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);
	/* 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, "error: failed to enable target core for widget %s\n",
			swidget->widget->name);
				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--;
+2 −0
Original line number Diff line number Diff line
@@ -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;
};