aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/sound/alsa/Procfile.txt5
-rw-r--r--sound/core/pcm_lib.c36
2 files changed, 40 insertions, 1 deletions
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
101 bit 0 = Enable XRUN/jiffies debug messages 101 bit 0 = Enable XRUN/jiffies debug messages
102 bit 1 = Show stack trace at XRUN / jiffies check 102 bit 1 = Show stack trace at XRUN / jiffies check
103 bit 2 = Enable additional jiffies check 103 bit 2 = Enable additional jiffies check
104 bit 3 = Log hwptr update at each period interrupt
105 bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
104 106
105 When the bit 0 is set, the driver will show the messages to 107 When the bit 0 is set, the driver will show the messages to
106 kernel log when an xrun is detected. The debug message is 108 kernel log when an xrun is detected. The debug message is
@@ -117,6 +119,9 @@ card*/pcm*/xrun_debug
117 buggy) hardware that doesn't give smooth pointer updates. 119 buggy) hardware that doesn't give smooth pointer updates.
118 This feature is enabled via the bit 2. 120 This feature is enabled via the bit 2.
119 121
122 Bits 3 and 4 are for logging the hwptr records. Note that
123 these will give flood of kernel messages.
124
120card*/pcm*/sub*/info 125card*/pcm*/sub*/info
121 The general information of this PCM sub-stream. 126 The general information of this PCM sub-stream.
122 127
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 333e4dd29450..72cfd47af6b8 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)
233 xrun(substream); 233 xrun(substream);
234 return -EPIPE; 234 return -EPIPE;
235 } 235 }
236 if (xrun_debug(substream, 8)) {
237 char name[16];
238 pcm_debug_name(substream, name, sizeof(name));
239 snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, "
240 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
241 name, (unsigned int)pos,
242 (unsigned int)runtime->period_size,
243 (unsigned int)runtime->buffer_size,
244 (unsigned long)old_hw_ptr,
245 (unsigned long)runtime->hw_ptr_base,
246 (unsigned long)runtime->hw_ptr_interrupt);
247 }
236 hw_base = runtime->hw_ptr_base; 248 hw_base = runtime->hw_ptr_base;
237 new_hw_ptr = hw_base + pos; 249 new_hw_ptr = hw_base + pos;
238 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; 250 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
@@ -244,18 +256,27 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
244 delta = new_hw_ptr - hw_ptr_interrupt; 256 delta = new_hw_ptr - hw_ptr_interrupt;
245 } 257 }
246 if (delta < 0) { 258 if (delta < 0) {
247 delta += runtime->buffer_size; 259 if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
260 delta += runtime->buffer_size;
248 if (delta < 0) { 261 if (delta < 0) {
249 hw_ptr_error(substream, 262 hw_ptr_error(substream,
250 "Unexpected hw_pointer value " 263 "Unexpected hw_pointer value "
251 "(stream=%i, pos=%ld, intr_ptr=%ld)\n", 264 "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
252 substream->stream, (long)pos, 265 substream->stream, (long)pos,
253 (long)hw_ptr_interrupt); 266 (long)hw_ptr_interrupt);
267#if 1
268 /* simply skipping the hwptr update seems more
269 * robust in some cases, e.g. on VMware with
270 * inaccurate timer source
271 */
272 return 0; /* skip this update */
273#else
254 /* rebase to interrupt position */ 274 /* rebase to interrupt position */
255 hw_base = new_hw_ptr = hw_ptr_interrupt; 275 hw_base = new_hw_ptr = hw_ptr_interrupt;
256 /* align hw_base to buffer_size */ 276 /* align hw_base to buffer_size */
257 hw_base -= hw_base % runtime->buffer_size; 277 hw_base -= hw_base % runtime->buffer_size;
258 delta = 0; 278 delta = 0;
279#endif
259 } else { 280 } else {
260 hw_base += runtime->buffer_size; 281 hw_base += runtime->buffer_size;
261 if (hw_base >= runtime->boundary) 282 if (hw_base >= runtime->boundary)
@@ -344,6 +365,19 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
344 xrun(substream); 365 xrun(substream);
345 return -EPIPE; 366 return -EPIPE;
346 } 367 }
368 if (xrun_debug(substream, 16)) {
369 char name[16];
370 pcm_debug_name(substream, name, sizeof(name));
371 snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
372 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
373 name, (unsigned int)pos,
374 (unsigned int)runtime->period_size,
375 (unsigned int)runtime->buffer_size,
376 (unsigned long)old_hw_ptr,
377 (unsigned long)runtime->hw_ptr_base,
378 (unsigned long)runtime->hw_ptr_interrupt);
379 }
380
347 hw_base = runtime->hw_ptr_base; 381 hw_base = runtime->hw_ptr_base;
348 new_hw_ptr = hw_base + pos; 382 new_hw_ptr = hw_base + pos;
349 383