From 7d235d23adecab8c3e3f334bcab6d3a31a006622 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 24 Jan 2023 17:01:10 +0100 Subject: [PATCH] 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 12c30e0d9..3cc9fae50 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 e01cd0697..669e701ae 100644 --- a/src/include/sof/audio/buffer.h +++ b/src/include/sof/audio/buffer.h @@ -186,6 +186,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 /* @@ -222,6 +224,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);