INIT_LIST_HEAD(&sdev->pcm_list);
INIT_LIST_HEAD(&sdev->kcontrol_list);
INIT_LIST_HEAD(&sdev->widget_list);
+ INIT_LIST_HEAD(&sdev->pipeline_list);
INIT_LIST_HEAD(&sdev->dai_list);
INIT_LIST_HEAD(&sdev->dai_link_list);
INIT_LIST_HEAD(&sdev->route_list);
w = snd_soc_dai_get_widget(dai, substream->stream);
swidget = w->dobj.private;
- pipe_widget = swidget->pipe_widget;
+ pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
switch (cmd) {
return ret;
}
- swidget->complete = sof_ipc3_complete_pipeline(sdev, swidget);
- if (swidget->complete < 0)
- return swidget->complete;
+ swidget->spipe->complete = sof_ipc3_complete_pipeline(sdev, swidget);
+ if (swidget->spipe->complete < 0)
+ return swidget->spipe->complete;
break;
default:
break;
if (!verify && !swidget->dynamic_pipeline_widget &&
SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) {
swidget->use_count = 0;
- swidget->complete = 0;
+ if (swidget->spipe)
+ swidget->spipe->complete = 0;
continue;
}
struct ipc4_pipeline_set_state_data *data;
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
+ struct snd_sof_pipeline *spipe;
struct snd_sof_pcm *spcm;
int ret;
int i, j;
pipeline_list = &spcm->stream[substream->stream].pipeline_list;
/* nothing to trigger if the list is empty */
- if (!pipeline_list->pipe_widgets)
+ if (!pipeline_list->pipelines)
return 0;
/* allocate memory for the pipeline data */
* sink->source would still be guaranteed for each fork independently.
*/
for (i = pipeline_list->count - 1; i >= 0; i--) {
- pipe_widget = pipeline_list->pipe_widgets[i];
+ spipe = pipeline_list->pipelines[i];
+ pipe_widget = spipe->pipe_widget;
pipeline = pipe_widget->private;
if (pipeline->state != state && !pipeline->skip_during_fe_trigger)
data->pipeline_ids[data->count++] = pipe_widget->instance_id;
/* update PAUSED state for all pipelines that were just triggered */
for (i = 0; i < data->count; i++) {
for (j = 0; j < pipeline_list->count; j++) {
- pipe_widget = pipeline_list->pipe_widgets[j];
+ spipe = pipeline_list->pipelines[j];
+ pipe_widget = spipe->pipe_widget;
pipeline = pipe_widget->private;
if (data->pipeline_ids[i] == pipe_widget->instance_id) {
/* update final state for all pipelines that were just triggered */
for (i = 0; i < data->count; i++) {
for (j = 0; j < pipeline_list->count; j++) {
- pipe_widget = pipeline_list->pipe_widgets[j];
+ spipe = pipeline_list->pipelines[j];
+ pipe_widget = spipe->pipe_widget;
pipeline = pipe_widget->private;
if (data->pipeline_ids[i] == pipe_widget->instance_id) {
for_each_pcm_streams(stream) {
pipeline_list = &spcm->stream[stream].pipeline_list;
- kfree(pipeline_list->pipe_widgets);
- pipeline_list->pipe_widgets = NULL;
+ kfree(pipeline_list->pipelines);
+ pipeline_list->pipelines = NULL;
}
}
pipeline_list = &spcm->stream[stream].pipeline_list;
/* allocate memory for max number of pipeline IDs */
- pipeline_list->pipe_widgets = kcalloc(ipc4_data->max_num_pipelines,
- sizeof(struct snd_sof_widget *),
- GFP_KERNEL);
- if (!pipeline_list->pipe_widgets) {
+ pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines,
+ sizeof(struct snd_sof_widget *), GFP_KERNEL);
+ if (!pipeline_list->pipelines) {
sof_ipc4_pcm_free(sdev, spcm);
return -ENOMEM;
}
total = SOF_IPC4_FW_PAGE(task_mem + queue_mem);
- pipe_widget = swidget->pipe_widget;
+ pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage += total;
}
struct sof_ipc4_pipeline *pipeline;
/* reset pipeline memory usage */
- pipe_widget = swidget->pipe_widget;
+ pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage = 0;
struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline;
- pipe_widget = swidget->pipe_widget;
+ pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
gtw_attr = ipc4_copier->gtw_attr;
static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
- struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_ipc4_pipeline *pipeline;
struct sof_ipc4_msg *msg;
* routes belonging to the same pipeline will be disconnected by the FW when the pipeline
* is freed. So avoid sending this IPC which will be ignored by the FW anyway.
*/
- if (src_widget->pipe_widget == sink_widget->pipe_widget)
+ if (src_widget->spipe->pipe_widget == sink_widget->spipe->pipe_widget)
goto out;
header = src_fw_module->man4_module_entry.id;
static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
unsigned int flags, struct snd_sof_dai_config_data *data)
{
- struct snd_sof_widget *pipe_widget = swidget->pipe_widget;
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_gtw_attributes *gtw_attr;
int sof_widget_free(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_widget *pipe_widget;
int err = 0;
int ret;
if (--swidget->use_count)
return 0;
+ pipe_widget = swidget->spipe->pipe_widget;
+
/* reset route setup status for all routes that contain this widget */
sof_reset_route_setup_status(sdev, swidget);
* skip for static pipelines
*/
if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
- ret = sof_widget_free(sdev, swidget->pipe_widget);
+ ret = sof_widget_free(sdev, pipe_widget);
if (ret < 0 && !err)
err = ret;
- swidget->pipe_widget->complete = 0;
}
+ /* 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);
* widget in the pipeline is freed. Skip setting up scheduler widget for static pipelines.
*/
if (swidget->dynamic_pipeline_widget && swidget->id != snd_soc_dapm_scheduler) {
- if (!swidget->pipe_widget) {
- dev_err(sdev->dev, "No scheduler widget set for %s\n",
- swidget->widget->name);
+ if (!swidget->spipe || !swidget->spipe->pipe_widget) {
+ dev_err(sdev->dev, "No pipeline set for %s\n", swidget->widget->name);
ret = -EINVAL;
goto use_count_dec;
}
- ret = sof_widget_setup(sdev, swidget->pipe_widget);
+ ret = sof_widget_setup(sdev, swidget->spipe->pipe_widget);
if (ret < 0)
goto use_count_dec;
}
snd_sof_dsp_core_put(sdev, swidget->core);
pipe_widget_free:
if (swidget->id != snd_soc_dapm_scheduler)
- sof_widget_free(sdev, swidget->pipe_widget);
+ sof_widget_free(sdev, swidget->spipe->pipe_widget);
use_count_dec:
swidget->use_count--;
return ret;
struct snd_sof_pcm_stream_pipeline_list *pipeline_list = &spcm->stream[dir].pipeline_list;
struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
struct snd_sof_widget *swidget = widget->dobj.private;
- struct snd_sof_widget *pipe_widget;
+ struct snd_sof_pipeline *spipe;
struct snd_soc_dapm_path *p;
int ret;
return ret;
/* skip populating the pipe_widgets array if it is NULL */
- if (!pipeline_list->pipe_widgets)
+ if (!pipeline_list->pipelines)
goto sink_setup;
/*
* order source to sink.
*/
for (i = 0; i < pipeline_list->count; i++) {
- pipe_widget = pipeline_list->pipe_widgets[i];
- if (pipe_widget == swidget->pipe_widget)
+ spipe = pipeline_list->pipelines[i];
+ if (spipe == swidget->spipe)
break;
}
if (i == pipeline_list->count) {
pipeline_list->count++;
- pipeline_list->pipe_widgets[i] = swidget->pipe_widget;
+ pipeline_list->pipelines[i] = swidget->spipe;
}
}
for_each_dapm_widgets(list, i, widget) {
struct snd_sof_widget *swidget = widget->dobj.private;
struct snd_sof_widget *pipe_widget;
+ struct snd_sof_pipeline *spipe;
if (!swidget)
continue;
- pipe_widget = swidget->pipe_widget;
+ spipe = swidget->spipe;
+ if (!spipe) {
+ dev_err(sdev->dev, "no pipeline found for %s\n",
+ swidget->widget->name);
+ ret = -EINVAL;
+ goto widget_free;
+ }
+
+ pipe_widget = spipe->pipe_widget;
if (!pipe_widget) {
dev_err(sdev->dev, "error: no pipeline widget found for %s\n",
swidget->widget->name);
goto widget_free;
}
- if (pipe_widget->complete)
+ if (spipe->complete)
continue;
if (tplg_ops && tplg_ops->pipeline_complete) {
- pipe_widget->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
- if (pipe_widget->complete < 0) {
- ret = pipe_widget->complete;
+ spipe->complete = tplg_ops->pipeline_complete(sdev, pipe_widget);
+ if (spipe->complete < 0) {
+ ret = spipe->complete;
goto widget_free;
}
}
/**
* struct snd_sof_pcm_stream_pipeline_list - List of pipelines associated with a PCM stream
* @count: number of pipeline widgets in the @pipe_widgets array
- * @pipe_widgets: array of pipeline widgets
+ * @pipelines: array of pipelines
*/
struct snd_sof_pcm_stream_pipeline_list {
u32 count;
- struct snd_sof_widget **pipe_widgets;
+ struct snd_sof_pipeline **pipelines;
};
/* PCM stream, mapped to FW component */
struct snd_soc_component *scomp;
int comp_id;
int pipeline_id;
- /*
- * complete flag is used to indicate that pipeline set up is complete for scheduler type
- * widgets. It is unused for all other widget types.
- */
- int complete;
/*
* the prepared flag is used to indicate that a widget has been prepared for getting set
* up in the DSP.
struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
- struct snd_sof_widget *pipe_widget;
+ struct snd_sof_pipeline *spipe;
void *module_info;
const guid_t uuid;
void *private; /* core does not touch this */
};
+/** struct snd_sof_pipeline - ASoC SOF pipeline
+ * @pipe_widget: Pointer to the pipeline widget
+ * @started_count: Count of number of PCM's that have started this pipeline
+ * @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.
+ * @list: List item in sdev pipeline_list
+ */
+struct snd_sof_pipeline {
+ struct snd_sof_widget *pipe_widget;
+ int started_count;
+ int paused_count;
+ int complete;
+ struct list_head list;
+};
+
/* ASoC SOF DAPM route */
struct snd_sof_route {
struct snd_soc_component *scomp;
struct list_head pcm_list;
struct list_head kcontrol_list;
struct list_head widget_list;
+ struct list_head pipeline_list;
struct list_head dai_list;
struct list_head dai_link_list;
struct list_head route_list;
swidget->scomp = scomp;
swidget->widget = w;
swidget->comp_id = sdev->next_comp_id++;
- swidget->complete = 0;
swidget->id = w->id;
swidget->pipeline_id = index;
swidget->private = NULL;
}
}
+ /* create and add pipeline for scheduler type widgets */
+ if (w->id == snd_soc_dapm_scheduler) {
+ struct snd_sof_pipeline *spipe;
+
+ spipe = kzalloc(sizeof(*spipe), GFP_KERNEL);
+ if (!spipe) {
+ kfree(swidget->private);
+ kfree(swidget->tuples);
+ kfree(swidget);
+ return -ENOMEM;
+ }
+
+ spipe->pipe_widget = swidget;
+ swidget->spipe = spipe;
+ list_add(&spipe->list, &sdev->pipeline_list);
+ }
+
w->dobj.private = swidget;
list_add(&swidget->list, &sdev->widget_list);
return ret;
sof_disconnect_dai_widget(scomp, widget);
break;
+ case snd_soc_dapm_scheduler:
+ {
+ struct snd_sof_pipeline *spipe = swidget->spipe;
+
+ list_del(&spipe->list);
+ kfree(spipe);
+ swidget->spipe = NULL;
+ break;
+ }
default:
break;
}
}
/**
- * sof_set_pipe_widget - Set pipe_widget for a component
+ * sof_set_widget_pipeline - Set pipeline for a component
* @sdev: pointer to struct snd_sof_dev
- * @pipe_widget: pointer to struct snd_sof_widget of type snd_soc_dapm_scheduler
+ * @spipe: pointer to struct snd_sof_pipeline
* @swidget: pointer to struct snd_sof_widget that has the same pipeline ID as @pipe_widget
*
* Return: 0 if successful, -EINVAL on error.
* The function checks if @swidget is associated with any volatile controls. If so, setting
* the dynamic_pipeline_widget is disallowed.
*/
-static int sof_set_pipe_widget(struct snd_sof_dev *sdev, struct snd_sof_widget *pipe_widget,
- struct snd_sof_widget *swidget)
+static int sof_set_widget_pipeline(struct snd_sof_dev *sdev, struct snd_sof_pipeline *spipe,
+ struct snd_sof_widget *swidget)
{
+ struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
struct snd_sof_control *scontrol;
if (pipe_widget->dynamic_pipeline_widget) {
}
}
- /* set the pipe_widget and apply the dynamic_pipeline_widget_flag */
- swidget->pipe_widget = pipe_widget;
+ /* set the pipeline and apply the dynamic_pipeline_widget_flag */
+ swidget->spipe = spipe;
swidget->dynamic_pipeline_widget = pipe_widget->dynamic_pipeline_widget;
return 0;
struct snd_sof_widget *swidget, *comp_swidget;
const struct sof_ipc_tplg_widget_ops *widget_ops;
struct snd_sof_control *scontrol;
+ struct snd_sof_pipeline *spipe;
int ret;
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
}
/* set the pipe_widget and apply the dynamic_pipeline_widget_flag */
- list_for_each_entry(swidget, &sdev->widget_list, list) {
- switch (swidget->id) {
- case snd_soc_dapm_scheduler:
- /*
- * Apply the dynamic_pipeline_widget flag and set the pipe_widget field
- * for all widgets that have the same pipeline ID as the scheduler widget
- */
- list_for_each_entry(comp_swidget, &sdev->widget_list, list)
- if (comp_swidget->pipeline_id == swidget->pipeline_id) {
- ret = sof_set_pipe_widget(sdev, swidget, comp_swidget);
- if (ret < 0)
- return ret;
- }
- break;
- default:
- break;
- }
+ list_for_each_entry(spipe, &sdev->pipeline_list, list) {
+ struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
+
+ /*
+ * Apply the dynamic_pipeline_widget flag and set the pipe_widget field
+ * for all widgets that have the same pipeline ID as the scheduler widget.
+ * Skip the scheduler widgets as they have their pipeline set during widget_ready
+ */
+ list_for_each_entry(comp_swidget, &sdev->widget_list, list)
+ if (comp_swidget->widget->id != snd_soc_dapm_scheduler &&
+ comp_swidget->pipeline_id == pipe_widget->pipeline_id) {
+ ret = sof_set_widget_pipeline(sdev, spipe, comp_swidget);
+ if (ret < 0)
+ return ret;
+ }
}
/* verify topology components loading including dynamic pipelines */