Hello,
While doing the validation of Skylake HDA driver using aplay and following parameters, we noticed underrun issues.
aplay -Dhw:0,0,0 -vv s_48K_16Bit_Sunshine.wav -F 100000 -B 200000 -d 20 Its setup is: stream : PLAYBACK access : RW_INTERLEAVED format : S16_LE subformat : STD channels : 2 rate : 48000 exact rate : 48000 (48000/1) msbits : 16 buffer_size : 9600 period_size : 4800 period_time : 100000 tstamp_mode : NONE period_step : 1 avail_min : 4800 period_event : 0 start_threshold : 9600 stop_threshold : 9600 silence_threshold: 0 silence_size : 0 boundary : 5404319552844595200 appl_ptr : 0 hw_ptr : 0
After doing further debugging, what I found is
1.DMA complete interrupt occurs for the first period. 2.Driver reads DMA position in buffer pointer and gets value of 4784. 3.Driver calls snd_pcm_period_elapsed() function to report period elapsed interrupt to application with DMA position = 4784. 4.snd_pcm_lib_write1() is waiting for “avail_min” free space to be available. In this case the avail_min = 4800 and at this interrupt the avail = 4874 and so it does not write any data. 5.DMA complete interrupt occurs for the second period. 6.Driver reads DMA position in the buffer pointer and gets value of 9600. 7.Driver calls snd_pcm_period_elapsed() function to report period elapsed interrupt. 8.Now the snd_pcm_lib_write1() gets avail > avail_min but it’s too late because DMA has already started playing data from first period, which is not yet written by the application. 9.This causes underrun.
Logs: 857.870974: hwptr: pcmC0D0p/sub0: IRQ: pos=4800, old=19200, base=19200, period=4800, buf=9600 857.871237: hwptr: pcmC0D0p/sub0: POS: pos=4800, old=24000, base=19200, period=4800, buf=9600 857.970972: hwptr: pcmC0D0p/sub0: IRQ: pos=0, old=24000, base=19200, period=4800, buf=9600 857.971101: hwptr: pcmC0D0p/sub0: POS: pos=0, old=28800, base=28800, period=4800, buf=9600 858.070971: hwptr: pcmC0D0p/sub0: IRQ: pos=4784, old=28800, base=28800, period=4800, buf=9600 858.170968: hwptr: pcmC0D0p/sub0: IRQ: pos=0, old=33584, base=28800, period=4800, buf=9600 858.170988: xrun: pcmC0D0p/sub0: XRUN: old=38400, base=38400, period=4800, buf=9600 858.172240: hwptr: pcmC0D0p/sub0: POS: pos=96, old=0, base=0, period=4800, buf=9600 858.269867: hwptr: pcmC0D0p/sub0: IRQ: pos=4798, old=96, base=0, period=4800, buf=9600 858.369902: hwptr: pcmC0D0p/sub0: IRQ: pos=0, old=4798, base=0, period=4800, buf=9600
I checked with HDA architects and they are saying that when the DMA completion interrupt occurs there can be slight delay before the DMA Position In Buffer Pointer gets updated. So driver is expected to refill data based on whatever content is reflected in the DMA Position In Buffer.
What is the right way to fix this issue ?
Thanks, Dhara.R
--