ASoC: rsnd: Enable IPMMU v2
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Mon, 16 Apr 2018 05:14:01 +0000 (05:14 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 16 Apr 2018 11:38:01 +0000 (12:38 +0100)
commit 4821d914fe747 ("ASoC: rsnd: use dma_sync_single_for_xxx() for
IOMMU") (= v1) which have been already reverted had supported IPMMU
support on rsnd driver.
Because memory allocating timing and DMAEngine access timing were
different, it used continuous memory and called dma map function by
itself.

OTOH, it is using DMA descriptor mode (= DMA cyclic mode), thus, there
was timing conflict between DMA sync/unsync and DMA transfer starting,
and it maked sound noise.

This patch supports IPMMU with coherent memory, and, it uses Audio DMAC
dev for allocating memory by snd_pcm_lib_preallocate_pages_for_all() to
indicate memory area to IPMMU.
One note is that Playback/Capture need each paired Audio DMAC dev.
Because of this, we need to keep each paired Audio DMAC dev when probing,
and use it when allocating each memory for IPMMU.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/rsnd.h

index 47a55d6bfd8029bf93898acab993a996534c438d..f9ac086d8e05b29c18326fd0e1961ae4bcf89aec 100644 (file)
@@ -1352,6 +1352,37 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
 #define PREALLOC_BUFFER                (32 * 1024)
 #define PREALLOC_BUFFER_MAX    (32 * 1024)
 
+static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd,
+                                 struct rsnd_dai_stream *io,
+                                 int stream)
+{
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_substream *substream;
+       int err;
+
+       /*
+        * use Audio-DMAC dev if we can use IPMMU
+        * see
+        *      rsnd_dmaen_attach()
+        */
+       if (io->dmac_dev)
+               dev = io->dmac_dev;
+
+       for (substream = rtd->pcm->streams[stream].substream;
+            substream;
+            substream = substream->next) {
+               err = snd_pcm_lib_preallocate_pages(substream,
+                                       SNDRV_DMA_TYPE_DEV,
+                                       dev,
+                                       PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -1366,11 +1397,17 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
        if (ret)
                return ret;
 
-       return snd_pcm_lib_preallocate_pages_for_all(
-               rtd->pcm,
-               SNDRV_DMA_TYPE_DEV,
-               rtd->card->snd_card->dev,
-               PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+       ret = rsnd_preallocate_pages(rtd, &rdai->playback,
+                                    SNDRV_PCM_STREAM_PLAYBACK);
+       if (ret)
+               return ret;
+
+       ret = rsnd_preallocate_pages(rtd, &rdai->capture,
+                                    SNDRV_PCM_STREAM_CAPTURE);
+       if (ret)
+               return ret;
+
+       return 0;
 }
 
 static const struct snd_soc_component_driver rsnd_soc_component = {
index 32ac97be26f1b6165b83f8e4bb5afb7e1c98d90d..ef82b94d038bfcbeb4f61ac7d09fdc049971d03b 100644 (file)
@@ -253,6 +253,13 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io,
                return -EAGAIN;
        }
 
+       /*
+        * use it for IPMMU if needed
+        * see
+        *      rsnd_preallocate_pages()
+        */
+       io->dmac_dev = chan->device->dev;
+
        dma_release_channel(chan);
 
        dmac->dmaen_num++;
index b1896f1eb2146f923787911a305d457b5320e9f1..6d7280d2d9be082c8a5c67309bede9cead5bdba0 100644 (file)
@@ -435,6 +435,7 @@ struct rsnd_dai_stream {
        struct snd_pcm_substream *substream;
        struct rsnd_mod *mod[RSND_MOD_MAX];
        struct rsnd_dai *rdai;
+       struct device *dmac_dev; /* for IPMMU */
        u32 parent_ssi_status;
 };
 #define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)