[PATCH 00/11] ASoC: SOF: Miscellaneous preparatory patches for IPC4
This series includes last few remaining miscellaneous patches to prepare for the introduction of new IPC version, IPC4, in the SOF driver. The changes include new IPC ops for topology parsing to set up the volume table, prepare the widgets for set up and free the routes. The remaining patches introduce new fields in the existing data structures for use in IPC4 and align the flows for widget/route set up so that they are common for both IPC3 and IPC4.
Ranjani Sridharan (11): ASoC: SOF: Add a new op to set up volume table ASoC: SOF: sof-audio: reset route status before freeing widget ASoC: SOF: sof-audio: Set up widgets from source to sink ASoC: SOF: pcm: Move the call to snd_sof_pcm_platform_hw_params() ASoC: SOF: expose a couple of functions ASoC: SOF: Add a route_free op in struct sof_ipc_tplg_ops ASoC: SOF: Add two new fields to struct snd_sof_widget ASoC: SOF: pcm: remove unnecessary function declaration ASoC: SOF: topology: Skip parsing DAI link tokens if not needed ASoC: SOF: clarify use of widget complete flag ASoC: SOF: Add a prepare op to IPC topology widget ops
sound/soc/sof/ipc3-control.c | 38 +++-- sound/soc/sof/pcm.c | 23 +-- sound/soc/sof/sof-audio.c | 302 +++++++++++++++++++++++++++++------ sound/soc/sof/sof-audio.h | 68 +++++++- sound/soc/sof/topology.c | 44 +++-- 5 files changed, 368 insertions(+), 107 deletions(-)
Add a new op set_up_volume_table for control IPC ops. Define and set the op for IPC3.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/ipc3-control.c | 18 ++++++++++++++++++ sound/soc/sof/sof-audio.h | 6 ++++++ sound/soc/sof/topology.c | 26 +++++++++++--------------- 3 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index cde9e481f7f2..bea26e73a741 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -694,6 +694,23 @@ static int sof_ipc3_widget_kcontrol_setup(struct snd_sof_dev *sdev, return 0; }
+static int +sof_ipc3_set_up_volume_table(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], int size) +{ + int i; + + /* init the volume table */ + scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); + if (!scontrol->volume_table) + return -ENOMEM; + + /* populate the volume table */ + for (i = 0; i < size ; i++) + scontrol->volume_table[i] = vol_compute_gain(i, tlv); + + return 0; +} + const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = { .volume_put = sof_ipc3_volume_put, .volume_get = sof_ipc3_volume_get, @@ -708,4 +725,5 @@ const struct sof_ipc_tplg_control_ops tplg_ipc3_control_ops = { .bytes_ext_volatile_get = sof_ipc3_bytes_ext_volatile_get, .update = sof_ipc3_control_update, .widget_kcontrol_setup = sof_ipc3_widget_kcontrol_setup, + .set_up_volume_table = sof_ipc3_set_up_volume_table, }; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index a0af7c421fd9..e254b22ea8a9 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -39,6 +39,8 @@ */ #define VOLUME_FWL 16
+#define SOF_TLV_ITEMS 3 + struct snd_sof_widget; struct snd_sof_route; struct snd_sof_control; @@ -88,6 +90,9 @@ struct sof_ipc_tplg_control_ops { void (*update)(struct snd_sof_dev *sdev, void *ipc_control_message); /* Optional callback to setup kcontrols associated with an swidget */ int (*widget_kcontrol_setup)(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); + /* mandatory callback to set up volume table for volume kcontrols */ + int (*set_up_volume_table)(struct snd_sof_control *scontrol, int tlv[SOF_TLV_ITEMS], + int size); };
/** @@ -464,4 +469,5 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so size_t object_size, int token_instance_num); int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, struct snd_sof_pcm *spcm, int dir); +u32 vol_compute_gain(u32 value, int *tlv); #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5e959f8c4cb9..739f343010fc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -32,7 +32,6 @@ #define VOL_HALF_DB_STEP 50
/* TLV data items */ -#define TLV_ITEMS 3 #define TLV_MIN 0 #define TLV_STEP 1 #define TLV_MUTE 2 @@ -134,7 +133,7 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so return 0; }
-static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) +static inline int get_tlv_data(const int *p, int tlv[SOF_TLV_ITEMS]) { /* we only support dB scale TLV type at the moment */ if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE) @@ -224,7 +223,7 @@ static u32 vol_pow32(u32 a, int exp, u32 fwl) * Function to calculate volume gain from TLV data. * This function can only handle gain steps that are multiples of 0.5 dB */ -static u32 vol_compute_gain(u32 value, int *tlv) +u32 vol_compute_gain(u32 value, int *tlv) { int dB_gain; u32 linear_gain; @@ -263,20 +262,17 @@ static u32 vol_compute_gain(u32 value, int *tlv) * "size" specifies the number of entries in the table */ static int set_up_volume_table(struct snd_sof_control *scontrol, - int tlv[TLV_ITEMS], int size) + int tlv[SOF_TLV_ITEMS], int size) { - int j; - - /* init the volume table */ - scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); - if (!scontrol->volume_table) - return -ENOMEM; + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
- /* populate the volume table */ - for (j = 0; j < size ; j++) - scontrol->volume_table[j] = vol_compute_gain(j, tlv); + if (tplg_ops->control->set_up_volume_table) + return tplg_ops->control->set_up_volume_table(scontrol, tlv, size);
- return 0; + dev_err(scomp->dev, "Mandatory op %s not set\n", __func__); + return -EINVAL; }
struct sof_dai_types { @@ -772,7 +768,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_mixer_control *mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); - int tlv[TLV_ITEMS]; + int tlv[SOF_TLV_ITEMS]; unsigned int mask; int ret;
This is in preparation for IPC4 which requires that the route be reset before the widget is freed. For IPC3, there is nothing more to be done other than setting the route status. So it is OK to be moved before the widget is freed.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/soc/sof/sof-audio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e2ec60887568..1180d6bab33e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -34,6 +34,9 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) if (--swidget->use_count) return 0;
+ /* reset route setup status for all routes that contain this widget */ + sof_reset_route_setup_status(sdev, swidget); + /* continue to disable core even if IPC fails */ if (tplg_ops->widget_free) err = tplg_ops->widget_free(sdev, swidget); @@ -50,8 +53,6 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) err = ret; }
- /* reset route setup status for all routes that contain this widget */ - sof_reset_route_setup_status(sdev, swidget); swidget->complete = 0;
/*
For IPC3, the order of setting up the widgets associated with a PCM doesn't matter. But for IPC4, widgets must be set up from the source to the sink in order. In order to accommodate this, change the sof_widget_list_setup/free() functions to set up/free widgets starting with the source widget all the way to the sink widget for all pipelines.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Kai Vehmanen kai.vehmanen@linux.intel.com --- sound/soc/sof/sof-audio.c | 170 +++++++++++++++++++++++++++----------- sound/soc/sof/sof-audio.h | 7 ++ 2 files changed, 130 insertions(+), 47 deletions(-)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 1180d6bab33e..0bc6c3ef0cd4 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -253,29 +253,135 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, return 0; }
+/* + * free all widgets in the sink path starting from the source widget + * (DAI type for capture, AIF type for playback) + */ +static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, + int dir) +{ + struct snd_soc_dapm_path *p; + int err; + int ret = 0; + + /* free all widgets even in case of error to keep use counts balanced */ + snd_soc_dapm_widget_for_each_sink_path(widget, p) { + if (!p->walking && p->sink->dobj.private && widget->dobj.private) { + p->walking = true; + if (WIDGET_IS_AIF_OR_DAI(widget->id)) { + err = sof_widget_free(sdev, widget->dobj.private); + if (err < 0) + ret = err; + } + + err = sof_widget_free(sdev, p->sink->dobj.private); + if (err < 0) + ret = err; + + err = sof_free_widgets_in_path(sdev, p->sink, dir); + if (err < 0) + ret = err; + p->walking = false; + } + } + + return ret; +} + +/* + * set up all widgets in the sink path starting from the source widget + * (DAI type for capture, AIF type for playback). + * The error path in this function ensures that all successfully set up widgets getting freed. + */ +static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, + int dir) +{ + struct snd_soc_dapm_path *p; + int ret; + + snd_soc_dapm_widget_for_each_sink_path(widget, p) { + if (!p->walking && p->sink->dobj.private && widget->dobj.private) { + p->walking = true; + if (WIDGET_IS_AIF_OR_DAI(widget->id)) { + ret = sof_widget_setup(sdev, widget->dobj.private); + if (ret < 0) + goto out; + } + + ret = sof_widget_setup(sdev, p->sink->dobj.private); + if (ret < 0) { + if (WIDGET_IS_AIF_OR_DAI(widget->id)) + sof_widget_free(sdev, widget->dobj.private); + goto out; + } + + ret = sof_set_up_widgets_in_path(sdev, p->sink, dir); + if (ret < 0) { + if (WIDGET_IS_AIF_OR_DAI(widget->id)) + sof_widget_free(sdev, widget->dobj.private); + sof_widget_free(sdev, p->sink->dobj.private); + } +out: + p->walking = false; + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int +sof_setup_or_free_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, + bool dir, enum sof_widget_op op) +{ + struct snd_soc_dapm_widget *widget; + int ret, i; + + for_each_dapm_widgets(list, i, widget) { + /* starting widget for playback is AIF type */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && !WIDGET_IS_AIF(widget->id)) + continue; + + /* starting widget for capture is DAI type */ + if (dir == SNDRV_PCM_STREAM_CAPTURE && !WIDGET_IS_DAI(widget->id)) + continue; + + switch (op) { + case SOF_WIDGET_SETUP: + ret = sof_set_up_widgets_in_path(sdev, widget, dir); + break; + case SOF_WIDGET_FREE: + ret = sof_free_widgets_in_path(sdev, widget, dir); + break; + default: + dev_err(sdev->dev, "Invalid widget op %d\n", op); + return -EINVAL; + } + if (ret < 0) { + dev_err(sdev->dev, "Failed to %s connected widgets\n", + op == SOF_WIDGET_SETUP ? "set up" : "free"); + return ret; + } + } + + return 0; +} + int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) { const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; struct snd_soc_dapm_widget *widget; - int i, ret, num_widgets; + int i, ret;
/* nothing to set up */ if (!list) return 0;
- /* set up widgets in the list */ - for_each_dapm_widgets(list, num_widgets, widget) { - struct snd_sof_widget *swidget = widget->dobj.private; - - if (!swidget) - continue; - - /* set up the widget */ - ret = sof_widget_setup(sdev, swidget); - if (ret < 0) - goto widget_free; - } + ret = sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_SETUP); + if (ret < 0) + return ret;
/* * error in setting pipeline connections will result in route status being reset for @@ -316,18 +422,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in return 0;
widget_free: - /* free all widgets that have been set up successfully */ - for_each_dapm_widgets(list, i, widget) { - struct snd_sof_widget *swidget = widget->dobj.private; - - if (!swidget) - continue; - - if (!num_widgets--) - break; - - sof_widget_free(sdev, swidget); - } + sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_FREE);
return ret; } @@ -335,37 +430,18 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) { struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; - struct snd_soc_dapm_widget *widget; - int i, ret; - int ret1 = 0; + int ret;
/* nothing to free */ if (!list) return 0;
- /* - * Free widgets in the list. This can fail but continue freeing other widgets to keep - * use_counts balanced. - */ - for_each_dapm_widgets(list, i, widget) { - struct snd_sof_widget *swidget = widget->dobj.private; - - if (!swidget) - continue; - - /* - * free widget and its pipe_widget. Either of these can fail, but free as many as - * possible before freeing the list and returning the error. - */ - ret = sof_widget_free(sdev, swidget); - if (ret < 0) - ret1 = ret; - } + ret = sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_FREE);
snd_soc_dapm_dai_free_widgets(&list); spcm->stream[dir].list = NULL;
- return ret1; + return ret; }
/* diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index e254b22ea8a9..eb882ed7d0e4 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -29,10 +29,17 @@ #define DMA_CHAN_INVALID 0xFFFFFFFF
#define WIDGET_IS_DAI(id) ((id) == snd_soc_dapm_dai_in || (id) == snd_soc_dapm_dai_out) +#define WIDGET_IS_AIF(id) ((id) == snd_soc_dapm_aif_in || (id) == snd_soc_dapm_aif_out) +#define WIDGET_IS_AIF_OR_DAI(id) (WIDGET_IS_DAI(id) || WIDGET_IS_AIF(id))
#define SOF_DAI_CLK_INTEL_SSP_MCLK 0 #define SOF_DAI_CLK_INTEL_SSP_BCLK 1
+enum sof_widget_op { + SOF_WIDGET_FREE, + SOF_WIDGET_SETUP, +}; + /* * Volume fractional word length define to 16 sets * the volume linear gain value to use Qx.16 format
IPC4 requires the platform_params be passed when invoking sof_pcm_setup_connected_widgets(). So move the call to snd_sof_pcm_platform_hw_params() before calling sof_pcm_setup_connected_widgets(). This has no functional impact.
sof_pcm_setup_connected_widgets will be modified in the follow up patches to accept the platform params as an argument.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/pcm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 6242327e663e..2d21e531ac4f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -150,6 +150,12 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream);
+ ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params); + if (ret < 0) { + dev_err(component->dev, "platform hw params failed\n"); + return ret; + } + /* if this is a repeated hw_params without hw_free, skip setting up widgets */ if (!spcm->stream[substream->stream].list) { ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream); @@ -166,12 +172,6 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, return ret; }
- ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params); - if (ret < 0) { - dev_err(component->dev, "platform hw params failed\n"); - return ret; - } - if (pcm_ops->hw_params) { ret = pcm_ops->hw_params(component, substream, params, &platform_params); if (ret < 0)
Expose the mixer_to_ipc() and ipc_to_mixer() functions for reuse in IPC4.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/ipc3-control.c | 20 -------------------- sound/soc/sof/sof-audio.h | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/sound/soc/sof/ipc3-control.c b/sound/soc/sof/ipc3-control.c index bea26e73a741..4347adcc6543 100644 --- a/sound/soc/sof/ipc3-control.c +++ b/sound/soc/sof/ipc3-control.c @@ -90,26 +90,6 @@ static int sof_ipc3_set_get_kcontrol_data(struct snd_sof_control *scontrol, bool return iops->set_get_data(sdev, cdata, cdata->rhdr.hdr.size, set); }
-static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) -{ - if (value >= size) - return volume_map[size - 1]; - - return volume_map[value]; -} - -static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (volume_map[i] >= value) - return i; - } - - return i - 1; -} - static void snd_sof_refresh_control(struct snd_sof_control *scontrol) { struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index eb882ed7d0e4..e3cfc813975b 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -48,6 +48,26 @@ enum sof_widget_op {
#define SOF_TLV_ITEMS 3
+static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) +{ + if (value >= size) + return volume_map[size - 1]; + + return volume_map[value]; +} + +static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (volume_map[i] >= value) + return i; + } + + return i - 1; +} + struct snd_sof_widget; struct snd_sof_route; struct snd_sof_control;
IPC4 requires that the widgets be unbound in the firmware before they are freed. So add a new op in struct sof_ipc_tplg_ops that will be used to send the IPC to the firmware to unbind widgets.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/sof-audio.c | 7 ++++++- sound/soc/sof/sof-audio.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 0bc6c3ef0cd4..07576ed3c4fa 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -14,11 +14,16 @@
static void sof_reset_route_setup_status(struct snd_sof_dev *sdev, struct snd_sof_widget *widget) { + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; struct snd_sof_route *sroute;
list_for_each_entry(sroute, &sdev->route_list, list) - if (sroute->src_widget == widget || sroute->sink_widget == widget) + if (sroute->src_widget == widget || sroute->sink_widget == widget) { + if (sroute->setup && tplg_ops->route_free) + tplg_ops->route_free(sdev, sroute); + sroute->setup = false; + } }
int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index e3cfc813975b..7ca87056b106 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -146,6 +146,7 @@ struct sof_ipc_tplg_widget_ops { * initialized to 0. * @control: Pointer to the IPC-specific ops for topology kcontrol IO * @route_setup: Function pointer for setting up pipeline connections + * @route_free: Optional op for freeing pipeline connections. * @token_list: List of all tokens supported by the IPC version. The size of the token_list * array should be SOF_TOKEN_COUNT. The unused elements in the array will be * initialized to 0. @@ -163,6 +164,7 @@ struct sof_ipc_tplg_ops { const struct sof_ipc_tplg_widget_ops *widget; const struct sof_ipc_tplg_control_ops *control; int (*route_setup)(struct snd_sof_dev *sdev, struct snd_sof_route *sroute); + int (*route_free)(struct snd_sof_dev *sdev, struct snd_sof_route *sroute); const struct sof_token_info *token_list; int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol); int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
Add two new fields, instance_id and module_info to struct snd_sof_widget. instance_id for widgets will be assigned when they are set up in the DSP and reset when the widgets are freed. module_info is used to save information the firmware provides about each module in its manifest.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/sof-audio.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 7ca87056b106..4deab3ded8a5 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -330,7 +330,12 @@ struct snd_sof_widget { int complete; int use_count; /* use_count will be protected by the PCM mutex held by the core */ int core; - int id; + int id; /* id is the DAPM widget type */ + /* + * Instance ID is set dynamically when the widget gets set up in the FW. It should be + * unique for each module type across all pipelines. This will not be used in SOF_IPC. + */ + int instance_id;
/* * Flag indicating if the widget should be set up dynamically when a PCM is opened. @@ -345,6 +350,7 @@ struct snd_sof_widget { struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ struct snd_sof_widget *pipe_widget; + void *module_info;
const guid_t uuid;
sof_pcm_setup_connected_widgets() can be a static function in pcm.c. No need to declare it in the header.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/pcm.c | 5 +++-- sound/soc/sof/sof-audio.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2d21e531ac4f..095ca0d9d5ae 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -82,8 +82,9 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
-int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, - struct snd_sof_pcm *spcm, int dir) +static int +sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, + struct snd_sof_pcm *spcm, int dir) { struct snd_soc_dai *dai; int ret, j; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 4deab3ded8a5..5967d034188a 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -502,7 +502,5 @@ int get_token_uuid(void *elem, void *object, u32 offset); int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum sof_tokens token_id, struct snd_sof_tuple *tuples, int num_tuples, size_t object_size, int token_instance_num); -int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, - struct snd_sof_pcm *spcm, int dir); u32 vol_compute_gain(u32 value, int *tlv); #endif
Do not parse these tokens if they are not defined in the IPC version specific token list. In the case of IPC4 with HDA topologies for example, no DAI link specific tokens need to be added in topology.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com --- sound/soc/sof/topology.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 739f343010fc..b1fcab7ce48e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1721,14 +1721,16 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ return -ENOMEM; }
- /* parse one set of DAI link tokens */ - ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), - SOF_DAI_LINK_TOKENS, 1, slink->tuples, - num_tuples, &slink->num_tuples); - if (ret < 0) { - dev_err(scomp->dev, "failed to parse %s for dai link %s\n", - token_list[SOF_DAI_LINK_TOKENS].name, link->name); - goto err; + if (token_list[SOF_DAI_LINK_TOKENS].tokens) { + /* parse one set of DAI link tokens */ + ret = sof_copy_tuples(sdev, private->array, le32_to_cpu(private->size), + SOF_DAI_LINK_TOKENS, 1, slink->tuples, + num_tuples, &slink->num_tuples); + if (ret < 0) { + dev_err(scomp->dev, "failed to parse %s for dai link %s\n", + token_list[SOF_DAI_LINK_TOKENS].name, link->name); + goto err; + } }
/* nothing more to do if there are no DAI type-specific tokens defined */
Currently, the complete flag is used only for the snd_soc_dapm_scheduler type widgets to indicate that the pipeline has been set up. All other widgets do not need it. Add a comment to clarify its usage and set the complete flag to false only for the scheduler widget in sof_widget_free().
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com --- sound/soc/sof/sof-audio.c | 3 +-- sound/soc/sof/sof-audio.h | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 07576ed3c4fa..f7c9e5db3d9e 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -58,8 +58,6 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) err = ret; }
- swidget->complete = 0; - /* * free the scheduler widget (same as pipe_widget) associated with the current swidget. * skip for static pipelines @@ -68,6 +66,7 @@ int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) ret = sof_widget_free(sdev, swidget->pipe_widget); if (ret < 0 && !err) err = ret; + swidget->pipe_widget->complete = 0; }
if (!err) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5967d034188a..2db4eb5edcf5 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -327,6 +327,10 @@ struct snd_sof_widget { 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; int use_count; /* use_count will be protected by the PCM mutex held by the core */ int core;
In order to set up a pipeline with IPC4, the total memory usage for the pipeline needs to be calculated based on the list of connected widgets. Add a new ipc_prepare() op to struct sof_ipc_tplg_widget_ops that will be used to calculate the memory usage for each widget in the pipelines associated with a PCM and prepare the widget for getting set up in the DSP. The prepare step will be used to allocate memory for the IPC payload, assign instance ID and update the config data for the widget based on the runtime PCM params. Once prepared, the setup step is used to send the IPC to create the widget in the DSP.
Add an ipc_unprepare() op to unprepare the widget i.e free the memory allocated during prepare, free the instance ID etc. This should be invoked after the widget is freed.
A new flag "prepared" is added to struct snd_sof_widget to track the prepared status of widgets.
Also, IPC4 requires the platform_params and the runtime PCM params in order to prepare a widget for set up. So modify the signature of sof_pcm_setup_connected_widgets() and sof_widget_list_setup() to accept these as arguments.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com Reviewed-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com Reviewed-by: Péter Ujfalusi peter.ujfalusi@linux.intel.com Reviewed-by: Bard Liao yung-chuan.liao@linux.intel.com --- sound/soc/sof/pcm.c | 8 ++- sound/soc/sof/sof-audio.c | 139 +++++++++++++++++++++++++++++++++++--- sound/soc/sof/sof-audio.h | 21 +++++- 3 files changed, 154 insertions(+), 14 deletions(-)
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 095ca0d9d5ae..a76d0b5b2ad9 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -84,7 +84,8 @@ EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
static int sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_runtime *rtd, - struct snd_sof_pcm *spcm, int dir) + struct snd_sof_pcm *spcm, struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params, int dir) { struct snd_soc_dai *dai; int ret, j; @@ -103,7 +104,7 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run
spcm->stream[dir].list = list;
- ret = sof_widget_list_setup(sdev, spcm, dir); + ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir); if (ret < 0) { dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n", spcm->pcm.pcm_id, dir); @@ -159,7 +160,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
/* if this is a repeated hw_params without hw_free, skip setting up widgets */ if (!spcm->stream[substream->stream].list) { - ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream); + ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, params, &platform_params, + substream->stream); if (ret < 0) return ret; } diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index f7c9e5db3d9e..26a62b3b3c37 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -257,6 +257,79 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev, return 0; }
+static void +sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget) +{ + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + struct snd_sof_widget *swidget = widget->dobj.private; + struct snd_soc_dapm_path *p; + + if (!widget_ops[widget->id].ipc_unprepare || !swidget->prepared) + goto sink_unprepare; + + /* unprepare the source widget */ + widget_ops[widget->id].ipc_unprepare(swidget); + swidget->prepared = false; + +sink_unprepare: + /* unprepare all widgets in the sink paths */ + snd_soc_dapm_widget_for_each_sink_path(widget, p) { + if (!p->walking && p->sink->dobj.private) { + p->walking = true; + sof_unprepare_widgets_in_path(sdev, p->sink); + p->walking = false; + } + } +} + +static int +sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; + const struct sof_ipc_tplg_widget_ops *widget_ops = ipc_tplg_ops->widget; + struct snd_sof_widget *swidget = widget->dobj.private; + struct snd_soc_dapm_path *p; + int ret; + + if (!widget_ops[widget->id].ipc_prepare || swidget->prepared) + goto sink_prepare; + + /* prepare the source widget */ + ret = widget_ops[widget->id].ipc_prepare(swidget, fe_params, platform_params, + pipeline_params, dir); + if (ret < 0) { + dev_err(sdev->dev, "failed to prepare widget %s\n", widget->name); + return ret; + } + + swidget->prepared = true; + +sink_prepare: + /* prepare all widgets in the sink paths */ + snd_soc_dapm_widget_for_each_sink_path(widget, p) { + if (!p->walking && p->sink->dobj.private) { + p->walking = true; + ret = sof_prepare_widgets_in_path(sdev, p->sink, fe_params, + platform_params, pipeline_params, dir); + p->walking = false; + if (ret < 0) { + /* unprepare the source widget */ + if (!widget_ops[widget->id].ipc_unprepare && swidget->prepared) { + widget_ops[widget->id].ipc_unprepare(swidget); + swidget->prepared = false; + } + return ret; + } + } + } + + return 0; +} + /* * free all widgets in the sink path starting from the source widget * (DAI type for capture, AIF type for playback) @@ -336,11 +409,15 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d }
static int -sof_setup_or_free_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, - bool dir, enum sof_widget_op op) +sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_list *list, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, int dir, + enum sof_widget_op op) { struct snd_soc_dapm_widget *widget; - int ret, i; + char *str; + int ret = 0; + int i;
for_each_dapm_widgets(list, i, widget) { /* starting widget for playback is AIF type */ @@ -354,17 +431,38 @@ sof_setup_or_free_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm switch (op) { case SOF_WIDGET_SETUP: ret = sof_set_up_widgets_in_path(sdev, widget, dir); + str = "set up"; break; case SOF_WIDGET_FREE: ret = sof_free_widgets_in_path(sdev, widget, dir); + str = "free"; + break; + case SOF_WIDGET_PREPARE: + { + struct snd_pcm_hw_params pipeline_params; + + str = "prepare"; + /* + * When walking the list of connected widgets, the pipeline_params for each + * widget is modified by the source widget in the path. Use a local + * copy of the runtime params as the pipeline_params so that the runtime + * params does not get overwritten. + */ + memcpy(&pipeline_params, fe_params, sizeof(*fe_params)); + + ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, + platform_params, &pipeline_params, dir); + break; + } + case SOF_WIDGET_UNPREPARE: + sof_unprepare_widgets_in_path(sdev, widget); break; default: dev_err(sdev->dev, "Invalid widget op %d\n", op); return -EINVAL; } if (ret < 0) { - dev_err(sdev->dev, "Failed to %s connected widgets\n", - op == SOF_WIDGET_SETUP ? "set up" : "free"); + dev_err(sdev->dev, "Failed to %s connected widgets\n", str); return ret; } } @@ -372,7 +470,10 @@ sof_setup_or_free_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm return 0; }
-int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir) +int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + int dir) { const struct sof_ipc_tplg_ops *ipc_tplg_ops = sdev->ipc->ops->tplg; struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list; @@ -383,10 +484,24 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in if (!list) return 0;
- ret = sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_SETUP); + /* + * Prepare widgets for set up. The prepare step is used to allocate memory, assign + * instance ID and pick the widget configuration based on the runtime PCM params. + */ + ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, + dir, SOF_WIDGET_PREPARE); if (ret < 0) return ret;
+ /* Set up is used to send the IPC to the DSP to create the widget */ + ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, + dir, SOF_WIDGET_SETUP); + if (ret < 0) { + ret = sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, + dir, SOF_WIDGET_UNPREPARE); + return ret; + } + /* * error in setting pipeline connections will result in route status being reset for * routes that were successfully set up when the widgets are freed. @@ -426,7 +541,9 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, in return 0;
widget_free: - sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_FREE); + sof_walk_widgets_in_order(sdev, list, fe_params, platform_params, dir, + SOF_WIDGET_FREE); + sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
return ret; } @@ -440,7 +557,11 @@ int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int if (!list) return 0;
- ret = sof_setup_or_free_widgets_in_order(sdev, list, dir, SOF_WIDGET_FREE); + /* send IPC to free widget in the DSP */ + ret = sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_FREE); + + /* unprepare the widget */ + sof_walk_widgets_in_order(sdev, list, NULL, NULL, dir, SOF_WIDGET_UNPREPARE);
snd_soc_dapm_dai_free_widgets(&list); spcm->stream[dir].list = NULL; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 2db4eb5edcf5..195248d11aaa 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -36,8 +36,10 @@ #define SOF_DAI_CLK_INTEL_SSP_BCLK 1
enum sof_widget_op { - SOF_WIDGET_FREE, + SOF_WIDGET_PREPARE, SOF_WIDGET_SETUP, + SOF_WIDGET_FREE, + SOF_WIDGET_UNPREPARE, };
/* @@ -129,6 +131,8 @@ struct sof_ipc_tplg_control_ops { * @token_list: List of token ID's that should be parsed for the widget * @token_list_size: number of elements in token_list * @bind_event: Function pointer for binding events to the widget + * @ipc_prepare: Optional op for preparing a widget for set up + * @ipc_unprepare: Optional op for unpreparing a widget */ struct sof_ipc_tplg_widget_ops { int (*ipc_setup)(struct snd_sof_widget *swidget); @@ -137,6 +141,11 @@ struct sof_ipc_tplg_widget_ops { int token_list_size; int (*bind_event)(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, u16 event_type); + int (*ipc_prepare)(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *source_params, int dir); + void (*ipc_unprepare)(struct snd_sof_widget *swidget); };
/** @@ -332,6 +341,11 @@ struct snd_sof_widget { * 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. + */ + bool prepared; int use_count; /* use_count will be protected by the PCM mutex held by the core */ int core; int id; /* id is the DAPM widget type */ @@ -492,7 +506,10 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc struct snd_soc_dapm_widget *wsink);
/* PCM */ -int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); +int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + int dir); int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm);
On Tue, 26 Apr 2022 10:17:32 -0700, Ranjani Sridharan wrote:
This series includes last few remaining miscellaneous patches to prepare for the introduction of new IPC version, IPC4, in the SOF driver. The changes include new IPC ops for topology parsing to set up the volume table, prepare the widgets for set up and free the routes. The remaining patches introduce new fields in the existing data structures for use in IPC4 and align the flows for widget/route set up so that they are common for both IPC3 and IPC4.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[01/11] ASoC: SOF: Add a new op to set up volume table commit: 48d2a1ceae03610a431535aca9106eab4201b191 [02/11] ASoC: SOF: sof-audio: reset route status before freeing widget commit: 33a3facdf8ccf1b777ef0c39841425ca8d8d4a40 [03/11] ASoC: SOF: sof-audio: Set up widgets from source to sink commit: 5da0590a090b096279227cf2b044b1ef9b9c6c1b [04/11] ASoC: SOF: pcm: Move the call to snd_sof_pcm_platform_hw_params() commit: f0d31dbb3fc44ac9cb0d9991cc0a629c88e80ac8 [05/11] ASoC: SOF: expose a couple of functions commit: 7b3a5be546a131f806fa015d1c78987daf1eb5c9 [06/11] ASoC: SOF: Add a route_free op in struct sof_ipc_tplg_ops commit: d77d7795547ae8e2ed23d1ce835b539ee1d794bb [07/11] ASoC: SOF: Add two new fields to struct snd_sof_widget commit: 36cbc9df3faca01500480acdda016222663da761 [08/11] ASoC: SOF: pcm: remove unnecessary function declaration commit: f18ad9caa0dfeb12cb386777b1130c5fba9a0079 [09/11] ASoC: SOF: topology: Skip parsing DAI link tokens if not needed commit: a5ba725e9dc928832ba97a4418e36fef8d0244c6 [10/11] ASoC: SOF: clarify use of widget complete flag commit: 463a809ba8efa127484d16ff588e3bcdb63fe41e [11/11] ASoC: SOF: Add a prepare op to IPC topology widget ops commit: 66344c6d92113e605d8212e79b1219406893ee05
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Ranjani Sridharan