Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: pcm: support for period wakeup disabling

This patch allows to disable period interrupts which are
not needed when the application relies on a system timer
to wake-up and refill the ring buffer. The behavior of
the driver is left unchanged, and interrupts are only
disabled if the application requests this configuration.
The behavior in case of underruns is slightly different,
instead of being detected during the period interrupts the
underruns are detected when the application calls
snd_pcm_update_avail, which in turns forces a refresh of the
hw pointer and shows the buffer is empty.

More specifically this patch makes a lot of sense when
PulseAudio relies on timer-based scheduling to access audio
devices such as HDAudio or Intel SST. Disabling interrupts
removes two unwanted wake-ups due to period elapsed events
in low-power playback modes. It also simplifies PulseAudio
voice modules used for speech calls.

To quote Lennart "This patch looks very interesting and
desirable. This is something have long been waiting for."

Support for this in hardware drivers is optional.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@intel.com>
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Clemens Ladisch and committed by
Takashi Iwai
ab69a490 d2b88e4c

+13
+3
include/sound/asound.h
··· 259 259 #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ 260 260 #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ 261 261 #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ 262 + #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */ 262 263 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ 263 264 264 265 typedef int __bitwise snd_pcm_state_t; ··· 335 334 #define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME 336 335 337 336 #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ 337 + #define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ 338 + #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ 338 339 339 340 struct snd_interval { 340 341 unsigned int min, max;
+1
include/sound/pcm.h
··· 297 297 unsigned int info; 298 298 unsigned int rate_num; 299 299 unsigned int rate_den; 300 + unsigned int no_period_wakeup: 1; 300 301 301 302 /* -- SW params -- */ 302 303 int tstamp_mode; /* mmap timestamp is updated */
+6
sound/core/pcm_lib.c
··· 373 373 (unsigned long)new_hw_ptr, 374 374 (unsigned long)runtime->hw_ptr_base); 375 375 } 376 + 377 + /* without period interrupts, there are no regular pointer updates */ 378 + if (runtime->no_period_wakeup) 379 + goto no_delta_check; 380 + 376 381 /* something must be really wrong */ 377 382 if (delta >= runtime->buffer_size + runtime->period_size) { 378 383 hw_ptr_error(substream, ··· 447 442 (long)old_hw_ptr); 448 443 } 449 444 445 + no_delta_check: 450 446 if (runtime->status->hw_ptr == new_hw_ptr) 451 447 return 0; 452 448
+3
sound/core/pcm_native.c
··· 423 423 runtime->info = params->info; 424 424 runtime->rate_num = params->rate_num; 425 425 runtime->rate_den = params->rate_den; 426 + runtime->no_period_wakeup = 427 + (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && 428 + (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); 426 429 427 430 bits = snd_pcm_format_physical_width(runtime->format); 428 431 runtime->sample_bits = bits;