Sometimes the hardware reports LPIB being advanced than POSBUF. When this happens, the driver adjusts to a positive value by adding the buffer size. Then the driver detects it as an error (greater than the period size), and stops the LPIB delay account from this point on.
When I took a close look at these conditions, the values shown are all very small numbers, and it'd be better to just ignore these values instead of discontinuing the LPIB delay correction.
In this patch, the driver checks a negative delay value and ignores if it's a significantly small error. Currently the threshold is set to 64 frames, but could be smaller.
Signed-off-by: Takashi Iwai tiwai@suse.de --- v1->v2: apply only when period size is greater than 64.
sound/pci/hda/hda_intel.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 80c5f14e8ecd..af86c71f27bf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -431,6 +431,8 @@ struct azx_dev { struct timecounter azx_tc; struct cyclecounter azx_cc;
+ int delay_negative_threshold; + #ifdef CONFIG_SND_HDA_DSP_LOADER struct mutex dsp_mutex; #endif @@ -2195,6 +2197,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) goto unlock; }
+ /* when LPIB delay correction gives a small negative value, + * we ignore it; currently set the threshold statically to + * 64 frames + */ + if (runtime->period_size > 64) + azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64); + else + azx_dev->delay_negative_threshold = 0; + /* wallclk has 24Mhz clock source */ azx_dev->period_wallclk = (((runtime->period_size * 24000) / runtime->rate) * 1000); @@ -2447,8 +2458,12 @@ static unsigned int azx_get_position(struct azx *chip, delay = pos - lpib_pos; else delay = lpib_pos - pos; - if (delay < 0) - delay += azx_dev->bufsize; + if (delay < 0) { + if (delay >= azx_dev->delay_negative_threshold) + delay = 0; + else + delay += azx_dev->bufsize; + } if (delay >= azx_dev->period_bytes) { snd_printk(KERN_WARNING SFX "%s: Unstable LPIB (%d >= %d); "