ASoC: soc-pcm: share DPCM BE DAI stop operation
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tue, 9 Mar 2021 01:08:17 +0000 (10:08 +0900)
committerMark Brown <broonie@kernel.org>
Fri, 12 Mar 2021 14:26:32 +0000 (14:26 +0000)
soc-pcm has very similar but different DPCM BE DAI stop operation at
1) dpcm_be_dai_startup() error case rollback
2) dpcm_be_dai_startup_unwind()
3) dpcm_be_dai_shutdown()

The differences are
1) for rollback
2) Doesn't check by snd_soc_dpcm_be_can_update() (Is this bug ?)
3) Do soc_pcm_hw_free() if it was not !OPENed and !HW_FREEed,
   and call soc_pcm_close().

We can share same code by
1) hw_free is not needed. Needs last dpcm as rollback.
2) hw_free is not needed.
3) hw_free is     needed.

This patch adds new dpcm_be_dai_stop() and share these 3.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a6rduoam.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/soc-dpcm.h
sound/soc/soc-compress.c
sound/soc/soc-pcm.c

index 0f6c50b..d76cb1e 100644 (file)
@@ -149,7 +149,8 @@ void dpcm_path_put(struct snd_soc_dapm_widget_list **list);
 int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
        int stream, struct snd_soc_dapm_widget_list **list, int new);
 int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
-int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream);
+void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
+                     int do_hw_free, struct snd_soc_dpcm *last);
 void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
 void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream);
 int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
@@ -159,4 +160,9 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
 int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
        int event);
 
+#define dpcm_be_dai_startup_rollback(fe, stream, last) \
+                                               dpcm_be_dai_stop(fe, stream, 0, last)
+#define dpcm_be_dai_startup_unwind(fe, stream) dpcm_be_dai_stop(fe, stream, 0, NULL)
+#define dpcm_be_dai_shutdown(fe, stream)       dpcm_be_dai_stop(fe, stream, 1, NULL)
+
 #endif
index 246a5e3..89445ba 100644 (file)
@@ -189,7 +189,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
        if (ret < 0)
                dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret);
 
-       ret = dpcm_be_dai_shutdown(fe, stream);
+       dpcm_be_dai_shutdown(fe, stream);
 
        /* mark FE's links ready to prune */
        for_each_dpcm_be(fe, stream, dpcm)
index 0ae386f..a27385a 100644 (file)
@@ -1417,18 +1417,24 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
        spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
 }
 
-static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
-       int stream)
+void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
+                     int do_hw_free, struct snd_soc_dpcm *last)
 {
        struct snd_soc_dpcm *dpcm;
 
        /* disable any enabled and non active backends */
        for_each_dpcm_be(fe, stream, dpcm) {
-
                struct snd_soc_pcm_runtime *be = dpcm->be;
                struct snd_pcm_substream *be_substream =
                        snd_soc_dpcm_get_substream(be, stream);
 
+               if (dpcm == last)
+                       return;
+
+               /* is this op for this BE ? */
+               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+                       continue;
+
                if (be->dpcm[stream].users == 0) {
                        dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
                                stream ? "capture" : "playback",
@@ -1439,8 +1445,15 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
                if (--be->dpcm[stream].users != 0)
                        continue;
 
-               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
-                       continue;
+               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) {
+                       if (!do_hw_free)
+                               continue;
+
+                       if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) {
+                               soc_pcm_hw_free(be_substream);
+                               be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+                       }
+               }
 
                soc_pcm_close(be_substream);
                be_substream->runtime = NULL;
@@ -1509,32 +1522,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
        return count;
 
 unwind:
-       /* disable any enabled and non active backends */
-       for_each_dpcm_be_rollback(fe, stream, dpcm) {
-               struct snd_soc_pcm_runtime *be = dpcm->be;
-               struct snd_pcm_substream *be_substream =
-                       snd_soc_dpcm_get_substream(be, stream);
-
-               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
-                       continue;
-
-               if (be->dpcm[stream].users == 0) {
-                       dev_err(be->dev, "ASoC: no users %s at close %d\n",
-                               stream ? "capture" : "playback",
-                               be->dpcm[stream].state);
-                       continue;
-               }
-
-               if (--be->dpcm[stream].users != 0)
-                       continue;
-
-               if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
-                       continue;
-
-               soc_pcm_close(be_substream);
-               be_substream->runtime = NULL;
-               be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
-       }
+       dpcm_be_dai_startup_rollback(fe, stream, dpcm);
 
        return err;
 }
@@ -1782,46 +1770,6 @@ be_err:
        return ret;
 }
 
-int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
-{
-       struct snd_soc_dpcm *dpcm;
-
-       /* only shutdown BEs that are either sinks or sources to this FE DAI */
-       for_each_dpcm_be(fe, stream, dpcm) {
-
-               struct snd_soc_pcm_runtime *be = dpcm->be;
-               struct snd_pcm_substream *be_substream =
-                       snd_soc_dpcm_get_substream(be, stream);
-
-               /* is this op for this BE ? */
-               if (!snd_soc_dpcm_be_can_update(fe, be, stream))
-                       continue;
-
-               if (be->dpcm[stream].users == 0)
-                       dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
-                               stream ? "capture" : "playback",
-                               be->dpcm[stream].state);
-
-               if (--be->dpcm[stream].users != 0)
-                       continue;
-
-               if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
-                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
-                       soc_pcm_hw_free(be_substream);
-                       be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
-               }
-
-               dev_dbg(be->dev, "ASoC: close BE %s\n",
-                       be->dai_link->name);
-
-               soc_pcm_close(be_substream);
-               be_substream->runtime = NULL;
-
-               be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
-       }
-       return 0;
-}
-
 static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
@@ -2371,9 +2319,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
        if (err < 0)
                dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err);
 
-       err = dpcm_be_dai_shutdown(fe, stream);
-       if (err < 0)
-               dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
+       dpcm_be_dai_shutdown(fe, stream);
 
        /* run the stream event for each BE */
        dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);