All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/4] DMA Engine: switch PL330 driver to non-irq-safe runtime PM
       [not found] <CGME20170124092750eucas1p2b806ec3340d9d57439cc6d8975b516ef@eucas1p2.samsung.com>
@ 2017-01-24  9:27   ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm
  Cc: Marek Szyprowski, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Vinod Koul, Ulf Hansson, Rafael J. Wysocki, Inki Dae

Hello,

This patchset changes the way the runtime PM is implemented in the PL330 DMA
engine driver. The main goal of such change is to add support for the audio
power domain to Exynos5 SoCs (5250, 542x, 5433, probably others) and let
it to be properly turned off, when no audio is being used. Switching to
non-irq-safe runtime PM is required to properly let power domain to be
turned off (irq-safe runtime PM keeps power domain turned on all the time)
and to integrate with clock controller's runtime PM (this cannot be
workarounded any other way, PL330 uses clocks from the controller, which
belongs to the same power domain).

For more details of the proposed change to the PL330 driver see patch #4.

Audio power domain on Exynos5 SoCs contains following hardware modules:
1. clock controller
2. pin controller
3. PL330 DMA controller
4. I2S audio controller

Patches for adding or fixing runtime PM for each of the above devices is
handled separately.

Runtime PM patches for clock controllers is possible and has been proposed
in the following thread (pending review): "[PATCH v4 0/4] Add runtime PM
support for clocks (on Exynos SoC example)",
http://www.spinics.net/lists/arm-kernel/msg550747.html

Runtime PM support for Exynos pin controller has been posted in the
following thread: "[PATCH 0/9] Runtime PM for Exynos pin controller driver",
http://www.spinics.net/lists/arm-kernel/msg550161.html

Exynos I2S driver supports runtime PM, but some fixes were needed for it
and they are already queued to linux-next.

This patchset is based on linux-next from 24th January 2017 with "dmaengine:
pl330: fix double lock" patch applied.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland


Changelog:

v6:
- fixed pl330 system sleep suspend/resume callbacks, previous implementation
  incorrectly tried to unprepare clocks unconditionally - after a fix pl330
  suspend/resume callbacks can be simply replaced by generic
  pm_runtime_force_{suspend,resume} helpers, what simplifies code even more

v5: https://www.spinics.net/lists/arm-kernel/msg555001.html
- added Acks
- additional mutex is indeed not needed, rely on dma_list_mutex in dmaengine
  core, added comment about locking

v4: http://www.spinics.net/lists/dmaengine/msg12329.html
- rebased onto "dmaengine: pl330: fix double lock" patch:
  http://www.spinics.net/lists/dmaengine/msg12289.html
- added a mutex to protect runtime PM links creation/removal to avoid races
- moved mem2mem channel case handing to pl330_{add,del}_slave_pm_link
  functions to simplify code and error paths

v3: http://www.spinics.net/lists/dmaengine/msg12245.html
- removed pl330_filter function as suggested by Arnd Bergmann
- removed pl330.h from arch/arm/plat-samsung/devs.c
- fixes some minor style issues pointed by Krzysztof Kozlowski

v2: https://www.spinics.net/lists/arm-kernel/msg552772.html
- rebased onto linux next-20170109
- improved patch description
- separated patch #3 from #4 (storing a pointer to slave device for each
  DMA channel) as requested by Krzysztof Kozlowski

v1: https://www.spinics.net/lists/arm-kernel/msg550008.html
- initial version


Patch summary:

Marek Szyprowski (4):
  dmaengine: pl330: remove pdata based initialization
  dmaengine: Forward slave device pointer to of_xlate callback
  dmaengine: pl330: Store pointer to slave device
  dmaengine: pl330: Don't require irq-safe runtime PM

 arch/arm/plat-samsung/devs.c    |   1 -
 drivers/dma/amba-pl08x.c        |   2 +-
 drivers/dma/at_hdmac.c          |   4 +-
 drivers/dma/at_xdmac.c          |   2 +-
 drivers/dma/bcm2835-dma.c       |   2 +-
 drivers/dma/coh901318.c         |   2 +-
 drivers/dma/cppi41.c            |   2 +-
 drivers/dma/dma-jz4780.c        |   2 +-
 drivers/dma/dmaengine.c         |   2 +-
 drivers/dma/dw/platform.c       |   2 +-
 drivers/dma/edma.c              |   4 +-
 drivers/dma/fsl-edma.c          |   2 +-
 drivers/dma/img-mdc-dma.c       |   2 +-
 drivers/dma/imx-dma.c           |   2 +-
 drivers/dma/imx-sdma.c          |   2 +-
 drivers/dma/k3dma.c             |   2 +-
 drivers/dma/lpc18xx-dmamux.c    |   2 +-
 drivers/dma/mmp_pdma.c          |   2 +-
 drivers/dma/mmp_tdma.c          |   2 +-
 drivers/dma/moxart-dma.c        |   2 +-
 drivers/dma/mxs-dma.c           |   2 +-
 drivers/dma/nbpfaxi.c           |   2 +-
 drivers/dma/of-dma.c            |  20 ++--
 drivers/dma/pl330.c             | 220 ++++++++++++++++------------------------
 drivers/dma/pxa_dma.c           |   2 +-
 drivers/dma/qcom/bam_dma.c      |   2 +-
 drivers/dma/sh/rcar-dmac.c      |   2 +-
 drivers/dma/sh/shdma-of.c       |   2 +-
 drivers/dma/sh/usb-dmac.c       |   2 +-
 drivers/dma/sirf-dma.c          |   2 +-
 drivers/dma/st_fdma.c           |   2 +-
 drivers/dma/ste_dma40.c         |   2 +-
 drivers/dma/stm32-dma.c         |   2 +-
 drivers/dma/sun4i-dma.c         |   2 +-
 drivers/dma/sun6i-dma.c         |   2 +-
 drivers/dma/tegra20-apb-dma.c   |   2 +-
 drivers/dma/tegra210-adma.c     |   2 +-
 drivers/dma/xilinx/xilinx_dma.c |   2 +-
 drivers/dma/xilinx/zynqmp_dma.c |   2 +-
 drivers/dma/zx_dma.c            |   2 +-
 include/linux/amba/pl330.h      |  35 -------
 include/linux/of_dma.h          |  17 ++--
 42 files changed, 145 insertions(+), 226 deletions(-)
 delete mode 100644 include/linux/amba/pl330.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 0/4] DMA Engine: switch PL330 driver to non-irq-safe runtime PM
@ 2017-01-24  9:27   ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This patchset changes the way the runtime PM is implemented in the PL330 DMA
engine driver. The main goal of such change is to add support for the audio
power domain to Exynos5 SoCs (5250, 542x, 5433, probably others) and let
it to be properly turned off, when no audio is being used. Switching to
non-irq-safe runtime PM is required to properly let power domain to be
turned off (irq-safe runtime PM keeps power domain turned on all the time)
and to integrate with clock controller's runtime PM (this cannot be
workarounded any other way, PL330 uses clocks from the controller, which
belongs to the same power domain).

For more details of the proposed change to the PL330 driver see patch #4.

Audio power domain on Exynos5 SoCs contains following hardware modules:
1. clock controller
2. pin controller
3. PL330 DMA controller
4. I2S audio controller

Patches for adding or fixing runtime PM for each of the above devices is
handled separately.

Runtime PM patches for clock controllers is possible and has been proposed
in the following thread (pending review): "[PATCH v4 0/4] Add runtime PM
support for clocks (on Exynos SoC example)",
http://www.spinics.net/lists/arm-kernel/msg550747.html

Runtime PM support for Exynos pin controller has been posted in the
following thread: "[PATCH 0/9] Runtime PM for Exynos pin controller driver",
http://www.spinics.net/lists/arm-kernel/msg550161.html

Exynos I2S driver supports runtime PM, but some fixes were needed for it
and they are already queued to linux-next.

This patchset is based on linux-next from 24th January 2017 with "dmaengine:
pl330: fix double lock" patch applied.

Best regards
Marek Szyprowski
Samsung R&D Institute Poland


Changelog:

v6:
- fixed pl330 system sleep suspend/resume callbacks, previous implementation
  incorrectly tried to unprepare clocks unconditionally - after a fix pl330
  suspend/resume callbacks can be simply replaced by generic
  pm_runtime_force_{suspend,resume} helpers, what simplifies code even more

v5: https://www.spinics.net/lists/arm-kernel/msg555001.html
- added Acks
- additional mutex is indeed not needed, rely on dma_list_mutex in dmaengine
  core, added comment about locking

v4: http://www.spinics.net/lists/dmaengine/msg12329.html
- rebased onto "dmaengine: pl330: fix double lock" patch:
  http://www.spinics.net/lists/dmaengine/msg12289.html
- added a mutex to protect runtime PM links creation/removal to avoid races
- moved mem2mem channel case handing to pl330_{add,del}_slave_pm_link
  functions to simplify code and error paths

v3: http://www.spinics.net/lists/dmaengine/msg12245.html
- removed pl330_filter function as suggested by Arnd Bergmann
- removed pl330.h from arch/arm/plat-samsung/devs.c
- fixes some minor style issues pointed by Krzysztof Kozlowski

v2: https://www.spinics.net/lists/arm-kernel/msg552772.html
- rebased onto linux next-20170109
- improved patch description
- separated patch #3 from #4 (storing a pointer to slave device for each
  DMA channel) as requested by Krzysztof Kozlowski

v1: https://www.spinics.net/lists/arm-kernel/msg550008.html
- initial version


Patch summary:

Marek Szyprowski (4):
  dmaengine: pl330: remove pdata based initialization
  dmaengine: Forward slave device pointer to of_xlate callback
  dmaengine: pl330: Store pointer to slave device
  dmaengine: pl330: Don't require irq-safe runtime PM

 arch/arm/plat-samsung/devs.c    |   1 -
 drivers/dma/amba-pl08x.c        |   2 +-
 drivers/dma/at_hdmac.c          |   4 +-
 drivers/dma/at_xdmac.c          |   2 +-
 drivers/dma/bcm2835-dma.c       |   2 +-
 drivers/dma/coh901318.c         |   2 +-
 drivers/dma/cppi41.c            |   2 +-
 drivers/dma/dma-jz4780.c        |   2 +-
 drivers/dma/dmaengine.c         |   2 +-
 drivers/dma/dw/platform.c       |   2 +-
 drivers/dma/edma.c              |   4 +-
 drivers/dma/fsl-edma.c          |   2 +-
 drivers/dma/img-mdc-dma.c       |   2 +-
 drivers/dma/imx-dma.c           |   2 +-
 drivers/dma/imx-sdma.c          |   2 +-
 drivers/dma/k3dma.c             |   2 +-
 drivers/dma/lpc18xx-dmamux.c    |   2 +-
 drivers/dma/mmp_pdma.c          |   2 +-
 drivers/dma/mmp_tdma.c          |   2 +-
 drivers/dma/moxart-dma.c        |   2 +-
 drivers/dma/mxs-dma.c           |   2 +-
 drivers/dma/nbpfaxi.c           |   2 +-
 drivers/dma/of-dma.c            |  20 ++--
 drivers/dma/pl330.c             | 220 ++++++++++++++++------------------------
 drivers/dma/pxa_dma.c           |   2 +-
 drivers/dma/qcom/bam_dma.c      |   2 +-
 drivers/dma/sh/rcar-dmac.c      |   2 +-
 drivers/dma/sh/shdma-of.c       |   2 +-
 drivers/dma/sh/usb-dmac.c       |   2 +-
 drivers/dma/sirf-dma.c          |   2 +-
 drivers/dma/st_fdma.c           |   2 +-
 drivers/dma/ste_dma40.c         |   2 +-
 drivers/dma/stm32-dma.c         |   2 +-
 drivers/dma/sun4i-dma.c         |   2 +-
 drivers/dma/sun6i-dma.c         |   2 +-
 drivers/dma/tegra20-apb-dma.c   |   2 +-
 drivers/dma/tegra210-adma.c     |   2 +-
 drivers/dma/xilinx/xilinx_dma.c |   2 +-
 drivers/dma/xilinx/zynqmp_dma.c |   2 +-
 drivers/dma/zx_dma.c            |   2 +-
 include/linux/amba/pl330.h      |  35 -------
 include/linux/of_dma.h          |  17 ++--
 42 files changed, 145 insertions(+), 226 deletions(-)
 delete mode 100644 include/linux/amba/pl330.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 1/4] dmaengine: pl330: remove pdata based initialization
       [not found]   ` <CGME20170124092750eucas1p1127947314c9ad7eed297c1b6739110cb@eucas1p1.samsung.com>
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm
  Cc: Marek Szyprowski, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Vinod Koul, Ulf Hansson, Rafael J. Wysocki, Inki Dae

This driver is now used only on platforms which support device tree, so
it is safe to remove legacy platform data based initialization code.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
For plat-samsung:
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 arch/arm/plat-samsung/devs.c |  1 -
 drivers/dma/pl330.c          | 42 ++++++++----------------------------------
 include/linux/amba/pl330.h   | 35 -----------------------------------
 3 files changed, 8 insertions(+), 70 deletions(-)
 delete mode 100644 include/linux/amba/pl330.h

diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 03fac123676d..dc269d9143bc 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -10,7 +10,6 @@
  * published by the Free Software Foundation.
 */
 
-#include <linux/amba/pl330.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 7539f73df9e0..78be12b45a45 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -22,7 +22,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
-#include <linux/amba/pl330.h>
 #include <linux/scatterlist.h>
 #include <linux/of.h>
 #include <linux/of_dma.h>
@@ -2076,18 +2075,6 @@ static void pl330_tasklet(unsigned long data)
 	}
 }
 
-bool pl330_filter(struct dma_chan *chan, void *param)
-{
-	u8 *peri_id;
-
-	if (chan->device->dev->driver != &pl330_driver.drv)
-		return false;
-
-	peri_id = chan->private;
-	return *peri_id == (unsigned long)param;
-}
-EXPORT_SYMBOL(pl330_filter);
-
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 						struct of_dma *ofdma)
 {
@@ -2832,7 +2819,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
-	struct dma_pl330_platdata *pdat;
 	struct pl330_config *pcfg;
 	struct pl330_dmac *pl330;
 	struct dma_pl330_chan *pch, *_p;
@@ -2842,8 +2828,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	int num_chan;
 	struct device_node *np = adev->dev.of_node;
 
-	pdat = dev_get_platdata(&adev->dev);
-
 	ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32));
 	if (ret)
 		return ret;
@@ -2856,7 +2840,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	pd = &pl330->ddma;
 	pd->dev = &adev->dev;
 
-	pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
+	pl330->mcbufsz = 0;
 
 	/* get quirk */
 	for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
@@ -2900,10 +2884,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	INIT_LIST_HEAD(&pd->channels);
 
 	/* Initialize channel parameters */
-	if (pdat)
-		num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan);
-	else
-		num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
+	num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
 
 	pl330->num_peripherals = num_chan;
 
@@ -2915,11 +2896,8 @@ static int __maybe_unused pl330_resume(struct device *dev)
 
 	for (i = 0; i < num_chan; i++) {
 		pch = &pl330->peripherals[i];
-		if (!adev->dev.of_node)
-			pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;
-		else
-			pch->chan.private = adev->dev.of_node;
 
+		pch->chan.private = adev->dev.of_node;
 		INIT_LIST_HEAD(&pch->submitted_list);
 		INIT_LIST_HEAD(&pch->work_list);
 		INIT_LIST_HEAD(&pch->completed_list);
@@ -2932,15 +2910,11 @@ static int __maybe_unused pl330_resume(struct device *dev)
 		list_add_tail(&pch->chan.device_node, &pd->channels);
 	}
 
-	if (pdat) {
-		pd->cap_mask = pdat->cap_mask;
-	} else {
-		dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-		if (pcfg->num_peri) {
-			dma_cap_set(DMA_SLAVE, pd->cap_mask);
-			dma_cap_set(DMA_CYCLIC, pd->cap_mask);
-			dma_cap_set(DMA_PRIVATE, pd->cap_mask);
-		}
+	dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+	if (pcfg->num_peri) {
+		dma_cap_set(DMA_SLAVE, pd->cap_mask);
+		dma_cap_set(DMA_CYCLIC, pd->cap_mask);
+		dma_cap_set(DMA_PRIVATE, pd->cap_mask);
 	}
 
 	pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
deleted file mode 100644
index fe93758e8403..000000000000
--- a/include/linux/amba/pl330.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* linux/include/linux/amba/pl330.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef	__AMBA_PL330_H_
-#define	__AMBA_PL330_H_
-
-#include <linux/dmaengine.h>
-
-struct dma_pl330_platdata {
-	/*
-	 * Number of valid peripherals connected to DMAC.
-	 * This may be different from the value read from
-	 * CR0, as the PL330 implementation might have 'holes'
-	 * in the peri list or the peri could also be reached
-	 * from another DMAC which the platform prefers.
-	 */
-	u8 nr_valid_peri;
-	/* Array of valid peripherals */
-	u8 *peri_id;
-	/* Operational capabilities */
-	dma_cap_mask_t cap_mask;
-	/* Bytes to allocate for MC buffer */
-	unsigned mcbuf_sz;
-};
-
-extern bool pl330_filter(struct dma_chan *chan, void *param);
-#endif	/* __AMBA_PL330_H_ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 1/4] dmaengine: pl330: remove pdata based initialization
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

This driver is now used only on platforms which support device tree, so
it is safe to remove legacy platform data based initialization code.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
For plat-samsung:
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
---
 arch/arm/plat-samsung/devs.c |  1 -
 drivers/dma/pl330.c          | 42 ++++++++----------------------------------
 include/linux/amba/pl330.h   | 35 -----------------------------------
 3 files changed, 8 insertions(+), 70 deletions(-)
 delete mode 100644 include/linux/amba/pl330.h

diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 03fac123676d..dc269d9143bc 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -10,7 +10,6 @@
  * published by the Free Software Foundation.
 */
 
-#include <linux/amba/pl330.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 7539f73df9e0..78be12b45a45 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -22,7 +22,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/amba/bus.h>
-#include <linux/amba/pl330.h>
 #include <linux/scatterlist.h>
 #include <linux/of.h>
 #include <linux/of_dma.h>
@@ -2076,18 +2075,6 @@ static void pl330_tasklet(unsigned long data)
 	}
 }
 
-bool pl330_filter(struct dma_chan *chan, void *param)
-{
-	u8 *peri_id;
-
-	if (chan->device->dev->driver != &pl330_driver.drv)
-		return false;
-
-	peri_id = chan->private;
-	return *peri_id == (unsigned long)param;
-}
-EXPORT_SYMBOL(pl330_filter);
-
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 						struct of_dma *ofdma)
 {
@@ -2832,7 +2819,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
-	struct dma_pl330_platdata *pdat;
 	struct pl330_config *pcfg;
 	struct pl330_dmac *pl330;
 	struct dma_pl330_chan *pch, *_p;
@@ -2842,8 +2828,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	int num_chan;
 	struct device_node *np = adev->dev.of_node;
 
-	pdat = dev_get_platdata(&adev->dev);
-
 	ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32));
 	if (ret)
 		return ret;
@@ -2856,7 +2840,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	pd = &pl330->ddma;
 	pd->dev = &adev->dev;
 
-	pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
+	pl330->mcbufsz = 0;
 
 	/* get quirk */
 	for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
@@ -2900,10 +2884,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 	INIT_LIST_HEAD(&pd->channels);
 
 	/* Initialize channel parameters */
-	if (pdat)
-		num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan);
-	else
-		num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
+	num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
 
 	pl330->num_peripherals = num_chan;
 
@@ -2915,11 +2896,8 @@ static int __maybe_unused pl330_resume(struct device *dev)
 
 	for (i = 0; i < num_chan; i++) {
 		pch = &pl330->peripherals[i];
-		if (!adev->dev.of_node)
-			pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;
-		else
-			pch->chan.private = adev->dev.of_node;
 
+		pch->chan.private = adev->dev.of_node;
 		INIT_LIST_HEAD(&pch->submitted_list);
 		INIT_LIST_HEAD(&pch->work_list);
 		INIT_LIST_HEAD(&pch->completed_list);
@@ -2932,15 +2910,11 @@ static int __maybe_unused pl330_resume(struct device *dev)
 		list_add_tail(&pch->chan.device_node, &pd->channels);
 	}
 
-	if (pdat) {
-		pd->cap_mask = pdat->cap_mask;
-	} else {
-		dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-		if (pcfg->num_peri) {
-			dma_cap_set(DMA_SLAVE, pd->cap_mask);
-			dma_cap_set(DMA_CYCLIC, pd->cap_mask);
-			dma_cap_set(DMA_PRIVATE, pd->cap_mask);
-		}
+	dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+	if (pcfg->num_peri) {
+		dma_cap_set(DMA_SLAVE, pd->cap_mask);
+		dma_cap_set(DMA_CYCLIC, pd->cap_mask);
+		dma_cap_set(DMA_PRIVATE, pd->cap_mask);
 	}
 
 	pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
deleted file mode 100644
index fe93758e8403..000000000000
--- a/include/linux/amba/pl330.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* linux/include/linux/amba/pl330.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef	__AMBA_PL330_H_
-#define	__AMBA_PL330_H_
-
-#include <linux/dmaengine.h>
-
-struct dma_pl330_platdata {
-	/*
-	 * Number of valid peripherals connected to DMAC.
-	 * This may be different from the value read from
-	 * CR0, as the PL330 implementation might have 'holes'
-	 * in the peri list or the peri could also be reached
-	 * from another DMAC which the platform prefers.
-	 */
-	u8 nr_valid_peri;
-	/* Array of valid peripherals */
-	u8 *peri_id;
-	/* Operational capabilities */
-	dma_cap_mask_t cap_mask;
-	/* Bytes to allocate for MC buffer */
-	unsigned mcbuf_sz;
-};
-
-extern bool pl330_filter(struct dma_chan *chan, void *param);
-#endif	/* __AMBA_PL330_H_ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
       [not found]   ` <CGME20170124092751eucas1p1411586335ad7083f7fff451212e002a3@eucas1p1.samsung.com>
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm
  Cc: Marek Szyprowski, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Vinod Koul, Ulf Hansson, Rafael J. Wysocki, Inki Dae

Add pointer to slave device to of_dma_xlate to let DMA engine driver
to know which slave device is using given DMA channel. This will be
later used to implement non-irq-safe runtime PM for DMA engine driver.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/amba-pl08x.c        |  2 +-
 drivers/dma/at_hdmac.c          |  4 ++--
 drivers/dma/at_xdmac.c          |  2 +-
 drivers/dma/bcm2835-dma.c       |  2 +-
 drivers/dma/coh901318.c         |  2 +-
 drivers/dma/cppi41.c            |  2 +-
 drivers/dma/dma-jz4780.c        |  2 +-
 drivers/dma/dmaengine.c         |  2 +-
 drivers/dma/dw/platform.c       |  2 +-
 drivers/dma/edma.c              |  4 ++--
 drivers/dma/fsl-edma.c          |  2 +-
 drivers/dma/img-mdc-dma.c       |  2 +-
 drivers/dma/imx-dma.c           |  2 +-
 drivers/dma/imx-sdma.c          |  2 +-
 drivers/dma/k3dma.c             |  2 +-
 drivers/dma/lpc18xx-dmamux.c    |  2 +-
 drivers/dma/mmp_pdma.c          |  2 +-
 drivers/dma/mmp_tdma.c          |  2 +-
 drivers/dma/moxart-dma.c        |  2 +-
 drivers/dma/mxs-dma.c           |  2 +-
 drivers/dma/nbpfaxi.c           |  2 +-
 drivers/dma/of-dma.c            | 20 ++++++++++++--------
 drivers/dma/pl330.c             |  3 ++-
 drivers/dma/pxa_dma.c           |  2 +-
 drivers/dma/qcom/bam_dma.c      |  2 +-
 drivers/dma/sh/rcar-dmac.c      |  2 +-
 drivers/dma/sh/shdma-of.c       |  2 +-
 drivers/dma/sh/usb-dmac.c       |  2 +-
 drivers/dma/sirf-dma.c          |  2 +-
 drivers/dma/st_fdma.c           |  2 +-
 drivers/dma/ste_dma40.c         |  2 +-
 drivers/dma/stm32-dma.c         |  2 +-
 drivers/dma/sun4i-dma.c         |  2 +-
 drivers/dma/sun6i-dma.c         |  2 +-
 drivers/dma/tegra20-apb-dma.c   |  2 +-
 drivers/dma/tegra210-adma.c     |  2 +-
 drivers/dma/xilinx/xilinx_dma.c |  2 +-
 drivers/dma/xilinx/zynqmp_dma.c |  2 +-
 drivers/dma/zx_dma.c            |  2 +-
 include/linux/of_dma.h          | 17 +++++++++--------
 40 files changed, 62 insertions(+), 56 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 0b7c6ce629a6..194089c98755 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -2059,7 +2059,7 @@ static struct dma_chan *pl08x_find_chan_id(struct pl08x_driver_data *pl08x,
 }
 
 static struct dma_chan *pl08x_of_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct pl08x_driver_data *pl08x = ofdma->of_dma_data;
 	struct dma_chan *dma_chan;
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 1baf3404a365..b228b263ac0c 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1788,7 +1788,7 @@ static bool at_dma_filter(struct dma_chan *chan, void *slave)
 }
 
 static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	struct dma_chan *chan;
 	struct at_dma_chan *atchan;
@@ -1847,7 +1847,7 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
 }
 #else
 static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	return NULL;
 }
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 7d4e0bcda9af..9ddd868c9b59 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -508,7 +508,7 @@ static inline void at_xdmac_increment_block_count(struct dma_chan *chan,
 }
 
 static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	struct at_xdmac		*atxdmac = of_dma->of_dma_data;
 	struct at_xdmac_chan	*atchan;
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index e18dc596cf24..e9c417ad2141 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -877,7 +877,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
 
 static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct bcm2835_dmadev *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index 74794c9859f6..dbc4fb44f326 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1779,7 +1779,7 @@ static bool coh901318_filter_base_and_id(struct dma_chan *chan, void *data)
 }
 
 static struct dma_chan *coh901318_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct coh901318_filter_args args = {
 		.base = ofdma->of_dma_data,
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index d5ba43a87a68..389a2278b6a0 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -932,7 +932,7 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
 };
 
 static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct of_dma_filter_info *info = ofdma->of_dma_data;
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 7373b7a555ec..f65f71649898 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -707,7 +707,7 @@ static bool jz4780_dma_filter_fn(struct dma_chan *chan, void *param)
 }
 
 static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
-	struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct jz4780_dma_dev *jzdma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = jzdma->dma_device.cap_mask;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 24e0221fd66d..721fa0bee7f5 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -708,7 +708,7 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
 
 	/* If device-tree is present get slave info from here */
 	if (dev->of_node)
-		chan = of_dma_request_slave_channel(dev->of_node, name);
+		chan = of_dma_request_slave_channel(dev, name);
 
 	/* If device was enumerated by ACPI get slave info from here */
 	if (has_acpi_companion(dev) && !chan)
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index b1655e40cfa2..1eb8a31b6775 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -29,7 +29,7 @@
 #define DRV_NAME	"dw_dmac"
 
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				 struct of_dma *ofdma, struct device *slave_dev)
 {
 	struct dw_dma *dw = ofdma->of_dma_data;
 	struct dw_dma_slave slave = {
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 3879f80a4815..d2e7d893d984 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -2117,7 +2117,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
 }
 
 static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct edma_cc *ecc = ofdma->of_dma_data;
 	struct dma_chan *chan = NULL;
@@ -2161,7 +2161,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
 }
 
 static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	return NULL;
 }
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 6775f2c74e25..915aa8182204 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -750,7 +750,7 @@ static void fsl_edma_issue_pending(struct dma_chan *chan)
 }
 
 static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
 	struct dma_chan *chan, *_chan;
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index 54db1411ce73..9a969cbdd384 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -793,7 +793,7 @@ static irqreturn_t mdc_chan_irq(int irq, void *dev_id)
 }
 
 static struct dma_chan *mdc_of_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct mdc_dma *mdma = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index ab0fb804fb1e..b145babe366b 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -1032,7 +1032,7 @@ static bool imxdma_filter_fn(struct dma_chan *chan, void *param)
 }
 
 static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct imxdma_engine *imxdma = ofdma->of_dma_data;
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index d1651a50c349..7c3cdb378f98 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1659,7 +1659,7 @@ static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
-				   struct of_dma *ofdma)
+				   struct of_dma *ofdma, struct device *slave)
 {
 	struct sdma_engine *sdma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = sdma->dma_device.cap_mask;
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 01e25c68dd5a..dd0e7fe9e54a 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -786,7 +786,7 @@ static int k3_dma_transfer_resume(struct dma_chan *chan)
 MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
 
 static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct k3_dma_dev *d = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c
index 761f32687055..e730bcc8d92e 100644
--- a/drivers/dma/lpc18xx-dmamux.c
+++ b/drivers/dma/lpc18xx-dmamux.c
@@ -53,7 +53,7 @@ static void lpc18xx_dmamux_free(struct device *dev, void *route_data)
 }
 
 static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec,
-				    struct of_dma *ofdma)
+				    struct of_dma *ofdma, struct device *slave)
 {
 	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
 	struct lpc18xx_dmamux_data *dmamux = platform_get_drvdata(pdev);
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index eb3a1f42ab06..569ec8f1ccee 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -993,7 +993,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
 MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids);
 
 static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct mmp_pdma_device *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 13c68b6434ce..ca56e73797c9 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -591,7 +591,7 @@ static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
-			       struct of_dma *ofdma)
+			       struct of_dma *ofdma, struct device *slave)
 {
 	struct mmp_tdma_device *tdev = ofdma->of_dma_data;
 	dma_cap_mask_t mask = tdev->device.cap_mask;
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
index e1a5c2242f6f..d7c32a3c1bac 100644
--- a/drivers/dma/moxart-dma.c
+++ b/drivers/dma/moxart-dma.c
@@ -330,7 +330,7 @@ static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
 }
 
 static struct dma_chan *moxart_of_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct moxart_dmadev *mdc = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index e217268c7098..3cc0e6b99f13 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -747,7 +747,7 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
-			       struct of_dma *ofdma)
+			       struct of_dma *ofdma, struct device *slave)
 {
 	struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = mxs_dma->dma_device.cap_mask;
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 3f45b9bdf201..cb6a981beacd 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1096,7 +1096,7 @@ static void nbpf_free_chan_resources(struct dma_chan *dchan)
 }
 
 static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct nbpf_device *nbpf = ofdma->of_dma_data;
 	struct dma_chan *dchan;
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index faae0bfe1109..b6fd9e10758c 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -54,7 +54,8 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
  * to request channel from the real DMA controller.
  */
 static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
-					    struct of_dma *ofdma)
+					    struct of_dma *ofdma,
+					    struct device *slave)
 {
 	struct dma_chan		*chan;
 	struct of_dma		*ofdma_target;
@@ -71,7 +72,8 @@ static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
 	if (!ofdma_target)
 		return NULL;
 
-	chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
+	chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target,
+					  slave);
 	if (chan) {
 		chan->router = ofdma->dma_router;
 		chan->route_data = route_data;
@@ -103,7 +105,8 @@ static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
  */
 int of_dma_controller_register(struct device_node *np,
 				struct dma_chan *(*of_dma_xlate)
-				(struct of_phandle_args *, struct of_dma *),
+				(struct of_phandle_args *, struct of_dma *,
+				 struct device *),
 				void *data)
 {
 	struct of_dma	*ofdma;
@@ -229,14 +232,15 @@ static int of_dma_match_channel(struct device_node *np, const char *name,
 
 /**
  * of_dma_request_slave_channel - Get the DMA slave channel
- * @np:		device node to get DMA request from
+ * @slave:		device to get DMA request from
  * @name:	name of desired channel
  *
  * Returns pointer to appropriate DMA channel on success or an error pointer.
  */
-struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 					      const char *name)
 {
+	struct device_node	*np = slave->of_node;
 	struct of_phandle_args	dma_spec;
 	struct of_dma		*ofdma;
 	struct dma_chan		*chan;
@@ -275,7 +279,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 		ofdma = of_dma_find_controller(&dma_spec);
 
 		if (ofdma) {
-			chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
+			chan = ofdma->of_dma_xlate(&dma_spec, ofdma, slave);
 		} else {
 			ret_no_channel = -EPROBE_DEFER;
 			chan = NULL;
@@ -305,7 +309,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
  * pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct of_dma_filter_info *info = ofdma->of_dma_data;
@@ -335,7 +339,7 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
  * Returns pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
-					 struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct dma_device *dev = ofdma->of_dma_data;
 	struct dma_chan *chan, *candidate = NULL;
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 78be12b45a45..b6b2cc912380 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2076,7 +2076,8 @@ static void pl330_tasklet(unsigned long data)
 }
 
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+					   struct of_dma *ofdma,
+					   struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct pl330_dmac *pl330 = ofdma->of_dma_data;
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index b53fb618bbf6..434764b43d68 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1336,7 +1336,7 @@ static int pxad_init_phys(struct platform_device *op,
 MODULE_DEVICE_TABLE(of, pxad_dt_ids);
 
 static struct dma_chan *pxad_dma_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct pxad_device *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 03c4eb3fd314..7ff3075c0702 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -1049,7 +1049,7 @@ static void bam_dma_free_desc(struct virt_dma_desc *vd)
 }
 
 static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *of)
+				      struct of_dma *of, struct device *slave)
 {
 	struct bam_device *bdev = container_of(of->of_dma_data,
 					struct bam_device, common);
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 4c357d475465..c450235ff51c 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1560,7 +1560,7 @@ static bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
 }
 
 static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct rcar_dmac_chan *rchan;
 	struct dma_chan *chan;
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
index f999f9b0d314..9953be99627b 100644
--- a/drivers/dma/sh/shdma-of.c
+++ b/drivers/dma/sh/shdma-of.c
@@ -20,7 +20,7 @@
 #define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
 
 static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	u32 id = dma_spec->args[0];
 	dma_cap_mask_t mask;
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 72c649713ace..0f06a9468df9 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -650,7 +650,7 @@ static bool usb_dmac_chan_filter(struct dma_chan *chan, void *arg)
 }
 
 static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
-					  struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct dma_chan *chan;
 	dma_cap_mask_t mask;
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index a0733ac3edb1..ed6f07b0d758 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -826,7 +826,7 @@ bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id)
 	BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
 
 static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
-	struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sirfsoc_dma *sdma = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
index bfb79bd0c6de..6a92a6505419 100644
--- a/drivers/dma/st_fdma.c
+++ b/drivers/dma/st_fdma.c
@@ -167,7 +167,7 @@ static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
 }
 
 static struct dma_chan *st_fdma_of_xlate(struct of_phandle_args *dma_spec,
-					 struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct st_fdma_dev *fdev = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index a6620b671d1d..9fade9209d93 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -2334,7 +2334,7 @@ static void d40_set_prio_realtime(struct d40_chan *d40c)
 #define D40_DT_FLAGS_HIGH_PRIO(flags)  ((flags >> 4) & 0x1)
 
 static struct dma_chan *d40_xlate(struct of_phandle_args *dma_spec,
-				  struct of_dma *ofdma)
+				  struct of_dma *ofdma, struct device *slave)
 {
 	struct stedma40_chan_cfg cfg;
 	dma_cap_mask_t cap;
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 49f86cabcfec..495a4f5c5c26 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -980,7 +980,7 @@ static void stm32_dma_set_config(struct stm32_dma_chan *chan,
 }
 
 static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct stm32_dma_device *dmadev = ofdma->of_dma_data;
 	struct device *dev = dmadev->ddev.dev;
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index 57aa227bfadb..c1a076334abf 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -909,7 +909,7 @@ static int sun4i_dma_config(struct dma_chan *chan,
 }
 
 static struct dma_chan *sun4i_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sun4i_dma_dev *priv = ofdma->of_dma_data;
 	struct sun4i_dma_vchan *vchan;
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a2358780ab2c..240e4a95913a 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -930,7 +930,7 @@ static void sun6i_dma_free_chan_resources(struct dma_chan *chan)
 }
 
 static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sun6i_dma_dev *sdev = ofdma->of_dma_data;
 	struct sun6i_vchan *vchan;
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 3722b9d8d9fe..e0eb5813fcf5 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1239,7 +1239,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 }
 
 static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct tegra_dma *tdma = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index b10cbaa82ff5..525af32132ac 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -605,7 +605,7 @@ static void tegra_adma_free_chan_resources(struct dma_chan *dc)
 }
 
 static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct tegra_adma *tdma = ofdma->of_dma_data;
 	struct tegra_adma_chan *tdc;
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 8288fe4d17c3..69cdfc39edb2 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -2461,7 +2461,7 @@ static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
  * Return: DMA channel pointer on success and NULL on error
  */
 static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct xilinx_dma_device *xdev = ofdma->of_dma_data;
 	int chan_id = dma_spec->args[0];
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index 6d221e5c72ee..6aa133c514f1 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -1040,7 +1040,7 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
  * Return: DMA channel pointer on success and NULL on error
  */
 static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec,
-					    struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct zynqmp_dma_device *zdev = ofdma->of_dma_data;
 
diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c
index 42ff3e66c1e1..6e050dbe5f26 100644
--- a/drivers/dma/zx_dma.c
+++ b/drivers/dma/zx_dma.c
@@ -732,7 +732,7 @@ static void zx_dma_free_desc(struct virt_dma_desc *vd)
 MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids);
 
 static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-					       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct zx_dma_dev *d = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index b90d8ec57c1f..a0a6c8c17669 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -22,7 +22,8 @@ struct of_dma {
 	struct list_head	of_dma_controllers;
 	struct device_node	*of_node;
 	struct dma_chan		*(*of_dma_xlate)
-				(struct of_phandle_args *, struct of_dma *);
+				(struct of_phandle_args *, struct of_dma *,
+				 struct device *);
 	void			*(*of_dma_route_allocate)
 				(struct of_phandle_args *, struct of_dma *);
 	struct dma_router	*dma_router;
@@ -37,7 +38,7 @@ struct of_dma_filter_info {
 #ifdef CONFIG_DMA_OF
 extern int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
-		(struct of_phandle_args *, struct of_dma *),
+		(struct of_phandle_args *, struct of_dma *, struct device *),
 		void *data);
 extern void of_dma_controller_free(struct device_node *np);
 
@@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
 		struct dma_router *dma_router);
 #define of_dma_router_free of_dma_controller_free
 
-extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 						     const char *name);
 extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma);
+		struct of_dma *ofdma, struct device *slave);
 extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma);
+		struct of_dma *ofdma, struct device *slave);
 
 #else
 static inline int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
-		(struct of_phandle_args *, struct of_dma *),
+		(struct of_phandle_args *, struct of_dma *, struct device *),
 		void *data)
 {
 	return -ENODEV;
@@ -77,14 +78,14 @@ static inline int of_dma_router_register(struct device_node *np,
 
 #define of_dma_router_free of_dma_controller_free
 
-static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+static inline struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 						     const char *name)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+		struct of_dma *ofdma, struct device *slave)
 {
 	return NULL;
 }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

Add pointer to slave device to of_dma_xlate to let DMA engine driver
to know which slave device is using given DMA channel. This will be
later used to implement non-irq-safe runtime PM for DMA engine driver.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/amba-pl08x.c        |  2 +-
 drivers/dma/at_hdmac.c          |  4 ++--
 drivers/dma/at_xdmac.c          |  2 +-
 drivers/dma/bcm2835-dma.c       |  2 +-
 drivers/dma/coh901318.c         |  2 +-
 drivers/dma/cppi41.c            |  2 +-
 drivers/dma/dma-jz4780.c        |  2 +-
 drivers/dma/dmaengine.c         |  2 +-
 drivers/dma/dw/platform.c       |  2 +-
 drivers/dma/edma.c              |  4 ++--
 drivers/dma/fsl-edma.c          |  2 +-
 drivers/dma/img-mdc-dma.c       |  2 +-
 drivers/dma/imx-dma.c           |  2 +-
 drivers/dma/imx-sdma.c          |  2 +-
 drivers/dma/k3dma.c             |  2 +-
 drivers/dma/lpc18xx-dmamux.c    |  2 +-
 drivers/dma/mmp_pdma.c          |  2 +-
 drivers/dma/mmp_tdma.c          |  2 +-
 drivers/dma/moxart-dma.c        |  2 +-
 drivers/dma/mxs-dma.c           |  2 +-
 drivers/dma/nbpfaxi.c           |  2 +-
 drivers/dma/of-dma.c            | 20 ++++++++++++--------
 drivers/dma/pl330.c             |  3 ++-
 drivers/dma/pxa_dma.c           |  2 +-
 drivers/dma/qcom/bam_dma.c      |  2 +-
 drivers/dma/sh/rcar-dmac.c      |  2 +-
 drivers/dma/sh/shdma-of.c       |  2 +-
 drivers/dma/sh/usb-dmac.c       |  2 +-
 drivers/dma/sirf-dma.c          |  2 +-
 drivers/dma/st_fdma.c           |  2 +-
 drivers/dma/ste_dma40.c         |  2 +-
 drivers/dma/stm32-dma.c         |  2 +-
 drivers/dma/sun4i-dma.c         |  2 +-
 drivers/dma/sun6i-dma.c         |  2 +-
 drivers/dma/tegra20-apb-dma.c   |  2 +-
 drivers/dma/tegra210-adma.c     |  2 +-
 drivers/dma/xilinx/xilinx_dma.c |  2 +-
 drivers/dma/xilinx/zynqmp_dma.c |  2 +-
 drivers/dma/zx_dma.c            |  2 +-
 include/linux/of_dma.h          | 17 +++++++++--------
 40 files changed, 62 insertions(+), 56 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 0b7c6ce629a6..194089c98755 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -2059,7 +2059,7 @@ static struct dma_chan *pl08x_find_chan_id(struct pl08x_driver_data *pl08x,
 }
 
 static struct dma_chan *pl08x_of_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct pl08x_driver_data *pl08x = ofdma->of_dma_data;
 	struct dma_chan *dma_chan;
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 1baf3404a365..b228b263ac0c 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1788,7 +1788,7 @@ static bool at_dma_filter(struct dma_chan *chan, void *slave)
 }
 
 static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	struct dma_chan *chan;
 	struct at_dma_chan *atchan;
@@ -1847,7 +1847,7 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
 }
 #else
 static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	return NULL;
 }
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 7d4e0bcda9af..9ddd868c9b59 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -508,7 +508,7 @@ static inline void at_xdmac_increment_block_count(struct dma_chan *chan,
 }
 
 static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *of_dma)
+				    struct of_dma *of_dma, struct device *slave)
 {
 	struct at_xdmac		*atxdmac = of_dma->of_dma_data;
 	struct at_xdmac_chan	*atchan;
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index e18dc596cf24..e9c417ad2141 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -877,7 +877,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
 MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
 
 static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct bcm2835_dmadev *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index 74794c9859f6..dbc4fb44f326 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1779,7 +1779,7 @@ static bool coh901318_filter_base_and_id(struct dma_chan *chan, void *data)
 }
 
 static struct dma_chan *coh901318_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct coh901318_filter_args args = {
 		.base = ofdma->of_dma_data,
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index d5ba43a87a68..389a2278b6a0 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -932,7 +932,7 @@ static bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
 };
 
 static struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct of_dma_filter_info *info = ofdma->of_dma_data;
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 7373b7a555ec..f65f71649898 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -707,7 +707,7 @@ static bool jz4780_dma_filter_fn(struct dma_chan *chan, void *param)
 }
 
 static struct dma_chan *jz4780_of_dma_xlate(struct of_phandle_args *dma_spec,
-	struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct jz4780_dma_dev *jzdma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = jzdma->dma_device.cap_mask;
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 24e0221fd66d..721fa0bee7f5 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -708,7 +708,7 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
 
 	/* If device-tree is present get slave info from here */
 	if (dev->of_node)
-		chan = of_dma_request_slave_channel(dev->of_node, name);
+		chan = of_dma_request_slave_channel(dev, name);
 
 	/* If device was enumerated by ACPI get slave info from here */
 	if (has_acpi_companion(dev) && !chan)
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index b1655e40cfa2..1eb8a31b6775 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -29,7 +29,7 @@
 #define DRV_NAME	"dw_dmac"
 
 static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				 struct of_dma *ofdma, struct device *slave_dev)
 {
 	struct dw_dma *dw = ofdma->of_dma_data;
 	struct dw_dma_slave slave = {
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 3879f80a4815..d2e7d893d984 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -2117,7 +2117,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
 }
 
 static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct edma_cc *ecc = ofdma->of_dma_data;
 	struct dma_chan *chan = NULL;
@@ -2161,7 +2161,7 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
 }
 
 static struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	return NULL;
 }
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index 6775f2c74e25..915aa8182204 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -750,7 +750,7 @@ static void fsl_edma_issue_pending(struct dma_chan *chan)
 }
 
 static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
 	struct dma_chan *chan, *_chan;
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index 54db1411ce73..9a969cbdd384 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -793,7 +793,7 @@ static irqreturn_t mdc_chan_irq(int irq, void *dev_id)
 }
 
 static struct dma_chan *mdc_of_xlate(struct of_phandle_args *dma_spec,
-				     struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct mdc_dma *mdma = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index ab0fb804fb1e..b145babe366b 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -1032,7 +1032,7 @@ static bool imxdma_filter_fn(struct dma_chan *chan, void *param)
 }
 
 static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct imxdma_engine *imxdma = ofdma->of_dma_data;
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index d1651a50c349..7c3cdb378f98 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1659,7 +1659,7 @@ static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
-				   struct of_dma *ofdma)
+				   struct of_dma *ofdma, struct device *slave)
 {
 	struct sdma_engine *sdma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = sdma->dma_device.cap_mask;
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 01e25c68dd5a..dd0e7fe9e54a 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -786,7 +786,7 @@ static int k3_dma_transfer_resume(struct dma_chan *chan)
 MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
 
 static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct k3_dma_dev *d = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c
index 761f32687055..e730bcc8d92e 100644
--- a/drivers/dma/lpc18xx-dmamux.c
+++ b/drivers/dma/lpc18xx-dmamux.c
@@ -53,7 +53,7 @@ static void lpc18xx_dmamux_free(struct device *dev, void *route_data)
 }
 
 static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec,
-				    struct of_dma *ofdma)
+				    struct of_dma *ofdma, struct device *slave)
 {
 	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
 	struct lpc18xx_dmamux_data *dmamux = platform_get_drvdata(pdev);
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index eb3a1f42ab06..569ec8f1ccee 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -993,7 +993,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
 MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids);
 
 static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct mmp_pdma_device *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 13c68b6434ce..ca56e73797c9 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -591,7 +591,7 @@ static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
-			       struct of_dma *ofdma)
+			       struct of_dma *ofdma, struct device *slave)
 {
 	struct mmp_tdma_device *tdev = ofdma->of_dma_data;
 	dma_cap_mask_t mask = tdev->device.cap_mask;
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
index e1a5c2242f6f..d7c32a3c1bac 100644
--- a/drivers/dma/moxart-dma.c
+++ b/drivers/dma/moxart-dma.c
@@ -330,7 +330,7 @@ static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
 }
 
 static struct dma_chan *moxart_of_xlate(struct of_phandle_args *dma_spec,
-					struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct moxart_dmadev *mdc = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index e217268c7098..3cc0e6b99f13 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -747,7 +747,7 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
 }
 
 static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
-			       struct of_dma *ofdma)
+			       struct of_dma *ofdma, struct device *slave)
 {
 	struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data;
 	dma_cap_mask_t mask = mxs_dma->dma_device.cap_mask;
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 3f45b9bdf201..cb6a981beacd 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1096,7 +1096,7 @@ static void nbpf_free_chan_resources(struct dma_chan *dchan)
 }
 
 static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
-				      struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct nbpf_device *nbpf = ofdma->of_dma_data;
 	struct dma_chan *dchan;
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index faae0bfe1109..b6fd9e10758c 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -54,7 +54,8 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
  * to request channel from the real DMA controller.
  */
 static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
-					    struct of_dma *ofdma)
+					    struct of_dma *ofdma,
+					    struct device *slave)
 {
 	struct dma_chan		*chan;
 	struct of_dma		*ofdma_target;
@@ -71,7 +72,8 @@ static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
 	if (!ofdma_target)
 		return NULL;
 
-	chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target);
+	chan = ofdma_target->of_dma_xlate(&dma_spec_target, ofdma_target,
+					  slave);
 	if (chan) {
 		chan->router = ofdma->dma_router;
 		chan->route_data = route_data;
@@ -103,7 +105,8 @@ static struct dma_chan *of_dma_router_xlate(struct of_phandle_args *dma_spec,
  */
 int of_dma_controller_register(struct device_node *np,
 				struct dma_chan *(*of_dma_xlate)
-				(struct of_phandle_args *, struct of_dma *),
+				(struct of_phandle_args *, struct of_dma *,
+				 struct device *),
 				void *data)
 {
 	struct of_dma	*ofdma;
@@ -229,14 +232,15 @@ static int of_dma_match_channel(struct device_node *np, const char *name,
 
 /**
  * of_dma_request_slave_channel - Get the DMA slave channel
- * @np:		device node to get DMA request from
+ * @slave:		device to get DMA request from
  * @name:	name of desired channel
  *
  * Returns pointer to appropriate DMA channel on success or an error pointer.
  */
-struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 					      const char *name)
 {
+	struct device_node	*np = slave->of_node;
 	struct of_phandle_args	dma_spec;
 	struct of_dma		*ofdma;
 	struct dma_chan		*chan;
@@ -275,7 +279,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 		ofdma = of_dma_find_controller(&dma_spec);
 
 		if (ofdma) {
-			chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
+			chan = ofdma->of_dma_xlate(&dma_spec, ofdma, slave);
 		} else {
 			ret_no_channel = -EPROBE_DEFER;
 			chan = NULL;
@@ -305,7 +309,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
  * pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct of_dma_filter_info *info = ofdma->of_dma_data;
@@ -335,7 +339,7 @@ struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
  * Returns pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
-					 struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct dma_device *dev = ofdma->of_dma_data;
 	struct dma_chan *chan, *candidate = NULL;
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 78be12b45a45..b6b2cc912380 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2076,7 +2076,8 @@ static void pl330_tasklet(unsigned long data)
 }
 
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+					   struct of_dma *ofdma,
+					   struct device *slave)
 {
 	int count = dma_spec->args_count;
 	struct pl330_dmac *pl330 = ofdma->of_dma_data;
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index b53fb618bbf6..434764b43d68 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1336,7 +1336,7 @@ static int pxad_init_phys(struct platform_device *op,
 MODULE_DEVICE_TABLE(of, pxad_dt_ids);
 
 static struct dma_chan *pxad_dma_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct pxad_device *d = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 03c4eb3fd314..7ff3075c0702 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -1049,7 +1049,7 @@ static void bam_dma_free_desc(struct virt_dma_desc *vd)
 }
 
 static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *of)
+				      struct of_dma *of, struct device *slave)
 {
 	struct bam_device *bdev = container_of(of->of_dma_data,
 					struct bam_device, common);
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 4c357d475465..c450235ff51c 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1560,7 +1560,7 @@ static bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
 }
 
 static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct rcar_dmac_chan *rchan;
 	struct dma_chan *chan;
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
index f999f9b0d314..9953be99627b 100644
--- a/drivers/dma/sh/shdma-of.c
+++ b/drivers/dma/sh/shdma-of.c
@@ -20,7 +20,7 @@
 #define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
 
 static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
-				       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	u32 id = dma_spec->args[0];
 	dma_cap_mask_t mask;
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 72c649713ace..0f06a9468df9 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -650,7 +650,7 @@ static bool usb_dmac_chan_filter(struct dma_chan *chan, void *arg)
 }
 
 static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec,
-					  struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct dma_chan *chan;
 	dma_cap_mask_t mask;
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index a0733ac3edb1..ed6f07b0d758 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -826,7 +826,7 @@ bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id)
 	BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
 
 static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
-	struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sirfsoc_dma *sdma = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
index bfb79bd0c6de..6a92a6505419 100644
--- a/drivers/dma/st_fdma.c
+++ b/drivers/dma/st_fdma.c
@@ -167,7 +167,7 @@ static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
 }
 
 static struct dma_chan *st_fdma_of_xlate(struct of_phandle_args *dma_spec,
-					 struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct st_fdma_dev *fdev = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index a6620b671d1d..9fade9209d93 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -2334,7 +2334,7 @@ static void d40_set_prio_realtime(struct d40_chan *d40c)
 #define D40_DT_FLAGS_HIGH_PRIO(flags)  ((flags >> 4) & 0x1)
 
 static struct dma_chan *d40_xlate(struct of_phandle_args *dma_spec,
-				  struct of_dma *ofdma)
+				  struct of_dma *ofdma, struct device *slave)
 {
 	struct stedma40_chan_cfg cfg;
 	dma_cap_mask_t cap;
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 49f86cabcfec..495a4f5c5c26 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -980,7 +980,7 @@ static void stm32_dma_set_config(struct stm32_dma_chan *chan,
 }
 
 static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct stm32_dma_device *dmadev = ofdma->of_dma_data;
 	struct device *dev = dmadev->ddev.dev;
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index 57aa227bfadb..c1a076334abf 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -909,7 +909,7 @@ static int sun4i_dma_config(struct dma_chan *chan,
 }
 
 static struct dma_chan *sun4i_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sun4i_dma_dev *priv = ofdma->of_dma_data;
 	struct sun4i_dma_vchan *vchan;
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a2358780ab2c..240e4a95913a 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -930,7 +930,7 @@ static void sun6i_dma_free_chan_resources(struct dma_chan *chan)
 }
 
 static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct sun6i_dma_dev *sdev = ofdma->of_dma_data;
 	struct sun6i_vchan *vchan;
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 3722b9d8d9fe..e0eb5813fcf5 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1239,7 +1239,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 }
 
 static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct tegra_dma *tdma = ofdma->of_dma_data;
 	struct dma_chan *chan;
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index b10cbaa82ff5..525af32132ac 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -605,7 +605,7 @@ static void tegra_adma_free_chan_resources(struct dma_chan *dc)
 }
 
 static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
-					   struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct tegra_adma *tdma = ofdma->of_dma_data;
 	struct tegra_adma_chan *tdc;
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 8288fe4d17c3..69cdfc39edb2 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -2461,7 +2461,7 @@ static int xilinx_dma_child_probe(struct xilinx_dma_device *xdev,
  * Return: DMA channel pointer on success and NULL on error
  */
 static struct dma_chan *of_dma_xilinx_xlate(struct of_phandle_args *dma_spec,
-						struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct xilinx_dma_device *xdev = ofdma->of_dma_data;
 	int chan_id = dma_spec->args[0];
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index 6d221e5c72ee..6aa133c514f1 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -1040,7 +1040,7 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
  * Return: DMA channel pointer on success and NULL on error
  */
 static struct dma_chan *of_zynqmp_dma_xlate(struct of_phandle_args *dma_spec,
-					    struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct zynqmp_dma_device *zdev = ofdma->of_dma_data;
 
diff --git a/drivers/dma/zx_dma.c b/drivers/dma/zx_dma.c
index 42ff3e66c1e1..6e050dbe5f26 100644
--- a/drivers/dma/zx_dma.c
+++ b/drivers/dma/zx_dma.c
@@ -732,7 +732,7 @@ static void zx_dma_free_desc(struct virt_dma_desc *vd)
 MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids);
 
 static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-					       struct of_dma *ofdma)
+				     struct of_dma *ofdma, struct device *slave)
 {
 	struct zx_dma_dev *d = ofdma->of_dma_data;
 	unsigned int request = dma_spec->args[0];
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index b90d8ec57c1f..a0a6c8c17669 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -22,7 +22,8 @@ struct of_dma {
 	struct list_head	of_dma_controllers;
 	struct device_node	*of_node;
 	struct dma_chan		*(*of_dma_xlate)
-				(struct of_phandle_args *, struct of_dma *);
+				(struct of_phandle_args *, struct of_dma *,
+				 struct device *);
 	void			*(*of_dma_route_allocate)
 				(struct of_phandle_args *, struct of_dma *);
 	struct dma_router	*dma_router;
@@ -37,7 +38,7 @@ struct of_dma_filter_info {
 #ifdef CONFIG_DMA_OF
 extern int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
-		(struct of_phandle_args *, struct of_dma *),
+		(struct of_phandle_args *, struct of_dma *, struct device *),
 		void *data);
 extern void of_dma_controller_free(struct device_node *np);
 
@@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
 		struct dma_router *dma_router);
 #define of_dma_router_free of_dma_controller_free
 
-extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 						     const char *name);
 extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma);
+		struct of_dma *ofdma, struct device *slave);
 extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma);
+		struct of_dma *ofdma, struct device *slave);
 
 #else
 static inline int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
-		(struct of_phandle_args *, struct of_dma *),
+		(struct of_phandle_args *, struct of_dma *, struct device *),
 		void *data)
 {
 	return -ENODEV;
@@ -77,14 +78,14 @@ static inline int of_dma_router_register(struct device_node *np,
 
 #define of_dma_router_free of_dma_controller_free
 
-static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
+static inline struct dma_chan *of_dma_request_slave_channel(struct device *slave,
 						     const char *name)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
-		struct of_dma *ofdma)
+		struct of_dma *ofdma, struct device *slave)
 {
 	return NULL;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 3/4] dmaengine: pl330: Store pointer to slave device
       [not found]   ` <CGME20170124092751eucas1p2807f068bdbcd695d0bec355e6b509d6c@eucas1p2.samsung.com>
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm
  Cc: Marek Szyprowski, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Vinod Koul, Ulf Hansson, Rafael J. Wysocki, Inki Dae

Store the pointer to slave device, which requested our channel. It will be
later used to implement runtime PM of PL330 DMA controller. Although
DMA channels might be requested many times, each DMA peripheral channel is
physically dedicated only for specific hardware, so there should be only
one slave device for each channel.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/pl330.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index b6b2cc912380..c77a3494659c 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -450,6 +450,7 @@ struct dma_pl330_chan {
 
 	/* for runtime pm tracking */
 	bool active;
+	struct device *slave;
 };
 
 struct pl330_dmac {
@@ -2093,6 +2094,14 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 	if (chan_id >= pl330->num_peripherals)
 		return NULL;
 
+	if (!pl330->peripherals[chan_id].slave) {
+		pl330->peripherals[chan_id].slave = slave;
+	} else if (pl330->peripherals[chan_id].slave != slave) {
+		dev_err(pl330->ddma.dev,
+			"Can't use same channel with multiple slave devices!\n");
+		return NULL;
+	}
+
 	return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 3/4] dmaengine: pl330: Store pointer to slave device
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

Store the pointer to slave device, which requested our channel. It will be
later used to implement runtime PM of PL330 DMA controller. Although
DMA channels might be requested many times, each DMA peripheral channel is
physically dedicated only for specific hardware, so there should be only
one slave device for each channel.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/pl330.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index b6b2cc912380..c77a3494659c 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -450,6 +450,7 @@ struct dma_pl330_chan {
 
 	/* for runtime pm tracking */
 	bool active;
+	struct device *slave;
 };
 
 struct pl330_dmac {
@@ -2093,6 +2094,14 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 	if (chan_id >= pl330->num_peripherals)
 		return NULL;
 
+	if (!pl330->peripherals[chan_id].slave) {
+		pl330->peripherals[chan_id].slave = slave;
+	} else if (pl330->peripherals[chan_id].slave != slave) {
+		dev_err(pl330->ddma.dev,
+			"Can't use same channel with multiple slave devices!\n");
+		return NULL;
+	}
+
 	return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 4/4] dmaengine: pl330: Don't require irq-safe runtime PM
       [not found]   ` <CGME20170124092752eucas1p2ee498423f61db49f60612ee11d343cf5@eucas1p2.samsung.com>
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm
  Cc: Marek Szyprowski, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Vinod Koul, Ulf Hansson, Rafael J. Wysocki, Inki Dae

This patch replaces irq-safe runtime PM with non-irq-safe version based on
the new approach. Existing, irq-safe runtime PM implementation for PL330 was
not bringing much benefits of its own - only clocks were enabled/disabled.

Till now non-irq-safe runtime PM implementation was only possible by calling
pm_runtime_get/put functions from alloc/free_chan_resources. All other DMA
engine API functions cannot be called from a context, which permits sleeping.
Such implementation, in practice would result in keeping DMA controller's
device active almost all the time, because most of the slave device drivers
(DMA engine clients) acquire DMA channel in their probe() function and
released it during driver removal.

This patch provides a new, different approach. It is based on an observation
that there can be only one slave device using each DMA channel. PL330 hardware
always has dedicated channels for each peripheral device. Using recently
introduced device dependencies (links) infrastructure one can ensure proper
runtime PM state of PL330 DMA controller basing on the runtime PM state of
the slave device.

In this approach in pl330_alloc_chan_resources() function a new dependency
is being created between PL330 DMA controller device (as a supplier) and
given slave device (as a consumer). This way PL330 DMA controller device
runtime active counter is increased when the slave device is resumed and
decreased the same time when given slave device is put to suspend. This way
it has been ensured to keep PL330 DMA controller runtime active if there is
an active used of any of its DMA channels. Slave device pointer is initially
stored in per-channel data in of_dma_xlate callback. This is similar to what
has been already implemented in Exynos IOMMU driver in commit 2f5f44f205cc95
("iommu/exynos: Use device dependency links to control runtime pm").

If slave device doesn't implement runtime PM or keeps device runtime active
all the time, then PL330 DMA controller will be runtime active all the time
when channel is being allocated. The goal is however to have runtime PM
added to all devices in the system, because it lets respective power
domains to be turned off, what gives the best results in terms of power
saving.

If one requests memory-to-memory channel, runtime active counter is
increased unconditionally. This might be a drawback of this approach, but
PL330 is not really used for memory-to-memory operations due to poor
performance in such operations compared to the CPU.

Introducing non-irq-safe runtime power management finally allows to turn off
audio power domain on Exynos5 SoCs.

Removal of irq-safe runtime PM is based on the revert of the following
commits:
1. commit 5c9e6c2b2ba3 "dmaengine: pl330: fix runtime pm support"
2. commit 81cc6edc0870 "dmaengine: pl330: Fix hang on dmaengine_terminate_all
   on certain boards"
3. commit ae43b3289186 "ARM: 8202/1: dmaengine: pl330: Add runtime Power
   Management support v12"

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/pl330.c | 166 +++++++++++++++++++++-------------------------------
 1 file changed, 66 insertions(+), 100 deletions(-)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index c77a3494659c..dff7228198f6 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -268,9 +268,6 @@ enum pl330_byteswap {
 
 #define NR_DEFAULT_DESC	16
 
-/* Delay for runtime PM autosuspend, ms */
-#define PL330_AUTOSUSPEND_DELAY 20
-
 /* Populated by the PL330 core driver for DMA API driver's info */
 struct pl330_config {
 	u32	periph_id;
@@ -449,8 +446,8 @@ struct dma_pl330_chan {
 	bool cyclic;
 
 	/* for runtime pm tracking */
-	bool active;
 	struct device *slave;
+	struct device_link *slave_link;
 };
 
 struct pl330_dmac {
@@ -2008,7 +2005,6 @@ static void pl330_tasklet(unsigned long data)
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
 	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
-	bool power_down = false;
 
 	spin_lock_irqsave(&pch->lock, flags);
 
@@ -2023,18 +2019,10 @@ static void pl330_tasklet(unsigned long data)
 	/* Try to submit a req imm. next to the last completed cookie */
 	fill_queue(pch);
 
-	if (list_empty(&pch->work_list)) {
-		spin_lock(&pch->thread->dmac->lock);
-		_stop(pch->thread);
-		spin_unlock(&pch->thread->dmac->lock);
-		power_down = true;
-		pch->active = false;
-	} else {
-		/* Make sure the PL330 Channel thread is active */
-		spin_lock(&pch->thread->dmac->lock);
-		_start(pch->thread);
-		spin_unlock(&pch->thread->dmac->lock);
-	}
+	/* Make sure the PL330 Channel thread is active */
+	spin_lock(&pch->thread->dmac->lock);
+	_start(pch->thread);
+	spin_unlock(&pch->thread->dmac->lock);
 
 	while (!list_empty(&pch->completed_list)) {
 		struct dmaengine_desc_callback cb;
@@ -2047,13 +2035,6 @@ static void pl330_tasklet(unsigned long data)
 		if (pch->cyclic) {
 			desc->status = PREP;
 			list_move_tail(&desc->node, &pch->work_list);
-			if (power_down) {
-				pch->active = true;
-				spin_lock(&pch->thread->dmac->lock);
-				_start(pch->thread);
-				spin_unlock(&pch->thread->dmac->lock);
-				power_down = false;
-			}
 		} else {
 			desc->status = FREE;
 			list_move_tail(&desc->node, &pch->dmac->desc_pool);
@@ -2068,12 +2049,6 @@ static void pl330_tasklet(unsigned long data)
 		}
 	}
 	spin_unlock_irqrestore(&pch->lock, flags);
-
-	/* If work list empty, power down */
-	if (power_down) {
-		pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-		pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
-	}
 }
 
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
@@ -2105,11 +2080,63 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 	return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
 }
 
+static int pl330_add_slave_pm_link(struct pl330_dmac *pl330,
+				   struct dma_pl330_chan *pch)
+{
+	int i;
+
+	/* No slave device means memory-to-memory channels */
+	if (!pch->slave)
+		return pm_runtime_get_sync(pl330->ddma.dev);
+
+	/*
+	 * No additional locking is needed, {alloc,free}_chan_resources
+	 * are called under dma_list_mutex in dmaengine core
+	 */
+	for (i = 0; i < pl330->num_peripherals; i++) {
+		if (pl330->peripherals[i].slave == pch->slave &&
+		    pl330->peripherals[i].slave_link) {
+			pch->slave_link = pl330->peripherals[i].slave_link;
+			return 0;
+		}
+	}
+
+	pch->slave_link = device_link_add(pch->slave, pl330->ddma.dev,
+				       DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (!pch->slave_link)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void pl330_del_slave_pm_link(struct pl330_dmac *pl330,
+				    struct dma_pl330_chan *pch)
+{
+	struct device_link *link = pch->slave_link;
+	int i, count = 0;
+
+	if (!pch->slave)
+		pm_runtime_put(pl330->ddma.dev);
+
+	for (i = 0; i < pl330->num_peripherals; i++)
+		if (pl330->peripherals[i].slave_link == link)
+			count++;
+
+	pch->slave_link = NULL;
+	if (count == 1)
+		device_link_del(link);
+}
+
 static int pl330_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
 	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
+	int ret;
+
+	ret = pl330_add_slave_pm_link(pl330, pch);
+	if (ret < 0)
+		return ret;
 
 	spin_lock_irqsave(&pl330->lock, flags);
 
@@ -2119,6 +2146,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 	pch->thread = pl330_request_channel(pl330);
 	if (!pch->thread) {
 		spin_unlock_irqrestore(&pl330->lock, flags);
+		pl330_del_slave_pm_link(pl330, pch);
 		return -ENOMEM;
 	}
 
@@ -2160,9 +2188,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	unsigned long flags;
 	struct pl330_dmac *pl330 = pch->dmac;
 	LIST_HEAD(list);
-	bool power_down = false;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
 	spin_lock(&pl330->lock);
 	_stop(pch->thread);
@@ -2171,8 +2197,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	pch->thread->req[0].desc = NULL;
 	pch->thread->req[1].desc = NULL;
 	pch->thread->req_running = -1;
-	power_down = pch->active;
-	pch->active = false;
 
 	/* Mark all desc done */
 	list_for_each_entry(desc, &pch->submitted_list, node) {
@@ -2189,10 +2213,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
 	list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
 	spin_unlock_irqrestore(&pch->lock, flags);
-	pm_runtime_mark_last_busy(pl330->ddma.dev);
-	if (power_down)
-		pm_runtime_put_autosuspend(pl330->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	return 0;
 }
@@ -2210,7 +2230,6 @@ static int pl330_pause(struct dma_chan *chan)
 	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
 
 	spin_lock(&pl330->lock);
@@ -2218,8 +2237,6 @@ static int pl330_pause(struct dma_chan *chan)
 	spin_unlock(&pl330->lock);
 
 	spin_unlock_irqrestore(&pch->lock, flags);
-	pm_runtime_mark_last_busy(pl330->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	return 0;
 }
@@ -2232,7 +2249,6 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 
 	tasklet_kill(&pch->task);
 
-	pm_runtime_get_sync(pch->dmac->ddma.dev);
 	spin_lock_irqsave(&pl330->lock, flags);
 
 	pl330_release_channel(pch->thread);
@@ -2242,19 +2258,17 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 
 	spin_unlock_irqrestore(&pl330->lock, flags);
-	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
+
+	pl330_del_slave_pm_link(pl330, pch);
 }
 
 static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
 					   struct dma_pl330_desc *desc)
 {
 	struct pl330_thread *thrd = pch->thread;
-	struct pl330_dmac *pl330 = pch->dmac;
 	void __iomem *regs = thrd->dmac->base;
 	u32 val, addr;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	val = addr = 0;
 	if (desc->rqcfg.src_inc) {
 		val = readl(regs + SA(thrd->id));
@@ -2263,8 +2277,6 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
 		val = readl(regs + DA(thrd->id));
 		addr = desc->px.dst_addr;
 	}
-	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	/* If DMAMOV hasn't finished yet, SAR/DAR can be zero */
 	if (!val)
@@ -2350,16 +2362,6 @@ static void pl330_issue_pending(struct dma_chan *chan)
 	unsigned long flags;
 
 	spin_lock_irqsave(&pch->lock, flags);
-	if (list_empty(&pch->work_list)) {
-		/*
-		 * Warn on nothing pending. Empty submitted_list may
-		 * break our pm_runtime usage counter as it is
-		 * updated on work_list emptiness status.
-		 */
-		WARN_ON(list_empty(&pch->submitted_list));
-		pch->active = true;
-		pm_runtime_get_sync(pch->dmac->ddma.dev);
-	}
 	list_splice_tail_init(&pch->submitted_list, &pch->work_list);
 	spin_unlock_irqrestore(&pch->lock, flags);
 
@@ -2787,44 +2789,12 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
 	BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
 
 /*
- * Runtime PM callbacks are provided by amba/bus.c driver.
- *
- * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
- * bus driver will only disable/enable the clock in runtime PM callbacks.
+ * Runtime PM callbacks are provided by amba/bus.c driver, system sleep
+ * suspend/resume is implemented by generic helpers, which use existing
+ * runtime PM callbacks.
  */
-static int __maybe_unused pl330_suspend(struct device *dev)
-{
-	struct amba_device *pcdev = to_amba_device(dev);
-
-	pm_runtime_disable(dev);
-
-	if (!pm_runtime_status_suspended(dev)) {
-		/* amba did not disable the clock */
-		amba_pclk_disable(pcdev);
-	}
-	amba_pclk_unprepare(pcdev);
-
-	return 0;
-}
-
-static int __maybe_unused pl330_resume(struct device *dev)
-{
-	struct amba_device *pcdev = to_amba_device(dev);
-	int ret;
-
-	ret = amba_pclk_prepare(pcdev);
-	if (ret)
-		return ret;
-
-	if (!pm_runtime_status_suspended(dev))
-		ret = amba_pclk_enable(pcdev);
-
-	pm_runtime_enable(dev);
-
-	return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
+static SIMPLE_DEV_PM_OPS(pl330_pm, pm_runtime_force_suspend,
+			 pm_runtime_force_resume);
 
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
@@ -2977,11 +2947,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 		pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
 		pcfg->num_peri, pcfg->num_events);
 
-	pm_runtime_irq_safe(&adev->dev);
-	pm_runtime_use_autosuspend(&adev->dev);
-	pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
-	pm_runtime_mark_last_busy(&adev->dev);
-	pm_runtime_put_autosuspend(&adev->dev);
+	pm_runtime_put(&adev->dev);
 
 	return 0;
 probe_err3:
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 4/4] dmaengine: pl330: Don't require irq-safe runtime PM
@ 2017-01-24  9:27       ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-24  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch replaces irq-safe runtime PM with non-irq-safe version based on
the new approach. Existing, irq-safe runtime PM implementation for PL330 was
not bringing much benefits of its own - only clocks were enabled/disabled.

Till now non-irq-safe runtime PM implementation was only possible by calling
pm_runtime_get/put functions from alloc/free_chan_resources. All other DMA
engine API functions cannot be called from a context, which permits sleeping.
Such implementation, in practice would result in keeping DMA controller's
device active almost all the time, because most of the slave device drivers
(DMA engine clients) acquire DMA channel in their probe() function and
released it during driver removal.

This patch provides a new, different approach. It is based on an observation
that there can be only one slave device using each DMA channel. PL330 hardware
always has dedicated channels for each peripheral device. Using recently
introduced device dependencies (links) infrastructure one can ensure proper
runtime PM state of PL330 DMA controller basing on the runtime PM state of
the slave device.

In this approach in pl330_alloc_chan_resources() function a new dependency
is being created between PL330 DMA controller device (as a supplier) and
given slave device (as a consumer). This way PL330 DMA controller device
runtime active counter is increased when the slave device is resumed and
decreased the same time when given slave device is put to suspend. This way
it has been ensured to keep PL330 DMA controller runtime active if there is
an active used of any of its DMA channels. Slave device pointer is initially
stored in per-channel data in of_dma_xlate callback. This is similar to what
has been already implemented in Exynos IOMMU driver in commit 2f5f44f205cc95
("iommu/exynos: Use device dependency links to control runtime pm").

If slave device doesn't implement runtime PM or keeps device runtime active
all the time, then PL330 DMA controller will be runtime active all the time
when channel is being allocated. The goal is however to have runtime PM
added to all devices in the system, because it lets respective power
domains to be turned off, what gives the best results in terms of power
saving.

If one requests memory-to-memory channel, runtime active counter is
increased unconditionally. This might be a drawback of this approach, but
PL330 is not really used for memory-to-memory operations due to poor
performance in such operations compared to the CPU.

Introducing non-irq-safe runtime power management finally allows to turn off
audio power domain on Exynos5 SoCs.

Removal of irq-safe runtime PM is based on the revert of the following
commits:
1. commit 5c9e6c2b2ba3 "dmaengine: pl330: fix runtime pm support"
2. commit 81cc6edc0870 "dmaengine: pl330: Fix hang on dmaengine_terminate_all
   on certain boards"
3. commit ae43b3289186 "ARM: 8202/1: dmaengine: pl330: Add runtime Power
   Management support v12"

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/dma/pl330.c | 166 +++++++++++++++++++++-------------------------------
 1 file changed, 66 insertions(+), 100 deletions(-)

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index c77a3494659c..dff7228198f6 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -268,9 +268,6 @@ enum pl330_byteswap {
 
 #define NR_DEFAULT_DESC	16
 
-/* Delay for runtime PM autosuspend, ms */
-#define PL330_AUTOSUSPEND_DELAY 20
-
 /* Populated by the PL330 core driver for DMA API driver's info */
 struct pl330_config {
 	u32	periph_id;
@@ -449,8 +446,8 @@ struct dma_pl330_chan {
 	bool cyclic;
 
 	/* for runtime pm tracking */
-	bool active;
 	struct device *slave;
+	struct device_link *slave_link;
 };
 
 struct pl330_dmac {
@@ -2008,7 +2005,6 @@ static void pl330_tasklet(unsigned long data)
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
 	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
-	bool power_down = false;
 
 	spin_lock_irqsave(&pch->lock, flags);
 
@@ -2023,18 +2019,10 @@ static void pl330_tasklet(unsigned long data)
 	/* Try to submit a req imm. next to the last completed cookie */
 	fill_queue(pch);
 
-	if (list_empty(&pch->work_list)) {
-		spin_lock(&pch->thread->dmac->lock);
-		_stop(pch->thread);
-		spin_unlock(&pch->thread->dmac->lock);
-		power_down = true;
-		pch->active = false;
-	} else {
-		/* Make sure the PL330 Channel thread is active */
-		spin_lock(&pch->thread->dmac->lock);
-		_start(pch->thread);
-		spin_unlock(&pch->thread->dmac->lock);
-	}
+	/* Make sure the PL330 Channel thread is active */
+	spin_lock(&pch->thread->dmac->lock);
+	_start(pch->thread);
+	spin_unlock(&pch->thread->dmac->lock);
 
 	while (!list_empty(&pch->completed_list)) {
 		struct dmaengine_desc_callback cb;
@@ -2047,13 +2035,6 @@ static void pl330_tasklet(unsigned long data)
 		if (pch->cyclic) {
 			desc->status = PREP;
 			list_move_tail(&desc->node, &pch->work_list);
-			if (power_down) {
-				pch->active = true;
-				spin_lock(&pch->thread->dmac->lock);
-				_start(pch->thread);
-				spin_unlock(&pch->thread->dmac->lock);
-				power_down = false;
-			}
 		} else {
 			desc->status = FREE;
 			list_move_tail(&desc->node, &pch->dmac->desc_pool);
@@ -2068,12 +2049,6 @@ static void pl330_tasklet(unsigned long data)
 		}
 	}
 	spin_unlock_irqrestore(&pch->lock, flags);
-
-	/* If work list empty, power down */
-	if (power_down) {
-		pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-		pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
-	}
 }
 
 static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
@@ -2105,11 +2080,63 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 	return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
 }
 
+static int pl330_add_slave_pm_link(struct pl330_dmac *pl330,
+				   struct dma_pl330_chan *pch)
+{
+	int i;
+
+	/* No slave device means memory-to-memory channels */
+	if (!pch->slave)
+		return pm_runtime_get_sync(pl330->ddma.dev);
+
+	/*
+	 * No additional locking is needed, {alloc,free}_chan_resources
+	 * are called under dma_list_mutex in dmaengine core
+	 */
+	for (i = 0; i < pl330->num_peripherals; i++) {
+		if (pl330->peripherals[i].slave == pch->slave &&
+		    pl330->peripherals[i].slave_link) {
+			pch->slave_link = pl330->peripherals[i].slave_link;
+			return 0;
+		}
+	}
+
+	pch->slave_link = device_link_add(pch->slave, pl330->ddma.dev,
+				       DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
+	if (!pch->slave_link)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void pl330_del_slave_pm_link(struct pl330_dmac *pl330,
+				    struct dma_pl330_chan *pch)
+{
+	struct device_link *link = pch->slave_link;
+	int i, count = 0;
+
+	if (!pch->slave)
+		pm_runtime_put(pl330->ddma.dev);
+
+	for (i = 0; i < pl330->num_peripherals; i++)
+		if (pl330->peripherals[i].slave_link == link)
+			count++;
+
+	pch->slave_link = NULL;
+	if (count == 1)
+		device_link_del(link);
+}
+
 static int pl330_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
 	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
+	int ret;
+
+	ret = pl330_add_slave_pm_link(pl330, pch);
+	if (ret < 0)
+		return ret;
 
 	spin_lock_irqsave(&pl330->lock, flags);
 
@@ -2119,6 +2146,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 	pch->thread = pl330_request_channel(pl330);
 	if (!pch->thread) {
 		spin_unlock_irqrestore(&pl330->lock, flags);
+		pl330_del_slave_pm_link(pl330, pch);
 		return -ENOMEM;
 	}
 
@@ -2160,9 +2188,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	unsigned long flags;
 	struct pl330_dmac *pl330 = pch->dmac;
 	LIST_HEAD(list);
-	bool power_down = false;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
 	spin_lock(&pl330->lock);
 	_stop(pch->thread);
@@ -2171,8 +2197,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	pch->thread->req[0].desc = NULL;
 	pch->thread->req[1].desc = NULL;
 	pch->thread->req_running = -1;
-	power_down = pch->active;
-	pch->active = false;
 
 	/* Mark all desc done */
 	list_for_each_entry(desc, &pch->submitted_list, node) {
@@ -2189,10 +2213,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
 	list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
 	list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
 	spin_unlock_irqrestore(&pch->lock, flags);
-	pm_runtime_mark_last_busy(pl330->ddma.dev);
-	if (power_down)
-		pm_runtime_put_autosuspend(pl330->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	return 0;
 }
@@ -2210,7 +2230,6 @@ static int pl330_pause(struct dma_chan *chan)
 	struct pl330_dmac *pl330 = pch->dmac;
 	unsigned long flags;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	spin_lock_irqsave(&pch->lock, flags);
 
 	spin_lock(&pl330->lock);
@@ -2218,8 +2237,6 @@ static int pl330_pause(struct dma_chan *chan)
 	spin_unlock(&pl330->lock);
 
 	spin_unlock_irqrestore(&pch->lock, flags);
-	pm_runtime_mark_last_busy(pl330->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	return 0;
 }
@@ -2232,7 +2249,6 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 
 	tasklet_kill(&pch->task);
 
-	pm_runtime_get_sync(pch->dmac->ddma.dev);
 	spin_lock_irqsave(&pl330->lock, flags);
 
 	pl330_release_channel(pch->thread);
@@ -2242,19 +2258,17 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 
 	spin_unlock_irqrestore(&pl330->lock, flags);
-	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-	pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
+
+	pl330_del_slave_pm_link(pl330, pch);
 }
 
 static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
 					   struct dma_pl330_desc *desc)
 {
 	struct pl330_thread *thrd = pch->thread;
-	struct pl330_dmac *pl330 = pch->dmac;
 	void __iomem *regs = thrd->dmac->base;
 	u32 val, addr;
 
-	pm_runtime_get_sync(pl330->ddma.dev);
 	val = addr = 0;
 	if (desc->rqcfg.src_inc) {
 		val = readl(regs + SA(thrd->id));
@@ -2263,8 +2277,6 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
 		val = readl(regs + DA(thrd->id));
 		addr = desc->px.dst_addr;
 	}
-	pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
-	pm_runtime_put_autosuspend(pl330->ddma.dev);
 
 	/* If DMAMOV hasn't finished yet, SAR/DAR can be zero */
 	if (!val)
@@ -2350,16 +2362,6 @@ static void pl330_issue_pending(struct dma_chan *chan)
 	unsigned long flags;
 
 	spin_lock_irqsave(&pch->lock, flags);
-	if (list_empty(&pch->work_list)) {
-		/*
-		 * Warn on nothing pending. Empty submitted_list may
-		 * break our pm_runtime usage counter as it is
-		 * updated on work_list emptiness status.
-		 */
-		WARN_ON(list_empty(&pch->submitted_list));
-		pch->active = true;
-		pm_runtime_get_sync(pch->dmac->ddma.dev);
-	}
 	list_splice_tail_init(&pch->submitted_list, &pch->work_list);
 	spin_unlock_irqrestore(&pch->lock, flags);
 
@@ -2787,44 +2789,12 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
 	BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
 
 /*
- * Runtime PM callbacks are provided by amba/bus.c driver.
- *
- * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
- * bus driver will only disable/enable the clock in runtime PM callbacks.
+ * Runtime PM callbacks are provided by amba/bus.c driver, system sleep
+ * suspend/resume is implemented by generic helpers, which use existing
+ * runtime PM callbacks.
  */
-static int __maybe_unused pl330_suspend(struct device *dev)
-{
-	struct amba_device *pcdev = to_amba_device(dev);
-
-	pm_runtime_disable(dev);
-
-	if (!pm_runtime_status_suspended(dev)) {
-		/* amba did not disable the clock */
-		amba_pclk_disable(pcdev);
-	}
-	amba_pclk_unprepare(pcdev);
-
-	return 0;
-}
-
-static int __maybe_unused pl330_resume(struct device *dev)
-{
-	struct amba_device *pcdev = to_amba_device(dev);
-	int ret;
-
-	ret = amba_pclk_prepare(pcdev);
-	if (ret)
-		return ret;
-
-	if (!pm_runtime_status_suspended(dev))
-		ret = amba_pclk_enable(pcdev);
-
-	pm_runtime_enable(dev);
-
-	return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
+static SIMPLE_DEV_PM_OPS(pl330_pm, pm_runtime_force_suspend,
+			 pm_runtime_force_resume);
 
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
@@ -2977,11 +2947,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
 		pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
 		pcfg->num_peri, pcfg->num_events);
 
-	pm_runtime_irq_safe(&adev->dev);
-	pm_runtime_use_autosuspend(&adev->dev);
-	pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
-	pm_runtime_mark_last_busy(&adev->dev);
-	pm_runtime_put_autosuspend(&adev->dev);
+	pm_runtime_put(&adev->dev);
 
 	return 0;
 probe_err3:
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
  2017-01-24  9:27       ` Marek Szyprowski
@ 2017-01-24 15:09         ` Ulf Hansson
  -1 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:09 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, Vinod Koul,
	Rafael J. Wysocki, Inki Dae

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Add pointer to slave device to of_dma_xlate to let DMA engine driver
> to know which slave device is using given DMA channel. This will be
> later used to implement non-irq-safe runtime PM for DMA engine driver.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

[...]

> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
> index b90d8ec57c1f..a0a6c8c17669 100644
> --- a/include/linux/of_dma.h
> +++ b/include/linux/of_dma.h
> @@ -22,7 +22,8 @@ struct of_dma {
>         struct list_head        of_dma_controllers;
>         struct device_node      *of_node;
>         struct dma_chan         *(*of_dma_xlate)
> -                               (struct of_phandle_args *, struct of_dma *);
> +                               (struct of_phandle_args *, struct of_dma *,
> +                                struct device *);
>         void                    *(*of_dma_route_allocate)
>                                 (struct of_phandle_args *, struct of_dma *);
>         struct dma_router       *dma_router;
> @@ -37,7 +38,7 @@ struct of_dma_filter_info {
>  #ifdef CONFIG_DMA_OF
>  extern int of_dma_controller_register(struct device_node *np,
>                 struct dma_chan *(*of_dma_xlate)
> -               (struct of_phandle_args *, struct of_dma *),
> +               (struct of_phandle_args *, struct of_dma *, struct device *),
>                 void *data);
>  extern void of_dma_controller_free(struct device_node *np);
>
> @@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
>                 struct dma_router *dma_router);
>  #define of_dma_router_free of_dma_controller_free
>
> -extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
> +extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
>                                                      const char *name);

I noticed that this API is being used from sound/soc/sh/rcar/dma.c, so
I assume this change triggers a compiler error. I guess you want to
fold in a change dealing with that as well.

[...]

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
@ 2017-01-24 15:09         ` Ulf Hansson
  0 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Add pointer to slave device to of_dma_xlate to let DMA engine driver
> to know which slave device is using given DMA channel. This will be
> later used to implement non-irq-safe runtime PM for DMA engine driver.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

[...]

> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
> index b90d8ec57c1f..a0a6c8c17669 100644
> --- a/include/linux/of_dma.h
> +++ b/include/linux/of_dma.h
> @@ -22,7 +22,8 @@ struct of_dma {
>         struct list_head        of_dma_controllers;
>         struct device_node      *of_node;
>         struct dma_chan         *(*of_dma_xlate)
> -                               (struct of_phandle_args *, struct of_dma *);
> +                               (struct of_phandle_args *, struct of_dma *,
> +                                struct device *);
>         void                    *(*of_dma_route_allocate)
>                                 (struct of_phandle_args *, struct of_dma *);
>         struct dma_router       *dma_router;
> @@ -37,7 +38,7 @@ struct of_dma_filter_info {
>  #ifdef CONFIG_DMA_OF
>  extern int of_dma_controller_register(struct device_node *np,
>                 struct dma_chan *(*of_dma_xlate)
> -               (struct of_phandle_args *, struct of_dma *),
> +               (struct of_phandle_args *, struct of_dma *, struct device *),
>                 void *data);
>  extern void of_dma_controller_free(struct device_node *np);
>
> @@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
>                 struct dma_router *dma_router);
>  #define of_dma_router_free of_dma_controller_free
>
> -extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
> +extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
>                                                      const char *name);

I noticed that this API is being used from sound/soc/sh/rcar/dma.c, so
I assume this change triggers a compiler error. I guess you want to
fold in a change dealing with that as well.

[...]

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/4] dmaengine: pl330: remove pdata based initialization
  2017-01-24  9:27       ` Marek Szyprowski
@ 2017-01-24 15:10         ` Ulf Hansson
  -1 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:10 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, Vinod Koul,
	Rafael J. Wysocki, Inki Dae

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> This driver is now used only on platforms which support device tree, so
> it is safe to remove legacy platform data based initialization code.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> For plat-samsung:
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  arch/arm/plat-samsung/devs.c |  1 -
>  drivers/dma/pl330.c          | 42 ++++++++----------------------------------
>  include/linux/amba/pl330.h   | 35 -----------------------------------
>  3 files changed, 8 insertions(+), 70 deletions(-)
>  delete mode 100644 include/linux/amba/pl330.h
>
> diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
> index 03fac123676d..dc269d9143bc 100644
> --- a/arch/arm/plat-samsung/devs.c
> +++ b/arch/arm/plat-samsung/devs.c
> @@ -10,7 +10,6 @@
>   * published by the Free Software Foundation.
>  */
>
> -#include <linux/amba/pl330.h>
>  #include <linux/kernel.h>
>  #include <linux/types.h>
>  #include <linux/interrupt.h>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 7539f73df9e0..78be12b45a45 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -22,7 +22,6 @@
>  #include <linux/dma-mapping.h>
>  #include <linux/dmaengine.h>
>  #include <linux/amba/bus.h>
> -#include <linux/amba/pl330.h>
>  #include <linux/scatterlist.h>
>  #include <linux/of.h>
>  #include <linux/of_dma.h>
> @@ -2076,18 +2075,6 @@ static void pl330_tasklet(unsigned long data)
>         }
>  }
>
> -bool pl330_filter(struct dma_chan *chan, void *param)
> -{
> -       u8 *peri_id;
> -
> -       if (chan->device->dev->driver != &pl330_driver.drv)
> -               return false;
> -
> -       peri_id = chan->private;
> -       return *peri_id == (unsigned long)param;
> -}
> -EXPORT_SYMBOL(pl330_filter);
> -
>  static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>                                                 struct of_dma *ofdma)
>  {
> @@ -2832,7 +2819,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
>  {
> -       struct dma_pl330_platdata *pdat;
>         struct pl330_config *pcfg;
>         struct pl330_dmac *pl330;
>         struct dma_pl330_chan *pch, *_p;
> @@ -2842,8 +2828,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         int num_chan;
>         struct device_node *np = adev->dev.of_node;
>
> -       pdat = dev_get_platdata(&adev->dev);
> -
>         ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32));
>         if (ret)
>                 return ret;
> @@ -2856,7 +2840,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         pd = &pl330->ddma;
>         pd->dev = &adev->dev;
>
> -       pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
> +       pl330->mcbufsz = 0;
>
>         /* get quirk */
>         for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
> @@ -2900,10 +2884,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         INIT_LIST_HEAD(&pd->channels);
>
>         /* Initialize channel parameters */
> -       if (pdat)
> -               num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan);
> -       else
> -               num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
> +       num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
>
>         pl330->num_peripherals = num_chan;
>
> @@ -2915,11 +2896,8 @@ static int __maybe_unused pl330_resume(struct device *dev)
>
>         for (i = 0; i < num_chan; i++) {
>                 pch = &pl330->peripherals[i];
> -               if (!adev->dev.of_node)
> -                       pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;
> -               else
> -                       pch->chan.private = adev->dev.of_node;
>
> +               pch->chan.private = adev->dev.of_node;
>                 INIT_LIST_HEAD(&pch->submitted_list);
>                 INIT_LIST_HEAD(&pch->work_list);
>                 INIT_LIST_HEAD(&pch->completed_list);
> @@ -2932,15 +2910,11 @@ static int __maybe_unused pl330_resume(struct device *dev)
>                 list_add_tail(&pch->chan.device_node, &pd->channels);
>         }
>
> -       if (pdat) {
> -               pd->cap_mask = pdat->cap_mask;
> -       } else {
> -               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
> -               if (pcfg->num_peri) {
> -                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
> -                       dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> -                       dma_cap_set(DMA_PRIVATE, pd->cap_mask);
> -               }
> +       dma_cap_set(DMA_MEMCPY, pd->cap_mask);
> +       if (pcfg->num_peri) {
> +               dma_cap_set(DMA_SLAVE, pd->cap_mask);
> +               dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> +               dma_cap_set(DMA_PRIVATE, pd->cap_mask);
>         }
>
>         pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
> diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
> deleted file mode 100644
> index fe93758e8403..000000000000
> --- a/include/linux/amba/pl330.h
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -/* linux/include/linux/amba/pl330.h
> - *
> - * Copyright (C) 2010 Samsung Electronics Co. Ltd.
> - *     Jaswinder Singh <jassi.brar@samsung.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - */
> -
> -#ifndef        __AMBA_PL330_H_
> -#define        __AMBA_PL330_H_
> -
> -#include <linux/dmaengine.h>
> -
> -struct dma_pl330_platdata {
> -       /*
> -        * Number of valid peripherals connected to DMAC.
> -        * This may be different from the value read from
> -        * CR0, as the PL330 implementation might have 'holes'
> -        * in the peri list or the peri could also be reached
> -        * from another DMAC which the platform prefers.
> -        */
> -       u8 nr_valid_peri;
> -       /* Array of valid peripherals */
> -       u8 *peri_id;
> -       /* Operational capabilities */
> -       dma_cap_mask_t cap_mask;
> -       /* Bytes to allocate for MC buffer */
> -       unsigned mcbuf_sz;
> -};
> -
> -extern bool pl330_filter(struct dma_chan *chan, void *param);
> -#endif /* __AMBA_PL330_H_ */
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 1/4] dmaengine: pl330: remove pdata based initialization
@ 2017-01-24 15:10         ` Ulf Hansson
  0 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> This driver is now used only on platforms which support device tree, so
> it is safe to remove legacy platform data based initialization code.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> For plat-samsung:
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  arch/arm/plat-samsung/devs.c |  1 -
>  drivers/dma/pl330.c          | 42 ++++++++----------------------------------
>  include/linux/amba/pl330.h   | 35 -----------------------------------
>  3 files changed, 8 insertions(+), 70 deletions(-)
>  delete mode 100644 include/linux/amba/pl330.h
>
> diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
> index 03fac123676d..dc269d9143bc 100644
> --- a/arch/arm/plat-samsung/devs.c
> +++ b/arch/arm/plat-samsung/devs.c
> @@ -10,7 +10,6 @@
>   * published by the Free Software Foundation.
>  */
>
> -#include <linux/amba/pl330.h>
>  #include <linux/kernel.h>
>  #include <linux/types.h>
>  #include <linux/interrupt.h>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 7539f73df9e0..78be12b45a45 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -22,7 +22,6 @@
>  #include <linux/dma-mapping.h>
>  #include <linux/dmaengine.h>
>  #include <linux/amba/bus.h>
> -#include <linux/amba/pl330.h>
>  #include <linux/scatterlist.h>
>  #include <linux/of.h>
>  #include <linux/of_dma.h>
> @@ -2076,18 +2075,6 @@ static void pl330_tasklet(unsigned long data)
>         }
>  }
>
> -bool pl330_filter(struct dma_chan *chan, void *param)
> -{
> -       u8 *peri_id;
> -
> -       if (chan->device->dev->driver != &pl330_driver.drv)
> -               return false;
> -
> -       peri_id = chan->private;
> -       return *peri_id == (unsigned long)param;
> -}
> -EXPORT_SYMBOL(pl330_filter);
> -
>  static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>                                                 struct of_dma *ofdma)
>  {
> @@ -2832,7 +2819,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
>  {
> -       struct dma_pl330_platdata *pdat;
>         struct pl330_config *pcfg;
>         struct pl330_dmac *pl330;
>         struct dma_pl330_chan *pch, *_p;
> @@ -2842,8 +2828,6 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         int num_chan;
>         struct device_node *np = adev->dev.of_node;
>
> -       pdat = dev_get_platdata(&adev->dev);
> -
>         ret = dma_set_mask_and_coherent(&adev->dev, DMA_BIT_MASK(32));
>         if (ret)
>                 return ret;
> @@ -2856,7 +2840,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         pd = &pl330->ddma;
>         pd->dev = &adev->dev;
>
> -       pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
> +       pl330->mcbufsz = 0;
>
>         /* get quirk */
>         for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
> @@ -2900,10 +2884,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>         INIT_LIST_HEAD(&pd->channels);
>
>         /* Initialize channel parameters */
> -       if (pdat)
> -               num_chan = max_t(int, pdat->nr_valid_peri, pcfg->num_chan);
> -       else
> -               num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
> +       num_chan = max_t(int, pcfg->num_peri, pcfg->num_chan);
>
>         pl330->num_peripherals = num_chan;
>
> @@ -2915,11 +2896,8 @@ static int __maybe_unused pl330_resume(struct device *dev)
>
>         for (i = 0; i < num_chan; i++) {
>                 pch = &pl330->peripherals[i];
> -               if (!adev->dev.of_node)
> -                       pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;
> -               else
> -                       pch->chan.private = adev->dev.of_node;
>
> +               pch->chan.private = adev->dev.of_node;
>                 INIT_LIST_HEAD(&pch->submitted_list);
>                 INIT_LIST_HEAD(&pch->work_list);
>                 INIT_LIST_HEAD(&pch->completed_list);
> @@ -2932,15 +2910,11 @@ static int __maybe_unused pl330_resume(struct device *dev)
>                 list_add_tail(&pch->chan.device_node, &pd->channels);
>         }
>
> -       if (pdat) {
> -               pd->cap_mask = pdat->cap_mask;
> -       } else {
> -               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
> -               if (pcfg->num_peri) {
> -                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
> -                       dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> -                       dma_cap_set(DMA_PRIVATE, pd->cap_mask);
> -               }
> +       dma_cap_set(DMA_MEMCPY, pd->cap_mask);
> +       if (pcfg->num_peri) {
> +               dma_cap_set(DMA_SLAVE, pd->cap_mask);
> +               dma_cap_set(DMA_CYCLIC, pd->cap_mask);
> +               dma_cap_set(DMA_PRIVATE, pd->cap_mask);
>         }
>
>         pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
> diff --git a/include/linux/amba/pl330.h b/include/linux/amba/pl330.h
> deleted file mode 100644
> index fe93758e8403..000000000000
> --- a/include/linux/amba/pl330.h
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -/* linux/include/linux/amba/pl330.h
> - *
> - * Copyright (C) 2010 Samsung Electronics Co. Ltd.
> - *     Jaswinder Singh <jassi.brar@samsung.com>
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - */
> -
> -#ifndef        __AMBA_PL330_H_
> -#define        __AMBA_PL330_H_
> -
> -#include <linux/dmaengine.h>
> -
> -struct dma_pl330_platdata {
> -       /*
> -        * Number of valid peripherals connected to DMAC.
> -        * This may be different from the value read from
> -        * CR0, as the PL330 implementation might have 'holes'
> -        * in the peri list or the peri could also be reached
> -        * from another DMAC which the platform prefers.
> -        */
> -       u8 nr_valid_peri;
> -       /* Array of valid peripherals */
> -       u8 *peri_id;
> -       /* Operational capabilities */
> -       dma_cap_mask_t cap_mask;
> -       /* Bytes to allocate for MC buffer */
> -       unsigned mcbuf_sz;
> -};
> -
> -extern bool pl330_filter(struct dma_chan *chan, void *param);
> -#endif /* __AMBA_PL330_H_ */
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 3/4] dmaengine: pl330: Store pointer to slave device
  2017-01-24  9:27       ` Marek Szyprowski
@ 2017-01-24 15:13         ` Ulf Hansson
  -1 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:13 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, Vinod Koul,
	Rafael J. Wysocki, Inki Dae

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Store the pointer to slave device, which requested our channel. It will be
> later used to implement runtime PM of PL330 DMA controller. Although
> DMA channels might be requested many times, each DMA peripheral channel is
> physically dedicated only for specific hardware, so there should be only
> one slave device for each channel.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  drivers/dma/pl330.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index b6b2cc912380..c77a3494659c 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -450,6 +450,7 @@ struct dma_pl330_chan {
>
>         /* for runtime pm tracking */
>         bool active;
> +       struct device *slave;
>  };
>
>  struct pl330_dmac {
> @@ -2093,6 +2094,14 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>         if (chan_id >= pl330->num_peripherals)
>                 return NULL;
>
> +       if (!pl330->peripherals[chan_id].slave) {
> +               pl330->peripherals[chan_id].slave = slave;
> +       } else if (pl330->peripherals[chan_id].slave != slave) {
> +               dev_err(pl330->ddma.dev,
> +                       "Can't use same channel with multiple slave devices!\n");
> +               return NULL;
> +       }
> +
>         return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
>  }
>
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 3/4] dmaengine: pl330: Store pointer to slave device
@ 2017-01-24 15:13         ` Ulf Hansson
  0 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> Store the pointer to slave device, which requested our channel. It will be
> later used to implement runtime PM of PL330 DMA controller. Although
> DMA channels might be requested many times, each DMA peripheral channel is
> physically dedicated only for specific hardware, so there should be only
> one slave device for each channel.
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  drivers/dma/pl330.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index b6b2cc912380..c77a3494659c 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -450,6 +450,7 @@ struct dma_pl330_chan {
>
>         /* for runtime pm tracking */
>         bool active;
> +       struct device *slave;
>  };
>
>  struct pl330_dmac {
> @@ -2093,6 +2094,14 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>         if (chan_id >= pl330->num_peripherals)
>                 return NULL;
>
> +       if (!pl330->peripherals[chan_id].slave) {
> +               pl330->peripherals[chan_id].slave = slave;
> +       } else if (pl330->peripherals[chan_id].slave != slave) {
> +               dev_err(pl330->ddma.dev,
> +                       "Can't use same channel with multiple slave devices!\n");
> +               return NULL;
> +       }
> +
>         return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
>  }
>
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 4/4] dmaengine: pl330: Don't require irq-safe runtime PM
  2017-01-24  9:27       ` Marek Szyprowski
@ 2017-01-24 15:29         ` Ulf Hansson
  -1 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:29 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, Vinod Koul,
	Rafael J. Wysocki, Inki Dae

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> This patch replaces irq-safe runtime PM with non-irq-safe version based on
> the new approach. Existing, irq-safe runtime PM implementation for PL330 was
> not bringing much benefits of its own - only clocks were enabled/disabled.
>
> Till now non-irq-safe runtime PM implementation was only possible by calling
> pm_runtime_get/put functions from alloc/free_chan_resources. All other DMA
> engine API functions cannot be called from a context, which permits sleeping.
> Such implementation, in practice would result in keeping DMA controller's
> device active almost all the time, because most of the slave device drivers
> (DMA engine clients) acquire DMA channel in their probe() function and
> released it during driver removal.
>
> This patch provides a new, different approach. It is based on an observation
> that there can be only one slave device using each DMA channel. PL330 hardware
> always has dedicated channels for each peripheral device. Using recently
> introduced device dependencies (links) infrastructure one can ensure proper
> runtime PM state of PL330 DMA controller basing on the runtime PM state of
> the slave device.
>
> In this approach in pl330_alloc_chan_resources() function a new dependency
> is being created between PL330 DMA controller device (as a supplier) and
> given slave device (as a consumer). This way PL330 DMA controller device
> runtime active counter is increased when the slave device is resumed and
> decreased the same time when given slave device is put to suspend. This way
> it has been ensured to keep PL330 DMA controller runtime active if there is
> an active used of any of its DMA channels. Slave device pointer is initially
> stored in per-channel data in of_dma_xlate callback. This is similar to what
> has been already implemented in Exynos IOMMU driver in commit 2f5f44f205cc95
> ("iommu/exynos: Use device dependency links to control runtime pm").
>
> If slave device doesn't implement runtime PM or keeps device runtime active
> all the time, then PL330 DMA controller will be runtime active all the time
> when channel is being allocated. The goal is however to have runtime PM

I would remove everything after "The goal is however.."  from this section.

Instead, what I think is important to state (may be added in the first
section in the change log) is however another limitation with irq-safe
runtime PM. That is, it may prevent the generic PM domain (genpd) from
being powered off, particularly in cases when the genpd doesn't have
the GENPD_FLAG_IRQ_SAFE set.

> added to all devices in the system, because it lets respective power
> domains to be turned off, what gives the best results in terms of power
> saving.
>
> If one requests memory-to-memory channel, runtime active counter is
> increased unconditionally. This might be a drawback of this approach, but
> PL330 is not really used for memory-to-memory operations due to poor
> performance in such operations compared to the CPU.
>
> Introducing non-irq-safe runtime power management finally allows to turn off
> audio power domain on Exynos5 SoCs.
>
> Removal of irq-safe runtime PM is based on the revert of the following
> commits:
> 1. commit 5c9e6c2b2ba3 "dmaengine: pl330: fix runtime pm support"
> 2. commit 81cc6edc0870 "dmaengine: pl330: Fix hang on dmaengine_terminate_all
>    on certain boards"
> 3. commit ae43b3289186 "ARM: 8202/1: dmaengine: pl330: Add runtime Power
>    Management support v12"
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Nice work!

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  drivers/dma/pl330.c | 166 +++++++++++++++++++++-------------------------------
>  1 file changed, 66 insertions(+), 100 deletions(-)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index c77a3494659c..dff7228198f6 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -268,9 +268,6 @@ enum pl330_byteswap {
>
>  #define NR_DEFAULT_DESC        16
>
> -/* Delay for runtime PM autosuspend, ms */
> -#define PL330_AUTOSUSPEND_DELAY 20
> -
>  /* Populated by the PL330 core driver for DMA API driver's info */
>  struct pl330_config {
>         u32     periph_id;
> @@ -449,8 +446,8 @@ struct dma_pl330_chan {
>         bool cyclic;
>
>         /* for runtime pm tracking */
> -       bool active;
>         struct device *slave;
> +       struct device_link *slave_link;
>  };
>
>  struct pl330_dmac {
> @@ -2008,7 +2005,6 @@ static void pl330_tasklet(unsigned long data)
>         struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
>         struct dma_pl330_desc *desc, *_dt;
>         unsigned long flags;
> -       bool power_down = false;
>
>         spin_lock_irqsave(&pch->lock, flags);
>
> @@ -2023,18 +2019,10 @@ static void pl330_tasklet(unsigned long data)
>         /* Try to submit a req imm. next to the last completed cookie */
>         fill_queue(pch);
>
> -       if (list_empty(&pch->work_list)) {
> -               spin_lock(&pch->thread->dmac->lock);
> -               _stop(pch->thread);
> -               spin_unlock(&pch->thread->dmac->lock);
> -               power_down = true;
> -               pch->active = false;
> -       } else {
> -               /* Make sure the PL330 Channel thread is active */
> -               spin_lock(&pch->thread->dmac->lock);
> -               _start(pch->thread);
> -               spin_unlock(&pch->thread->dmac->lock);
> -       }
> +       /* Make sure the PL330 Channel thread is active */
> +       spin_lock(&pch->thread->dmac->lock);
> +       _start(pch->thread);
> +       spin_unlock(&pch->thread->dmac->lock);
>
>         while (!list_empty(&pch->completed_list)) {
>                 struct dmaengine_desc_callback cb;
> @@ -2047,13 +2035,6 @@ static void pl330_tasklet(unsigned long data)
>                 if (pch->cyclic) {
>                         desc->status = PREP;
>                         list_move_tail(&desc->node, &pch->work_list);
> -                       if (power_down) {
> -                               pch->active = true;
> -                               spin_lock(&pch->thread->dmac->lock);
> -                               _start(pch->thread);
> -                               spin_unlock(&pch->thread->dmac->lock);
> -                               power_down = false;
> -                       }
>                 } else {
>                         desc->status = FREE;
>                         list_move_tail(&desc->node, &pch->dmac->desc_pool);
> @@ -2068,12 +2049,6 @@ static void pl330_tasklet(unsigned long data)
>                 }
>         }
>         spin_unlock_irqrestore(&pch->lock, flags);
> -
> -       /* If work list empty, power down */
> -       if (power_down) {
> -               pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -               pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
> -       }
>  }
>
>  static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
> @@ -2105,11 +2080,63 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>         return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
>  }
>
> +static int pl330_add_slave_pm_link(struct pl330_dmac *pl330,
> +                                  struct dma_pl330_chan *pch)
> +{
> +       int i;
> +
> +       /* No slave device means memory-to-memory channels */
> +       if (!pch->slave)
> +               return pm_runtime_get_sync(pl330->ddma.dev);
> +
> +       /*
> +        * No additional locking is needed, {alloc,free}_chan_resources
> +        * are called under dma_list_mutex in dmaengine core
> +        */
> +       for (i = 0; i < pl330->num_peripherals; i++) {
> +               if (pl330->peripherals[i].slave == pch->slave &&
> +                   pl330->peripherals[i].slave_link) {
> +                       pch->slave_link = pl330->peripherals[i].slave_link;
> +                       return 0;
> +               }
> +       }
> +
> +       pch->slave_link = device_link_add(pch->slave, pl330->ddma.dev,
> +                                      DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
> +       if (!pch->slave_link)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static void pl330_del_slave_pm_link(struct pl330_dmac *pl330,
> +                                   struct dma_pl330_chan *pch)
> +{
> +       struct device_link *link = pch->slave_link;
> +       int i, count = 0;
> +
> +       if (!pch->slave)
> +               pm_runtime_put(pl330->ddma.dev);
> +
> +       for (i = 0; i < pl330->num_peripherals; i++)
> +               if (pl330->peripherals[i].slave_link == link)
> +                       count++;
> +
> +       pch->slave_link = NULL;
> +       if (count == 1)
> +               device_link_del(link);
> +}
> +
>  static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  {
>         struct dma_pl330_chan *pch = to_pchan(chan);
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
> +       int ret;
> +
> +       ret = pl330_add_slave_pm_link(pl330, pch);
> +       if (ret < 0)
> +               return ret;
>
>         spin_lock_irqsave(&pl330->lock, flags);
>
> @@ -2119,6 +2146,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>         pch->thread = pl330_request_channel(pl330);
>         if (!pch->thread) {
>                 spin_unlock_irqrestore(&pl330->lock, flags);
> +               pl330_del_slave_pm_link(pl330, pch);
>                 return -ENOMEM;
>         }
>
> @@ -2160,9 +2188,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         unsigned long flags;
>         struct pl330_dmac *pl330 = pch->dmac;
>         LIST_HEAD(list);
> -       bool power_down = false;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>         spin_lock(&pl330->lock);
>         _stop(pch->thread);
> @@ -2171,8 +2197,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         pch->thread->req[0].desc = NULL;
>         pch->thread->req[1].desc = NULL;
>         pch->thread->req_running = -1;
> -       power_down = pch->active;
> -       pch->active = false;
>
>         /* Mark all desc done */
>         list_for_each_entry(desc, &pch->submitted_list, node) {
> @@ -2189,10 +2213,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
>         list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
>         spin_unlock_irqrestore(&pch->lock, flags);
> -       pm_runtime_mark_last_busy(pl330->ddma.dev);
> -       if (power_down)
> -               pm_runtime_put_autosuspend(pl330->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         return 0;
>  }
> @@ -2210,7 +2230,6 @@ static int pl330_pause(struct dma_chan *chan)
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>
>         spin_lock(&pl330->lock);
> @@ -2218,8 +2237,6 @@ static int pl330_pause(struct dma_chan *chan)
>         spin_unlock(&pl330->lock);
>
>         spin_unlock_irqrestore(&pch->lock, flags);
> -       pm_runtime_mark_last_busy(pl330->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         return 0;
>  }
> @@ -2232,7 +2249,6 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>
>         tasklet_kill(&pch->task);
>
> -       pm_runtime_get_sync(pch->dmac->ddma.dev);
>         spin_lock_irqsave(&pl330->lock, flags);
>
>         pl330_release_channel(pch->thread);
> @@ -2242,19 +2258,17 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>                 list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
>
>         spin_unlock_irqrestore(&pl330->lock, flags);
> -       pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -       pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
> +
> +       pl330_del_slave_pm_link(pl330, pch);
>  }
>
>  static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                                            struct dma_pl330_desc *desc)
>  {
>         struct pl330_thread *thrd = pch->thread;
> -       struct pl330_dmac *pl330 = pch->dmac;
>         void __iomem *regs = thrd->dmac->base;
>         u32 val, addr;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         val = addr = 0;
>         if (desc->rqcfg.src_inc) {
>                 val = readl(regs + SA(thrd->id));
> @@ -2263,8 +2277,6 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                 val = readl(regs + DA(thrd->id));
>                 addr = desc->px.dst_addr;
>         }
> -       pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         /* If DMAMOV hasn't finished yet, SAR/DAR can be zero */
>         if (!val)
> @@ -2350,16 +2362,6 @@ static void pl330_issue_pending(struct dma_chan *chan)
>         unsigned long flags;
>
>         spin_lock_irqsave(&pch->lock, flags);
> -       if (list_empty(&pch->work_list)) {
> -               /*
> -                * Warn on nothing pending. Empty submitted_list may
> -                * break our pm_runtime usage counter as it is
> -                * updated on work_list emptiness status.
> -                */
> -               WARN_ON(list_empty(&pch->submitted_list));
> -               pch->active = true;
> -               pm_runtime_get_sync(pch->dmac->ddma.dev);
> -       }
>         list_splice_tail_init(&pch->submitted_list, &pch->work_list);
>         spin_unlock_irqrestore(&pch->lock, flags);
>
> @@ -2787,44 +2789,12 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
>         BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
>
>  /*
> - * Runtime PM callbacks are provided by amba/bus.c driver.
> - *
> - * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> - * bus driver will only disable/enable the clock in runtime PM callbacks.
> + * Runtime PM callbacks are provided by amba/bus.c driver, system sleep
> + * suspend/resume is implemented by generic helpers, which use existing
> + * runtime PM callbacks.
>   */
> -static int __maybe_unused pl330_suspend(struct device *dev)
> -{
> -       struct amba_device *pcdev = to_amba_device(dev);
> -
> -       pm_runtime_disable(dev);
> -
> -       if (!pm_runtime_status_suspended(dev)) {
> -               /* amba did not disable the clock */
> -               amba_pclk_disable(pcdev);
> -       }
> -       amba_pclk_unprepare(pcdev);
> -
> -       return 0;
> -}
> -
> -static int __maybe_unused pl330_resume(struct device *dev)
> -{
> -       struct amba_device *pcdev = to_amba_device(dev);
> -       int ret;
> -
> -       ret = amba_pclk_prepare(pcdev);
> -       if (ret)
> -               return ret;
> -
> -       if (!pm_runtime_status_suspended(dev))
> -               ret = amba_pclk_enable(pcdev);
> -
> -       pm_runtime_enable(dev);
> -
> -       return ret;
> -}
> -
> -static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
> +static SIMPLE_DEV_PM_OPS(pl330_pm, pm_runtime_force_suspend,
> +                        pm_runtime_force_resume);
>
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
> @@ -2977,11 +2947,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>                 pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
>                 pcfg->num_peri, pcfg->num_events);
>
> -       pm_runtime_irq_safe(&adev->dev);
> -       pm_runtime_use_autosuspend(&adev->dev);
> -       pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
> -       pm_runtime_mark_last_busy(&adev->dev);
> -       pm_runtime_put_autosuspend(&adev->dev);
> +       pm_runtime_put(&adev->dev);
>
>         return 0;
>  probe_err3:
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 4/4] dmaengine: pl330: Don't require irq-safe runtime PM
@ 2017-01-24 15:29         ` Ulf Hansson
  0 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-24 15:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
> This patch replaces irq-safe runtime PM with non-irq-safe version based on
> the new approach. Existing, irq-safe runtime PM implementation for PL330 was
> not bringing much benefits of its own - only clocks were enabled/disabled.
>
> Till now non-irq-safe runtime PM implementation was only possible by calling
> pm_runtime_get/put functions from alloc/free_chan_resources. All other DMA
> engine API functions cannot be called from a context, which permits sleeping.
> Such implementation, in practice would result in keeping DMA controller's
> device active almost all the time, because most of the slave device drivers
> (DMA engine clients) acquire DMA channel in their probe() function and
> released it during driver removal.
>
> This patch provides a new, different approach. It is based on an observation
> that there can be only one slave device using each DMA channel. PL330 hardware
> always has dedicated channels for each peripheral device. Using recently
> introduced device dependencies (links) infrastructure one can ensure proper
> runtime PM state of PL330 DMA controller basing on the runtime PM state of
> the slave device.
>
> In this approach in pl330_alloc_chan_resources() function a new dependency
> is being created between PL330 DMA controller device (as a supplier) and
> given slave device (as a consumer). This way PL330 DMA controller device
> runtime active counter is increased when the slave device is resumed and
> decreased the same time when given slave device is put to suspend. This way
> it has been ensured to keep PL330 DMA controller runtime active if there is
> an active used of any of its DMA channels. Slave device pointer is initially
> stored in per-channel data in of_dma_xlate callback. This is similar to what
> has been already implemented in Exynos IOMMU driver in commit 2f5f44f205cc95
> ("iommu/exynos: Use device dependency links to control runtime pm").
>
> If slave device doesn't implement runtime PM or keeps device runtime active
> all the time, then PL330 DMA controller will be runtime active all the time
> when channel is being allocated. The goal is however to have runtime PM

I would remove everything after "The goal is however.."  from this section.

Instead, what I think is important to state (may be added in the first
section in the change log) is however another limitation with irq-safe
runtime PM. That is, it may prevent the generic PM domain (genpd) from
being powered off, particularly in cases when the genpd doesn't have
the GENPD_FLAG_IRQ_SAFE set.

> added to all devices in the system, because it lets respective power
> domains to be turned off, what gives the best results in terms of power
> saving.
>
> If one requests memory-to-memory channel, runtime active counter is
> increased unconditionally. This might be a drawback of this approach, but
> PL330 is not really used for memory-to-memory operations due to poor
> performance in such operations compared to the CPU.
>
> Introducing non-irq-safe runtime power management finally allows to turn off
> audio power domain on Exynos5 SoCs.
>
> Removal of irq-safe runtime PM is based on the revert of the following
> commits:
> 1. commit 5c9e6c2b2ba3 "dmaengine: pl330: fix runtime pm support"
> 2. commit 81cc6edc0870 "dmaengine: pl330: Fix hang on dmaengine_terminate_all
>    on certain boards"
> 3. commit ae43b3289186 "ARM: 8202/1: dmaengine: pl330: Add runtime Power
>    Management support v12"
>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
> Acked-by: Arnd Bergmann <arnd@arndb.de>

Nice work!

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  drivers/dma/pl330.c | 166 +++++++++++++++++++++-------------------------------
>  1 file changed, 66 insertions(+), 100 deletions(-)
>
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index c77a3494659c..dff7228198f6 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -268,9 +268,6 @@ enum pl330_byteswap {
>
>  #define NR_DEFAULT_DESC        16
>
> -/* Delay for runtime PM autosuspend, ms */
> -#define PL330_AUTOSUSPEND_DELAY 20
> -
>  /* Populated by the PL330 core driver for DMA API driver's info */
>  struct pl330_config {
>         u32     periph_id;
> @@ -449,8 +446,8 @@ struct dma_pl330_chan {
>         bool cyclic;
>
>         /* for runtime pm tracking */
> -       bool active;
>         struct device *slave;
> +       struct device_link *slave_link;
>  };
>
>  struct pl330_dmac {
> @@ -2008,7 +2005,6 @@ static void pl330_tasklet(unsigned long data)
>         struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
>         struct dma_pl330_desc *desc, *_dt;
>         unsigned long flags;
> -       bool power_down = false;
>
>         spin_lock_irqsave(&pch->lock, flags);
>
> @@ -2023,18 +2019,10 @@ static void pl330_tasklet(unsigned long data)
>         /* Try to submit a req imm. next to the last completed cookie */
>         fill_queue(pch);
>
> -       if (list_empty(&pch->work_list)) {
> -               spin_lock(&pch->thread->dmac->lock);
> -               _stop(pch->thread);
> -               spin_unlock(&pch->thread->dmac->lock);
> -               power_down = true;
> -               pch->active = false;
> -       } else {
> -               /* Make sure the PL330 Channel thread is active */
> -               spin_lock(&pch->thread->dmac->lock);
> -               _start(pch->thread);
> -               spin_unlock(&pch->thread->dmac->lock);
> -       }
> +       /* Make sure the PL330 Channel thread is active */
> +       spin_lock(&pch->thread->dmac->lock);
> +       _start(pch->thread);
> +       spin_unlock(&pch->thread->dmac->lock);
>
>         while (!list_empty(&pch->completed_list)) {
>                 struct dmaengine_desc_callback cb;
> @@ -2047,13 +2035,6 @@ static void pl330_tasklet(unsigned long data)
>                 if (pch->cyclic) {
>                         desc->status = PREP;
>                         list_move_tail(&desc->node, &pch->work_list);
> -                       if (power_down) {
> -                               pch->active = true;
> -                               spin_lock(&pch->thread->dmac->lock);
> -                               _start(pch->thread);
> -                               spin_unlock(&pch->thread->dmac->lock);
> -                               power_down = false;
> -                       }
>                 } else {
>                         desc->status = FREE;
>                         list_move_tail(&desc->node, &pch->dmac->desc_pool);
> @@ -2068,12 +2049,6 @@ static void pl330_tasklet(unsigned long data)
>                 }
>         }
>         spin_unlock_irqrestore(&pch->lock, flags);
> -
> -       /* If work list empty, power down */
> -       if (power_down) {
> -               pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -               pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
> -       }
>  }
>
>  static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
> @@ -2105,11 +2080,63 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
>         return dma_get_slave_channel(&pl330->peripherals[chan_id].chan);
>  }
>
> +static int pl330_add_slave_pm_link(struct pl330_dmac *pl330,
> +                                  struct dma_pl330_chan *pch)
> +{
> +       int i;
> +
> +       /* No slave device means memory-to-memory channels */
> +       if (!pch->slave)
> +               return pm_runtime_get_sync(pl330->ddma.dev);
> +
> +       /*
> +        * No additional locking is needed, {alloc,free}_chan_resources
> +        * are called under dma_list_mutex in dmaengine core
> +        */
> +       for (i = 0; i < pl330->num_peripherals; i++) {
> +               if (pl330->peripherals[i].slave == pch->slave &&
> +                   pl330->peripherals[i].slave_link) {
> +                       pch->slave_link = pl330->peripherals[i].slave_link;
> +                       return 0;
> +               }
> +       }
> +
> +       pch->slave_link = device_link_add(pch->slave, pl330->ddma.dev,
> +                                      DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
> +       if (!pch->slave_link)
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static void pl330_del_slave_pm_link(struct pl330_dmac *pl330,
> +                                   struct dma_pl330_chan *pch)
> +{
> +       struct device_link *link = pch->slave_link;
> +       int i, count = 0;
> +
> +       if (!pch->slave)
> +               pm_runtime_put(pl330->ddma.dev);
> +
> +       for (i = 0; i < pl330->num_peripherals; i++)
> +               if (pl330->peripherals[i].slave_link == link)
> +                       count++;
> +
> +       pch->slave_link = NULL;
> +       if (count == 1)
> +               device_link_del(link);
> +}
> +
>  static int pl330_alloc_chan_resources(struct dma_chan *chan)
>  {
>         struct dma_pl330_chan *pch = to_pchan(chan);
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
> +       int ret;
> +
> +       ret = pl330_add_slave_pm_link(pl330, pch);
> +       if (ret < 0)
> +               return ret;
>
>         spin_lock_irqsave(&pl330->lock, flags);
>
> @@ -2119,6 +2146,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
>         pch->thread = pl330_request_channel(pl330);
>         if (!pch->thread) {
>                 spin_unlock_irqrestore(&pl330->lock, flags);
> +               pl330_del_slave_pm_link(pl330, pch);
>                 return -ENOMEM;
>         }
>
> @@ -2160,9 +2188,7 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         unsigned long flags;
>         struct pl330_dmac *pl330 = pch->dmac;
>         LIST_HEAD(list);
> -       bool power_down = false;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>         spin_lock(&pl330->lock);
>         _stop(pch->thread);
> @@ -2171,8 +2197,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         pch->thread->req[0].desc = NULL;
>         pch->thread->req[1].desc = NULL;
>         pch->thread->req_running = -1;
> -       power_down = pch->active;
> -       pch->active = false;
>
>         /* Mark all desc done */
>         list_for_each_entry(desc, &pch->submitted_list, node) {
> @@ -2189,10 +2213,6 @@ static int pl330_terminate_all(struct dma_chan *chan)
>         list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
>         list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
>         spin_unlock_irqrestore(&pch->lock, flags);
> -       pm_runtime_mark_last_busy(pl330->ddma.dev);
> -       if (power_down)
> -               pm_runtime_put_autosuspend(pl330->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         return 0;
>  }
> @@ -2210,7 +2230,6 @@ static int pl330_pause(struct dma_chan *chan)
>         struct pl330_dmac *pl330 = pch->dmac;
>         unsigned long flags;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         spin_lock_irqsave(&pch->lock, flags);
>
>         spin_lock(&pl330->lock);
> @@ -2218,8 +2237,6 @@ static int pl330_pause(struct dma_chan *chan)
>         spin_unlock(&pl330->lock);
>
>         spin_unlock_irqrestore(&pch->lock, flags);
> -       pm_runtime_mark_last_busy(pl330->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         return 0;
>  }
> @@ -2232,7 +2249,6 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>
>         tasklet_kill(&pch->task);
>
> -       pm_runtime_get_sync(pch->dmac->ddma.dev);
>         spin_lock_irqsave(&pl330->lock, flags);
>
>         pl330_release_channel(pch->thread);
> @@ -2242,19 +2258,17 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
>                 list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
>
>         spin_unlock_irqrestore(&pl330->lock, flags);
> -       pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -       pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
> +
> +       pl330_del_slave_pm_link(pl330, pch);
>  }
>
>  static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                                            struct dma_pl330_desc *desc)
>  {
>         struct pl330_thread *thrd = pch->thread;
> -       struct pl330_dmac *pl330 = pch->dmac;
>         void __iomem *regs = thrd->dmac->base;
>         u32 val, addr;
>
> -       pm_runtime_get_sync(pl330->ddma.dev);
>         val = addr = 0;
>         if (desc->rqcfg.src_inc) {
>                 val = readl(regs + SA(thrd->id));
> @@ -2263,8 +2277,6 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
>                 val = readl(regs + DA(thrd->id));
>                 addr = desc->px.dst_addr;
>         }
> -       pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
> -       pm_runtime_put_autosuspend(pl330->ddma.dev);
>
>         /* If DMAMOV hasn't finished yet, SAR/DAR can be zero */
>         if (!val)
> @@ -2350,16 +2362,6 @@ static void pl330_issue_pending(struct dma_chan *chan)
>         unsigned long flags;
>
>         spin_lock_irqsave(&pch->lock, flags);
> -       if (list_empty(&pch->work_list)) {
> -               /*
> -                * Warn on nothing pending. Empty submitted_list may
> -                * break our pm_runtime usage counter as it is
> -                * updated on work_list emptiness status.
> -                */
> -               WARN_ON(list_empty(&pch->submitted_list));
> -               pch->active = true;
> -               pm_runtime_get_sync(pch->dmac->ddma.dev);
> -       }
>         list_splice_tail_init(&pch->submitted_list, &pch->work_list);
>         spin_unlock_irqrestore(&pch->lock, flags);
>
> @@ -2787,44 +2789,12 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
>         BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
>
>  /*
> - * Runtime PM callbacks are provided by amba/bus.c driver.
> - *
> - * It is assumed here that IRQ safe runtime PM is chosen in probe and amba
> - * bus driver will only disable/enable the clock in runtime PM callbacks.
> + * Runtime PM callbacks are provided by amba/bus.c driver, system sleep
> + * suspend/resume is implemented by generic helpers, which use existing
> + * runtime PM callbacks.
>   */
> -static int __maybe_unused pl330_suspend(struct device *dev)
> -{
> -       struct amba_device *pcdev = to_amba_device(dev);
> -
> -       pm_runtime_disable(dev);
> -
> -       if (!pm_runtime_status_suspended(dev)) {
> -               /* amba did not disable the clock */
> -               amba_pclk_disable(pcdev);
> -       }
> -       amba_pclk_unprepare(pcdev);
> -
> -       return 0;
> -}
> -
> -static int __maybe_unused pl330_resume(struct device *dev)
> -{
> -       struct amba_device *pcdev = to_amba_device(dev);
> -       int ret;
> -
> -       ret = amba_pclk_prepare(pcdev);
> -       if (ret)
> -               return ret;
> -
> -       if (!pm_runtime_status_suspended(dev))
> -               ret = amba_pclk_enable(pcdev);
> -
> -       pm_runtime_enable(dev);
> -
> -       return ret;
> -}
> -
> -static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume);
> +static SIMPLE_DEV_PM_OPS(pl330_pm, pm_runtime_force_suspend,
> +                        pm_runtime_force_resume);
>
>  static int
>  pl330_probe(struct amba_device *adev, const struct amba_id *id)
> @@ -2977,11 +2947,7 @@ static int __maybe_unused pl330_resume(struct device *dev)
>                 pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan,
>                 pcfg->num_peri, pcfg->num_events);
>
> -       pm_runtime_irq_safe(&adev->dev);
> -       pm_runtime_use_autosuspend(&adev->dev);
> -       pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY);
> -       pm_runtime_mark_last_busy(&adev->dev);
> -       pm_runtime_put_autosuspend(&adev->dev);
> +       pm_runtime_put(&adev->dev);
>
>         return 0;
>  probe_err3:
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
  2017-01-24 15:09         ` Ulf Hansson
@ 2017-01-25 10:13           ` Marek Szyprowski
  -1 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-25 10:13 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-samsung-soc, dmaengine, linux-arm-kernel, linux-pm,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, Vinod Koul,
	Rafael J. Wysocki, Inki Dae

Hi Ulf,

On 2017-01-24 16:09, Ulf Hansson wrote:
> On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> Add pointer to slave device to of_dma_xlate to let DMA engine driver
>> to know which slave device is using given DMA channel. This will be
>> later used to implement non-irq-safe runtime PM for DMA engine driver.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Acked-by: Arnd Bergmann <arnd@arndb.de>
> [...]
>
>> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
>> index b90d8ec57c1f..a0a6c8c17669 100644
>> --- a/include/linux/of_dma.h
>> +++ b/include/linux/of_dma.h
>> @@ -22,7 +22,8 @@ struct of_dma {
>>          struct list_head        of_dma_controllers;
>>          struct device_node      *of_node;
>>          struct dma_chan         *(*of_dma_xlate)
>> -                               (struct of_phandle_args *, struct of_dma *);
>> +                               (struct of_phandle_args *, struct of_dma *,
>> +                                struct device *);
>>          void                    *(*of_dma_route_allocate)
>>                                  (struct of_phandle_args *, struct of_dma *);
>>          struct dma_router       *dma_router;
>> @@ -37,7 +38,7 @@ struct of_dma_filter_info {
>>   #ifdef CONFIG_DMA_OF
>>   extern int of_dma_controller_register(struct device_node *np,
>>                  struct dma_chan *(*of_dma_xlate)
>> -               (struct of_phandle_args *, struct of_dma *),
>> +               (struct of_phandle_args *, struct of_dma *, struct device *),
>>                  void *data);
>>   extern void of_dma_controller_free(struct device_node *np);
>>
>> @@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
>>                  struct dma_router *dma_router);
>>   #define of_dma_router_free of_dma_controller_free
>>
>> -extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
>> +extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
>>                                                       const char *name);
> I noticed that this API is being used from sound/soc/sh/rcar/dma.c, so
> I assume this change triggers a compiler error. I guess you want to
> fold in a change dealing with that as well.

Right. Thanks for pointing this.

I didn't expect that of_dma_request_slave_channel() is used outside 
drivers/dma,
especially in such a creative way as in sh/rcar driver. I will change a 
function
signature to:

of_dma_request_slave_channel(struct device *slave, struct device_node 
*np, const char *name)

then, as there is no direct relation between device and of node pointer, 
from
which rcar driver extracts the dma channel data.

I would also expect that zero-day build robot will complain about missing
sh/rcar driver update, but I didn't get any message from it.

> [...]
>
> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback
@ 2017-01-25 10:13           ` Marek Szyprowski
  0 siblings, 0 replies; 20+ messages in thread
From: Marek Szyprowski @ 2017-01-25 10:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ulf,

On 2017-01-24 16:09, Ulf Hansson wrote:
> On 24 January 2017 at 10:27, Marek Szyprowski <m.szyprowski@samsung.com> wrote:
>> Add pointer to slave device to of_dma_xlate to let DMA engine driver
>> to know which slave device is using given DMA channel. This will be
>> later used to implement non-irq-safe runtime PM for DMA engine driver.
>>
>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Acked-by: Arnd Bergmann <arnd@arndb.de>
> [...]
>
>> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
>> index b90d8ec57c1f..a0a6c8c17669 100644
>> --- a/include/linux/of_dma.h
>> +++ b/include/linux/of_dma.h
>> @@ -22,7 +22,8 @@ struct of_dma {
>>          struct list_head        of_dma_controllers;
>>          struct device_node      *of_node;
>>          struct dma_chan         *(*of_dma_xlate)
>> -                               (struct of_phandle_args *, struct of_dma *);
>> +                               (struct of_phandle_args *, struct of_dma *,
>> +                                struct device *);
>>          void                    *(*of_dma_route_allocate)
>>                                  (struct of_phandle_args *, struct of_dma *);
>>          struct dma_router       *dma_router;
>> @@ -37,7 +38,7 @@ struct of_dma_filter_info {
>>   #ifdef CONFIG_DMA_OF
>>   extern int of_dma_controller_register(struct device_node *np,
>>                  struct dma_chan *(*of_dma_xlate)
>> -               (struct of_phandle_args *, struct of_dma *),
>> +               (struct of_phandle_args *, struct of_dma *, struct device *),
>>                  void *data);
>>   extern void of_dma_controller_free(struct device_node *np);
>>
>> @@ -47,17 +48,17 @@ extern int of_dma_router_register(struct device_node *np,
>>                  struct dma_router *dma_router);
>>   #define of_dma_router_free of_dma_controller_free
>>
>> -extern struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
>> +extern struct dma_chan *of_dma_request_slave_channel(struct device *slave,
>>                                                       const char *name);
> I noticed that this API is being used from sound/soc/sh/rcar/dma.c, so
> I assume this change triggers a compiler error. I guess you want to
> fold in a change dealing with that as well.

Right. Thanks for pointing this.

I didn't expect that of_dma_request_slave_channel() is used outside 
drivers/dma,
especially in such a creative way as in sh/rcar driver. I will change a 
function
signature to:

of_dma_request_slave_channel(struct device *slave, struct device_node 
*np, const char *name)

then, as there is no direct relation between device and of node pointer, 
from
which rcar driver extracts the dma channel data.

I would also expect that zero-day build robot will complain about missing
sh/rcar driver update, but I didn't get any message from it.

> [...]
>
> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-01-25 10:13 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20170124092750eucas1p2b806ec3340d9d57439cc6d8975b516ef@eucas1p2.samsung.com>
2017-01-24  9:27 ` [PATCH v6 0/4] DMA Engine: switch PL330 driver to non-irq-safe runtime PM Marek Szyprowski
2017-01-24  9:27   ` Marek Szyprowski
     [not found]   ` <CGME20170124092750eucas1p1127947314c9ad7eed297c1b6739110cb@eucas1p1.samsung.com>
2017-01-24  9:27     ` [PATCH v6 1/4] dmaengine: pl330: remove pdata based initialization Marek Szyprowski
2017-01-24  9:27       ` Marek Szyprowski
2017-01-24 15:10       ` Ulf Hansson
2017-01-24 15:10         ` Ulf Hansson
     [not found]   ` <CGME20170124092751eucas1p1411586335ad7083f7fff451212e002a3@eucas1p1.samsung.com>
2017-01-24  9:27     ` [PATCH v6 2/4] dmaengine: Forward slave device pointer to of_xlate callback Marek Szyprowski
2017-01-24  9:27       ` Marek Szyprowski
2017-01-24 15:09       ` Ulf Hansson
2017-01-24 15:09         ` Ulf Hansson
2017-01-25 10:13         ` Marek Szyprowski
2017-01-25 10:13           ` Marek Szyprowski
     [not found]   ` <CGME20170124092751eucas1p2807f068bdbcd695d0bec355e6b509d6c@eucas1p2.samsung.com>
2017-01-24  9:27     ` [PATCH v6 3/4] dmaengine: pl330: Store pointer to slave device Marek Szyprowski
2017-01-24  9:27       ` Marek Szyprowski
2017-01-24 15:13       ` Ulf Hansson
2017-01-24 15:13         ` Ulf Hansson
     [not found]   ` <CGME20170124092752eucas1p2ee498423f61db49f60612ee11d343cf5@eucas1p2.samsung.com>
2017-01-24  9:27     ` [PATCH v6 4/4] dmaengine: pl330: Don't require irq-safe runtime PM Marek Szyprowski
2017-01-24  9:27       ` Marek Szyprowski
2017-01-24 15:29       ` Ulf Hansson
2017-01-24 15:29         ` Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.