On 21/03/2023 11:26, Peter Ujfalusi wrote: > From: Jyri Sarha <jyri.sarha@xxxxxxxxx> > > Add logic for setting up and tearing down chained DMA connections. > > Since pipelines are not used, all the logic to set the pipeline states > can be bypassed, with only the DMA programming sequences remaining. In > addition the same format needs to be used for host- and link-DMA, > without the usual fixup to use the S32_LE format on the link. > > Note however that for convenience and compatibility with existing > definitions, the topology relies on the concept of pipelines with a > 'USE_CHAIN_DMA' token indicating that all the logic shall be bypassed. > > Unlike 'normal' ALSA sequences, the chain DMA is not programmed in > hw_params/hw_free. The IPC message to set-up and tear-down chained DMA > are sent in sof_ipc4_trigger_pipelines(), but the contents prepared > earlier. > > Chained DMA is only supported by the Intel HDA DAI for now, and only > S16_LE and S32_LE formats are supported for now. > > Signed-off-by: Jyri Sarha <jyri.sarha@xxxxxxxxx> > Reviewed-by: Rander Wang <rander.wang@xxxxxxxxx> > Signed-off-by: Peter Ujfalusi <peter.ujfalusi@xxxxxxxxxxxxxxx> > --- > include/uapi/sound/sof/tokens.h | 1 + > sound/soc/sof/intel/hda-dai-ops.c | 18 ++++- > sound/soc/sof/ipc4-pcm.c | 122 +++++++++++++++++++++++++++++- > sound/soc/sof/ipc4-topology.c | 120 ++++++++++++++++++++++++++++- > sound/soc/sof/ipc4-topology.h | 2 + > 5 files changed, 255 insertions(+), 8 deletions(-) > > diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h > index bd02842124f9..bbc37877aaff 100644 > --- a/include/uapi/sound/sof/tokens.h > +++ b/include/uapi/sound/sof/tokens.h > @@ -54,6 +54,7 @@ > #define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206 > #define SOF_TKN_SCHED_LP_MODE 207 > #define SOF_TKN_SCHED_MEM_USAGE 208 > +#define SOF_TKN_SCHED_USE_CHAIN_DMA 209 > > /* volume */ > #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 > diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c > index be109f33715f..de48f13259f1 100644 > --- a/sound/soc/sof/intel/hda-dai-ops.c > +++ b/sound/soc/sof/intel/hda-dai-ops.c > @@ -277,6 +277,15 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = { > .post_trigger = hda_ipc4_post_trigger > }; > > +static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = { > + .get_hext_stream = hda_get_hext_stream, > + .assign_hext_stream = hda_assign_hext_stream, > + .release_hext_stream = hda_release_hext_stream, > + .setup_hext_stream = hda_setup_hext_stream, > + .reset_hext_stream = hda_reset_hext_stream, > + .trigger = hda_trigger, > +}; > + > static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai, > struct snd_pcm_substream *substream, int cmd) > { > @@ -331,8 +340,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg > { > struct sof_ipc4_copier *ipc4_copier = sdai->private; > > - if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) > + if (ipc4_copier->dai_type == SOF_DAI_INTEL_HDA) { > + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; > + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; > + > + if (pipeline->use_chain_dma) > + return &hda_ipc4_chain_dma_ops; > + > return &hda_ipc4_dma_ops; > + } > break; > } > default: > diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c > index 4598057b7f28..db64200ba1e5 100644 > --- a/sound/soc/sof/ipc4-pcm.c > +++ b/sound/soc/sof/ipc4-pcm.c > @@ -193,6 +193,88 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, > * prepare ioctl before the START trigger. > */ > > +/* > + * Chained DMA is a special case where there is no processing on > + * DSP. The samples are just moved over by host side DMA to a single > + * buffer on DSP and directly from there to link DMA. However, the > + * model on SOF driver has two notional pipelines, one at host DAI, > + * and another at link DAI. They both shall have the use_chain_dma > + * attribute. > + */ > + > +static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, > + struct snd_sof_pcm_stream_pipeline_list *pipeline_list, > + int state, int cmd) > +{ > + bool allocate, enable, set_fifo_size; > + struct sof_ipc4_msg msg = {{ 0 }}; > + int i; > + > + switch (state) { > + case SOF_IPC4_PIPE_RUNNING: /* Allocate and start chained dma */ > + allocate = true; > + enable = true; > + /* > + * SOF assumes creation of a new stream from the presence of fifo_size > + * in the message, so we must leave it out in pause release case. > + */ > + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) > + set_fifo_size = false; > + else > + set_fifo_size = true; > + break; > + case SOF_IPC4_PIPE_PAUSED: /* Disable chained DMA. */ > + allocate = true; > + enable = false; > + set_fifo_size = false; > + break; > + case SOF_IPC4_PIPE_RESET: /* Disable and free chained DMA. */ > + allocate = false; > + enable = false; > + set_fifo_size = false; > + break; > + default: > + dev_err(sdev->dev, "Unexpected state %d", state); > + return -EINVAL; > + } > + > + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA); > + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); > + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); > + > + /* > + * To set-up the DMA chain, the host DMA ID and SCS setting > + * are retrieved from the host pipeline configuration. Likewise > + * the link DMA ID and fifo_size are retrieved from the link > + * pipeline configuration. > + */ > + for (i = 0; i < pipeline_list->count; i++) { > + struct snd_sof_pipeline *spipe = pipeline_list->pipelines[i]; > + struct snd_sof_widget *pipe_widget = spipe->pipe_widget; > + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; > + > + if (!pipeline->use_chain_dma) { > + dev_err(sdev->dev, > + "All pipelines in chained DMA stream should have use_chain_dma attribute set."); > + return -EINVAL; > + } > + > + msg.primary |= pipeline->msg.primary; > + > + /* Add fifo_size (actually DMA buffer size) field to the message */ > + if (set_fifo_size) > + msg.extension |= pipeline->msg.extension; > + } > + > + if (allocate) > + msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK; > + > + if (enable) > + msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK; > + > + return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); > +} > + > static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, > struct snd_pcm_substream *substream, int state, int cmd) > { > @@ -201,6 +283,8 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, > struct snd_sof_pcm_stream_pipeline_list *pipeline_list; > struct sof_ipc4_fw_data *ipc4_data = sdev->private; > struct ipc4_pipeline_set_state_data *trigger_list; > + struct snd_sof_widget *pipe_widget; > + struct sof_ipc4_pipeline *pipeline; > struct snd_sof_pipeline *spipe; > struct snd_sof_pcm *spcm; > int ret; > @@ -218,6 +302,17 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, > if (!pipeline_list->pipelines || !pipeline_list->count) > return 0; > > + spipe = pipeline_list->pipelines[0]; > + pipe_widget = spipe->pipe_widget; > + pipeline = pipe_widget->private; > + > + /* > + * If use_chain_dma attribute is set we proceed to chained DMA > + * trigger function that handles the rest for the substream. > + */ > + if (pipeline->use_chain_dma) > + return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd); > + > /* allocate memory for the pipeline data */ > trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), > GFP_KERNEL); > @@ -422,8 +517,10 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, > struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); > struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); > struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); > + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); > struct sof_ipc4_copier *ipc4_copier; > - int ret; > + bool use_chain_dma = false; > + int dir; > > if (!dai) { > dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, > @@ -438,9 +535,26 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, > return -EINVAL; > } > > - ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); > - if (ret) > - return ret; > + for_each_pcm_streams(dir) { > + struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, dir); > + > + if (w) { > + struct snd_sof_widget *swidget = w->dobj.private; > + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; > + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; > + > + if (pipeline->use_chain_dma) > + use_chain_dma = true; > + } > + } > + > + /* Chain DMA does not use copiers, so no fixup needed */ > + if (!use_chain_dma) { > + int ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); > + > + if (ret) > + return ret; > + } > > switch (ipc4_copier->dai_type) { > case SOF_DAI_INTEL_SSP: > diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c > index 3a4a3267017b..f1e1aed94da4 100644 > --- a/sound/soc/sof/ipc4-topology.c > +++ b/sound/soc/sof/ipc4-topology.c > @@ -19,6 +19,7 @@ > > #define SOF_IPC4_GAIN_PARAM_ID 0 > #define SOF_IPC4_TPLG_ABI_SIZE 6 > +#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2 > > static DEFINE_IDA(alh_group_ida); > static DEFINE_IDA(pipeline_ida); > @@ -26,6 +27,8 @@ static DEFINE_IDA(pipeline_ida); > static const struct sof_topology_token ipc4_sched_tokens[] = { > {SOF_TKN_SCHED_LP_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, > offsetof(struct sof_ipc4_pipeline, lp_mode)}, > + {SOF_TKN_SCHED_USE_CHAIN_DMA, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, > + offsetof(struct sof_ipc4_pipeline, use_chain_dma)}, > {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, > offsetof(struct sof_ipc4_pipeline, core_id)}, > }; > @@ -475,6 +478,8 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) > struct snd_soc_component *scomp = swidget->scomp; > struct snd_sof_dai *dai = swidget->private; > struct sof_ipc4_copier *ipc4_copier; > + struct snd_sof_widget *pipe_widget; > + struct sof_ipc4_pipeline *pipeline; > int node_type = 0; > int ret; > > @@ -512,6 +517,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) > > ipc4_copier->data.gtw_cfg.node_id = SOF_IPC4_NODE_TYPE(node_type); > > + pipe_widget = swidget->spipe->pipe_widget; > + pipeline = pipe_widget->private; > + if (pipeline->use_chain_dma && ipc4_copier->dai_type != SOF_DAI_INTEL_HDA) { > + dev_err(scomp->dev, > + "Bad DAI type '%d', Chained DMA is only supported by HDA DAIs (%d).\n", > + ipc4_copier->dai_type, SOF_DAI_INTEL_HDA); > + ret = -ENODEV; > + goto free_available_fmt; > + } > + > switch (ipc4_copier->dai_type) { > case SOF_DAI_INTEL_ALH: > { > @@ -643,6 +658,12 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget) > > swidget->core = pipeline->core_id; > > + if (pipeline->use_chain_dma) { > + dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name); > + swidget->private = pipeline; > + return 0; > + } > + > /* parse one set of pipeline tokens */ > ret = sof_update_ipc_object(scomp, swidget, SOF_PIPELINE_TOKENS, swidget->tuples, > swidget->num_tuples, sizeof(*swidget), 1); > @@ -1103,11 +1124,21 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) > pipeline->mem_usage = 0; > > if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) { > + if (pipeline->use_chain_dma) { > + pipeline->msg.primary = 0; > + pipeline->msg.extension = 0; > + } > ipc4_copier = swidget->private; > } else if (WIDGET_IS_DAI(swidget->id)) { > struct snd_sof_dai *dai = swidget->private; > > ipc4_copier = dai->private; > + > + if (pipeline->use_chain_dma) { > + pipeline->msg.primary = 0; > + pipeline->msg.extension = 0; > + } > + > if (ipc4_copier->dai_type == SOF_DAI_INTEL_ALH) { > struct sof_ipc4_copier_data *copier_data = &ipc4_copier->data; > struct sof_ipc4_alh_configuration_blob *blob; > @@ -1344,13 +1375,44 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, > return ret; > } > > - pipe_widget = swidget->spipe->pipe_widget; > - pipeline = pipe_widget->private; > ipc4_copier = (struct sof_ipc4_copier *)swidget->private; > gtw_attr = ipc4_copier->gtw_attr; > copier_data = &ipc4_copier->data; > available_fmt = &ipc4_copier->available_fmt; > > + pipe_widget = swidget->spipe->pipe_widget; > + pipeline = pipe_widget->private; > + > + if (pipeline->use_chain_dma) { > + u32 host_dma_id; > + u32 fifo_size; > + > + host_dma_id = platform_params->stream_tag - 1; > + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(host_dma_id); > + > + /* Set SCS bit for S16_LE format only */ > + if (params_format(fe_params) == SNDRV_PCM_FORMAT_S16_LE) > + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_SCS_MASK; > + > + /* > + * Despite its name the bitfield 'fifo_size' is used to define DMA buffer > + * size. The expression calculates 2ms buffer size. > + */ > + fifo_size = DIV_ROUND_UP((SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * > + params_rate(fe_params) * > + params_channels(fe_params) * > + params_physical_width(fe_params)), 8000); > + pipeline->msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(fifo_size); > + > + /* > + * Chain DMA does not support stream timestamping, set node_id to invalid > + * to skip the code in sof_ipc4_get_stream_start_offset(). > + */ > + copier_data->gtw_cfg.node_id = SOF_IPC4_INVALID_NODE_ID; > + > + return 0; > + } > + > /* > * Use the input_pin_fmts to match pcm params for playback and the output_pin_fmts > * for capture. > @@ -1375,6 +1437,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, > case snd_soc_dapm_dai_in: > case snd_soc_dapm_dai_out: > { > + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; > + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; > + > + if (pipeline->use_chain_dma) > + return 0; > + > dai = swidget->private; > > ipc4_copier = (struct sof_ipc4_copier *)dai->private; > @@ -1921,6 +1989,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget > case snd_soc_dapm_scheduler: > pipeline = swidget->private; > > + if (pipeline->use_chain_dma) > + return 0; > + > dev_dbg(sdev->dev, "pipeline: %d memory pages: %d\n", swidget->pipeline_id, > pipeline->mem_usage); > > @@ -1943,6 +2014,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget > { > struct sof_ipc4_copier *ipc4_copier = swidget->private; > > + pipeline = pipe_widget->private; > + if (pipeline->use_chain_dma) > + return 0; > + > ipc_size = ipc4_copier->ipc_config_size; > ipc_data = ipc4_copier->ipc_config_data; > > @@ -1955,6 +2030,10 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget > struct snd_sof_dai *dai = swidget->private; > struct sof_ipc4_copier *ipc4_copier = dai->private; > > + pipeline = pipe_widget->private; > + if (pipeline->use_chain_dma) > + return 0; > + > ipc_size = ipc4_copier->ipc_config_size; > ipc_data = ipc4_copier->ipc_config_data; > > @@ -2066,6 +2145,9 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget > struct sof_ipc4_msg msg = {{ 0 }}; > u32 header; > > + if (pipeline->use_chain_dma) > + return 0; there should be a mutex_unlock(&ipc4_data->pipeline_state_mutex); before the return. I will send a v2 asap. > + > header = SOF_IPC4_GLB_PIPE_INSTANCE_ID(swidget->instance_id); > header |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_DELETE_PIPELINE); > header |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); > @@ -2082,7 +2164,11 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget > pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; > ida_free(&pipeline_ida, swidget->instance_id); > } else { > - ida_free(&fw_module->m_ida, swidget->instance_id); > + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; > + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; > + > + if (!pipeline->use_chain_dma) > + ida_free(&fw_module->m_ida, swidget->instance_id); > } > > mutex_unlock(&ipc4_data->pipeline_state_mutex); > @@ -2234,12 +2320,27 @@ static int sof_ipc4_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route * > { > struct snd_sof_widget *src_widget = sroute->src_widget; > struct snd_sof_widget *sink_widget = sroute->sink_widget; > + struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; > + struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; > struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; > struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; > + struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; > + struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; > struct sof_ipc4_msg msg = {{ 0 }}; > u32 header, extension; > int ret; > > + /* no route set up if chain DMA is used */ > + if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) { > + if (!src_pipeline->use_chain_dma || !sink_pipeline->use_chain_dma) { > + dev_err(sdev->dev, > + "use_chain_dma must be set for both src %s and sink %s pipelines\n", > + src_widget->widget->name, sink_widget->widget->name); > + return -EINVAL; > + } > + return 0; > + } > + > sroute->src_queue_id = sof_ipc4_get_queue_id(src_widget, sink_widget, > SOF_PIN_TYPE_OUTPUT); > if (sroute->src_queue_id < 0) { > @@ -2310,9 +2411,17 @@ static int sof_ipc4_route_free(struct snd_sof_dev *sdev, struct snd_sof_route *s > struct sof_ipc4_fw_module *src_fw_module = src_widget->module_info; > struct sof_ipc4_fw_module *sink_fw_module = sink_widget->module_info; > struct sof_ipc4_msg msg = {{ 0 }}; > + struct snd_sof_widget *src_pipe_widget = src_widget->spipe->pipe_widget; > + struct snd_sof_widget *sink_pipe_widget = sink_widget->spipe->pipe_widget; > + struct sof_ipc4_pipeline *src_pipeline = src_pipe_widget->private; > + struct sof_ipc4_pipeline *sink_pipeline = sink_pipe_widget->private; > u32 header, extension; > int ret = 0; > > + /* no route is set up if chain DMA is used */ > + if (src_pipeline->use_chain_dma || sink_pipeline->use_chain_dma) > + return 0; > + > dev_dbg(sdev->dev, "unbind modules %s:%d -> %s:%d\n", > src_widget->widget->name, sroute->src_queue_id, > sink_widget->widget->name, sroute->dst_queue_id); > @@ -2374,6 +2483,11 @@ static int sof_ipc4_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * > > switch (ipc4_copier->dai_type) { > case SOF_DAI_INTEL_HDA: > + if (pipeline->use_chain_dma) { > + pipeline->msg.primary &= ~SOF_IPC4_GLB_CHAIN_DMA_LINK_ID_MASK; > + pipeline->msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(data->dai_data); > + break; > + } > gtw_attr = ipc4_copier->gtw_attr; > gtw_attr->lp_buffer_alloc = pipeline->lp_mode; > pipeline->skip_during_fe_trigger = true; > diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h > index 015027b23588..cf007282867b 100644 > --- a/sound/soc/sof/ipc4-topology.h > +++ b/sound/soc/sof/ipc4-topology.h > @@ -126,6 +126,7 @@ struct sof_ipc4_copier_config_set_sink_format { > * @mem_usage: Memory usage > * @core_id: Target core for the pipeline > * @state: Pipeline state > + * @use_chain_dma: flag to indicate if the firmware shall use chained DMA > * @msg: message structure for pipeline > * @skip_during_fe_trigger: skip triggering this pipeline during the FE DAI trigger > */ > @@ -135,6 +136,7 @@ struct sof_ipc4_pipeline { > uint32_t mem_usage; > uint32_t core_id; > int state; > + bool use_chain_dma; > struct sof_ipc4_msg msg; > bool skip_during_fe_trigger; > }; -- Péter