From: Louis Chauvet <louis.chauvet@bootlin.com>
To: linux-sound@vger.kernel.org, dmaengine@vger.kernel.org,
alsa-devel@alsa-project.org
Cc: miquel.raynal@bootlin.com, perex@perex.cz, tiwai@suse.com,
broonie@kernel.org, lars@metafoo.de, lgirdwood@gmail.com
Subject: DMA Transfer Synchronization Issue in Out-of-Tree Sound Card Driver
Date: Tue, 21 May 2024 10:31:12 +0200 [thread overview]
Message-ID: <Zkxb0FTzW6wlnYYO@localhost.localdomain> (raw)
Hello everyone,
I am currently developing an out-of-tree driver for a sound card that
utilizes XDMA for sample transfers. I am currently using a kernel 6.5 with
the latest xdma driver cherry-picked, but I don't think any changes since
6.5 is addressing my issue.
My initial issue pertains to the completion of DMA transfers between a
start and a stop command in ALSA. If the interval is too brief, the
transfer does not conclude properly, leading to distorted samples. A
straightforward solution to this problem was to adequately wait for the
transfer to finish upon the stop, ie. sleeping until we know the hardware
is done with the transfert (the XDMA controller does not support stopping
in the middle of a transfer).
To address this DMA issue, I have created a patch [1] that guarantees the
completion of the DMA transfer upon the return of xdma_synchronize. This
means xdma_synchronize now sleeps, but looking at other drivers around it
appears expected to be able to do so.
Regarding the audio implementation, the following patch enforces the
synchronization:
int playback_trigger(struct snd_pcm_substream *substream, int command)
{
struct my_dev *my_dev = snd_pcm_substream_chip(substream);
switch (command) {
case SNDRV_PCM_TRIGGER_START:
/* Synchronize on start, because the trigger stop is called from an IRQ context */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dmaengine_synchronize(my_dev->playback_dma_chan);
pipe_start(&my_dev->playback, substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
pipe_stop(&my_dev->playback, substream);
break;
default:
return -EINVAL;
}
return 0;
}
In order for a sleepable function like dmaengine_synchronize() to work in
the trigger callbacks, the audio card nonatomic flag had to be set. It
basically leads the sound core towards the use of a mutex instead of a
spinlock.
static int probe([...]) {
struct snd_pcm *pcm;
[...]
/* This flag is needed to be able to sleep in start/stop callbacks */
pcm->nonatomic = true;
[...]
snd_pcm_set_managed_buffer_all(pcm, [...]);
}
This approach generally works well, but leads to "scheduling while
atomic" errors. Indeed, the IRQ handler from the XDMA driver invokes a
function within the sound subsystem, which subsequently acquires a
mutex...
At the moment, the only solution I've found is to replace the
wait_for_completion() in the XDMA driver [2] with a busy wait loop.
However, this approach seems incorrect, as all other synchronization
functions in other DMA drivers are sleeping, which should not cause an
issue.
The problem might be related to the sound driver. Should I avoid manually
using dmaengine_synchronize? How to achieve the same effect in this case?
Perhaps there is a more traditional way to properly clean the stream in
the sound subsystem which I overlooked?
Could someone please provide guidance on how to resolve this issue?
Thanks,
Louis Chauvet
[1]: https://lore.kernel.org/all/20240327-digigram-xdma-fixes-v1-2-45f4a52c0283@bootlin.com/
[2]: https://elixir.bootlin.com/linux/latest/source/drivers/dma/xilinx/xdma.c#L550
--
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next reply other threads:[~2024-05-21 8:31 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-21 8:31 Louis Chauvet [this message]
2024-05-21 18:32 ` DMA Transfer Synchronization Issue in Out-of-Tree Sound Card Driver Mark Brown
2024-05-22 5:52 ` Takashi Iwai
2024-05-24 16:13 ` Louis Chauvet
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Zkxb0FTzW6wlnYYO@localhost.localdomain \
--to=louis.chauvet@bootlin.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=dmaengine@vger.kernel.org \
--cc=lars@metafoo.de \
--cc=lgirdwood@gmail.com \
--cc=linux-sound@vger.kernel.org \
--cc=miquel.raynal@bootlin.com \
--cc=perex@perex.cz \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox