Skip to content

Commit

Permalink
ASoC: SOF: add support for dynamic pipelines with multi-core
Browse files Browse the repository at this point in the history
This patch adds support for dynamic pipelines with multi-core
by using the platform-specific core_get/put() ops to
power up/down a core when a widget is set up/freed.

Along with this, a few redundant functions are removed:
1. sof_pipeline_core_enable() is no longer needed as the
pipeline core will be set up when the pipeline widget
is set up
2. sof_core_enable() is replaced with snd_sof_core_get()
3. sof_load_pipeline_ipc() is not needed. Just send the
IPC in sof_widget_setup.

Finally, core power down sof_widget_unload() in topology
removal is also removed as it is not really needed. For dynamic
pipelines, the cores will be powered off when they are not used.
For static pipelines, the cores will be powered off in the device
remove callback.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  • Loading branch information
ranj063 committed Jun 30, 2021
1 parent 46a4d78 commit 9bfcc3f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 123 deletions.
66 changes: 52 additions & 14 deletions sound/soc/sof/sof-audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
.id = swidget->comp_id,
};
struct sof_ipc_reply reply;
int ret;
int ret, core;

if (!swidget->private)
return 0;
Expand All @@ -116,10 +116,17 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
if (--swidget->use_count)
return 0;

core = swidget->core;

switch (swidget->id) {
case snd_soc_dapm_scheduler:
{
const struct sof_ipc_pipe_new *pipeline = swidget->private;

core = pipeline->core;
ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
break;
}
case snd_soc_dapm_buffer:
ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
break;
Expand All @@ -128,20 +135,27 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
break;
}

/* continue to disable core even if IPC fails */
ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
&reply, sizeof(reply));
if (ret < 0) {
if (ret < 0)
dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
swidget->use_count++;
return ret;
}

/*
* disable widget core. continue to route setup status and complete flag
* even if this fails
*/
if (snd_sof_dsp_core_put(sdev, core) < 0)
dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n",
core, swidget->widget->name);


/* reset route setup status for all routes that contain this widget */
sof_reset_route_setup_status(sdev, swidget);
swidget->complete = 0;
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);

return 0;
return ret;
}
EXPORT_SYMBOL(sof_widget_free);

Expand All @@ -154,6 +168,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
struct snd_sof_dai *dai;
size_t ipc_size;
int ret;
int core;

/* skip if there is no private data */
if (!swidget->private)
Expand All @@ -163,20 +178,31 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
if (++swidget->use_count > 1)
return 0;

ret = sof_pipeline_core_enable(sdev, swidget);
/* set core ID */
core = swidget->core;
if (swidget->id == snd_soc_dapm_scheduler) {
pipeline = swidget->private;
core = pipeline->core;
}

/* enable widget core */
ret = snd_sof_dsp_core_get(sdev, core);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to enable target core: %d for widget %s\n",
ret, swidget->widget->name);
goto use_count_dec;
dev_err(sdev->dev, "error: failed to enable target core for widget %s\n",
swidget->widget->name);
swidget->use_count--;
return ret;
}

switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
ipc_size = sizeof(struct sof_ipc_comp_dai) + sizeof(struct sof_ipc_comp_ext);
comp = kzalloc(ipc_size, GFP_KERNEL);
if (!comp)
return -ENOMEM;
if (!comp) {
ret = -ENOMEM;
goto use_count_dec;
}

dai = swidget->private;
dai->configured = false;
Expand Down Expand Up @@ -204,7 +230,9 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
break;
case snd_soc_dapm_scheduler:
pipeline = swidget->private;
ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), &r, sizeof(r));
swidget->complete = 0;
break;
default:
hdr = swidget->private;
Expand Down Expand Up @@ -232,6 +260,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)

use_count_dec:
swidget->use_count--;
snd_sof_dsp_core_put(sdev, core);
return ret;
}
EXPORT_SYMBOL(sof_widget_setup);
Expand Down Expand Up @@ -416,6 +445,8 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in

pipe_widget->complete = snd_sof_complete_pipeline(sdev, pipe_widget);
if (pipe_widget->complete < 0) {
dev_err(sdev->dev, "failed to complete pipeline %s\n",
pipe_widget->widget->name);
ret = pipe_widget->complete;
goto widget_free;
}
Expand Down Expand Up @@ -675,6 +706,7 @@ int sof_set_up_pipelines(struct snd_sof_dev *sdev, bool verify)
*/
int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify)
{
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
int ret;
Expand All @@ -686,8 +718,14 @@ int sof_tear_down_pipelines(struct snd_sof_dev *sdev, bool verify)
* loading the sound card unavailable to open PCMs.
*/
list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
if (!verify) {
if (swidget->dynamic_pipeline_widget)
continue;

/* Do not free widgets for static pipelines with FW ABI older than 3.19 */
if (!verify && !swidget->dynamic_pipeline_widget &&
v->abi_version < SOF_ABI_VER(3, 19, 0)) {
swidget->use_count = 0;
swidget->complete = 0;
continue;
}

Expand Down
6 changes: 0 additions & 6 deletions sound/soc/sof/sof-audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file);
int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget);

int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r);
int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
const struct snd_sof_widget *swidget);

/*
* Stream IPC
*/
Expand Down
103 changes: 0 additions & 103 deletions sound/soc/sof/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -1329,69 +1329,6 @@ static int sof_control_unload(struct snd_soc_component *scomp,
* DAI Topology
*/

/* Static DSP core power management so far, should be extended in the future */
static int sof_core_enable(struct snd_sof_dev *sdev, int core)
{
struct sof_ipc_pm_core_config pm_core_config = {
.hdr = {
.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE,
.size = sizeof(pm_core_config),
},
.enable_mask = sdev->enabled_cores_mask | BIT(core),
};
int ret;

if (sdev->enabled_cores_mask & BIT(core))
return 0;

/* power up the core if it is host managed */
ret = snd_sof_dsp_core_power_up(sdev, BIT(core));
if (ret < 0) {
dev_err(sdev->dev, "error: %d powering up core %d\n",
ret, core);
return ret;
}

/* Now notify DSP */
ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd,
&pm_core_config, sizeof(pm_core_config),
&pm_core_config, sizeof(pm_core_config));
if (ret < 0) {
dev_err(sdev->dev, "error: core %d enable ipc failure %d\n",
core, ret);
goto err;
}
return ret;
err:
/* power down core if it is host managed and return the original error if this fails too */
if (snd_sof_dsp_core_power_down(sdev, BIT(core)) < 0)
dev_err(sdev->dev, "error: powering down core %d\n", core);

return ret;
}

int sof_pipeline_core_enable(struct snd_sof_dev *sdev,
const struct snd_sof_widget *swidget)
{
const struct sof_ipc_pipe_new *pipeline;
int ret;

if (swidget->id == snd_soc_dapm_scheduler) {
pipeline = swidget->private;
} else {
pipeline = snd_sof_pipeline_find(sdev, swidget->pipeline_id);
if (!pipeline)
return -ENOENT;
}

/* First enable the pipeline core */
ret = sof_core_enable(sdev, pipeline->core);
if (ret < 0)
return ret;

return sof_core_enable(sdev, swidget->core);
}

static int sof_connect_dai_widget(struct snd_soc_component *scomp,
struct snd_soc_dapm_widget *w,
struct snd_soc_tplg_dapm_widget *tw,
Expand Down Expand Up @@ -1687,26 +1624,6 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index,
return ret;
}

/*
* Pipeline Topology
*/
int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r)
{
int ret = sof_core_enable(sdev, pipeline->core);

if (ret < 0)
return ret;

ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
sizeof(*pipeline), r, sizeof(*r));
if (ret < 0)
dev_err(sdev->dev, "error: load pipeline ipc failure\n");

return ret;
}

static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index,
struct snd_sof_widget *swidget,
struct snd_soc_tplg_dapm_widget *tw)
Expand Down Expand Up @@ -2485,10 +2402,8 @@ static int sof_route_unload(struct snd_soc_component *scomp,
static int sof_widget_unload(struct snd_soc_component *scomp,
struct snd_soc_dobj *dobj)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
const struct snd_kcontrol_new *kc;
struct snd_soc_dapm_widget *widget;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_control *scontrol;
struct snd_sof_widget *swidget;
struct soc_mixer_control *sm;
Expand All @@ -2515,24 +2430,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp,
list_del(&dai->list);
}
break;
case snd_soc_dapm_scheduler:

/* power down the pipeline schedule core */
pipeline = swidget->private;

/*
* Runtime PM should still function normally if topology loading fails and
* it's components are unloaded. Do not power down the primary core so that the
* CTX_SAVE IPC can succeed during runtime suspend.
*/
if (pipeline->core == SOF_DSP_PRIMARY_CORE)
break;

ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core);
if (ret < 0)
dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n",
pipeline->core);
break;
default:
break;
}
Expand Down

0 comments on commit 9bfcc3f

Please sign in to comment.