[alsa-devel] [PATCH] ALSA: add support for disabling period irq
Jaroslav Kysela
perex at perex.cz
Mon Nov 1 23:41:02 CET 2010
On Mon, 1 Nov 2010, Pierre-Louis Bossart wrote:
> Merged and cleaned patch based on earlier patches posted
> on alsa-devel by Clemens Ladisch <clemens at ladisch.de> and
> Pierre-Louis Bossart <pierre-louis.bossart at intel.com>
>
> This patch disables 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."
>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at intel.com>
> ---
> core/pcm_lib.c | 8 ++++++--
> core/pcm_native.c | 6 ++++++
> include/asound.h | 4 ++++
> include/pcm.h | 1 +
> pci/hda/hda_intel.c | 9 ++++++---
> pci/oxygen/oxygen_pcm.c | 14 ++++++++++----
> 6 files changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/core/pcm_lib.c b/core/pcm_lib.c
> index a1707cc..4963d8f 100644
> --- a/core/pcm_lib.c
> +++ b/core/pcm_lib.c
> @@ -374,7 +374,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
> (unsigned long)runtime->hw_ptr_base);
> }
> /* something must be really wrong */
> - if (delta >= runtime->buffer_size + runtime->period_size) {
> + if (delta >= runtime->buffer_size + runtime->period_size &&
> + !runtime->no_period_irq) {
> hw_ptr_error(substream,
> "Unexpected hw_pointer value %s"
> "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
> @@ -395,6 +396,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
> */
> if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
> goto no_jiffies_check;
> + if (runtime->no_period_irq)
> + goto no_jiffies_check;
> hdelta = delta;
> if (hdelta < runtime->delay)
> goto no_jiffies_check;
> @@ -431,7 +434,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
> hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
> }
> no_jiffies_check:
> - if (delta > runtime->period_size + runtime->period_size / 2) {
> + if (delta > runtime->period_size + runtime->period_size / 2 &&
> + !runtime->no_period_irq) {
> hw_ptr_error(substream,
> "Lost interrupts? %s"
> "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
Use one 'if' and a goto behind the last condition to simplify things.
> diff --git a/core/pcm_native.c b/core/pcm_native.c
> index 8bc7cb3..92c8c59 100644
> --- a/core/pcm_native.c
> +++ b/core/pcm_native.c
> @@ -412,6 +412,12 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
> goto _error;
> }
>
> + if (params->info & SNDRV_PCM_INFO_NO_PERIOD_IRQ)
> + runtime->no_period_irq = !!(params->flags &
> + SNDRV_PCM_HW_PARAMS_NO_PERIOD_IRQ);
> + else
> + runtime->no_period_irq = 0;
> +
> runtime->access = params_access(params);
> runtime->format = params_format(params);
> runtime->subformat = params_subformat(params);
> diff --git a/include/asound.h b/include/asound.h
> index a1803ec..d4b5f2d 100644
> --- a/include/asound.h
> +++ b/include/asound.h
> @@ -259,6 +259,7 @@ typedef int __bitwise snd_pcm_subformat_t;
> #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
> #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
> #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
> +#define SNDRV_PCM_INFO_NO_PERIOD_IRQ 0x00800000 /* period interrupt can be disabled */
> #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
>
> typedef int __bitwise snd_pcm_state_t;
> @@ -334,6 +335,9 @@ typedef int snd_pcm_hw_param_t;
> #define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
>
> #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */
> +#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */
> +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_IRQ (1<<2) /* disable period
> + interrupts */
>
> struct snd_interval {
> unsigned int min, max;
The PCM protocol version should be increased.
> diff --git a/include/pcm.h b/include/pcm.h
> index dfd9b76..9abb4aa 100644
> --- a/include/pcm.h
> +++ b/include/pcm.h
> @@ -297,6 +297,7 @@ struct snd_pcm_runtime {
> unsigned int info;
> unsigned int rate_num;
> unsigned int rate_den;
> + bool no_period_irq;
I would use an unsigned int bit field rather than bool in this case to
make addition in-line with other structures in this file.
Jaroslav
-----
Jaroslav Kysela <perex at perex.cz>
Linux Kernel Sound Maintainer
ALSA Project, Red Hat, Inc.
More information about the Alsa-devel
mailing list