[RFC PATCH v3 0/4] Reuse the dma channel if available in Back-End
Reuse the dma channel if available in Back-End
Shengjiu Wang (4): ASoC: soc-card: export snd_soc_lookup_component_nolocked ASoC: dmaengine_pcm: export soc_component_to_pcm ASoC: fsl_asrc_dma: Reuse the dma channel if available in Back-End ASoC: fsl_asrc_dma: Fix data copying speed issue with EDMA
changes in v3: - update according to Nicolin's comments - split previous 0003 patch to two patches
changes in v2: - update according to Mark's comments and split the patch
include/sound/dmaengine_pcm.h | 11 +++++++ include/sound/soc.h | 2 ++ sound/soc/fsl/fsl_asrc_common.h | 2 ++ sound/soc/fsl/fsl_asrc_dma.c | 47 +++++++++++++++++++-------- sound/soc/soc-core.c | 3 +- sound/soc/soc-generic-dmaengine-pcm.c | 12 ------- 6 files changed, 50 insertions(+), 27 deletions(-)
snd_soc_lookup_component_nolocked can be used for the DPCM case that Front-End needs to get the unused platform component but added by Back-End cpu dai driver.
If the component is gotten, then we can get the dma chan created by Back-End component and reused it in Front-End.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 74868436ac79..565612a8d690 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -444,6 +444,8 @@ int devm_snd_soc_register_component(struct device *dev, const struct snd_soc_component_driver *component_driver, struct snd_soc_dai_driver *dai_drv, int num_dai); void snd_soc_unregister_component(struct device *dev); +struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev, + const char *driver_name); struct snd_soc_component *snd_soc_lookup_component(struct device *dev, const char *driver_name);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b07eca2c6ccc..d4c73e86d058 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -310,7 +310,7 @@ struct snd_soc_component *snd_soc_rtdcom_lookup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_rtdcom_lookup);
-static struct snd_soc_component +struct snd_soc_component *snd_soc_lookup_component_nolocked(struct device *dev, const char *driver_name) { struct snd_soc_component *component; @@ -329,6 +329,7 @@ static struct snd_soc_component
return found_component; } +EXPORT_SYMBOL_GPL(snd_soc_lookup_component_nolocked);
struct snd_soc_component *snd_soc_lookup_component(struct device *dev, const char *driver_name)
On Fri, Jun 12, 2020 at 03:37:48PM +0800, Shengjiu Wang wrote:
snd_soc_lookup_component_nolocked can be used for the DPCM case that Front-End needs to get the unused platform component but added by Back-End cpu dai driver.
If the component is gotten, then we can get the dma chan created by Back-End component and reused it in Front-End.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
In DPCM case, Front-End needs to get the dma chan which has been requested by Back-End and reuse it.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- include/sound/dmaengine_pcm.h | 11 +++++++++++ sound/soc/soc-generic-dmaengine-pcm.c | 12 ------------ 2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index b65220685920..8c5e38180fb0 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -161,4 +161,15 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
#define SND_DMAENGINE_PCM_DRV_NAME "snd_dmaengine_pcm"
+struct dmaengine_pcm { + struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; + const struct snd_dmaengine_pcm_config *config; + struct snd_soc_component component; + unsigned int flags; +}; + +static inline struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p) +{ + return container_of(p, struct dmaengine_pcm, component); +} #endif diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index f728309a0833..80a4e71f2d95 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -21,18 +21,6 @@ */ #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(31)
-struct dmaengine_pcm { - struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; - const struct snd_dmaengine_pcm_config *config; - struct snd_soc_component component; - unsigned int flags; -}; - -static struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p) -{ - return container_of(p, struct dmaengine_pcm, component); -} - static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm, struct snd_pcm_substream *substream) {
On Fri, Jun 12, 2020 at 03:37:49PM +0800, Shengjiu Wang wrote:
In DPCM case, Front-End needs to get the dma chan which has been requested by Back-End and reuse it.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
The dma channel has been requested by Back-End cpu dai driver already. If fsl_asrc_dma requests dma chan with same dma:tx symlink, then there will be below warning with SDMA.
[ 48.174236] fsl-esai-dai 2024000.esai: Cannot create DMA dma:tx symlink
So if we can reuse the dma channel of Back-End, then the issue can be fixed.
In order to get the dma channel which is already requested in Back-End. we use the exported two functions (snd_soc_lookup_component_nolocked and soc_component_to_pcm). If we can get the dma channel, then reuse it, if can't, then request a new one.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_asrc_dma.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index d6a3fc5f87e5..d88e6343e0a2 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -135,6 +135,8 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; + struct dma_chan *tmp_chan = NULL, *be_chan = NULL; + struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; struct dma_slave_config config_fe, config_be; enum asrc_pair_index index = pair->index; @@ -142,7 +144,6 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, int stream = substream->stream; struct imx_dma_data *tmp_data; struct snd_soc_dpcm *dpcm; - struct dma_chan *tmp_chan; struct device *dev_be; u8 dir = tx ? OUT : IN; dma_cap_mask_t mask; @@ -197,18 +198,30 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_CYCLIC, mask);
+ /* + * The Back-End device might have already requested a DMA channel, + * so try to reuse it first, and then request a new one upon NULL. + */ + component_be = snd_soc_lookup_component_nolocked(dev_be, SND_DMAENGINE_PCM_DRV_NAME); + if (component_be) { + be_chan = soc_component_to_pcm(component_be)->chan[substream->stream]; + tmp_chan = be_chan; + } + if (!tmp_chan) + tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); + /* * An EDMA DEV_TO_DEV channel is fixed and bound with DMA event of each * peripheral, unlike SDMA channel that is allocated dynamically. So no - * need to configure dma_request and dma_request2, but get dma_chan via - * dma_request_slave_channel directly with dma name of Front-End device + * need to configure dma_request and dma_request2, but get dma_chan of + * Back-End device directly via dma_request_slave_channel. */ if (!asrc->use_edma) { /* Get DMA request of Back-End */ - tmp_chan = dma_request_slave_channel(dev_be, tx ? "tx" : "rx"); tmp_data = tmp_chan->private; pair->dma_data.dma_request = tmp_data->dma_request; - dma_release_channel(tmp_chan); + if (!be_chan) + dma_release_channel(tmp_chan);
/* Get DMA request of Front-End */ tmp_chan = asrc->get_dma_channel(pair, dir); @@ -221,6 +234,8 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, pair->dma_chan[dir] = dma_request_channel(mask, filter, &pair->dma_data); } else { + if (!be_chan) + dma_release_channel(tmp_chan); pair->dma_chan[dir] = asrc->get_dma_channel(pair, dir); }
On Fri, Jun 12, 2020 at 03:37:50PM +0800, Shengjiu Wang wrote:
The dma channel has been requested by Back-End cpu dai driver already. If fsl_asrc_dma requests dma chan with same dma:tx symlink, then there will be below warning with SDMA.
[ 48.174236] fsl-esai-dai 2024000.esai: Cannot create DMA dma:tx symlink
So if we can reuse the dma channel of Back-End, then the issue can be fixed.
In order to get the dma channel which is already requested in Back-End. we use the exported two functions (snd_soc_lookup_component_nolocked and soc_component_to_pcm). If we can get the dma channel, then reuse it, if can't, then request a new one.
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
With EDMA, there is two dma channels can be used for dev_to_dev, one is from ASRC, one is from another peripheral (ESAI or SAI).
If we select the dma channel of ASRC, there is an issue for ideal ratio case, the speed of copy data is faster than sample frequency, because ASRC output data is very fast in ideal ratio mode.
So it is reasonable to use the dma channel of Back-End peripheral. then copying speed of DMA is controlled by data consumption speed in the peripheral FIFO,
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com --- sound/soc/fsl/fsl_asrc_common.h | 2 ++ sound/soc/fsl/fsl_asrc_dma.c | 26 +++++++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h index 77665b15c8db..7e1c13ca37f1 100644 --- a/sound/soc/fsl/fsl_asrc_common.h +++ b/sound/soc/fsl/fsl_asrc_common.h @@ -32,6 +32,7 @@ enum asrc_pair_index { * @dma_chan: inputer and output DMA channels * @dma_data: private dma data * @pos: hardware pointer position + * @req_dma_chan: flag to release dev_to_dev chan * @private: pair private area */ struct fsl_asrc_pair { @@ -45,6 +46,7 @@ struct fsl_asrc_pair { struct dma_chan *dma_chan[2]; struct imx_dma_data dma_data; unsigned int pos; + bool req_dma_chan;
void *private; }; diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index d88e6343e0a2..5f01a58f422a 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -233,11 +233,11 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
pair->dma_chan[dir] = dma_request_channel(mask, filter, &pair->dma_data); + pair->req_dma_chan = true; } else { - if (!be_chan) - dma_release_channel(tmp_chan); - pair->dma_chan[dir] = - asrc->get_dma_channel(pair, dir); + pair->dma_chan[dir] = tmp_chan; + /* Do not flag to release if we are reusing the Back-End one */ + pair->req_dma_chan = !be_chan; }
if (!pair->dma_chan[dir]) { @@ -276,7 +276,8 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be); if (ret) { dev_err(dev, "failed to config DMA channel for Back-End\n"); - dma_release_channel(pair->dma_chan[dir]); + if (pair->req_dma_chan) + dma_release_channel(pair->dma_chan[dir]); return ret; }
@@ -288,19 +289,22 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, static int fsl_asrc_dma_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; + u8 dir = tx ? OUT : IN;
snd_pcm_set_runtime_buffer(substream, NULL);
- if (pair->dma_chan[IN]) - dma_release_channel(pair->dma_chan[IN]); + if (pair->dma_chan[!dir]) + dma_release_channel(pair->dma_chan[!dir]);
- if (pair->dma_chan[OUT]) - dma_release_channel(pair->dma_chan[OUT]); + /* release dev_to_dev chan if we aren't reusing the Back-End one */ + if (pair->dma_chan[dir] && pair->req_dma_chan) + dma_release_channel(pair->dma_chan[dir]);
- pair->dma_chan[IN] = NULL; - pair->dma_chan[OUT] = NULL; + pair->dma_chan[!dir] = NULL; + pair->dma_chan[dir] = NULL;
return 0; }
On Fri, Jun 12, 2020 at 03:37:51PM +0800, Shengjiu Wang wrote:
With EDMA, there is two dma channels can be used for dev_to_dev, one is from ASRC, one is from another peripheral (ESAI or SAI).
If we select the dma channel of ASRC, there is an issue for ideal ratio case, the speed of copy data is faster than sample frequency, because ASRC output data is very fast in ideal ratio mode.
So it is reasonable to use the dma channel of Back-End peripheral. then copying speed of DMA is controlled by data consumption speed in the peripheral FIFO,
Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com
Reviewed-by: Nicolin Chen nicoleotsuka@gmail.com
On Fri, 12 Jun 2020 15:37:47 +0800, Shengjiu Wang wrote:
Reuse the dma channel if available in Back-End
Shengjiu Wang (4): ASoC: soc-card: export snd_soc_lookup_component_nolocked ASoC: dmaengine_pcm: export soc_component_to_pcm ASoC: fsl_asrc_dma: Reuse the dma channel if available in Back-End ASoC: fsl_asrc_dma: Fix data copying speed issue with EDMA
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/4] ASoC: soc-card: export snd_soc_lookup_component_nolocked commit: 6fbea6b6a838f9aa941fe53a3637fd8d8aab1eba [2/4] ASoC: dmaengine_pcm: export soc_component_to_pcm commit: a9a21e1eafc94b79502cab8272b392f7f63ef7bb [3/4] ASoC: fsl_asrc_dma: Reuse the dma channel if available in Back-End commit: 706e2c8811585f42612b6cff218ab3adbe63a4ee [4/4] ASoC: fsl_asrc_dma: Fix data copying speed issue with EDMA commit: b287a6d9723c601dd947f1c27d4cc0192e384a5a
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
participants (3)
-
Mark Brown
-
Nicolin Chen
-
Shengjiu Wang