From 72ee157b65a33fe32c694b8c5489e41269a58e80 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 23 Jan 2023 15:28:34 +0100 Subject: [PATCH 1/5] buffer: Rename buffer_init to buffer_init_stream Change name of the buffer_init to buffer_init_stream because it is only responsible for initiating a stream. Omit the caps parameter because it is only assigned to a structure field. Assign this field in the function caller. Signed-off-by: Adrian Warecki --- src/audio/buffer.c | 5 +++-- src/include/sof/audio/buffer.h | 5 +---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/audio/buffer.c b/src/audio/buffer.c index 59b92d90b890..6ad41f7cebde 100644 --- a/src/audio/buffer.c +++ b/src/audio/buffer.c @@ -60,6 +60,7 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u CORE_CHECK_STRUCT_INIT(buffer, is_shared); buffer->is_shared = is_shared; + buffer->caps = caps; stream_addr = rballoc_align(0, caps, size, align); if (!stream_addr) { rfree(buffer); @@ -70,7 +71,7 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u /* From here no more uncached access to the buffer object, except its list headers */ audio_stream_set_addr(&buffer->stream, stream_addr); - buffer_init(buffer, size, caps); + buffer_init_stream(buffer, size); audio_stream_set_underrun(&buffer->stream, !!(flags & SOF_BUF_UNDERRUN_PERMITTED)); audio_stream_set_overrun(&buffer->stream, !!(flags & SOF_BUF_OVERRUN_PERMITTED)); @@ -193,7 +194,7 @@ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignmen if (new_ptr) buffer->stream.addr = new_ptr; - buffer_init(buffer, size, buffer->caps); + buffer_init_stream(buffer, size); return 0; } diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 662e329c1027..df0384d79c97 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -286,11 +286,8 @@ static inline void buffer_reset_pos(struct comp_buffer *buffer, void *data) } /* Run-time buffer re-configuration calls this too, so it must use cached access */ -static inline void buffer_init(struct comp_buffer *buffer, - uint32_t size, uint32_t caps) +static inline void buffer_init_stream(struct comp_buffer *buffer, size_t size) { - buffer->caps = caps; - /* addr should be set in alloc function */ audio_stream_init(&buffer->stream, buffer->stream.addr, size); } From 303fd7e88c0bb75db1cd686658030794496d62ff Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 23 Jan 2023 16:00:20 +0100 Subject: [PATCH 2/5] buffer: Extract buffer structure initialization from buffer_alloc Move part of the code responsible for initializing the buffer structure to the new function buffer_alloc_struct, which will also be used by a new buffer allocation function. Signed-off-by: Adrian Warecki --- src/audio/buffer.c | 53 ++++++++++++++++++++++------------ src/include/sof/audio/buffer.h | 2 +- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/audio/buffer.c b/src/audio/buffer.c index 6ad41f7cebde..12c30e0d939a 100644 --- a/src/audio/buffer.c +++ b/src/audio/buffer.c @@ -32,20 +32,12 @@ DECLARE_SOF_RT_UUID("buffer", buffer_uuid, 0x42544c92, 0x8e92, 0x4e41, 0xb6, 0x79, 0x34, 0x51, 0x9f, 0x1c, 0x1d, 0x28); DECLARE_TR_CTX(buffer_tr, SOF_UUID(buffer_uuid), LOG_LEVEL_INFO); -struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align, - bool is_shared) +static struct comp_buffer *buffer_alloc_struct(void *stream_addr, size_t size, uint32_t caps, + uint32_t flags, bool is_shared) { struct comp_buffer *buffer; - void *stream_addr; - tr_dbg(&buffer_tr, "buffer_alloc()"); - - /* validate request */ - if (size == 0) { - tr_err(&buffer_tr, "buffer_alloc(): new size = %u is invalid", - size); - return NULL; - } + tr_dbg(&buffer_tr, "buffer_alloc_struct()"); /* allocate new buffer */ enum mem_zone zone = is_shared ? SOF_MEM_ZONE_RUNTIME_SHARED : SOF_MEM_ZONE_RUNTIME; @@ -53,7 +45,7 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u buffer = rzalloc(zone, 0, SOF_MEM_CAPS_RAM, sizeof(*buffer)); if (!buffer) { - tr_err(&buffer_tr, "buffer_alloc(): could not alloc structure"); + tr_err(&buffer_tr, "buffer_alloc_struct(): could not alloc structure"); return NULL; } @@ -61,13 +53,6 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u buffer->is_shared = is_shared; buffer->caps = caps; - stream_addr = rballoc_align(0, caps, size, align); - if (!stream_addr) { - rfree(buffer); - tr_err(&buffer_tr, "buffer_alloc(): could not alloc size = %u bytes of type = %u", - size, caps); - return NULL; - } /* From here no more uncached access to the buffer object, except its list headers */ audio_stream_set_addr(&buffer->stream, stream_addr); @@ -82,6 +67,36 @@ struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, u return buffer; } +struct comp_buffer *buffer_alloc(size_t size, uint32_t caps, uint32_t flags, uint32_t align, + bool is_shared) +{ + struct comp_buffer *buffer; + void *stream_addr; + + tr_dbg(&buffer_tr, "buffer_alloc()"); + + /* validate request */ + if (size == 0) { + tr_err(&buffer_tr, "buffer_alloc(): new size = %zu is invalid", size); + return NULL; + } + + stream_addr = rballoc_align(0, caps, size, align); + if (!stream_addr) { + tr_err(&buffer_tr, "buffer_alloc(): could not alloc size = %zu bytes of type = %u", + size, caps); + return NULL; + } + + buffer = buffer_alloc_struct(stream_addr, size, caps, flags, is_shared); + if (!buffer) { + tr_err(&buffer_tr, "buffer_alloc(): could not alloc buffer structure"); + rfree(stream_addr); + } + + return buffer; +} + #if CONFIG_ZEPHYR_DP_SCHEDULER int buffer_create_shadow_dp_queue(struct comp_buffer *buffer, bool at_input) { diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index df0384d79c97..0a6d5ba23573 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -188,7 +188,7 @@ struct buffer_cb_free { } while (0) /* pipeline buffer creation and destruction */ -struct comp_buffer *buffer_alloc(uint32_t size, uint32_t caps, uint32_t flags, uint32_t align, +struct comp_buffer *buffer_alloc(size_t size, uint32_t caps, uint32_t flags, uint32_t align, bool is_shared); struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared); #if CONFIG_ZEPHYR_DP_SCHEDULER From e60ca9dad9c9a129354ea53b73c7738ac9865bd7 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 24 Jan 2023 17:01:10 +0100 Subject: [PATCH 3/5] buffer: Add buffer range allocation functions Add two new buffer allocation functions buffer_set_size_range and buffer_alloc_range dedicated to deep buffering. They try to allocate the largest possible buffer according to the suggested size. If this size cannot be obtained, it will be reduced step by step until it reaches the minimum size. Signed-off-by: Adrian Warecki --- src/audio/buffer.c | 100 +++++++++++++++++++++++++++++++++ src/include/sof/audio/buffer.h | 4 ++ 2 files changed, 104 insertions(+) diff --git a/src/audio/buffer.c b/src/audio/buffer.c index 12c30e0d939a..3cc9fae5008b 100644 --- a/src/audio/buffer.c +++ b/src/audio/buffer.c @@ -164,6 +164,49 @@ int buffer_sync_shadow_dp_queue(struct comp_buffer *buffer, size_t limit) } #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ +struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_size, uint32_t caps, + uint32_t flags, uint32_t align, bool is_shared) +{ + struct comp_buffer *buffer; + size_t size; + void *stream_addr = NULL; + + tr_dbg(&buffer_tr, "buffer_alloc_range(): %zu -- %zu bytes", minimum_size, preferred_size); + + /* validate request */ + if (minimum_size == 0 || preferred_size < minimum_size) { + tr_err(&buffer_tr, "buffer_alloc_range(): new size range %zu -- %zu is invalid", + minimum_size, preferred_size); + return NULL; + } + + /* Align preferred size to a multiple of the minimum size */ + if (preferred_size % minimum_size) + preferred_size += minimum_size - preferred_size % minimum_size; + + for (size = preferred_size; size >= minimum_size; size -= minimum_size) { + stream_addr = rballoc_align(0, caps, size, align); + if (stream_addr) + break; + } + + tr_dbg(&buffer_tr, "buffer_alloc_range(): allocated %zu bytes", size); + + if (!stream_addr) { + tr_err(&buffer_tr, "buffer_alloc_range(): could not alloc size = %zu bytes of type = %u", + minimum_size, caps); + return NULL; + } + + buffer = buffer_alloc_struct(stream_addr, size, caps, flags, is_shared); + if (!buffer) { + tr_err(&buffer_tr, "buffer_alloc_range(): could not alloc buffer structure"); + rfree(stream_addr); + } + + return buffer; +} + void buffer_zero(struct comp_buffer *buffer) { buf_dbg(buffer, "stream_zero()"); @@ -214,6 +257,63 @@ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignmen return 0; } +int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, size_t minimum_size, + uint32_t alignment) +{ + void *ptr = audio_stream_get_addr(&buffer->stream); + const size_t actual_size = audio_stream_get_size(&buffer->stream); + void *new_ptr = NULL; + size_t new_size; + + CORE_CHECK_STRUCT(buffer); + + /* validate request */ + if (minimum_size == 0 || preferred_size < minimum_size) { + buf_err(buffer, "resize size range %zu -- %zu is invalid", minimum_size, + preferred_size); + return -EINVAL; + } + + /* Align preferred size to a multiple of the minimum size */ + if (preferred_size % minimum_size) + preferred_size += minimum_size - preferred_size % minimum_size; + + if (preferred_size == actual_size) + return 0; + + if (!alignment) { + for (new_size = preferred_size; new_size >= minimum_size; + new_size -= minimum_size) { + new_ptr = rbrealloc(ptr, SOF_MEM_FLAG_NO_COPY, buffer->caps, new_size, + actual_size); + if (new_ptr) + break; + } + } else { + for (new_size = preferred_size; new_size >= minimum_size; + new_size -= minimum_size) { + new_ptr = rbrealloc_align(ptr, SOF_MEM_FLAG_NO_COPY, buffer->caps, new_size, + actual_size, alignment); + if (new_ptr) + break; + } + } + + /* we couldn't allocate bigger chunk */ + if (!new_ptr && new_size > actual_size) { + buf_err(buffer, "resize can't alloc %zu bytes type %u", new_size, buffer->caps); + return -ENOMEM; + } + + /* use bigger chunk, else just use the old chunk but set smaller */ + if (new_ptr) + buffer->stream.addr = new_ptr; + + buffer_init_stream(buffer, new_size); + + return 0; +} + int buffer_set_params(struct comp_buffer *buffer, struct sof_ipc_stream_params *params, bool force_update) { diff --git a/src/include/sof/audio/buffer.h b/src/include/sof/audio/buffer.h index 0a6d5ba23573..4d89f98beb20 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -190,6 +190,8 @@ struct buffer_cb_free { /* pipeline buffer creation and destruction */ struct comp_buffer *buffer_alloc(size_t size, uint32_t caps, uint32_t flags, uint32_t align, bool is_shared); +struct comp_buffer *buffer_alloc_range(size_t preferred_size, size_t minimum_size, uint32_t caps, + uint32_t flags, uint32_t align, bool is_shared); struct comp_buffer *buffer_new(const struct sof_ipc_buffer *desc, bool is_shared); #if CONFIG_ZEPHYR_DP_SCHEDULER /* @@ -226,6 +228,8 @@ int buffer_create_shadow_dp_queue(struct comp_buffer *buffer, bool at_input); int buffer_sync_shadow_dp_queue(struct comp_buffer *buffer, size_t limit); #endif /* CONFIG_ZEPHYR_DP_SCHEDULER */ int buffer_set_size(struct comp_buffer *buffer, uint32_t size, uint32_t alignment); +int buffer_set_size_range(struct comp_buffer *buffer, size_t preferred_size, size_t minimum_size, + uint32_t alignment); void buffer_free(struct comp_buffer *buffer); void buffer_zero(struct comp_buffer *buffer); From 4f08e7794688f10c557c3a9eb90cd71163bc979e Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 21 May 2024 16:51:09 +0200 Subject: [PATCH 4/5] zephyr: dai: Use the buffer_alloc_range function to allocate a buffer Change buffer allocation functions to buffer_alloc_range and buffer_set_size_range. This makes it possible to allocate the buffer even if the suggested size given in ipc cannot be met. Signed-off-by: Adrian Warecki --- src/audio/dai-zephyr.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 872a1ee9bd61..48f20d589abc 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -797,6 +797,7 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; + uint32_t buffer_size_preferred; uint32_t addr_align; uint32_t align; int err; @@ -873,21 +874,23 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, comp_err(dev, "dai_set_dma_buffer(): no valid dma buffer period count"); return -EINVAL; } - buffer_size = ALIGN_UP(period_count * period_bytes, align); - *pc = period_count; + period_count = MAX(period_count, + SOF_DIV_ROUND_UP(dd->ipc_config.dma_buffer_size, period_bytes)); + buffer_size_preferred = ALIGN_UP(period_count * period_bytes, align); /* alloc DMA buffer or change its size if exists */ if (dd->dma_buffer) { - err = buffer_set_size(dd->dma_buffer, buffer_size, addr_align); + err = buffer_set_size_range(dd->dma_buffer, buffer_size_preferred, buffer_size, + addr_align); if (err < 0) { comp_err(dev, "dai_set_dma_buffer(): buffer_size = %u failed", buffer_size); return err; } } else { - dd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align, false); + dd->dma_buffer = buffer_alloc_range(buffer_size_preferred, buffer_size, + SOF_MEM_CAPS_DMA, 0, addr_align, false); if (!dd->dma_buffer) { comp_err(dev, "dai_set_dma_buffer(): failed to alloc dma buffer"); return -ENOMEM; @@ -904,6 +907,7 @@ static int dai_set_dma_buffer(struct dai_data *dd, struct comp_dev *dev, dd->sampling = get_sample_bytes(hw_params.frame_fmt); } + *pc = audio_stream_get_size(&dd->dma_buffer->stream) / period_bytes; dd->fast_mode = dd->ipc_config.feature_mask & BIT(IPC4_COPIER_FAST_MODE); return 0; } From 7c63508449376dc58b48165c87966f09c08374cc Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 21 May 2024 17:01:59 +0200 Subject: [PATCH 5/5] zephyr: host: Use the buffer_alloc_range function to allocate a buffer Change buffer allocation functions to buffer_alloc_range and buffer_set_size_range. This makes it possible to allocate the buffer even if the suggested size given in ipc cannot be met. Signed-off-by: Adrian Warecki --- src/audio/host-zephyr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 6f9d00a32401..5b6ba474f4d7 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -748,6 +748,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, uint32_t period_count; uint32_t period_bytes; uint32_t buffer_size; + uint32_t buffer_size_preferred; uint32_t addr_align; uint32_t align; int i, channel, err; @@ -821,8 +822,9 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, /* calculate DMA buffer size */ round_up_size = (params->frame_fmt == SOF_IPC_FRAME_S24_3LE) ? (3 * align) : align; buffer_size = ROUND_UP(period_bytes, round_up_size) * period_count; + buffer_size_preferred = buffer_size; if (hd->ipc_host.dma_buffer_size != 0) - buffer_size = ROUND_UP(hd->ipc_host.dma_buffer_size, buffer_size); + buffer_size_preferred = ROUND_UP(hd->ipc_host.dma_buffer_size, buffer_size); /* alloc DMA buffer or change its size if exists */ /* @@ -830,7 +832,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, * but we have to write back caches after we finish anywae */ if (hd->dma_buffer) { - err = buffer_set_size(hd->dma_buffer, buffer_size, addr_align); + err = buffer_set_size_range(hd->dma_buffer, buffer_size_preferred, buffer_size, + addr_align); if (err < 0) { comp_err(dev, "host_params(): buffer_set_size() failed, buffer_size = %u", buffer_size); @@ -838,8 +841,8 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, } } else { /* allocate not shared buffer */ - hd->dma_buffer = buffer_alloc(buffer_size, SOF_MEM_CAPS_DMA, 0, - addr_align, false); + hd->dma_buffer = buffer_alloc_range(buffer_size_preferred, buffer_size, + SOF_MEM_CAPS_DMA, 0, addr_align, false); if (!hd->dma_buffer) { comp_err(dev, "host_params(): failed to alloc dma buffer"); return -ENOMEM; @@ -861,6 +864,7 @@ int host_common_params(struct host_data *hd, struct comp_dev *dev, config->dest_width = config->src_width; hd->dma_buffer_size = audio_stream_get_size(&hd->dma_buffer->stream); } + buffer_size = audio_stream_get_size(&hd->dma_buffer->stream); /* create SG DMA elems for local DMA buffer */ err = create_local_elems(hd, dev, period_count, buffer_size / period_count,