Skip to content

Commit 18f3ba5

Browse files
committed
ASoC: SOF: ipc4-topology: Change DeepBuffer from static to dynamic mode
Currently the DeepBuffer results static host DMA buffer and thus static minimum ALSA period size which can be a limiting factor for user space. DeepBuffer of static 100ms host DMA buffer can only be opened with at least 110ms ALSA period size, if for the same endpoint there is a need for smaller (or larger) buffer then a new PCM device must be created with different DeepBuffer configuration. This does not scale in real life. With Dynamic DeepBuffer the host DMA buffer size is calculated based on the requested ALSA period size using the DEEP_BUFFER token as a maximum limit for the host DMA buffer. This way applications can use the same DeepBuffer enabled PCM for different use cases and still benefit of the power saving of a bigger host DMA buffer. As an example, the DEEP_BUFFER in topology is set to 100ms (interpreted as maximum size with this patch): ALSA period: 8 -> dma buffer: 4 ms ALSA period: 10 -> dma buffer: 6 ms ALSA period: 16 -> dma buffer: 12 ms ALSA period: 19 -> dma buffer: 15 ms ALSA period: 20 -> dma buffer: 20 ms ALSA period: 50 -> dma buffer: 50 ms ALSA period: 100 -> dma buffer: 100 ms ALSA period: 150 -> dma buffer: 100 ms ALSA period: 2000 -> dma buffer: 100 ms The Dynamic DeepBuffer will give applications the means to choose between lower latency (small host DMA buffer) or higher power save (big host DMA buffer) with higher latency on the same device with topology providing a meaningful upper limit of the buffer size. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent a3a5425 commit 18f3ba5

File tree

2 files changed

+95
-44
lines changed

2 files changed

+95
-44
lines changed

sound/soc/sof/ipc4-topology.c

Lines changed: 84 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -669,22 +669,15 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
669669
goto free_available_fmt;
670670

671671
sps = &spcm->stream[dir];
672-
sof_update_ipc_object(scomp, &sps->dsp_max_burst_size_in_ms,
673-
SOF_COPIER_DEEP_BUFFER_TOKENS,
674-
swidget->tuples,
675-
swidget->num_tuples, sizeof(u32), 1);
676-
677-
/* Set default DMA buffer size if it is not specified in topology */
678-
if (!sps->dsp_max_burst_size_in_ms) {
672+
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
679673
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
680674
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
681675

682-
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
683-
sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
684-
SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
685-
else
686-
/* Capture data is copied from DSP to host in 1ms bursts */
687-
sps->dsp_max_burst_size_in_ms = 1;
676+
sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
677+
SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
678+
} else {
679+
/* Capture data is copied from DSP to host in 1ms bursts */
680+
sps->dsp_max_burst_size_in_ms = 1;
688681
}
689682

690683
skip_gtw_cfg:
@@ -2042,6 +2035,79 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget
20422035
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(host_dma_id);
20432036
}
20442037

2038+
static void
2039+
sof_ipc4_set_host_copier_dma_buffer_size(struct snd_sof_widget *swidget,
2040+
unsigned int fe_period_bytes)
2041+
{
2042+
unsigned int min_size, no_headroom_mark, fw_period_bytes;
2043+
struct snd_soc_component *scomp = swidget->scomp;
2044+
struct sof_ipc4_copier_data *copier_data;
2045+
struct sof_ipc4_copier *ipc4_copier;
2046+
unsigned int deep_buffer_dma_ms = 0;
2047+
u32 buffer_bytes;
2048+
int ret;
2049+
2050+
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
2051+
copier_data = &ipc4_copier->data;
2052+
2053+
if (swidget->id == snd_soc_dapm_aif_in)
2054+
fw_period_bytes = copier_data->base_config.ibs;
2055+
else
2056+
fw_period_bytes = copier_data->base_config.obs;
2057+
2058+
/*
2059+
* Calculate the minimum size of the host copier DMA host buffer and the
2060+
* cut-out watermark when no headroom is needed to be added between the
2061+
* host copier buffer size and the ALSA period size
2062+
*/
2063+
min_size = SOF_IPC4_MIN_DMA_BUFFER_SIZE * fw_period_bytes;
2064+
no_headroom_mark = SOF_IPC4_NO_DMA_BUFFER_HEADROOM_MS * fw_period_bytes;
2065+
2066+
/* parse the deep buffer dma size */
2067+
ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
2068+
SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
2069+
swidget->num_tuples, sizeof(u32), 1);
2070+
if (ret) {
2071+
dev_dbg(scomp->dev,
2072+
"Failed to parse deep buffer dma size for %s\n",
2073+
swidget->widget->name);
2074+
buffer_bytes = min_size;
2075+
goto out;
2076+
}
2077+
2078+
/*
2079+
* Non Deepbuffer and small ALSA periods must use the minimal host DMA
2080+
* buffer size in firmware.
2081+
* Note: smaller than 2x the minimum host DMA buffer size for ALSA
2082+
* period is not allowed and should be protected by platform code with
2083+
* constraint.
2084+
*
2085+
* Add headroom the between host copier DMA buffer size and the ALSA
2086+
* period size if the ALSA period is less than
2087+
* SOF_IPC4_NO_DMA_BUFFER_HEADROOM_MS, otherwise equal the host copier
2088+
* DMA buffer size to ALSA period size, capped at the maximum DeepBuffer
2089+
* depth specified in topology
2090+
*/
2091+
if (deep_buffer_dma_ms <= SOF_IPC4_MIN_DMA_BUFFER_SIZE ||
2092+
fe_period_bytes < (min_size * 2))
2093+
buffer_bytes = min_size;
2094+
else if (fe_period_bytes < no_headroom_mark)
2095+
buffer_bytes = fe_period_bytes - min_size;
2096+
else
2097+
buffer_bytes = min(deep_buffer_dma_ms * fw_period_bytes,
2098+
fe_period_bytes);
2099+
2100+
out:
2101+
dev_dbg(scomp->dev,
2102+
"%s, dma buffer%s: %u ms (max: %u) / %u bytes, ALSA period: %u / %u\n",
2103+
swidget->widget->name, deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
2104+
buffer_bytes / fw_period_bytes,
2105+
deep_buffer_dma_ms ? deep_buffer_dma_ms : SOF_IPC4_MIN_DMA_BUFFER_SIZE,
2106+
buffer_bytes, fe_period_bytes / fw_period_bytes, fe_period_bytes);
2107+
2108+
copier_data->gtw_cfg.dma_buffer_size = buffer_bytes;
2109+
}
2110+
20452111
static int
20462112
sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20472113
struct snd_pcm_hw_params *fe_params,
@@ -2063,7 +2129,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20632129
u32 **data;
20642130
int ipc_size, ret, out_ref_valid_bits;
20652131
u32 out_ref_rate, out_ref_channels, out_ref_type;
2066-
u32 deep_buffer_dma_ms = 0;
20672132
bool single_output_bitdepth;
20682133
int i;
20692134

@@ -2081,16 +2146,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20812146
str_yes_no(pipeline->use_chain_dma),
20822147
platform_params->stream_tag);
20832148

2084-
/* parse the deep buffer dma size */
2085-
ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
2086-
SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
2087-
swidget->num_tuples, sizeof(u32), 1);
2088-
if (ret) {
2089-
dev_err(scomp->dev, "Failed to parse deep buffer dma size for %s\n",
2090-
swidget->widget->name);
2091-
return ret;
2092-
}
2093-
20942149
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
20952150
gtw_attr = ipc4_copier->gtw_attr;
20962151
copier_data = &ipc4_copier->data;
@@ -2425,34 +2480,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
24252480
* in topology.
24262481
*/
24272482
switch (swidget->id) {
2483+
case snd_soc_dapm_aif_in:
2484+
case snd_soc_dapm_aif_out:
2485+
sof_ipc4_set_host_copier_dma_buffer_size(swidget,
2486+
params_period_bytes(fe_params));
2487+
break;
24282488
case snd_soc_dapm_dai_in:
24292489
copier_data->gtw_cfg.dma_buffer_size =
24302490
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
24312491
break;
2432-
case snd_soc_dapm_aif_in:
2433-
copier_data->gtw_cfg.dma_buffer_size =
2434-
max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
2435-
copier_data->base_config.ibs;
2436-
dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
2437-
swidget->widget->name,
2438-
deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
2439-
max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
2440-
copier_data->gtw_cfg.dma_buffer_size);
2441-
break;
24422492
case snd_soc_dapm_dai_out:
24432493
copier_data->gtw_cfg.dma_buffer_size =
24442494
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
24452495
break;
2446-
case snd_soc_dapm_aif_out:
2447-
copier_data->gtw_cfg.dma_buffer_size =
2448-
max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms) *
2449-
copier_data->base_config.obs;
2450-
dev_dbg(sdev->dev, "copier %s, dma buffer%s: %u ms (%u bytes)",
2451-
swidget->widget->name,
2452-
deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
2453-
max((u32)SOF_IPC4_MIN_DMA_BUFFER_SIZE, deep_buffer_dma_ms),
2454-
copier_data->gtw_cfg.dma_buffer_size);
2455-
break;
24562496
default:
24572497
break;
24582498
}

sound/soc/sof/ipc4-topology.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@
7676
/* ChainDMA in fw uses 5ms DMA buffer */
7777
#define SOF_IPC4_CHAIN_DMA_BUFFER_SIZE 5
7878

79+
/*
80+
* When the host DMA buffer size is larger than 8ms, the firmware switches from
81+
* a constant fill mode to burst mode, keeping a 4ms threshold to trigger a
82+
* transfer of approximately host DMA buffer size - 4ms after the initial burst
83+
* to fill the entire buffer.
84+
* To simplify the logic, above 20ms ALSA period size use the same size for host
85+
* DMA buffer, while if the ALSA period size is smaller than 20ms, then use a
86+
* headroom between host DMA buffer and ALSA period size.
87+
*/
88+
#define SOF_IPC4_NO_DMA_BUFFER_HEADROOM_MS 20
89+
7990
/*
8091
* The base of multi-gateways. Multi-gateways addressing starts from
8192
* ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources

0 commit comments

Comments
 (0)