aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_native.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-06-19 16:39:18 -0400
committerTakashi Iwai <tiwai@suse.de>2017-06-23 09:39:47 -0400
commit42f945970af9df6216e3d771b4df371d02d8742c (patch)
treee0737461cdf10f91602f80eea364b7f6fd542c27 /sound/core/pcm_native.c
parentc2d6af53a43fd8bb528eac8f31ffb666e9c74cf7 (diff)
ALSA: pcm: Add the explicit appl_ptr sync support
Currently x86 platforms use the PCM status/control mmaps for transferring the PCM status and appl_ptr between kernel and user-spaces. The mmap is a most efficient way of communication, but it has a drawback per its nature, namely, it can't notify the change explicitly to kernel. The lack of appl_ptr update notification is a problem on a few existing drivers, but it's mostly a small issue and negligible. However, a new type of driver that uses DSP for a deep buffer management requires the exact position of appl_ptr for calculating the buffer prefetch size, and the asynchronous appl_ptr update between kernel and user-spaces becomes a significant problem for it. How can we enforce user-space to report the appl_ptr update? The way is relatively simple. Just by disabling the PCM control mmap, the user-space is supposed to fall back to the mode using SYNC_PTR ioctl, and the kernel gets control over that. This fallback mode is used in all non-x86 platforms as default, and also in the 32bit compatible model on all platforms including x86. It's been implemented already over a decade, so we can say it's fairly safe and stably working. With the help of the knowledge above, this patch introduces a new PCM info flag SNDRV_PCM_INFO_SYNC_APPLPTR for achieving the appl_ptr sync from user-space. When a driver sets this flag at open, the PCM status / control mmap is disabled, which effectively switches to SYNC_PTR mode in user-space side. In this version, both PCM status and control mmaps are disabled although only the latter, control mmap, is the target. It's because the current alsa-lib implementation supposes that both status and control mmaps are always coupled, thus it handles a fatal error when only one of them fails. Of course, the disablement of the status/control mmaps may bring a slight performance overhead. Thus, as of now, this should be used only for the dedicated devices that deserves. Note that the disablement of mmap is a sort of workaround. In the later patch, we'll introduce the way to identify the protocol version alsa-lib supports, and keep mmap working while the sync_ptr is performed together. Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r--sound/core/pcm_native.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index d35c6614fdab..9ade0c8b54a3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3376,10 +3376,29 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
3376 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 3376 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
3377 return 0; 3377 return 0;
3378} 3378}
3379
3380static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
3381{
3382 if (pcm_file->no_compat_mmap)
3383 return false;
3384 /* Disallow the status/control mmap when SYNC_APPLPTR flag is set;
3385 * it enforces the user-space to fall back to snd_pcm_sync_ptr(),
3386 * thus it effectively assures the manual update of appl_ptr.
3387 * In theory, it should be enough to disallow only PCM control mmap,
3388 * but since the current alsa-lib implementation requires both status
3389 * and control mmaps always paired, we have to disable both of them.
3390 */
3391 if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)
3392 return false;
3393 return true;
3394}
3395
3379#else /* ! coherent mmap */ 3396#else /* ! coherent mmap */
3380/* 3397/*
3381 * don't support mmap for status and control records. 3398 * don't support mmap for status and control records.
3382 */ 3399 */
3400#define pcm_status_mmap_allowed(pcm_file) false
3401
3383static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, 3402static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
3384 struct vm_area_struct *area) 3403 struct vm_area_struct *area)
3385{ 3404{
@@ -3563,11 +3582,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
3563 offset = area->vm_pgoff << PAGE_SHIFT; 3582 offset = area->vm_pgoff << PAGE_SHIFT;
3564 switch (offset) { 3583 switch (offset) {
3565 case SNDRV_PCM_MMAP_OFFSET_STATUS: 3584 case SNDRV_PCM_MMAP_OFFSET_STATUS:
3566 if (pcm_file->no_compat_mmap) 3585 if (!pcm_status_mmap_allowed(pcm_file))
3567 return -ENXIO; 3586 return -ENXIO;
3568 return snd_pcm_mmap_status(substream, file, area); 3587 return snd_pcm_mmap_status(substream, file, area);
3569 case SNDRV_PCM_MMAP_OFFSET_CONTROL: 3588 case SNDRV_PCM_MMAP_OFFSET_CONTROL:
3570 if (pcm_file->no_compat_mmap) 3589 if (!pcm_status_mmap_allowed(pcm_file))
3571 return -ENXIO; 3590 return -ENXIO;
3572 return snd_pcm_mmap_control(substream, file, area); 3591 return snd_pcm_mmap_control(substream, file, area);
3573 default: 3592 default: