Loading Documentation/sound/alsa/Procfile.txt +4 −13 Original line number Original line Diff line number Diff line Loading @@ -101,10 +101,6 @@ card*/pcm*/xrun_debug bit 0 = Enable XRUN/jiffies debug messages bit 0 = Enable XRUN/jiffies debug messages bit 1 = Show stack trace at XRUN / jiffies check bit 1 = Show stack trace at XRUN / jiffies check bit 2 = Enable additional 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() bit 5 = Show last 10 positions on error bit 6 = Do above only once When the bit 0 is set, the driver will show the messages to When the bit 0 is set, the driver will show the messages to kernel log when an xrun is detected. The debug message is kernel log when an xrun is detected. The debug message is Loading @@ -121,15 +117,6 @@ card*/pcm*/xrun_debug buggy) hardware that doesn't give smooth pointer updates. buggy) hardware that doesn't give smooth pointer updates. This feature is enabled via the bit 2. 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. When bit 5 is set, the driver logs the last 10 xrun errors and the proc file shows each jiffies, position, period_size, buffer_size, old_hw_ptr, and hw_ptr_base values. When bit 6 is set, the full xrun log is shown only once. card*/pcm*/sub*/info card*/pcm*/sub*/info The general information of this PCM sub-stream. The general information of this PCM sub-stream. Loading @@ -146,6 +133,10 @@ card*/pcm*/sub*/sw_params card*/pcm*/sub*/prealloc card*/pcm*/sub*/prealloc The buffer pre-allocation information. The buffer pre-allocation information. card*/pcm*/sub*/xrun_injection Triggers an XRUN to the running stream when any value is written to this proc file. Used for fault injection. This entry is write-only. AC97 Codec Information AC97 Codec Information ---------------------- ---------------------- Loading include/sound/pcm.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -416,7 +416,10 @@ struct snd_pcm_substream { struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_max_entry; struct snd_info_entry *proc_prealloc_max_entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG struct snd_info_entry *proc_xrun_injection_entry; #endif #endif #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ /* misc flags */ unsigned int hw_opened: 1; unsigned int hw_opened: 1; }; }; Loading sound/core/Makefile +3 −0 Original line number Original line Diff line number Diff line Loading @@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o pcm_memory.o memalloc.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o # for trace-points CFLAGS_pcm_lib.o := -I$(src) snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-rawmidi-objs := rawmidi.o snd-rawmidi-objs := rawmidi.o Loading sound/core/pcm.c +33 −0 Original line number Original line Diff line number Diff line Loading @@ -483,6 +483,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, } } #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_runtime *runtime; snd_pcm_stream_lock_irq(substream); runtime = substream->runtime; if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock_irq(substream); } static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) struct snd_info_buffer *buffer) { { Loading Loading @@ -614,6 +627,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } } substream->proc_status_entry = entry; substream->proc_status_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(card, "xrun_injection", substream->proc_root); if (entry) { entry->private_data = substream; entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | S_IWUSR; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } substream->proc_xrun_injection_entry = entry; #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ return 0; return 0; } } Loading @@ -627,6 +656,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) substream->proc_sw_params_entry = NULL; substream->proc_sw_params_entry = NULL; snd_info_free_entry(substream->proc_status_entry); snd_info_free_entry(substream->proc_status_entry); substream->proc_status_entry = NULL; substream->proc_status_entry = NULL; #ifdef CONFIG_SND_PCM_XRUN_DEBUG snd_info_free_entry(substream->proc_xrun_injection_entry); substream->proc_xrun_injection_entry = NULL; #endif snd_info_free_entry(substream->proc_root); snd_info_free_entry(substream->proc_root); substream->proc_root = NULL; substream->proc_root = NULL; return 0; return 0; Loading sound/core/pcm_lib.c +25 −123 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,15 @@ #include <sound/pcm_params.h> #include <sound/pcm_params.h> #include <sound/timer.h> #include <sound/timer.h> #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define CREATE_TRACE_POINTS #include "pcm_trace.h" #else #define trace_hwptr(substream, pos, in_interrupt) #define trace_xrun(substream) #define trace_hw_ptr_error(substream, reason) #endif /* /* * fill ring buffer with silence * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area * runtime->silence_start: starting pointer to silence area Loading Loading @@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name); #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ #define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ #define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG Loading @@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream) { { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime; trace_xrun(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); Loading @@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream) } } #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define hw_ptr_error(substream, fmt, args...) \ #define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \ do { \ do { \ trace_hw_ptr_error(substream, reason); \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ xrun_log_show(substream); \ pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \ pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \ (in_interrupt) ? 'Q' : 'P', ##args); \ dump_stack_on_xrun(substream); \ dump_stack_on_xrun(substream); \ } \ } \ } while (0) } while (0) #define XRUN_LOG_CNT 10 struct hwptr_log_entry { unsigned int in_interrupt; unsigned long jiffies; snd_pcm_uframes_t pos; snd_pcm_uframes_t period_size; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t old_hw_ptr; snd_pcm_uframes_t hw_ptr_base; }; struct snd_pcm_hwptr_log { unsigned int idx; unsigned int hit: 1; struct hwptr_log_entry entries[XRUN_LOG_CNT]; }; static void xrun_log(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hwptr_log *log = runtime->hwptr_log; struct hwptr_log_entry *entry; if (log == NULL) { log = kzalloc(sizeof(*log), GFP_ATOMIC); if (log == NULL) return; runtime->hwptr_log = log; } else { if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; } entry = &log->entries[log->idx]; entry->in_interrupt = in_interrupt; entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; entry->buffer_size = runtime->buffer_size; entry->old_hw_ptr = runtime->status->hw_ptr; entry->hw_ptr_base = runtime->hw_ptr_base; log->idx = (log->idx + 1) % XRUN_LOG_CNT; } static void xrun_log_show(struct snd_pcm_substream *substream) { struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; struct hwptr_log_entry *entry; char name[16]; unsigned int idx; int cnt; if (log == NULL) return; if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; snd_pcm_debug_name(substream, name, sizeof(name)); for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { entry = &log->entries[idx]; if (entry->period_size == 0) break; pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " "hwptr=%ld/%ld\n", name, entry->in_interrupt ? "[Q] " : "", entry->jiffies, (unsigned long)entry->pos, (unsigned long)entry->period_size, (unsigned long)entry->buffer_size, (unsigned long)entry->old_hw_ptr, (unsigned long)entry->hw_ptr_base); idx++; idx %= XRUN_LOG_CNT; } log->hit = 1; } #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define xrun_log(substream, pos, in_interrupt) do { } while (0) #define xrun_log_show(substream) do { } while (0) #endif #endif Loading Loading @@ -343,17 +271,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (printk_ratelimit()) { if (printk_ratelimit()) { char name[16]; char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); snd_pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); pcm_err(substream->pcm, pcm_err(substream->pcm, "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n", "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, name, pos, runtime->buffer_size, runtime->period_size); runtime->period_size); } } pos = 0; pos = 0; } } pos -= pos % runtime->min_align; pos -= pos % runtime->min_align; if (xrun_debug(substream, XRUN_DEBUG_LOG)) trace_hwptr(substream, pos, in_interrupt); xrun_log(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; new_hw_ptr = hw_base + pos; if (in_interrupt) { if (in_interrupt) { Loading Loading @@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = new_hw_ptr - old_hw_ptr; delta = new_hw_ptr - old_hw_ptr; if (delta < 0) if (delta < 0) delta += runtime->boundary; delta += runtime->boundary; if (xrun_debug(substream, in_interrupt ? XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); pcm_dbg(substream->pcm, "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n", in_interrupt ? "period" : "hwptr", name, (unsigned int)pos, (unsigned int)runtime->period_size, (unsigned int)runtime->buffer_size, (unsigned long)delta, (unsigned long)old_hw_ptr, (unsigned long)new_hw_ptr, (unsigned long)runtime->hw_ptr_base); } if (runtime->no_period_wakeup) { if (runtime->no_period_wakeup) { snd_pcm_sframes_t xrun_threshold; snd_pcm_sframes_t xrun_threshold; Loading Loading @@ -431,11 +341,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* something must be really wrong */ /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr", "Unexpected hw_pointer value %s" "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", "(stream=%i, pos=%ld, new_hw_ptr=%ld, " "old_hw_ptr=%ld)\n", in_interrupt ? "[Q] " : "[P]", substream->stream, (long)pos, substream->stream, (long)pos, (long)new_hw_ptr, (long)old_hw_ptr); (long)new_hw_ptr, (long)old_hw_ptr); return 0; return 0; Loading Loading @@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta--; delta--; } } /* align hw_base to buffer_size */ /* align hw_base to buffer_size */ hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "hw_ptr skipping", "hw_ptr skipping! %s" "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", "(pos=%ld, delta=%ld, period=%ld, " "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", in_interrupt ? "[Q] " : "", (long)pos, (long)hdelta, (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, (long)runtime->period_size, jdelta, ((hdelta * HZ) / runtime->rate), hw_base, ((hdelta * HZ) / runtime->rate), hw_base, Loading @@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } } no_jiffies_check: no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { if (delta > runtime->period_size + runtime->period_size / 2) { hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "Lost interrupts? %s" "Lost interrupts?", "(stream=%i, delta=%ld, new_hw_ptr=%ld, " "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", "old_hw_ptr=%ld)\n", in_interrupt ? "[Q] " : "", substream->stream, (long)delta, substream->stream, (long)delta, (long)new_hw_ptr, (long)new_hw_ptr, (long)old_hw_ptr); (long)old_hw_ptr); Loading Loading
Documentation/sound/alsa/Procfile.txt +4 −13 Original line number Original line Diff line number Diff line Loading @@ -101,10 +101,6 @@ card*/pcm*/xrun_debug bit 0 = Enable XRUN/jiffies debug messages bit 0 = Enable XRUN/jiffies debug messages bit 1 = Show stack trace at XRUN / jiffies check bit 1 = Show stack trace at XRUN / jiffies check bit 2 = Enable additional 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() bit 5 = Show last 10 positions on error bit 6 = Do above only once When the bit 0 is set, the driver will show the messages to When the bit 0 is set, the driver will show the messages to kernel log when an xrun is detected. The debug message is kernel log when an xrun is detected. The debug message is Loading @@ -121,15 +117,6 @@ card*/pcm*/xrun_debug buggy) hardware that doesn't give smooth pointer updates. buggy) hardware that doesn't give smooth pointer updates. This feature is enabled via the bit 2. 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. When bit 5 is set, the driver logs the last 10 xrun errors and the proc file shows each jiffies, position, period_size, buffer_size, old_hw_ptr, and hw_ptr_base values. When bit 6 is set, the full xrun log is shown only once. card*/pcm*/sub*/info card*/pcm*/sub*/info The general information of this PCM sub-stream. The general information of this PCM sub-stream. Loading @@ -146,6 +133,10 @@ card*/pcm*/sub*/sw_params card*/pcm*/sub*/prealloc card*/pcm*/sub*/prealloc The buffer pre-allocation information. The buffer pre-allocation information. card*/pcm*/sub*/xrun_injection Triggers an XRUN to the running stream when any value is written to this proc file. Used for fault injection. This entry is write-only. AC97 Codec Information AC97 Codec Information ---------------------- ---------------------- Loading
include/sound/pcm.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -416,7 +416,10 @@ struct snd_pcm_substream { struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_status_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_max_entry; struct snd_info_entry *proc_prealloc_max_entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG struct snd_info_entry *proc_xrun_injection_entry; #endif #endif #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ /* misc flags */ unsigned int hw_opened: 1; unsigned int hw_opened: 1; }; }; Loading
sound/core/Makefile +3 −0 Original line number Original line Diff line number Diff line Loading @@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o pcm_memory.o memalloc.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o # for trace-points CFLAGS_pcm_lib.o := -I$(src) snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-pcm-dmaengine-objs := pcm_dmaengine.o snd-rawmidi-objs := rawmidi.o snd-rawmidi-objs := rawmidi.o Loading
sound/core/pcm.c +33 −0 Original line number Original line Diff line number Diff line Loading @@ -483,6 +483,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, } } #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_runtime *runtime; snd_pcm_stream_lock_irq(substream); runtime = substream->runtime; if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock_irq(substream); } static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) struct snd_info_buffer *buffer) { { Loading Loading @@ -614,6 +627,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) } } substream->proc_status_entry = entry; substream->proc_status_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(card, "xrun_injection", substream->proc_root); if (entry) { entry->private_data = substream; entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | S_IWUSR; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; } } substream->proc_xrun_injection_entry = entry; #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ return 0; return 0; } } Loading @@ -627,6 +656,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) substream->proc_sw_params_entry = NULL; substream->proc_sw_params_entry = NULL; snd_info_free_entry(substream->proc_status_entry); snd_info_free_entry(substream->proc_status_entry); substream->proc_status_entry = NULL; substream->proc_status_entry = NULL; #ifdef CONFIG_SND_PCM_XRUN_DEBUG snd_info_free_entry(substream->proc_xrun_injection_entry); substream->proc_xrun_injection_entry = NULL; #endif snd_info_free_entry(substream->proc_root); snd_info_free_entry(substream->proc_root); substream->proc_root = NULL; substream->proc_root = NULL; return 0; return 0; Loading
sound/core/pcm_lib.c +25 −123 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,15 @@ #include <sound/pcm_params.h> #include <sound/pcm_params.h> #include <sound/timer.h> #include <sound/timer.h> #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define CREATE_TRACE_POINTS #include "pcm_trace.h" #else #define trace_hwptr(substream, pos, in_interrupt) #define trace_xrun(substream) #define trace_hw_ptr_error(substream, reason) #endif /* /* * fill ring buffer with silence * fill ring buffer with silence * runtime->silence_start: starting pointer to silence area * runtime->silence_start: starting pointer to silence area Loading Loading @@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name); #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ #define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ #define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG Loading @@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream) { { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime; trace_xrun(substream); if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); Loading @@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream) } } #ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG #define hw_ptr_error(substream, fmt, args...) \ #define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \ do { \ do { \ trace_hw_ptr_error(substream, reason); \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ xrun_log_show(substream); \ pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \ pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \ (in_interrupt) ? 'Q' : 'P', ##args); \ dump_stack_on_xrun(substream); \ dump_stack_on_xrun(substream); \ } \ } \ } while (0) } while (0) #define XRUN_LOG_CNT 10 struct hwptr_log_entry { unsigned int in_interrupt; unsigned long jiffies; snd_pcm_uframes_t pos; snd_pcm_uframes_t period_size; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t old_hw_ptr; snd_pcm_uframes_t hw_ptr_base; }; struct snd_pcm_hwptr_log { unsigned int idx; unsigned int hit: 1; struct hwptr_log_entry entries[XRUN_LOG_CNT]; }; static void xrun_log(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, int in_interrupt) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hwptr_log *log = runtime->hwptr_log; struct hwptr_log_entry *entry; if (log == NULL) { log = kzalloc(sizeof(*log), GFP_ATOMIC); if (log == NULL) return; runtime->hwptr_log = log; } else { if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; } entry = &log->entries[log->idx]; entry->in_interrupt = in_interrupt; entry->jiffies = jiffies; entry->pos = pos; entry->period_size = runtime->period_size; entry->buffer_size = runtime->buffer_size; entry->old_hw_ptr = runtime->status->hw_ptr; entry->hw_ptr_base = runtime->hw_ptr_base; log->idx = (log->idx + 1) % XRUN_LOG_CNT; } static void xrun_log_show(struct snd_pcm_substream *substream) { struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; struct hwptr_log_entry *entry; char name[16]; unsigned int idx; int cnt; if (log == NULL) return; if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; snd_pcm_debug_name(substream, name, sizeof(name)); for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { entry = &log->entries[idx]; if (entry->period_size == 0) break; pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " "hwptr=%ld/%ld\n", name, entry->in_interrupt ? "[Q] " : "", entry->jiffies, (unsigned long)entry->pos, (unsigned long)entry->period_size, (unsigned long)entry->buffer_size, (unsigned long)entry->old_hw_ptr, (unsigned long)entry->hw_ptr_base); idx++; idx %= XRUN_LOG_CNT; } log->hit = 1; } #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define xrun_log(substream, pos, in_interrupt) do { } while (0) #define xrun_log_show(substream) do { } while (0) #endif #endif Loading Loading @@ -343,17 +271,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (printk_ratelimit()) { if (printk_ratelimit()) { char name[16]; char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); snd_pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); pcm_err(substream->pcm, pcm_err(substream->pcm, "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n", "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", name, pos, runtime->buffer_size, name, pos, runtime->buffer_size, runtime->period_size); runtime->period_size); } } pos = 0; pos = 0; } } pos -= pos % runtime->min_align; pos -= pos % runtime->min_align; if (xrun_debug(substream, XRUN_DEBUG_LOG)) trace_hwptr(substream, pos, in_interrupt); xrun_log(substream, pos, in_interrupt); hw_base = runtime->hw_ptr_base; hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; new_hw_ptr = hw_base + pos; if (in_interrupt) { if (in_interrupt) { Loading Loading @@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta = new_hw_ptr - old_hw_ptr; delta = new_hw_ptr - old_hw_ptr; if (delta < 0) if (delta < 0) delta += runtime->boundary; delta += runtime->boundary; if (xrun_debug(substream, in_interrupt ? XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { char name[16]; snd_pcm_debug_name(substream, name, sizeof(name)); pcm_dbg(substream->pcm, "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n", in_interrupt ? "period" : "hwptr", name, (unsigned int)pos, (unsigned int)runtime->period_size, (unsigned int)runtime->buffer_size, (unsigned long)delta, (unsigned long)old_hw_ptr, (unsigned long)new_hw_ptr, (unsigned long)runtime->hw_ptr_base); } if (runtime->no_period_wakeup) { if (runtime->no_period_wakeup) { snd_pcm_sframes_t xrun_threshold; snd_pcm_sframes_t xrun_threshold; Loading Loading @@ -431,11 +341,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, /* something must be really wrong */ /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr", "Unexpected hw_pointer value %s" "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", "(stream=%i, pos=%ld, new_hw_ptr=%ld, " "old_hw_ptr=%ld)\n", in_interrupt ? "[Q] " : "[P]", substream->stream, (long)pos, substream->stream, (long)pos, (long)new_hw_ptr, (long)old_hw_ptr); (long)new_hw_ptr, (long)old_hw_ptr); return 0; return 0; Loading Loading @@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, delta--; delta--; } } /* align hw_base to buffer_size */ /* align hw_base to buffer_size */ hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "hw_ptr skipping", "hw_ptr skipping! %s" "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", "(pos=%ld, delta=%ld, period=%ld, " "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", in_interrupt ? "[Q] " : "", (long)pos, (long)hdelta, (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, (long)runtime->period_size, jdelta, ((hdelta * HZ) / runtime->rate), hw_base, ((hdelta * HZ) / runtime->rate), hw_base, Loading @@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, } } no_jiffies_check: no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { if (delta > runtime->period_size + runtime->period_size / 2) { hw_ptr_error(substream, hw_ptr_error(substream, in_interrupt, "Lost interrupts? %s" "Lost interrupts?", "(stream=%i, delta=%ld, new_hw_ptr=%ld, " "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", "old_hw_ptr=%ld)\n", in_interrupt ? "[Q] " : "", substream->stream, (long)delta, substream->stream, (long)delta, (long)new_hw_ptr, (long)new_hw_ptr, (long)old_hw_ptr); (long)old_hw_ptr); Loading