From 316650f33d121cc21b1ad8ddd89c14eb28f28324 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 17 Sep 2024 15:27:48 +0300 Subject: [PATCH] ASoC: SOF: Intel: hda-stream: Always use at least two BDLE for transfers The HDA specification states that the SDnLVI (Last Valid Index) must be at least 1 (two BDLE entry). Update the debug prints as well to provide better information. While the LVI=0 worked so far without issues, it is better to align with the specification to avoid unforeseen issues with FW loading. Notes: - The LVI > 0 rules is valid and honored for audio use cases - LVI == 0 is used with software controlled (SPIB) transfers only for firmware and library loading, which is permitted by the hardware - This is not spelled out in the specification and it is better to avoid cases Signed-off-by: Peter Ujfalusi --- sound/soc/sof/intel/hda-stream.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3ac63ce67ab1ce..eaa22f7dc545b3 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -119,13 +119,38 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, int remain, ioc; period_bytes = hstream->period_bytes; - dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); - if (!period_bytes) + dev_dbg(sdev->dev, "period_bytes: %#x, bufsize: %#x\n", period_bytes, + hstream->bufsize); + + if (!period_bytes) { + unsigned int chunk_size; + + chunk_size = snd_sgbuf_get_chunk_size(dmab, 0, hstream->bufsize); + period_bytes = hstream->bufsize; + /* + * HDA spec demands that the LVI value must be at least one + * before the DMA operation can begin. This means that there + * must be at least two BDLE present for the transfer. + * + * If the buffer is not a single continuous are then the + * hda_setup_bdle() will create multiple BLDEs for each segment. + * If the memory is a single continuous area, force it to be + * split into two 'periods', otherwise the transfer will be + * split to multiple BDLE for each chunk in hda_setup_bdle() + * + * Note: period_bytes == 0 can only happen for firmware or + * library loading. The data size is 4K aligned, which ensures + * that the second chunk's start address will be 128-byte + * aligned. + */ + if (chunk_size == hstream->bufsize) + period_bytes /= 2; + } periods = hstream->bufsize / period_bytes; - dev_dbg(sdev->dev, "periods:%d\n", periods); + dev_dbg(sdev->dev, "periods: %d\n", periods); remain = hstream->bufsize % period_bytes; if (remain)