From 79452f0a28aa5a40522c487b42a5fc423647ad98 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Jul 2009 12:51:51 +0200 Subject: ALSA: pcm - Fix regressions with VMware VMware tends to report PCM positions and period updates at utterly wrong timing. This screws up the recent PCM core code that tries to correct the position based on the irq timing. Now, when a backward irq position is detected, skip the update instead of rebasing. (This is almost the old behavior before 2.6.30.) Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 333e4dd29450..3b673e2f991d 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -244,18 +244,27 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) delta = new_hw_ptr - hw_ptr_interrupt; } if (delta < 0) { - delta += runtime->buffer_size; + if (runtime->periods == 1) + delta += runtime->buffer_size; if (delta < 0) { hw_ptr_error(substream, "Unexpected hw_pointer value " "(stream=%i, pos=%ld, intr_ptr=%ld)\n", substream->stream, (long)pos, (long)hw_ptr_interrupt); +#if 1 + /* simply skipping the hwptr update seems more + * robust in some cases, e.g. on VMware with + * inaccurate timer source + */ + return 0; /* skip this update */ +#else /* rebase to interrupt position */ hw_base = new_hw_ptr = hw_ptr_interrupt; /* align hw_base to buffer_size */ hw_base -= hw_base % runtime->buffer_size; delta = 0; +#endif } else { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) -- cgit v1.2.3 From cedb8118e8cef21a2b73fd9cb70660ac19124c16 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Jul 2009 11:04:13 +0200 Subject: ALSA: pcm - Add logging of hwptr updates and interrupt updates Added the logging functionality to xrun_debug to record the hwptr updates via snd_pcm_update_hw_ptr() and snd_pcm_update_hwptr_interrupt(), corresponding to 16 and 8, respectively. For example, # echo 9 > /proc/asound/card0/pcm0p/xrun_debug will record the position and other parameters at each period interrupt together with the normal XRUN debugging. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 5 +++++ sound/core/pcm_lib.c | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'sound') diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index 381908d8ca42..719a819f8cc2 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -101,6 +101,8 @@ card*/pcm*/xrun_debug bit 0 = Enable XRUN/jiffies debug messages bit 1 = Show stack trace at XRUN / jiffies check bit 2 = Enable additional jiffies check + bit 3 = Log hwptr update at each period interrupt + bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr() When the bit 0 is set, the driver will show the messages to kernel log when an xrun is detected. The debug message is @@ -117,6 +119,9 @@ card*/pcm*/xrun_debug buggy) hardware that doesn't give smooth pointer updates. This feature is enabled via the bit 2. + Bits 3 and 4 are for logging the hwptr records. Note that + these will give flood of kernel messages. + card*/pcm*/sub*/info The general information of this PCM sub-stream. diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3b673e2f991d..065eaf0a386c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -233,6 +233,18 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) xrun(substream); return -EPIPE; } + if (xrun_debug(substream, 8)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " + "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + name, pos, + (int)runtime->period_size, + (int)runtime->buffer_size, + (long)old_hw_ptr, + (long)runtime->hw_ptr_base, + (long)runtime->hw_ptr_interrupt); + } hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; @@ -353,6 +365,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) xrun(substream); return -EPIPE; } + if (xrun_debug(substream, 16)) { + char name[16]; + pcm_debug_name(substream, name, sizeof(name)); + snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " + "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", + name, pos, + (int)runtime->period_size, + (int)runtime->buffer_size, + (long)old_hw_ptr, + (long)runtime->hw_ptr_base, + (long)runtime->hw_ptr_interrupt); + } + hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; -- cgit v1.2.3 From 89350640439e0160056de26995d52deb18202b3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Jul 2009 14:28:37 +0200 Subject: ALSA: pcm - Fix warnings in debug loggings Add proper cast. Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 065eaf0a386c..d315f72949f4 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -238,12 +238,12 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) pcm_debug_name(substream, name, sizeof(name)); snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", - name, pos, - (int)runtime->period_size, - (int)runtime->buffer_size, - (long)old_hw_ptr, - (long)runtime->hw_ptr_base, - (long)runtime->hw_ptr_interrupt); + name, (unsigned int)pos, + (unsigned int)runtime->period_size, + (unsigned int)runtime->buffer_size, + (unsigned long)old_hw_ptr, + (unsigned long)runtime->hw_ptr_base, + (unsigned long)runtime->hw_ptr_interrupt); } hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; @@ -370,12 +370,12 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) pcm_debug_name(substream, name, sizeof(name)); snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", - name, pos, - (int)runtime->period_size, - (int)runtime->buffer_size, - (long)old_hw_ptr, - (long)runtime->hw_ptr_base, - (long)runtime->hw_ptr_interrupt); + name, (unsigned int)pos, + (unsigned int)runtime->period_size, + (unsigned int)runtime->buffer_size, + (unsigned long)old_hw_ptr, + (unsigned long)runtime->hw_ptr_base, + (unsigned long)runtime->hw_ptr_interrupt); } hw_base = runtime->hw_ptr_base; -- cgit v1.2.3 From 947ca210f1df7656e19890832cb71fc3bdd88707 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Jul 2009 16:21:08 +0200 Subject: ALSA: pcm - Fix hwptr buffer-size overlap bug The fix 79452f0a28aa5a40522c487b42a5fc423647ad98 introduced another bug due to the missing offset for the overlapped hwptr. When the hwptr goes back to zero, the delta value has to be corrected with the buffer size. Otherwise this causes looping sounds. Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index d315f72949f4..72cfd47af6b8 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -256,7 +256,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) delta = new_hw_ptr - hw_ptr_interrupt; } if (delta < 0) { - if (runtime->periods == 1) + if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) delta += runtime->buffer_size; if (delta < 0) { hw_ptr_error(substream, -- cgit v1.2.3