ASoC: SOF: Intel: hda: release link DMA for paused streams during suspend
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Wed, 12 Jun 2019 17:23:38 +0000 (12:23 -0500)
committerMark Brown <broonie@kernel.org>
Mon, 17 Jun 2019 12:43:48 +0000 (13:43 +0100)
Paused streams do not get suspended when the system enters S3.
So, clear and release link DMA channel for such streams in the
hda_dsp_set_hw_params_upon_resume() callback. Also, invalidate
the link DMA channel in the DAI config before restoring the
dai config upon resume. Also, modify the signature for the
set_hw_params_upon_resume() op to return an int.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ops.h
sound/soc/sof/pm.c
sound/soc/sof/sof-priv.h

index 5b73115a0b787352c443cbcf37db532691f58652..c6eea3079ab747f7e1073d8b01b2943d2b9e7529 100644 (file)
@@ -454,18 +454,45 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state)
        return 0;
 }
 
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
        struct hdac_bus *bus = sof_to_bus(sdev);
        struct sof_intel_hda_stream *hda_stream;
        struct hdac_ext_stream *stream;
        struct hdac_stream *s;
 
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct snd_soc_pcm_runtime *rtd;
+       struct hdac_ext_link *link;
+       const char *name;
+       int stream_tag;
+#endif
+
        /* set internal flag for BE */
        list_for_each_entry(s, &bus->stream_list, list) {
                stream = stream_to_hdac_ext_stream(s);
                hda_stream = container_of(stream, struct sof_intel_hda_stream,
                                          hda_stream);
                hda_stream->hw_params_upon_resume = 1;
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+               /*
+                * clear and release stream. This should already be taken care
+                * for running streams when the SUSPEND trigger is called.
+                * But paused streams do not get suspended, so this needs to be
+                * done explicitly during suspend.
+                */
+               if (stream->link_substream) {
+                       rtd = snd_pcm_substream_chip(stream->link_substream);
+                       name = rtd->codec_dai->component->name;
+                       link = snd_hdac_ext_bus_get_link(bus, name);
+                       if (!link)
+                               return -EINVAL;
+                       stream_tag = hdac_stream(stream)->stream_tag;
+                       snd_hdac_ext_link_clear_stream_id(link, stream_tag);
+                       snd_hdac_ext_stream_release(stream,
+                                                   HDAC_EXT_STREAM_TYPE_LINK);
+               }
+#endif
        }
+       return 0;
 }
index 2862b4b3b07c6a916f6a2752943e94c39104c662..327621ef5cf3a1e927e051e75273c592e9b8abb4 100644 (file)
@@ -451,7 +451,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state);
 int hda_dsp_resume(struct snd_sof_dev *sdev);
 int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state);
 int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
-void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
+int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
 void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
 void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
 void hda_ipc_dump(struct snd_sof_dev *sdev);
index 80fc3b374c2b3bd27aa2198813c8c008136f78b0..a2329735375096bd3f902b10313fdf36cae95096 100644 (file)
@@ -134,10 +134,11 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev,
        return 0;
 }
 
-static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
        if (sof_ops(sdev)->set_hw_params_upon_resume)
-               sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+               return sof_ops(sdev)->set_hw_params_upon_resume(sdev);
+       return 0;
 }
 
 static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq)
index b7843f02ef671ec9b9952c5da30caf582f9f8d7d..8eeb3a1029f24d168b779badb35aecac1a45cd5a 100644 (file)
@@ -153,6 +153,15 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev)
                        continue;
                }
 
+               /*
+                * The link DMA channel would be invalidated for running
+                * streams but not for streams that were in the PAUSED
+                * state during suspend. So invalidate it here before setting
+                * the dai config in the DSP.
+                */
+               if (config->type == SOF_DAI_INTEL_HDA)
+                       config->hda.link_dma_ch = DMA_CHAN_INVALID;
+
                ret = sof_ipc_tx_message(sdev->ipc,
                                         config->hdr.cmd, config,
                                         config->hdr.size,
@@ -204,7 +213,7 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd)
                                 sizeof(pm_ctx), &reply, sizeof(reply));
 }
 
-static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
+static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
 {
        struct snd_pcm_substream *substream;
        struct snd_sof_pcm *spcm;
@@ -229,7 +238,7 @@ static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
        }
 
        /* set internal flag for BE */
-       snd_sof_dsp_hw_params_upon_resume(sdev);
+       return snd_sof_dsp_hw_params_upon_resume(sdev);
 }
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
@@ -333,8 +342,15 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
        snd_sof_release_trace(sdev);
 
        /* set restore_stream for all streams during system suspend */
-       if (!runtime_suspend)
-               sof_set_hw_params_upon_resume(sdev);
+       if (!runtime_suspend) {
+               ret = sof_set_hw_params_upon_resume(sdev);
+               if (ret < 0) {
+                       dev_err(sdev->dev,
+                               "error: setting hw_params flag during suspend %d\n",
+                               ret);
+                       return ret;
+               }
+       }
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
        /* cache debugfs contents during runtime suspend */
index b80d93e5df2f9dc704ab47e16c71f819a6d2e3f8..cf1b047f8cb66b5ca4b02c39cd562839fa5cca0b 100644 (file)
@@ -172,7 +172,7 @@ struct snd_sof_dsp_ops {
        int (*runtime_suspend)(struct snd_sof_dev *sof_dev,
                               int state); /* optional */
        int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */
-       void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
+       int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */
 
        /* DSP clocking */
        int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */