Skip to content

Commit 8149018

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 d4b2952 commit 8149018

2 files changed

Lines changed: 95 additions & 44 deletions

File tree

sound/soc/sof/ipc4-topology.c

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

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

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

691684
skip_gtw_cfg:
@@ -2043,6 +2036,79 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget
20432036
copier_data->gtw_cfg.node_id |= SOF_IPC4_NODE_INDEX(host_dma_id);
20442037
}
20452038

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

@@ -2082,16 +2147,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20822147
str_yes_no(pipeline->use_chain_dma),
20832148
platform_params->stream_tag);
20842149

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

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)