From f240406babfe1526998e10583ea5eccc2676a433 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 5 Jan 2010 17:19:34 +0100 Subject: ALSA: pcm_lib - cleanup & merge hw_ptr update functions Do general cleanup in snd_pcm_update_hw_ptr*() routines and merge them. The main change is hw_ptr_interrupt variable removal to simplify code logic. This variable can be computed directly from hw_ptr. Ensure that updated hw_ptr is not lower than previous one (it was possible with old code in some obscure situations when interrupt was delayed or the lowlevel driver returns wrong ring buffer position value). Signed-off-by: Jaroslav Kysela --- sound/core/pcm_native.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/core/pcm_native.c') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 29ab46a12e11..8e777f71717c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1247,8 +1247,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) if (err < 0) return err; runtime->hw_ptr_base = 0; - runtime->hw_ptr_interrupt = runtime->status->hw_ptr - - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; return 0; -- cgit v1.2.3 From 1250932e48d3b698415b1f04775433cf1da688d6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 7 Jan 2010 15:36:31 +0100 Subject: ALSA: pcm_lib - optimize wake_up() calls for PCM I/O As noted by pl bossart , the PCM I/O routines (snd_pcm_lib_write1, snd_pcm_lib_read1) should block wake_up() calls until all samples are not processed. Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 3 +++ sound/core/pcm_lib.c | 30 ++++++++++++++++++++---------- sound/core/pcm_native.c | 6 ++++-- 3 files changed, 27 insertions(+), 12 deletions(-) (limited to 'sound/core/pcm_native.c') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index fe1b131842be..e26fb3c58037 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -311,6 +311,7 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ + unsigned int nowake: 1; /* no wakeup (data-copy in progress) */ wait_queue_head_t sleep; struct fasync_struct *fasync; @@ -839,6 +840,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime); int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 70a4f7428d78..a63226232ef4 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -263,8 +263,8 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #endif -static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +int snd_pcm_update_state(struct snd_pcm_substream *substream, + struct snd_pcm_runtime *runtime) { snd_pcm_uframes_t avail; @@ -285,7 +285,7 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, return -EPIPE; } } - if (avail >= runtime->control->avail_min) + if (!runtime->nowake && avail >= runtime->control->avail_min) wake_up(&runtime->sleep); return 0; } @@ -441,7 +441,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - return snd_pcm_update_hw_ptr_post(substream, runtime); + return snd_pcm_update_state(substream, runtime); } /* CAUTION: call it with irq disabled */ @@ -1792,6 +1792,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1813,15 +1814,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) - goto _end; + err = transfer(substream, appl_ofs, data, offset, frames); snd_pcm_stream_lock_irq(substream); + if (err < 0) + goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -1850,8 +1853,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } } _end_unlock: + runtime->nowake = 0; + if (xfer > 0 && err >= 0) + snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); - _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } @@ -2009,6 +2014,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } + runtime->nowake = 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2037,15 +2043,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { + runtime->nowake = 0; snd_pcm_stream_unlock_irq(substream); return -EINVAL; } appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; snd_pcm_stream_unlock_irq(substream); - if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) - goto _end; + err = transfer(substream, appl_ofs, data, offset, frames); snd_pcm_stream_lock_irq(substream); + if (err < 0) + goto _end_unlock; switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2068,8 +2076,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, xfer += frames; } _end_unlock: + runtime->nowake = 0; + if (xfer > 0 && err >= 0) + snd_pcm_update_state(substream, runtime); snd_pcm_stream_unlock_irq(substream); - _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 8e777f71717c..27284f628361 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -516,6 +516,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, struct snd_pcm_sw_params *params) { struct snd_pcm_runtime *runtime; + int err; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; @@ -540,6 +541,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (params->silence_threshold > runtime->buffer_size) return -EINVAL; } + err = 0; snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; runtime->period_step = params->period_step; @@ -553,10 +555,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - wake_up(&runtime->sleep); + err = snd_pcm_update_state(substream, runtime); } snd_pcm_stream_unlock_irq(substream); - return 0; + return err; } static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, -- cgit v1.2.3