[alsa-devel] [PATCH 0/8] ASoC: rsnd: DMA power fix and IOMMU support
Hi Mark
These patches are for Renesas sound DMA. 1st feature is that it can power save for Audio DMAC. 2nd feature is that it can support IOMMU
1) - 5) : cleanup for 6) - 8) 6) - 7) : Audio DMAC power save 8) : IOMMU support
Kuninori Morimoto (8): 1) ASoC: rsnd: depends on OF 2) ASoC: rsnd: remove non DT support for DMA 3) ASoC: rsnd: don't use devm_request_irq() for SSI 4) ASoC: rsnd: remove rsnd_dma_detach() 5) ASoC: rsnd: don't call unneeded of_node_put() on dma.c 6) ASoC: rsnd: add nolock_start/stop callback 7) ASoC: rsnd: Request/Release DMA channel each time 8) ASoC: rsnd: use dma_sync_single_for_xxx() for IOMMU
sound/soc/sh/Kconfig | 1 + sound/soc/sh/rcar/core.c | 30 +++++++++++++- sound/soc/sh/rcar/dma.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------- sound/soc/sh/rcar/rsnd.h | 18 ++++++-- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 22 +++++----- 6 files changed, 248 insertions(+), 129 deletions(-)
Best regards --- Kuninori Morimoto
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current Renesas sound driver is completely depends on CONFIG_OF
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6db6405..610fa85 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK + depends on OF select SND_SIMPLE_CARD select REGMAP_MMIO help
On Tue, Oct 25, 2016 at 12:35:53AM +0000, Kuninori Morimoto wrote:
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK
- depends on OF select SND_SIMPLE_CARD select REGMAP_MMIO help
Can we have an || COMPILE_TEST to help build coverage if there isn't a build time dependency on DT please?
Hi Mark
@@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK
- depends on OF select SND_SIMPLE_CARD select REGMAP_MMIO help
Can we have an || COMPILE_TEST to help build coverage if there isn't a build time dependency on DT please?
Thanks. will do in v2
The patch
ASoC: rsnd: depends on OF
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 609c94865adcef3dba070a2d3905e4b67b4e6919 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Wed, 26 Oct 2016 04:12:34 +0000 Subject: [PATCH] ASoC: rsnd: depends on OF
Current Renesas sound driver is completely depends on CONFIG_OF
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6db6405d952f..610fa85b3acd 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK + depends on OF select SND_SIMPLE_CARD select REGMAP_MMIO help
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current Renesas Sound driver is based on DeviceTree, and no one is using this driver from non DT. Non-DT support is no longer needed. Let's remove it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dma.c | 21 ++++++--------------- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 3 +-- 4 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index b3bdd36..e0761ca 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -191,7 +191,7 @@ static int rsnd_dmaen_remove(struct rsnd_mod *mod, }
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); @@ -208,17 +208,8 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return -EIO; }
- if (dev->of_node) { - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - } else { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
- dmaen->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(uintptr_t)id); - } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); @@ -394,7 +385,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, }
static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -627,7 +618,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, }
int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod, int id) + struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; @@ -636,7 +627,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; @@ -695,7 +686,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
- ret = attach(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index b3b4d89..2460d1f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -199,7 +199,7 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, * R-Car DMA */ int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); + struct rsnd_mod *mod, struct rsnd_mod **dma_mod); void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 969a516..e13d6d4 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -475,7 +475,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; }
- ret = rsnd_dma_attach(io, mod, &src->dma, 0); + ret = rsnd_dma_attach(io, mod, &src->dma);
return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 94a19f9..59cd982 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -669,7 +669,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int dma_id = 0; /* not needed */ int ret;
/* @@ -684,7 +683,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret;
/* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); + ret = rsnd_dma_attach(io, mod, &ssi->dma);
return ret; }
The patch
ASoC: rsnd: remove non DT support for DMA
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From b99305d20122174c9fd0469bae036f0c401999b5 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Tue, 25 Oct 2016 00:36:13 +0000 Subject: [PATCH] ASoC: rsnd: remove non DT support for DMA
Current Renesas Sound driver is based on DeviceTree, and no one is using this driver from non DT. Non-DT support is no longer needed. Let's remove it.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/dma.c | 21 ++++++--------------- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 3 +-- 4 files changed, 9 insertions(+), 19 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index b3bdd362a511..e0761cac0ab7 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -191,7 +191,7 @@ static int rsnd_dmaen_remove(struct rsnd_mod *mod, }
static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); @@ -208,17 +208,8 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return -EIO; }
- if (dev->of_node) { - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - } else { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to);
- dmaen->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(uintptr_t)id); - } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); @@ -394,7 +385,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, }
static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -627,7 +618,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, }
int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod, int id) + struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; @@ -636,7 +627,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; @@ -695,7 +686,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to));
- ret = attach(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index b3b4d89347be..2460d1fbf775 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -199,7 +199,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); * R-Car DMA */ int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); + struct rsnd_mod *mod, struct rsnd_mod **dma_mod); void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 969a5169de25..e13d6d439b32 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -475,7 +475,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; }
- ret = rsnd_dma_attach(io, mod, &src->dma, 0); + ret = rsnd_dma_attach(io, mod, &src->dma);
return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 94a19f975fa2..59cd9824d8a4 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -669,7 +669,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int dma_id = 0; /* not needed */ int ret;
/* @@ -684,7 +683,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret;
/* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); + ret = rsnd_dma_attach(io, mod, &ssi->dma);
return ret; }
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
SSI will use DMA mode, and migh be fallback to PIO mode. Using devm_request_irq() makes its operation more complex when it fallbacks to PIO mode. Let's use manual request_irq()/free_irq()
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/ssi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 59cd982..b0338d0 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -644,10 +644,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (ret < 0) return ret;
- ret = devm_request_irq(dev, ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + /* + * SSI might be called again as PIO fallback + * It is easy to manual handling for IRQ request/free + */ + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod);
return ret; } @@ -693,12 +697,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->irq;
/* PIO will request IRQ again */ - if (ssi->dma) - devm_free_irq(dev, irq, mod); + free_irq(ssi->irq, mod);
rsnd_dma_detach(mod, &ssi->dma);
The patch
ASoC: rsnd: don't use devm_request_irq() for SSI
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 701172dca15ba9860ba73d3e18082fbd2a78f2c9 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Tue, 25 Oct 2016 00:36:34 +0000 Subject: [PATCH] ASoC: rsnd: don't use devm_request_irq() for SSI
SSI will use DMA mode, and migh be fallback to PIO mode. Using devm_request_irq() makes its operation more complex when it fallbacks to PIO mode. Let's use manual request_irq()/free_irq()
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/ssi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 59cd9824d8a4..b0338d0a4cde 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -644,10 +644,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (ret < 0) return ret;
- ret = devm_request_irq(dev, ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + /* + * SSI might be called again as PIO fallback + * It is easy to manual handling for IRQ request/free + */ + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod);
return ret; } @@ -693,12 +697,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->irq;
/* PIO will request IRQ again */ - if (ssi->dma) - devm_free_irq(dev, irq, mod); + free_irq(ssi->irq, mod);
rsnd_dma_detach(mod, &ssi->dma);
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
DMA mod is now connected to stream via rsnd_dai_connect(). This means DMA mod can use .remove for its clearance. rsnd_dma_detach() is no longer needed.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dma.c | 11 ----------- sound/soc/sh/rcar/rsnd.h | 1 - sound/soc/sh/rcar/ssi.c | 2 -- 3 files changed, 14 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index e0761ca..c85a551 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -698,17 +698,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, return 0; }
-void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod) -{ - if (*dma_mod) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - devm_kfree(dev, *dma_mod); - *dma_mod = NULL; - } -} - int rsnd_dma_probe(struct rsnd_priv *priv) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 2460d1f..c1cee1a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -200,7 +200,6 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, */ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod); -void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b0338d0..e23e07b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -701,8 +701,6 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, /* PIO will request IRQ again */ free_irq(ssi->irq, mod);
- rsnd_dma_detach(mod, &ssi->dma); - return 0; }
The patch
ASoC: rsnd: remove rsnd_dma_detach()
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From dae4b83295ae50a86b5e3c60e7b6e2c597a1b69d Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Tue, 25 Oct 2016 00:36:56 +0000 Subject: [PATCH] ASoC: rsnd: remove rsnd_dma_detach()
DMA mod is now connected to stream via rsnd_dai_connect(). This means DMA mod can use .remove for its clearance. rsnd_dma_detach() is no longer needed.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/dma.c | 11 ----------- sound/soc/sh/rcar/rsnd.h | 1 - sound/soc/sh/rcar/ssi.c | 2 -- 3 files changed, 14 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index e0761cac0ab7..c85a55111392 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -698,17 +698,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, return 0; }
-void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod) -{ - if (*dma_mod) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - devm_kfree(dev, *dma_mod); - *dma_mod = NULL; - } -} - int rsnd_dma_probe(struct rsnd_priv *priv) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 2460d1fbf775..c1cee1ab3e62 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -200,7 +200,6 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); */ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod); -void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b0338d0a4cde..e23e07b54d8c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -701,8 +701,6 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, /* PIO will request IRQ again */ free_irq(ssi->irq, mod);
- rsnd_dma_detach(mod, &ssi->dma); - return 0; }
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current rsnd_dmaen_start() is calling of_node_put() for np, but it is not needed if it goes through this loop. This patch tidyup it
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dma.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index c85a551..2f03277 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -143,19 +143,17 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { - struct dma_chan *chan; + struct dma_chan *chan = NULL; struct device_node *np; int i = 0;
for_each_child_of_node(of_node, np) { - if (i == rsnd_mod_id(mod)) - break; + if (i == rsnd_mod_id(mod) && (!chan)) + chan = of_dma_request_slave_channel(np, name); i++; }
- chan = of_dma_request_slave_channel(np, name); - - of_node_put(np); + /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node);
return chan;
The patch
ASoC: rsnd: don't call unneeded of_node_put() on dma.c
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 161ba1f1a5c99c4525eb39cc71ec984e0a39e6d7 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Tue, 25 Oct 2016 00:37:18 +0000 Subject: [PATCH] ASoC: rsnd: don't call unneeded of_node_put() on dma.c
Current rsnd_dmaen_start() is calling of_node_put() for np, but it is not needed if it goes through this loop. This patch tidyup it
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/dma.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index c85a55111392..2f0327714625 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -143,19 +143,17 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { - struct dma_chan *chan; + struct dma_chan *chan = NULL; struct device_node *np; int i = 0;
for_each_child_of_node(of_node, np) { - if (i == rsnd_mod_id(mod)) - break; + if (i == rsnd_mod_id(mod) && (!chan)) + chan = of_dma_request_slave_channel(np, name); i++; }
- chan = of_dma_request_slave_channel(np, name); - - of_node_put(np); + /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node);
return chan;
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. To fixup this issue, it should request/release DMA channel on each playback/recorde timing. But, DMA channel request/release function uses mutex lock inside. This means it will breaks current spinlock's interrupt protect. To solve this issue, DMA channel request/release function needs to be called from non-spinlock area. This patch adds its callback.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 26 ++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ea14a14..9ffa299 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -716,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; }
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + return rsnd_dai_call(nolock_start, io, priv); +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(nolock_stop, io, priv); +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c1cee1a..422b534 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -259,6 +259,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*nolock_start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*nolock_stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); };
struct rsnd_dai_stream; @@ -276,8 +282,9 @@ struct rsnd_mod { /* * status * - * 0xH0000CB0 + * 0xH0000CBA * + * A 0: nolock_start 1: nolock_stop * B 0: init 1: quit * C 0: start 1: stop * @@ -287,6 +294,8 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ +#define __rsnd_mod_shift_nolock_start 0 +#define __rsnd_mod_shift_nolock_stop 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -300,6 +309,8 @@ struct rsnd_mod {
#define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 +#define __rsnd_mod_add_nolock_start 1 +#define __rsnd_mod_add_nolock_stop -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -319,6 +330,8 @@ struct rsnd_mod { #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 +#define __rsnd_mod_call_nolock_start 0 +#define __rsnd_mod_call_nolock_stop 1
#define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
The patch
ASoC: rsnd: add nolock_start/stop callback
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 10a9cca13220888c20a259abbd42ea117cddfdb0 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Tue, 25 Oct 2016 00:37:35 +0000 Subject: [PATCH] ASoC: rsnd: add nolock_start/stop callback
Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. To fixup this issue, it should request/release DMA channel on each playback/recorde timing. But, DMA channel request/release function uses mutex lock inside. This means it will breaks current spinlock's interrupt protect. To solve this issue, DMA channel request/release function needs to be called from non-spinlock area. This patch adds its callback.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/core.c | 26 ++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ea14a1470de2..9ffa29941ceb 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -716,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; }
+static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + return rsnd_dai_call(nolock_start, io, priv); +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(nolock_stop, io, priv); +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c1cee1ab3e62..422b5344b687 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -259,6 +259,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*nolock_start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*nolock_stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); };
struct rsnd_dai_stream; @@ -276,8 +282,9 @@ struct rsnd_mod { /* * status * - * 0xH0000CB0 + * 0xH0000CBA * + * A 0: nolock_start 1: nolock_stop * B 0: init 1: quit * C 0: start 1: stop * @@ -287,6 +294,8 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ +#define __rsnd_mod_shift_nolock_start 0 +#define __rsnd_mod_shift_nolock_stop 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -300,6 +309,8 @@ struct rsnd_mod {
#define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 +#define __rsnd_mod_add_nolock_start 1 +#define __rsnd_mod_add_nolock_stop -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -319,6 +330,8 @@ struct rsnd_mod { #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 +#define __rsnd_mod_call_nolock_start 0 +#define __rsnd_mod_call_nolock_stop 1
#define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. This patch fixup to request/release DMA channel each time.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/dma.c | 182 ++++++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 77 deletions(-)
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 2f03277..27a5a2e 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -34,6 +34,8 @@ struct rsnd_dmapp {
struct rsnd_dma { struct rsnd_mod mod; + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -92,6 +94,20 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); }
+static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, + struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + if ((!mod_from && !mod_to) || + (mod_from && mod_to)) + return NULL; + + if (mod_from) + return rsnd_mod_dma_req(io, mod_from); + else + return rsnd_mod_dma_req(io, mod_to); +} + static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -99,7 +115,59 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- dmaengine_terminate_all(dmaen->chan); + if (dmaen->chan) { + dmaengine_terminate_all(dmaen->chan); + } + + return 0; +} + +static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + /* + * DMAEngine release uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + if (dmaen->chan) + dma_release_channel(dmaen->chan); + + dmaen->chan = NULL; + + return 0; +} + +static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct device *dev = rsnd_priv_to_dev(priv); + + if (dmaen->chan) { + dev_err(dev, "it already has dma channel\n"); + return -EIO; + } + + /* + * DMAEngine request uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + dmaen->chan = rsnd_dmaen_request_channel(io, + dma->mod_from, + dma->mod_to); + if (IS_ERR_OR_NULL(dmaen->chan)) { + dmaen->chan = NULL; + dev_err(dev, "can't get dma channel\n"); + return PTR_ERR(dmaen->chan); + }
return 0; } @@ -113,7 +181,23 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; + struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); + int ret; + + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.src_addr = dma->src_addr; + cfg.dst_addr = dma->dst_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + dev_dbg(dev, "%s[%d] %pad -> %pad\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + &cfg.src_addr, &cfg.dst_addr); + + ret = dmaengine_slave_config(dmaen->chan, &cfg); + if (ret < 0) + return ret;
desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, @@ -159,97 +243,39 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, return chan; }
-static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - if ((!mod_from && !mod_to) || - (mod_from && mod_to)) - return NULL; - - if (mod_from) - return rsnd_mod_dma_req(io, mod_from); - else - return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; - - return 0; -} - static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_slave_config cfg = {}; - int is_play = rsnd_io_is_play(io); - int ret; - - if (dmaen->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } - - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - - if (IS_ERR_OR_NULL(dmaen->chan)) { - dmaen->chan = NULL; - dev_err(dev, "can't get dma channel\n"); - goto rsnd_dma_channel_err; + struct dma_chan *chan; + + /* try to get DMAEngine channel */ + chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); + if (IS_ERR_OR_NULL(chan)) { + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + return -EAGAIN; }
- cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = dma->src_addr; - cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - - dev_dbg(dev, "%s[%d] %pad -> %pad\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - &cfg.src_addr, &cfg.dst_addr); - - ret = dmaengine_slave_config(dmaen->chan, &cfg); - if (ret < 0) - goto rsnd_dma_attach_err; + dma_release_channel(chan);
dmac->dmaen_num++;
return 0; - -rsnd_dma_attach_err: - rsnd_dmaen_remove(mod, io, priv); -rsnd_dma_channel_err: - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; }
static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", + .nolock_start = rsnd_dmaen_nolock_start, + .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .remove = rsnd_dmaen_remove, };
/* @@ -671,9 +697,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod,
*dma_mod = rsnd_mod_get(dma);
- dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) @@ -687,6 +710,11 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; + + dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); + dma->mod_from = mod_from; + dma->mod_to = mod_to; }
ret = rsnd_dai_connect(*dma_mod, io, type);
On Tue, Oct 25, 2016 at 12:37:59AM +0000, Kuninori Morimoto wrote:
Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. This patch fixup to request/release DMA channel each time.
Isn't this something which should be handled by better power management in the DMA driver rather than this?
Hi Mark Cc: Laurent
Thank you for your feedback
Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. This patch fixup to request/release DMA channel each time.
Isn't this something which should be handled by better power management in the DMA driver rather than this?
I discussed about this topic with Laurent. Yes, the best choice is that DMAEngine side should care about it, but, it can't on current DMAEngine design.
# We need to call pm_runtime_get_sync() to power the hardware on # which can't be called in atomic context. # And dma_async_issue_pending() needs to be callable in atomic context # so to fix this we would likely need to extend the DMA engine API
So, current *better* choice is sound driver request/release DMA channel each time.
I will post v2 patch with [1/8] update
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
IOMMU needs DMA mapping function to use it. One solution is that we can use DMA mapped dev on snd_pcm_lib_preallocate_pages_for_all() for SNDRV_DMA_TYPE_DEV. But pcm_new and dma map timing are mismatched. Thus, this patch uses SNDRV_DMA_TYPE_CONTINUOUS for pcm_new, and use dma_sync_single_for_xxx() for each transfer.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- sound/soc/sh/rcar/core.c | 4 +-- sound/soc/sh/rcar/dma.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9ffa299..912dc62 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1126,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); }
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 27a5a2e..119aa8d 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,10 @@
struct rsnd_dmaen { struct dma_chan *chan; + dma_addr_t dma_buf; + unsigned int dma_len; + unsigned int dma_period; + unsigned int dma_cnt; };
struct rsnd_dmapp { @@ -58,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ +#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) +#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) +static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, + int i, int sync) +{ + struct device *dev = dmaen->chan->device->dev; + enum dma_data_direction dir; + int is_play = rsnd_io_is_play(io); + dma_addr_t buf; + int len, max; + size_t period; + + len = dmaen->dma_len; + period = dmaen->dma_period; + max = len / period; + i = i % max; + buf = dmaen->dma_buf + (period * i); + + dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + if (sync) + dma_sync_single_for_device(dev, buf, period, dir); + else + dma_sync_single_for_cpu(dev, buf, period, dir); +} + static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags;
@@ -78,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags);
- if (rsnd_io_is_working(io)) + if (rsnd_io_is_working(io)) { + rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); + + /* + * Next period is already started. + * Let's sync Next Next period + * see + * rsnd_dmaen_start() + */ + rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); + elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
+ dmaen->dma_cnt++; + } + spin_unlock_irqrestore(&priv->lock, flags);
if (elapsed) @@ -116,7 +161,12 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
if (dmaen->chan) { + int is_play = rsnd_io_is_play(io); + dmaengine_terminate_all(dmaen->chan); + dma_unmap_single(dmaen->chan->device->dev, + dmaen->dma_buf, dmaen->dma_len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); }
return 0; @@ -182,7 +232,11 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; + dma_addr_t buf; + size_t len; + size_t period; int is_play = rsnd_io_is_play(io); + int i; int ret;
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; @@ -199,10 +253,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, if (ret < 0) return ret;
+ len = snd_pcm_lib_buffer_bytes(substream); + period = snd_pcm_lib_period_bytes(substream); + buf = dma_map_single(dmaen->chan->device->dev, + substream->runtime->dma_area, + len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(dmaen->chan->device->dev, buf)) { + dev_err(dev, "dma map failed\n"); + return -EIO; + } + desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), + buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -214,6 +277,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma);
+ dmaen->dma_buf = buf; + dmaen->dma_len = len; + dmaen->dma_period = period; + dmaen->dma_cnt = 0; + + /* + * synchronize this and next period + * see + * __rsnd_dmaen_complete() + */ + for (i = 0; i < 2; i++) + rsnd_dmaen_sync(dmaen, io, i); + if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO;
The patch
ASoC: rsnd: use dma_sync_single_for_xxx() for IOMMU
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 4821d914fe747a91453021675a74069776f0b819 Mon Sep 17 00:00:00 2001
From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Date: Mon, 14 Nov 2016 04:20:56 +0000 Subject: [PATCH] ASoC: rsnd: use dma_sync_single_for_xxx() for IOMMU
IOMMU needs DMA mapping function to use it. One solution is that we can use DMA mapped dev on snd_pcm_lib_preallocate_pages_for_all() for SNDRV_DMA_TYPE_DEV. But pcm_new and dma map timing are mismatched. Thus, this patch uses SNDRV_DMA_TYPE_CONTINUOUS for pcm_new, and use dma_sync_single_for_xxx() for each transfer.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/sh/rcar/core.c | 4 +-- sound/soc/sh/rcar/dma.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9ffa29941ceb..912dc62ff9c7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1126,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); }
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 3c663a5cfe8b..1f405c833867 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,10 @@
struct rsnd_dmaen { struct dma_chan *chan; + dma_addr_t dma_buf; + unsigned int dma_len; + unsigned int dma_period; + unsigned int dma_cnt; };
struct rsnd_dmapp { @@ -58,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ +#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) +#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) +static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, + int i, int sync) +{ + struct device *dev = dmaen->chan->device->dev; + enum dma_data_direction dir; + int is_play = rsnd_io_is_play(io); + dma_addr_t buf; + int len, max; + size_t period; + + len = dmaen->dma_len; + period = dmaen->dma_period; + max = len / period; + i = i % max; + buf = dmaen->dma_buf + (period * i); + + dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + if (sync) + dma_sync_single_for_device(dev, buf, period, dir); + else + dma_sync_single_for_cpu(dev, buf, period, dir); +} + static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags;
@@ -78,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags);
- if (rsnd_io_is_working(io)) + if (rsnd_io_is_working(io)) { + rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); + + /* + * Next period is already started. + * Let's sync Next Next period + * see + * rsnd_dmaen_start() + */ + rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); + elapsed = rsnd_dai_pointer_update(io, io->byte_per_period);
+ dmaen->dma_cnt++; + } + spin_unlock_irqrestore(&priv->lock, flags);
if (elapsed) @@ -116,7 +161,12 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
if (dmaen->chan) { + int is_play = rsnd_io_is_play(io); + dmaengine_terminate_all(dmaen->chan); + dma_unmap_single(dmaen->chan->device->dev, + dmaen->dma_buf, dmaen->dma_len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); }
return 0; @@ -184,7 +234,11 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; + dma_addr_t buf; + size_t len; + size_t period; int is_play = rsnd_io_is_play(io); + int i; int ret;
cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; @@ -201,10 +255,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, if (ret < 0) return ret;
+ len = snd_pcm_lib_buffer_bytes(substream); + period = snd_pcm_lib_period_bytes(substream); + buf = dma_map_single(dmaen->chan->device->dev, + substream->runtime->dma_area, + len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(dmaen->chan->device->dev, buf)) { + dev_err(dev, "dma map failed\n"); + return -EIO; + } + desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), + buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -216,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma);
+ dmaen->dma_buf = buf; + dmaen->dma_len = len; + dmaen->dma_period = period; + dmaen->dma_cnt = 0; + + /* + * synchronize this and next period + * see + * __rsnd_dmaen_complete() + */ + for (i = 0; i < 2; i++) + rsnd_dmaen_sync(dmaen, io, i); + if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO;
participants (2)
-
Kuninori Morimoto
-
Mark Brown