Skip to content

Commit d8231a7

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 (with a headroom between the two) 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 time of 20ms will result 10ms host DMA Buffer - before the patch if 10ms host DMA buffer was desired, the minimum ALSA period size was 20ms ALSA period size of 50ms will result 40ms host DMA buffer - before the patch if 40ms host DMA buffer was desired, the minimum ALSA period size was 50ms ALSA period size of 110ms will result 100ms host DMA buffer - before the patch if 100ms host DMA buffer was desired, the minimum ALSA period size was 110ms ALSA period size of 500ms will result 100ms host DMA buffer - Like before this patch: 500ms ALSA period would use 100ms host DMA buffer 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 fedfcf1 commit d8231a7

File tree

2 files changed

+80
-44
lines changed

2 files changed

+80
-44
lines changed

sound/soc/sof/ipc4-topology.c

Lines changed: 72 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,67 @@ 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 sof_ipc4_set_host_dma_buffer_size(struct snd_sof_widget *swidget,
2039+
unsigned int fe_period_bytes)
2040+
{
2041+
unsigned int min_size, max_size, headroom, host_period_bytes;
2042+
struct snd_soc_component *scomp = swidget->scomp;
2043+
struct sof_ipc4_copier_data *copier_data;
2044+
struct sof_ipc4_copier *ipc4_copier;
2045+
unsigned int deep_buffer_dma_ms = 0;
2046+
u32 buffer_bytes;
2047+
int ret;
2048+
2049+
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
2050+
copier_data = &ipc4_copier->data;
2051+
2052+
if (swidget->id == snd_soc_dapm_aif_in)
2053+
host_period_bytes = copier_data->base_config.ibs;
2054+
else
2055+
host_period_bytes = copier_data->base_config.obs;
2056+
2057+
min_size = SOF_IPC4_MIN_DMA_BUFFER_SIZE * host_period_bytes;
2058+
headroom = min(SOF_IPC4_ALSA_PERIOD_MAX_HEADROOM_MS * host_period_bytes,
2059+
fe_period_bytes / 2);
2060+
2061+
/* parse the deep buffer dma size */
2062+
ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
2063+
SOF_COPIER_DEEP_BUFFER_TOKENS, swidget->tuples,
2064+
swidget->num_tuples, sizeof(u32), 1);
2065+
if (ret) {
2066+
dev_dbg(scomp->dev,
2067+
"Failed to parse deep buffer dma size for %s\n",
2068+
swidget->widget->name);
2069+
buffer_bytes = min_size;
2070+
goto out;
2071+
}
2072+
2073+
max_size = deep_buffer_dma_ms * host_period_bytes;
2074+
2075+
/*
2076+
* Non Deepbuffer and small ALSA periods must use the minimal host DMA
2077+
* buffer size.
2078+
* Note: smaller than 2x the minimum host DMA buffer size for ALSA
2079+
* period is not allowed and should be protected by platform code with
2080+
* constraint
2081+
*/
2082+
if (deep_buffer_dma_ms <= SOF_IPC4_MIN_DMA_BUFFER_SIZE ||
2083+
(min_size * 2) > fe_period_bytes)
2084+
buffer_bytes = min_size;
2085+
else
2086+
buffer_bytes = min(max_size, fe_period_bytes - headroom);
2087+
2088+
out:
2089+
dev_dbg(scomp->dev,
2090+
"%s, dma buffer%s: %u ms (max: %u) / %u bytes, ALSA period: %u / %u\n",
2091+
swidget->widget->name, deep_buffer_dma_ms ? " (using Deep Buffer)" : "",
2092+
buffer_bytes / host_period_bytes,
2093+
deep_buffer_dma_ms ? deep_buffer_dma_ms : SOF_IPC4_MIN_DMA_BUFFER_SIZE,
2094+
buffer_bytes, fe_period_bytes / host_period_bytes, fe_period_bytes);
2095+
2096+
copier_data->gtw_cfg.dma_buffer_size = buffer_bytes;
2097+
}
2098+
20452099
static int
20462100
sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20472101
struct snd_pcm_hw_params *fe_params,
@@ -2063,7 +2117,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20632117
u32 **data;
20642118
int ipc_size, ret, out_ref_valid_bits;
20652119
u32 out_ref_rate, out_ref_channels, out_ref_type;
2066-
u32 deep_buffer_dma_ms = 0;
20672120
bool single_output_bitdepth;
20682121
int i;
20692122

@@ -2081,16 +2134,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
20812134
str_yes_no(pipeline->use_chain_dma),
20822135
platform_params->stream_tag);
20832136

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-
20942137
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
20952138
gtw_attr = ipc4_copier->gtw_attr;
20962139
copier_data = &ipc4_copier->data;
@@ -2425,34 +2468,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
24252468
* in topology.
24262469
*/
24272470
switch (swidget->id) {
2471+
case snd_soc_dapm_aif_in:
2472+
case snd_soc_dapm_aif_out:
2473+
sof_ipc4_set_host_dma_buffer_size(swidget,
2474+
params_period_bytes(fe_params));
2475+
break;
24282476
case snd_soc_dapm_dai_in:
24292477
copier_data->gtw_cfg.dma_buffer_size =
24302478
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.ibs;
24312479
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;
24422480
case snd_soc_dapm_dai_out:
24432481
copier_data->gtw_cfg.dma_buffer_size =
24442482
SOF_IPC4_MIN_DMA_BUFFER_SIZE * copier_data->base_config.obs;
24452483
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;
24562484
default:
24572485
break;
24582486
}

sound/soc/sof/ipc4-topology.h

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

79+
/*
80+
* When Deep buffer is enabled for a device we need to keep a headroom between
81+
* the host DMA buffer and ALSA period size to compensate for DMA bursts.
82+
* The maximum headroom is 10ms, which is based on how the firmware moves data
83+
* between host buffer and the rest of the pipeline.
84+
*/
85+
#define SOF_IPC4_ALSA_PERIOD_MAX_HEADROOM_MS 10
86+
7987
/*
8088
* The base of multi-gateways. Multi-gateways addressing starts from
8189
* ALH_MULTI_GTW_BASE and there are ALH_MULTI_GTW_COUNT multi-sources

0 commit comments

Comments
 (0)