summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/sof/intel/hda-pcm.c29
-rw-r--r--sound/soc/sof/ipc4-topology.c9
-rw-r--r--sound/soc/sof/ipc4-topology.h7
3 files changed, 33 insertions, 12 deletions
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 1dd8d2092c3b..da6c1e7263cd 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -29,6 +29,8 @@
#define SDnFMT_BITS(x) ((x) << 4)
#define SDnFMT_CHAN(x) ((x) << 0)
+#define HDA_MAX_PERIOD_TIME_HEADROOM 10
+
static bool hda_always_enable_dmi_l1;
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
@@ -291,19 +293,30 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
* amount of data in one initial burst to fill up the host DMA buffer.
* Consequent DMA burst sizes are shorter and their length can vary.
- * To make sure that userspace allocate large enough ALSA buffer we need
- * to place a constraint on the buffer time.
+ * To avoid immediate xrun by the initial burst we need to place
+ * constraint on the period size (via PERIOD_TIME) to cover the size of
+ * the host buffer.
+ * We need to add headroom of max 10ms as the firmware needs time to
+ * settle to the 1ms pacing and initially it can run faster for few
+ * internal periods.
*
* On capture the DMA will transfer 1ms chunks.
- *
- * Exact dsp_max_burst_size_in_ms constraint is racy, so set the
- * constraint to a minimum of 2x dsp_max_burst_size_in_ms.
*/
- if (spcm->stream[direction].dsp_max_burst_size_in_ms)
+ if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
+ unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
+
+ /*
+ * add headroom over the maximum burst size to cover the time
+ * needed for the DMA pace to settle.
+ * Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
+ */
+ period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
+
snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_TIME,
- spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ period_time * USEC_PER_MSEC,
UINT_MAX);
+ }
/* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream;
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 36568160f163..221e9d4052b8 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -665,8 +665,13 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
swidget->tuples,
swidget->num_tuples, sizeof(u32), 1);
/* Set default DMA buffer size if it is not specified in topology */
- if (!sps->dsp_max_burst_size_in_ms)
- sps->dsp_max_burst_size_in_ms = SOF_IPC4_MIN_DMA_BUFFER_SIZE;
+ if (!sps->dsp_max_burst_size_in_ms) {
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+
+ sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
+ SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
+ }
} else {
/* Capture data is copied from DSP to host in 1ms bursts */
spcm->stream[dir].dsp_max_burst_size_in_ms = 1;
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 6b29692dff16..191b51d97993 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -70,8 +70,11 @@
#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
-/* FW requires minimum 2ms DMA buffer size */
-#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 2
+/* FW requires minimum 4ms DMA buffer size */
+#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 4
+
+/* ChainDMA in fw uses 5ms DMA buffer */
+#define SOF_IPC4_CHAIN_DMA_BUFFER_SIZE 5
/*
* The base of multi-gateways. Multi-gateways addressing starts from