From e7b2ef74eb8040dd3aaff4157e4108b540bbdf64 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 31 Jan 2024 20:30:20 +0200 Subject: [PATCH] [DNM] ASoC: SOF: ipc4: stop host DMA for chain DMA pause Unlike normal pipelines, chain-dma PCM DMA is stopped when PCM is put on pause. If host doesn't stop the DMA, this will trigger errors on FW. WIP implementation, this is a crude way to pass the chain-dma usage flag from IPC4 specific code, via generic PCM code to HDA host DMA handling. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda-pcm.c | 12 +++++++++++- sound/soc/sof/intel/hda-probes.c | 2 +- sound/soc/sof/intel/hda-stream.c | 7 ++++--- sound/soc/sof/intel/hda-trace.c | 2 +- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ipc4-pcm.c | 16 ++++++++++++++++ sound/soc/sof/pcm.c | 8 +++++--- sound/soc/sof/sof-audio.h | 1 + 9 files changed, 41 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index df668806a8c4cf..5f01f337ac91e2 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -249,7 +249,7 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int hstream->running = true; return 0; default: - return hda_dsp_stream_trigger(sdev, hext_stream, cmd); + return hda_dsp_stream_trigger(sdev, hext_stream, cmd, false); } } EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 9847d749d09f45..bc02a49ee06b8b 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -172,8 +172,18 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_component *scomp = sdev->component; + struct snd_sof_pcm *spcm; + + spcm = snd_sof_find_spcm_dai(scomp, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } - return hda_dsp_stream_trigger(sdev, hext_stream, cmd); + return hda_dsp_stream_trigger(sdev, hext_stream, cmd, spcm->use_chain); } EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c index be0fd56ddb276f..e1ea31db54c98b 100644 --- a/sound/soc/sof/intel/hda-probes.c +++ b/sound/soc/sof/intel/hda-probes.c @@ -107,7 +107,7 @@ static int hda_probes_compr_trigger(struct sof_client_dev *cdev, struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); - return hda_dsp_stream_trigger(sdev, hext_stream, cmd); + return hda_dsp_stream_trigger(sdev, hext_stream, cmd, false); } static int hda_probes_compr_pointer(struct sof_client_dev *cdev, diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 7822139f07889d..b4dcc9483b62b9 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -331,7 +331,7 @@ static int hda_dsp_stream_reset(struct snd_sof_dev *sdev, struct hdac_stream *hs } int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, - struct hdac_ext_stream *hext_stream, int cmd) + struct hdac_ext_stream *hext_stream, int cmd, bool use_chain) { struct hdac_stream *hstream = &hext_stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); @@ -342,7 +342,7 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, /* cmd must be for audio stream */ switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!sdev->dspless_mode_selected) + if (!use_chain && !sdev->dspless_mode_selected) break; fallthrough; case SNDRV_PCM_TRIGGER_START: @@ -372,11 +372,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (!sdev->dspless_mode_selected) + if ((!use_chain && !sdev->dspless_mode_selected)) break; fallthrough; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: + dev_dbg(sdev->dev, "hda_stream_trigger stop cmd %d\n", cmd); snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_SD_CTL_DMA_START | diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index f0d959ba50c424..7fe5b30733e24d 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -93,6 +93,6 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd); + return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd, false); } EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0156d866e3b225..ff749c4c731325 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -656,7 +656,7 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct snd_pcm_hw_params *params); int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, - struct hdac_ext_stream *hext_stream, int cmd); + struct hdac_ext_stream *hext_stream, int cmd, bool use_chain); irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 0f332c8cdbe6af..73c9312c0a0d2f 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -807,13 +807,29 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_sof_pcm_stream_pipeline_list *pipeline_list; struct sof_ipc4_timestamp_info *time_info; + struct snd_sof_widget *pipe_widget; + struct sof_ipc4_pipeline *pipeline; + struct snd_sof_pipeline *spipe; struct snd_sof_pcm *spcm; spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; + pipeline_list = &spcm->stream[substream->stream].pipeline_list; + + /* nothing to trigger if the list is empty */ + if (pipeline_list->pipelines && pipeline_list->count) { + spipe = pipeline_list->pipelines[0]; + pipe_widget = spipe->pipe_widget; + pipeline = pipe_widget->private; + + if (pipeline->use_chain_dma) + spcm->use_chain = true; + } + time_info = spcm->stream[substream->stream].private; /* delay calculation is not supported by current fw_reg ABI */ if (!time_info) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 33d576b1764783..d902009034e4da 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -304,7 +304,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ipc_first = true; + if (!spcm->use_chain) + ipc_first = true; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (pcm_ops && pcm_ops->ipc_first_on_start) @@ -343,7 +344,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, fallthrough; case SNDRV_PCM_TRIGGER_STOP: - ipc_first = true; + if (!spcm->use_chain) + ipc_first = true; if (pcm_ops && pcm_ops->reset_hw_params_during_stop) reset_hw_params = true; break; @@ -369,7 +371,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: /* invoke platform trigger to stop DMA even if pcm_ops isn't set or if it failed */ - if (!pcm_ops || !pcm_ops->platform_stop_during_hw_free) + if (spcm->use_chain || !pcm_ops || !pcm_ops->platform_stop_during_hw_free) snd_sof_pcm_platform_trigger(sdev, substream, cmd); break; default: diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 9ea2ac5adac79e..3643d87ff34136 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -341,6 +341,7 @@ struct snd_sof_pcm { struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; bool prepared[2]; /* PCM_PARAMS set successfully */ + bool use_chain; }; struct snd_sof_led_control {