From dd3aa388f103f50c325a9daa7699138675a53c5f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 11:27:38 +0100 Subject: [PATCH 01/56] scripts: create symlink for community base FW binary Currently the symlink for sof-ipc4/platform/sof-basefw.ri is not created. Fix this so that deployable builds can be copied directly to target from staging directory. Signed-off-by: Liam Girdwood --- scripts/xtensa-build-zephyr.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/xtensa-build-zephyr.py b/scripts/xtensa-build-zephyr.py index 40931ba6623a..c30aa6feb8a7 100755 --- a/scripts/xtensa-build-zephyr.py +++ b/scripts/xtensa-build-zephyr.py @@ -1150,6 +1150,16 @@ def install_platform(platform, sof_output_dir, platf_build_environ, platform_wco os.makedirs(alias_key_dir, exist_ok=True) symlink_or_copy(install_key_dir, output_fwname, alias_key_dir, alias_fwname) + + # Also create the "plain" sof-.ri symlink in the + # sof//sof-ipc4/ directory, so that when + # copying the entire sof//sof-ipc4 directory to + # the target, all platforms are there. + alias_vendor_dir = pathlib.Path(sof_output_dir, p_alias).parent + alias_ipc4_dir = pathlib.Path(alias_vendor_dir, p_alias) + alias_install_key_dir = alias_ipc4_dir / "community" + os.makedirs(alias_ipc4_dir, exist_ok=True) + symlink_or_copy(alias_install_key_dir, alias_fwname, alias_ipc4_dir, alias_fwname) else: # non deployable builds and IPC3 deployable builds are using the same symlink scheme # The production key is usually different From 4ac9396af273bbbb8747653f37a97c2e62a57261 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 12:03:30 +0100 Subject: [PATCH 02/56] alloc: add a simple virtual page allocator Add a simple page allocator that will manage and allocate continuous pages from a virtual memory region and map them to non continuous physical pages. Simplicity is due to fixed block size, max number of blocks and continuous allocations only. Signed-off-by: Liam Girdwood --- zephyr/Kconfig | 10 + zephyr/include/sof/lib/vpage.h | 48 +++++ zephyr/lib/vpages.c | 341 +++++++++++++++++++++++++++++++++ 3 files changed, 399 insertions(+) create mode 100644 zephyr/include/sof/lib/vpage.h create mode 100644 zephyr/lib/vpages.c diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 1314454a0466..3d77d5dc3c8d 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -76,6 +76,16 @@ config SOF_ZEPHYR_USERSPACE_MODULE_HEAP_SIZE module has its own independent heap to which only it has access. This heap is shared between instances of the same module. +config SOF_VPAGE_ELEMS + int "Number of virtual memory allocation elements" + default 128 + help + This setting defines the maximum number of virtual memory allocation + elements that can be tracked. Each allocation element represents a + contiguous block of virtual memory allocated from the virtual memory + heap. Increasing this number allows for more simultaneous allocations, + but also increases the memory overhead for tracking these allocations. + config ZEPHYR_NATIVE_DRIVERS bool "Use Zephyr native drivers" help diff --git a/zephyr/include/sof/lib/vpage.h b/zephyr/include/sof/lib/vpage.h new file mode 100644 index 000000000000..0aea2fdeda97 --- /dev/null +++ b/zephyr/include/sof/lib/vpage.h @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2025 Intel Corporation. + +/* Virtual Page Allocator API */ +#ifndef __SOF_LIB_VPAGE_H__ +#define __SOF_LIB_VPAGE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Allocate virtual pages + * Allocates a specified number of contiguous virtual memory pages. + * + * @param[in] pages Number of 4kB pages to allocate. + * + * @return Pointer to the allocated virtual memory region, or NULL on failure. + */ +void *vpage_alloc(uint32_t pages); + +/** + * @brief Free virtual pages + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param[in] ptr Pointer to the memory pages to free. + */ +void vpage_free(void *ptr); + +/** + * @brief Initialize virtual page allocator + * + * Initializes a virtual page allocator that manages a virtual memory region + * using a page table and block structures. + * + * @retval 0 if successful. + * @retval -ENOMEM on creation failure. + */ +int vpage_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SOF_LIB_VPAGE_H__ */ diff --git a/zephyr/lib/vpages.c b/zephyr/lib/vpages.c new file mode 100644 index 000000000000..491b184001a7 --- /dev/null +++ b/zephyr/lib/vpages.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(vpage, CONFIG_SOF_LOG_LEVEL); + +/* Simple Page Allocator. + * + * This allocator manages the allocation and deallocation of virtual memory pages from + * a predefined virtual memory region roughly twice the size of the physical memory + * region. + * + * Both memory regions are divided into 4kB pages that are represented as blocks in a + * bitmap using the zephyr sys_mem_blocks API. + * + * The blocks APIs track the allocation of physical memory pages and virtual memory pages + * separately. The physical memory pages are mapped to the virtual memory pages as needed to + * provide a contiguous virtual memory space to the user. + */ + +#define VPAGE_ALLOC_ELEMS CONFIG_SOF_VPAGE_ELEMS /* max number of allocation elements */ + +/* + * Virtual memory allocation element - tracks allocated virtual page id and size + */ +struct valloc_elem { + uint16_t pages; /* number of 4kB pages allocated in contiguous block */ + uint16_t vpage; /* virtual page number from start of region */ +}; + +/* + * Virtual page table structure + * + * This structure holds all information about virtual memory pages + * including the number of free and total pages, the virtual memory + * region, the block allocator for virtual pages and the allocation + * elements. + */ +struct vpage_context { + struct k_mutex lock; + uint32_t free_pages; /* number of free 4kB pages */ + uint32_t total_pages; /* total number of 4kB pages */ + + /* Virtual memory region information */ + const struct sys_mm_drv_region *virtual_region; + struct sys_mem_blocks vpage_blocks; + + /* allocation elements to track page id to allocation size */ + uint32_t num_elems; /* number of allocated elements in use*/ + struct valloc_elem velems[VPAGE_ALLOC_ELEMS]; +}; + +/* uncache persistent across all cores */ +static struct vpage_context page_context; +static sys_bitarray_t bitmap; + +/* singleton across all cores */ +static int vpage_init_done; + +/** + * @brief Allocate and map virtual memory pages + * + * Allocates memory pages from the virtual page allocator. + * Maps physical memory pages to the virtual region as needed. + * + * @param pages Number of 4kB pages to allocate. + * @param ptr Pointer to store the address of allocated pages. + * @retval 0 if successful. + */ +static int vpages_alloc_and_map(uint32_t pages, void **ptr) +{ + void *vaddr; + int ret; + + /* check for valid pages and ptr */ + if (!pages || !ptr) + return -EINVAL; + + *ptr = NULL; + + /* quick check for enough free pages */ + if (page_context.free_pages < pages) { + LOG_ERR("error: not enough free pages %d for requested pages %d", + page_context.free_pages, pages); + return -ENOMEM; + } + + /* check for allocation elements */ + if (page_context.num_elems >= VPAGE_ALLOC_ELEMS) { + LOG_ERR("error: max allocation elements reached"); + return -ENOMEM; + } + + /* allocate virtual continuous blocks */ + ret = sys_mem_blocks_alloc_contiguous(&page_context.vpage_blocks, pages, &vaddr); + if (ret < 0) { + LOG_ERR("error: failed to allocate %d continuous virtual pages, free %d", + pages, page_context.free_pages); + return ret; + } + + /* map the virtual blocks in virtual region to free physical blocks */ + ret = sys_mm_drv_map_region_safe(page_context.virtual_region, vaddr, + 0, pages * CONFIG_MM_DRV_PAGE_SIZE, SYS_MM_MEM_PERM_RW); + if (ret < 0) { + LOG_ERR("error: failed to map virtual region %p to physical region %p, error %d", + vaddr, page_context.virtual_region->addr, ret); + sys_mem_blocks_free(&page_context.vpage_blocks, pages, &vaddr); + return ret; + } + + /* success update the free pages */ + page_context.free_pages -= pages; + + /* store the size and virtual page number in first free alloc element, + * we have already checked for a free element before the mapping. + */ + for (int i = 0; i < VPAGE_ALLOC_ELEMS; i++) { + if (page_context.velems[i].pages == 0) { + page_context.velems[i].pages = pages; + page_context.velems[i].vpage = + (POINTER_TO_UINT(vaddr) - + POINTER_TO_UINT(page_context.vpage_blocks.buffer)) / + CONFIG_MM_DRV_PAGE_SIZE; + page_context.num_elems++; + break; + } + } + + /* return the virtual address */ + *ptr = vaddr; + return ret; +} + +/** + * @brief Allocate virtual memory pages + * + * Allocates virtual memory pages from the virtual page allocator. + * + * @param pages Number of 4kB pages to allocate. + * @retval ptr to allocated pages if successful. + * @retval NULL on allocation failure. + */ +void *vpage_alloc(uint32_t pages) +{ + void *ptr; + int err; + + k_mutex_lock(&page_context.lock, K_FOREVER); + err = vpages_alloc_and_map(pages, &ptr); + k_mutex_unlock(&page_context.lock); + if (err < 0) { + LOG_ERR("vpage_alloc failed %d for %d pages, total %d free %d", + err, pages, page_context.total_pages, page_context.free_pages); + } + LOG_INF("vpage_alloc ptr %p pages %d free %d/%d", ptr, pages, page_context.free_pages, + page_context.total_pages); + return ptr; +} + +/** + * @brief Free and unmap virtual memory pages + * + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param ptr Pointer to the memory pages to free. + * @retval 0 if successful. + * @retval -EINVAL if ptr is invalid. + */ +static int vpages_free_and_unmap(uintptr_t *ptr) +{ + int pages = 0; + int ret; + + /* check for valid ptr which must be page aligned */ + if (!ptr || ((uintptr_t)ptr % CONFIG_MM_DRV_PAGE_SIZE) != 0) { + LOG_ERR("error: invalid page pointer %p", ptr); + return -EINVAL; + } + + /* find the allocation element */ + for (int i = 0; i < VPAGE_ALLOC_ELEMS; i++) { + if (page_context.velems[i].pages > 0 && + page_context.velems[i].vpage == + (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(page_context.vpage_blocks.buffer)) / + CONFIG_MM_DRV_PAGE_SIZE) { + + pages = page_context.velems[i].pages; + + LOG_DBG("found allocation element %d pages %d vpage %d for ptr %p", + i, page_context.velems[i].pages, + page_context.velems[i].vpage, ptr); + + /* clear the element */ + page_context.velems[i].pages = 0; + page_context.velems[i].vpage = 0; + page_context.num_elems--; + break; + } + } + + /* check we found allocation element */ + if (pages == 0) { + LOG_ERR("error: invalid page pointer %p not found", ptr); + return -EINVAL; + } + + /* unmap the pages from virtual region */ + ret = sys_mm_drv_unmap_region((void *)ptr, pages * CONFIG_MM_DRV_PAGE_SIZE); + if (ret < 0) { + LOG_ERR("error: failed to unmap virtual region %p pages %d, error %d", + ptr, pages, ret); + return ret; + } + + /* free physical blocks */ + ret = sys_mem_blocks_free_contiguous(&page_context.vpage_blocks, ptr, pages); + if (ret < 0) { + LOG_ERR("error: failed to free %d continuous virtual page blocks at %p, error %d", + pages, ptr, ret); + return ret; + } + + /* success update the free pages */ + page_context.free_pages += pages; + return ret; +} + +/** + * @brief Free virtual pages + * Frees previously allocated virtual memory pages and unmaps them. + * + * @param ptr + */ +void vpage_free(void *ptr) +{ + k_mutex_lock(&page_context.lock, K_FOREVER); + vpages_free_and_unmap((uintptr_t *)ptr); + assert(!ret); /* should never fail */ + k_mutex_unlock(&page_context.lock); + LOG_INF("vpage_free done ptr %p free pages %d/%d", ptr, page_context.free_pages, + page_context.total_pages); +} + +/** + * @brief Initialize virtual page allocator + * + * Initializes a virtual page allocator that manages a virtual memory region + * using a page table and block structures. + * + * @retval 0 if successful. + * @retval -ENOMEM on creation failure. + */ +static int vpage_init(void) +{ + const struct sys_mm_drv_region *virtual_memory_regions; + const struct sys_mm_drv_region *region; + uint32_t *bundles = NULL; + size_t block_count, bitmap_num_bundles; + int ret; + + /* Check if already initialized */ + if (vpage_init_done) + return 0; + + /* create the virtual memory region and add it to the system */ + ret = adsp_add_virtual_memory_region(adsp_mm_get_unused_l2_start_aligned(), + CONFIG_SOF_ZEPHYR_VIRTUAL_HEAP_REGION_SIZE, + VIRTUAL_REGION_SHARED_HEAP_ATTR); + if (ret) + return ret; + + memset(&page_context, 0, sizeof(page_context)); + k_mutex_init(&page_context.lock); + + /* now find the virtual region in all memory regions */ + virtual_memory_regions = sys_mm_drv_query_memory_regions(); + SYS_MM_DRV_MEMORY_REGION_FOREACH(virtual_memory_regions, region) { + if (region->attr == VIRTUAL_REGION_SHARED_HEAP_ATTR) { + page_context.virtual_region = region; + break; + } + } + + /* check for a valid region */ + if (!page_context.virtual_region) { + LOG_ERR("error: no valid virtual region found"); + return -EINVAL; + } + + block_count = region->size / CONFIG_MM_DRV_PAGE_SIZE; + if (block_count == 0) { + LOG_ERR("error: virtual region too small %d", region->size); + return -ENOMEM; + } + page_context.total_pages = block_count; + page_context.free_pages = block_count; + page_context.num_elems = 0; + + /* bundles are uint32_t of bits */ + bitmap_num_bundles = SOF_DIV_ROUND_UP(block_count, 32); + + /* allocate memory for bitmap bundles */ + bundles = rzalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, + bitmap_num_bundles * sizeof(uint32_t)); + if (!bundles) { + LOG_ERR("error: virtual region bitmap alloc failed"); + return -ENOMEM; + } + + /* Fill allocators data based on config and virtual region data */ + page_context.vpage_blocks.info.num_blocks = block_count; + page_context.vpage_blocks.info.blk_sz_shift = 12; /* 4kB blocks */ + /* buffer is the start of the physical memory region */ + page_context.vpage_blocks.buffer = (uint8_t *)page_context.virtual_region->addr; + + /* initialize bitmap */ + bitmap.num_bits = block_count; + bitmap.num_bundles = bitmap_num_bundles; + bitmap.bundles = bundles; + page_context.vpage_blocks.bitmap = &bitmap; + + LOG_INF("vpage_init region %p size 0x%x pages %d", + (void *)page_context.virtual_region->addr, + (int)page_context.virtual_region->size, block_count); + + vpage_init_done = 1; + return 0; +} + +SYS_INIT(vpage_init, POST_KERNEL, 1); + From 122270f8afeb4a1121e33857d42d06774304ead4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 12:29:09 +0100 Subject: [PATCH 03/56] alloc: add pre-allocated continuous virtual regions Add support for Pre Allocated COntinuous Virtual Regions that support bulk static memory allocation is a linear heap and temporary allocations in a zephyr heap. The intention is that we map the batch/bulk allocations from pipeline and module construction to the linear heap for more concentrated memory page usage that also means module objects will also be closer in cache. We will also allocate the more temporary runtime configuration data to the zephyr heap within the PACOVR so that they can be freed and re-allocated on runtime changes. This again keeps the pipeline runtime data concentrated in less pages and closer in cache. Signed-off-by: Liam Girdwood --- zephyr/Kconfig | 10 ++ zephyr/include/sof/lib/pacovr.h | 114 ++++++++++++++ zephyr/lib/pacovr.c | 255 ++++++++++++++++++++++++++++++++ 3 files changed, 379 insertions(+) create mode 100644 zephyr/include/sof/lib/pacovr.h create mode 100644 zephyr/lib/pacovr.c diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 3d77d5dc3c8d..cf5d28750c27 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -76,6 +76,16 @@ config SOF_ZEPHYR_USERSPACE_MODULE_HEAP_SIZE module has its own independent heap to which only it has access. This heap is shared between instances of the same module. +config SOF_PACOVR + bool "Enable PACOVR memory allocator" + default y if ACE + default n + depends on ACE + help + Enable the PACOVR memory allocator for pipeline resource management. + PACOVR provides a way to manage memory resources for audio pipelines, + including both batch and scratch allocations. + config SOF_VPAGE_ELEMS int "Number of virtual memory allocation elements" default 128 diff --git a/zephyr/include/sof/lib/pacovr.h b/zephyr/include/sof/lib/pacovr.h new file mode 100644 index 000000000000..db6d52ba0faa --- /dev/null +++ b/zephyr/include/sof/lib/pacovr.h @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2025 Intel Corporation. + +/* Pre Allocated Contiguous Virtual Region */ +#ifndef __SOF_LIB_PACOVR_H__ +#define __SOF_LIB_PACOVR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pacovr; + +/** + * @brief Create a new PACOVR instance. + * + * Create a new PACOVR instance with specified batch and scratch sizes. Total + * size is the sum of batch and scratch sizes. + * + * @param[in] batch_size Size of the PACOVR batch region. + * @param[in] scratch_size Size of the scratch heap. + * @return struct pacovr* Pointer to the new PACOVR instance, or NULL on failure. + */ +struct pacovr *pacovr_create(size_t batch_size, size_t scratch_size); + +/** + * @brief Destroy a PACOVR instance. + * + * Free all associated resources and deallocate the PACOVR instance. + * + * @param[in] p Pointer to the PACOVR instance to destroy. + */ +void pacovr_destroy(struct pacovr *p); + +/** + * @brief Allocate memory from the PACOVR dynamic heap. + * + * Allocate memory from the PACOVR dynamic heap. Intended use for temporary + * allocations during audio processing. i.e. change of parameters or kcontrols. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_dynamic_alloc(struct pacovr *p, size_t size); + +/** + * @brief Allocate memory with alignment from the PACOVR dynamic heap. + * + * Allocate memory with alignment from the PACOVR dynamic heap. Intended use for + * temporary allocations during audio processing. i.e. change of parameters or + * kcontrols. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_dynamic_alloc_align(struct pacovr *p, size_t size, size_t align); + +/** + * @brief Free memory from the PACOVR dynamic heap. + * + * Free memory from the PACOVR dynamic heap. Intended use for temporary + * allocations during audio processing. i.e. change of parameters or + * kcontrols. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] ptr Pointer to the memory to free. + */ +void pacovr_dynamic_free(struct pacovr *p, void *ptr); + +/** + * @brief Allocate memory from the PACOVR static allocator. + * + * Allocate memory from the PACOVR static allocator. Intended use for + * allocations that persist for the lifetime of the audio processing pipeline. + * i.e. component data, buffers, etc. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_static_alloc(struct pacovr *p, size_t size); + +/** + * @brief Free memory from the PACOVR static allocator. + * + * Free memory from the PACOVR static allocator. This is a no-op and is + * intended for tuning and tracking only. Static allocations are freed + * when the PACOVR instance is destroyed. Any call to this function usually + * means the allocation should have been from the dynamic heap. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] ptr Pointer to the memory to free. + */ +void pacovr_static_free(struct pacovr *p, void *ptr); + +/** + * @brief Log PACOVR memory usage. + * + * @param[in] p Pointer to the PACOVR instance. + */ +void pacovr_info(struct pacovr *p); + +#ifdef __cplusplus +} +#endif + +#endif /* __SOF_LIB_PACOVR_H__ */ diff --git a/zephyr/lib/pacovr.c b/zephyr/lib/pacovr.c new file mode 100644 index 000000000000..087737487fe4 --- /dev/null +++ b/zephyr/lib/pacovr.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(pacovr, CONFIG_SOF_LOG_LEVEL); + +/* + * Pre Allocated COntiguous Virtual memory Region - PACOVR. + * + * This allocator manages a pre-allocated virtual memory region that uses the + * virtual page allocator to allocate and free memory pages. + * + * It is designed for use cases where a contiguous virtual memory region + * is required, such as for batched allocation of audio pipelines and modules. + * + * New pipelines will create a new PACOVR that will contain a dynamic heap at + * the start of the region and above the dynamic heap will be a simple static + * linear incrementing allocator for audio pipeline modules. + * + * The dynamic heap is used for temporary allocations during audio processing whilst + * the static allocator is used for long term allocations that are freed when the + * pipeline is destroyed. + * + * TODO: Pipeline/module reset() could reset the dynamic heap. + */ + +/** + * @brief PACOVR memory region structure. + * + * This structure represents a PACOVR memory region, which includes + * information about the base address, size, and allocation status + * of the region. + * The PACOVR memory region is divided into two main areas: + * 1. Dynamic Heap: A dynamic memory area used for multiple temporary allocations + * and frees over the lifetime of the audio processing pipeline. + * 2. Static Allocator: A simple incrementing allocator used for long-term static + * allocations that persist for the lifetime of the audio processing pipeline. + */ +struct pacovr { + uint8_t *base; /* base address of region */ + size_t size; /* size of whole region in bytes */ + size_t static_used; /* used bytes in static heap */ + size_t dynamic_size; /* size of dynamic heap */ + size_t static_size; /* size of static heap */ + size_t pages; /* size of region in pages */ + struct k_heap dynamic; /* dynamic heap */ + uint8_t *static_ptr; /* current static alloc pointer */ + int static_free_count; /* number of static frees - tuning only */ +}; + +/** + * @brief Create a new PACOVR instance. + * @param[in] static_size Size of the PACOVR static region. + * @param[in] dynamic_size Size of the dynamic heap. + * @return struct pacovr* Pointer to the new PACOVR instance, or NULL on failure. + */ +struct pacovr *pacovr_create(size_t static_size, size_t dynamic_size) +{ + struct pacovr *p; + uint32_t pages; + size_t total_size; + + if (!static_size || !dynamic_size) { + LOG_ERR("error: invalid pacovr static size %d or dynamic size %d", + static_size, dynamic_size); + return NULL; + } + + /* align up static size and dynamic size to nearest page */ + static_size = ALIGN_UP(static_size, CONFIG_MM_DRV_PAGE_SIZE); + dynamic_size = ALIGN_UP(dynamic_size, CONFIG_MM_DRV_PAGE_SIZE); + total_size = static_size + dynamic_size; + + /* allocate pacovr structure in userspace */ + p = rzalloc(SOF_MEM_FLAG_USER, sizeof(*p)); + if (!p) + return NULL; + + /* allocate pages for pacovr */ + pages = (static_size + dynamic_size) / CONFIG_MM_DRV_PAGE_SIZE; + p->base = vpage_alloc(pages); + if (!p->base) { + rfree(p); + return NULL; + } + + /* init pacovr */ + p->size = total_size; + p->dynamic_size = dynamic_size; + p->static_size = static_size; + p->pages = pages; + p->static_ptr = p->base + dynamic_size; + + /* init dynamic heap */ + sys_heap_init(&p->dynamic.heap, p->base, dynamic_size); + + LOG_INF("pacovr created at base %p total size 0x%x pages %d dynamic 0x%x static 0x%x", + (void *)p->base, total_size, pages, dynamic_size, static_size); + + return p; +} + +/** + * @brief Destroy a PACOVR instance. + * + * @param[in] p Pointer to the PACOVR instance to destroy. + */ +void pacovr_destroy(struct pacovr *p) +{ + if (!p) + return; + LOG_INF("pacovr destroy base %p size 0x%x pages %d static used 0x%x free count %d", + (void *)p->base, p->size, p->pages, p->static_used, p->static_free_count); + vpage_free(p->base); + rfree(p); +} + +/** + * @brief Allocate memory from the PACOVR dynamic heap. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_dynamic_alloc(struct pacovr *p, size_t size) +{ + void *ptr; + + if (!p || !size) + return NULL; + + ptr = sys_heap_alloc(&p->dynamic.heap, size); + if (!ptr) { + LOG_ERR("error: pacovr dynamic alloc failed"); + return NULL; + } + + return ptr; +} + +/** + * @brief Allocate memory with alignment from the PACOVR dynamic heap. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_dynamic_alloc_align(struct pacovr *p, size_t size, size_t align) +{ + void *ptr; + + if (!p || !size) + return NULL; + + /* align up size to 4 bytes - force aligned loads and stores */ + if (!align) + align = sizeof(uint32_t); + + ptr = sys_heap_aligned_alloc(&p->dynamic.heap, size, align); + if (!ptr) { + LOG_ERR("error: pacovr dynamic alloc failed"); + return NULL; + } + + return ptr; +} + +/** + * @brief Free memory from the PACOVR dynamic heap. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] ptr Pointer to the memory to free. + */ +void pacovr_dynamic_free(struct pacovr *p, void *ptr) +{ + if (!p || !ptr) + return; + + sys_heap_free(&p->dynamic.heap, ptr); +} + +/** + * @brief Allocate memory from the PACOVR static allocator. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] size Size of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *pacovr_static_alloc(struct pacovr *p, size_t size) +{ + void *ptr; + + if (!p || !size) + return NULL; + + /* align up size to 4 bytes - force aligned loads and stores */ + size = ALIGN_UP(size, 4); + + /* check we have enough static space left */ + if (p->static_used + size > p->static_size) { + LOG_ERR("error: pacovr static alloc failed for %d bytes, only %d bytes free", + size, p->static_size - p->static_used); + return NULL; + } + + /* allocate memory */ + ptr = p->static_ptr; + p->static_ptr += size; + p->static_used += size; + return ptr; +} + +/** + * @brief Free memory from the PACOVR static allocator. + * + * @param[in] p Pointer to the PACOVR instance. + * @param[in] ptr Pointer to the memory to free. + */ +void pacovr_static_free(struct pacovr *p, void *ptr) +{ + if (!p || !ptr) + return; + + /* simple free, just increment free count, this is for tuning only */ + p->static_free_count++; + + LOG_DBG("pacovr static free %p count %d", ptr, p->static_free_count); +} + +/** + * @brief Log PACOVR memory usage. + * + * @param[in] p Pointer to the PACOVR instance. + */ +void pacovr_info(struct pacovr *p) +{ + if (!p) + return; + + LOG_INF("pacovr info base %p size 0x%x pages %d static used 0x%x free count %d", + (void *)p->base, p->size, p->pages, p->static_used, p->static_free_count); +} +EXPORT_SYMBOL(pacovr_info); From 7821809433911d8211c189574bc9563488b2288f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 12:40:21 +0100 Subject: [PATCH 04/56] alloc: add support to build pacovr or vmh PACOVR and VMH are mutually exclusive. Make sure we only build one. Signed-off-by: Liam Girdwood --- zephyr/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 3e0207b17a0d..c47695e8081d 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -288,7 +288,13 @@ if (CONFIG_SOC_SERIES_INTEL_ADSP_ACE) ) # Sources for virtual heap management - zephyr_library_sources( + # Virtual memory support is required and can be enabled with + # either VMH or PACOVR. + zephyr_library_sources_ifdef(CONFIG_SOF_PACOVR + lib/vpages.c + lib/pacovr.c + ) + zephyr_library_sources_ifndef(CONFIG_SOF_PACOVR, lib/regions_mm.c ) From 875620aad2b62b3eb11d4f1e73f4c93bec4d1c01 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 12:45:07 +0100 Subject: [PATCH 05/56] WIP: pipeline: pacovr: Add support for pacovr allocations per pipeline Allocate a PACOVR on pipeline construction and destroy PACOVR on pipeline destruction. TODO: get the static/dynamic heap sizes from topology. Signed-off-by: Liam Girdwood --- src/audio/pipeline/pipeline-graph.c | 17 +++++++++++++++++ src/include/sof/audio/pipeline.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 678b8095289f..105c2c7bd1da 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -127,6 +128,18 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t return NULL; } +#if CONFIG_SOF_PACOVR + /* create a pacovr region for all resources */ + // TODO: make batch and scratch sizes configurable from topology + size_t scratch_size = 0x4000; /* 16kB scratch */ + size_t batch_size = 0x20000; /* 128kB batch */ + p->pacovr = pacovr_create(batch_size, scratch_size); + if (!p->pacovr) { + pipe_err(p, "pipeline_new(): pacovr_create() failed."); + goto free; + } +#endif + /* init pipeline */ p->comp_id = comp_id; p->priority = priority; @@ -236,6 +249,10 @@ int pipeline_free(struct pipeline *p) pipeline_posn_offset_put(p->posn_offset); +#if CONFIG_SOF_PACOVR + /* free pacovr region */ + pacovr_destroy(p->pacovr); +#endif /* now free the pipeline */ rfree(p); diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 5221d330e0f1..5f9f2d13000c 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,9 @@ struct pipeline { uint32_t time_domain; /**< scheduling time domain */ uint32_t attributes; /**< pipeline attributes from IPC extension msg/ */ + /* pipeline resource management */ + struct pacovr *pacovr; + /* runtime status */ int32_t xrun_bytes; /* last xrun length */ uint32_t status; /* pipeline status */ From 2146f8853501522cee4ef30ff95340af84f20e5f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 8 Oct 2025 12:49:06 +0100 Subject: [PATCH 06/56] WIP: module: pacovr: Add support for pacovr allocations per module Use the PACOVR static linear heap for module initialization allocations and the dynamic heap for runtime module allocations. Signed-off-by: Liam Girdwood --- src/audio/module_adapter/module/generic.c | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index f77377a54cea..44af38769a64 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -188,8 +188,19 @@ void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignm return NULL; } - /* Allocate buffer memory for module */ +#if CONFIG_SOF_PACOVR + /* do we need to use the dynamic heap or the static heap? */ + if (mod->priv.state != MODULE_INITIALIZED) { + /* static allocator */ + ptr = pacovr_static_alloc(mod->dev->pipeline->pacovr, size); + } else { + /* dynamic allocator */ + ptr = pacovr_dynamic_alloc_align(mod->dev->pipeline->pacovr, size, alignment); + } +#else + /* Allocate memory for module */ ptr = rballoc_align(SOF_MEM_FLAG_USER, size, alignment); +#endif if (!ptr) { comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", @@ -238,8 +249,19 @@ void *mod_alloc_align(struct processing_module *mod, size_t size, size_t alignme return NULL; } +#if CONFIG_SOF_PACOVR + /* do we need to use the dynamic heap or the static heap? */ + if (mod->priv.state != MODULE_INITIALIZED) { + /* static allocator */ + ptr = pacovr_static_alloc(mod->dev->pipeline->pacovr, size); + } else { + /* dynamic allocator */ + ptr = pacovr_dynamic_alloc_align(mod->dev->pipeline->pacovr, size, alignment); + } +#else /* Allocate memory for module */ ptr = rmalloc_align(SOF_MEM_FLAG_USER, size, alignment); +#endif if (!ptr) { comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", @@ -340,7 +362,18 @@ static int free_contents(struct processing_module *mod, struct module_resource * switch (container->type) { case MOD_RES_HEAP: +#if CONFIG_SOF_PACOVR + /* do we need to use the scratch heap or the batch heap? */ + if (mod->priv.state != MODULE_INITIALIZED) { + /* static allocator */ + pacovr_static_free(mod->dev->pipeline->pacovr, container->ptr); + } else { + /* dynamic allocator */ + pacovr_dynamic_free(mod->dev->pipeline->pacovr, container->ptr); + } +#else rfree(container->ptr); +#endif res->heap_usage -= container->size; return 0; #if CONFIG_COMP_BLOB From 7b3286b3853e08dc397c257e26de1334639ffe13 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 7 Aug 2025 13:06:20 +0300 Subject: [PATCH 07/56] Audio: Aria: All memory allocations through module API Allocate all memory through module API mod_alloc() and friends and remove all redundant rfree() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/aria/aria.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/audio/aria/aria.c b/src/audio/aria/aria.c index ef9ced95adde..e54e1148b85a 100644 --- a/src/audio/aria/aria.c +++ b/src/audio/aria/aria.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -126,7 +125,7 @@ static int aria_init(struct processing_module *mod) list_init(&dev->bsource_list); list_init(&dev->bsink_list); - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { return -ENOMEM; } @@ -145,10 +144,9 @@ static int aria_init(struct processing_module *mod) } mod_data->private = cd; - buf = rballoc(SOF_MEM_FLAG_USER, req_mem); + buf = mod_balloc(mod, req_mem); if (!buf) { - rfree(cd); comp_err(dev, "allocation failed for size %d", req_mem); return -ENOMEM; } @@ -158,10 +156,6 @@ static int aria_init(struct processing_module *mod) static int aria_free(struct processing_module *mod) { - struct aria_data *cd = module_get_private_data(mod); - - rfree(cd->data_addr); - rfree(cd); return 0; } From b5822b07f2c0df1e034601dc23db695f8bc5b5af Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 7 Aug 2025 15:38:01 +0300 Subject: [PATCH 08/56] Audio: ASRC: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/asrc/asrc.c | 47 +++++++++++---------------- src/audio/asrc/asrc_farrow.c | 62 ++++++++++++++++++++---------------- src/audio/asrc/asrc_farrow.h | 8 ++--- src/audio/asrc/asrc_ipc3.c | 1 - src/audio/asrc/asrc_ipc4.c | 1 - 5 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/audio/asrc/asrc.c b/src/audio/asrc/asrc.c index 281d2f82aaf7..88ea243fb9cb 100644 --- a/src/audio/asrc/asrc.c +++ b/src/audio/asrc/asrc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -217,7 +216,7 @@ static int asrc_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -242,7 +241,7 @@ static int asrc_init(struct processing_module *mod) return 0; } -static int asrc_initialize_buffers(struct asrc_farrow *src_obj) +static int asrc_initialize_buffers(struct processing_module *mod, struct asrc_farrow *src_obj) { int32_t *buf_32; int16_t *buf_16; @@ -261,7 +260,7 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) buffer_size = src_obj->buffer_length * sizeof(int32_t); for (ch = 0; ch < src_obj->num_channels; ch++) { - buf_32 = rzalloc(SOF_MEM_FLAG_USER, buffer_size); + buf_32 = mod_zalloc(mod, buffer_size); if (!buf_32) return -ENOMEM; @@ -272,7 +271,7 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) buffer_size = src_obj->buffer_length * sizeof(int16_t); for (ch = 0; ch < src_obj->num_channels; ch++) { - buf_16 = rzalloc(SOF_MEM_FLAG_USER, buffer_size); + buf_16 = mod_zalloc(mod, buffer_size); if (!buf_16) return -ENOMEM; @@ -284,7 +283,7 @@ static int asrc_initialize_buffers(struct asrc_farrow *src_obj) return 0; } -static void asrc_release_buffers(struct asrc_farrow *src_obj) +static void asrc_release_buffers(struct processing_module *mod, struct asrc_farrow *src_obj) { int32_t *buf_32; int16_t *buf_16; @@ -299,7 +298,7 @@ static void asrc_release_buffers(struct asrc_farrow *src_obj) if (buf_32) { src_obj->ring_buffers32[ch] = NULL; - rfree(buf_32); + mod_free(mod, buf_32); } } else @@ -308,23 +307,17 @@ static void asrc_release_buffers(struct asrc_farrow *src_obj) if (buf_16) { src_obj->ring_buffers16[ch] = NULL; - rfree(buf_16); + mod_free(mod, buf_16); } } } static int asrc_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; comp_dbg(dev, "asrc_free()"); - rfree(cd->buf); - asrc_release_buffers(cd->asrc_obj); - asrc_free_polyphase_filter(cd->asrc_obj); - rfree(cd->asrc_obj); - rfree(cd); return 0; } @@ -614,8 +607,7 @@ static int asrc_prepare(struct processing_module *mod, cd->buf_size = (cd->source_frames_max + cd->sink_frames_max) * frame_bytes; - cd->buf = rzalloc(SOF_MEM_FLAG_USER, - cd->buf_size); + cd->buf = mod_zalloc(mod, cd->buf_size); if (!cd->buf) { cd->buf_size = 0; comp_err(dev, "asrc_prepare(), allocation fail for size %d", @@ -632,7 +624,7 @@ static int asrc_prepare(struct processing_module *mod, /* Get required size and allocate memory for ASRC */ sample_bits = sample_bytes * 8; - ret = asrc_get_required_size(dev, &cd->asrc_size, + ret = asrc_get_required_size(mod, &cd->asrc_size, audio_stream_get_channels(&sourceb->stream), sample_bits); if (ret) { @@ -640,8 +632,7 @@ static int asrc_prepare(struct processing_module *mod, goto err_free_buf; } - cd->asrc_obj = rzalloc(SOF_MEM_FLAG_USER, - cd->asrc_size); + cd->asrc_obj = mod_zalloc(mod, cd->asrc_size); if (!cd->asrc_obj) { comp_err(dev, "asrc_prepare(), allocation fail for size %d", cd->asrc_size); @@ -659,7 +650,7 @@ static int asrc_prepare(struct processing_module *mod, fs_sec = cd->source_rate; } - ret = asrc_initialise(dev, cd->asrc_obj, audio_stream_get_channels(&sourceb->stream), + ret = asrc_initialise(mod, cd->asrc_obj, audio_stream_get_channels(&sourceb->stream), fs_prim, fs_sec, ASRC_IOF_INTERLEAVED, ASRC_IOF_INTERLEAVED, ASRC_BM_LINEAR, cd->frames, sample_bits, @@ -670,7 +661,7 @@ static int asrc_prepare(struct processing_module *mod, } /* Allocate ring buffers */ - ret = asrc_initialize_buffers(cd->asrc_obj); + ret = asrc_initialize_buffers(mod, cd->asrc_obj); /* check for errors */ if (ret) { @@ -698,12 +689,12 @@ static int asrc_prepare(struct processing_module *mod, return 0; err_free_asrc: - asrc_release_buffers(cd->asrc_obj); - rfree(cd->asrc_obj); + asrc_release_buffers(mod, cd->asrc_obj); + mod_free(mod, cd->asrc_obj); cd->asrc_obj = NULL; err_free_buf: - rfree(cd->buf); + mod_free(mod, cd->buf); cd->buf = NULL; err: @@ -865,10 +856,10 @@ static int asrc_reset(struct processing_module *mod) asrc_dai_stop_timestamp(cd); /* Free the allocations those were done in prepare() */ - asrc_release_buffers(cd->asrc_obj); - asrc_free_polyphase_filter(cd->asrc_obj); - rfree(cd->asrc_obj); - rfree(cd->buf); + asrc_release_buffers(mod, cd->asrc_obj); + asrc_free_polyphase_filter(mod, cd->asrc_obj); + mod_free(mod, cd->asrc_obj); + mod_free(mod, cd->buf); cd->asrc_obj = NULL; cd->buf = NULL; diff --git a/src/audio/asrc/asrc_farrow.c b/src/audio/asrc/asrc_farrow.c index 987a11408af0..e840a8082a3b 100644 --- a/src/audio/asrc/asrc_farrow.c +++ b/src/audio/asrc/asrc_farrow.c @@ -11,9 +11,9 @@ #include #include #include -#include #include #include +#include #include "asrc_farrow.h" LOG_MODULE_DECLARE(asrc, CONFIG_SOF_LOG_LEVEL); @@ -243,7 +243,7 @@ static const struct asrc_filter_params c_filter_params[CR_NUM] = { * Initialise the pointers to the filters, set the number of filters * and their length */ -static enum asrc_error_code initialise_filter(struct comp_dev *dev, +static enum asrc_error_code initialise_filter(struct processing_module *mod, struct asrc_farrow *src_obj); /* @@ -268,11 +268,12 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, * Pointers to each channels data. Buffers are allocated externally. */ -enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, +enum asrc_error_code asrc_get_required_size(struct processing_module *mod, int *required_size, int num_channels, int bit_depth) { + struct comp_dev *dev = mod->dev; int size; /* check for parameter errors */ @@ -318,7 +319,7 @@ enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, return ASRC_EC_OK; } -enum asrc_error_code asrc_initialise(struct comp_dev *dev, +enum asrc_error_code asrc_initialise(struct processing_module *mod, struct asrc_farrow *src_obj, int num_channels, int32_t fs_prim, @@ -331,6 +332,7 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, enum asrc_control_mode control_mode, enum asrc_operation_mode operation_mode) { + struct comp_dev *dev = mod->dev; enum asrc_error_code error_code; /* check for parameter errors */ @@ -410,7 +412,7 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, * also sets the pointer to the corresponding * calc_impulse_response_nX function. */ - error_code = initialise_filter(dev, src_obj); + error_code = initialise_filter(mod, src_obj); /* check for errors */ if (error_code != ASRC_EC_OK) { @@ -438,10 +440,12 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, return ASRC_EC_OK; } -enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, +enum asrc_error_code asrc_set_fs_ratio(struct processing_module *mod, struct asrc_farrow *src_obj, int32_t fs_prim, int32_t fs_sec) { + struct comp_dev *dev = mod->dev; + /* Check for parameter errors */ if (!src_obj) { comp_err(dev, "asrc_set_fs_ratio(), null src_obj"); @@ -490,7 +494,7 @@ enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, /* See initialise_asrc(...) for further information * Update the filters accordingly */ - enum asrc_error_code error_code = initialise_filter(dev, src_obj); + enum asrc_error_code error_code = initialise_filter(mod, src_obj); /* check for errors */ if (error_code != ASRC_EC_OK) { comp_err(dev, "asrc_set_fs_ratio(), failed filter initialise"); @@ -554,28 +558,29 @@ enum asrc_error_code asrc_set_output_format(struct comp_dev *dev, return ASRC_EC_OK; } -static const int32_t *__get_polyphase_filter(const int32_t *filter, size_t size) +static const int32_t *__get_polyphase_filter(struct processing_module *mod, + const int32_t *filter, size_t size) { #if CONFIG_FAST_GET - return fast_get(filter, size); + return mod_fast_get(mod, filter, size); #else return filter; #endif } -#define get_polyphase_filter(f) __get_polyphase_filter(f, sizeof(f)) +#define get_polyphase_filter(m, f) __get_polyphase_filter(m, f, sizeof(f)) -static void put_polyphase_filter(const int32_t *filter) +static void put_polyphase_filter(struct processing_module *mod, const int32_t *filter) { #if CONFIG_FAST_GET - fast_put(filter); + mod_fast_put(mod, filter); #endif } -void asrc_free_polyphase_filter(struct asrc_farrow *src_obj) +void asrc_free_polyphase_filter(struct processing_module *mod, struct asrc_farrow *src_obj) { if (src_obj && src_obj->polyphase_filters) { - put_polyphase_filter(src_obj->polyphase_filters); + put_polyphase_filter(mod, src_obj->polyphase_filters); src_obj->polyphase_filters = NULL; } } @@ -583,9 +588,10 @@ void asrc_free_polyphase_filter(struct asrc_farrow *src_obj) /* * FILTER FUNCTIONS */ -static enum asrc_error_code initialise_filter(struct comp_dev *dev, +static enum asrc_error_code initialise_filter(struct processing_module *mod, struct asrc_farrow *src_obj) { + struct comp_dev *dev = mod->dev; int fs_in; int fs_out; @@ -606,7 +612,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, /* Reset coefficients for possible exit with error. */ src_obj->filter_length = 0; src_obj->num_filters = 0; - asrc_free_polyphase_filter(src_obj); + asrc_free_polyphase_filter(mod, src_obj); if (fs_in == 0 || fs_out == 0) { /* Avoid possible divisions by zero. */ @@ -622,7 +628,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO48000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO48000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to48000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to48000); } else if (fs_in <= fs_out) { /* All upsampling use cases can share the same set of * filter coefficients. @@ -631,7 +637,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_44100TO48000].filter_length; src_obj->num_filters = c_filter_params[CR_44100TO48000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff44100to48000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff44100to48000); } else if (fs_in == 48000) { switch (fs_out) { #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_08000) @@ -640,7 +646,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO08000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO08000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to08000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to08000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_11025) @@ -649,7 +655,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO11025].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO11025].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to11025); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to11025); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_12000) @@ -658,7 +664,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO12000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO12000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to12000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to12000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_16000) @@ -667,7 +673,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO16000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO16000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to16000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to16000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_22050) @@ -676,7 +682,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO22050].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO22050].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to22050); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to22050); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_24000) @@ -685,7 +691,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO24000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO24000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to24000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to24000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_32000) @@ -694,7 +700,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO32000].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO32000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to32000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to32000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_48000_TO_44100) @@ -703,7 +709,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_48000TO44100].filter_length; src_obj->num_filters = c_filter_params[CR_48000TO44100].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff48000to44100); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff48000to44100); break; #endif default: @@ -719,7 +725,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_24000TO08000].filter_length; src_obj->num_filters = c_filter_params[CR_24000TO08000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff24000to08000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff24000to08000); break; #endif #if (CONFIG_ASRC_SUPPORT_CONVERSION_24000_TO_16000) @@ -728,7 +734,7 @@ static enum asrc_error_code initialise_filter(struct comp_dev *dev, c_filter_params[CR_24000TO16000].filter_length; src_obj->num_filters = c_filter_params[CR_24000TO16000].num_filters; - src_obj->polyphase_filters = get_polyphase_filter(coeff24000to16000); + src_obj->polyphase_filters = get_polyphase_filter(mod, coeff24000to16000); break; #endif default: diff --git a/src/audio/asrc/asrc_farrow.h b/src/audio/asrc/asrc_farrow.h index 766ead172d58..48e564c2d1e1 100644 --- a/src/audio/asrc/asrc_farrow.h +++ b/src/audio/asrc/asrc_farrow.h @@ -231,7 +231,7 @@ struct asrc_farrow { * @param[in] bit_depth The wordlength that will be used for representing * the PCM samples, must be 16 or 32. */ -enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, +enum asrc_error_code asrc_get_required_size(struct processing_module *mod, int *required_size, int num_channels, int bit_depth); @@ -268,7 +268,7 @@ enum asrc_error_code asrc_get_required_size(struct comp_dev *dev, * @param[in] operation_mode Choose 'push' or 'pull', depending on the mode * you want your ASRC to operate in. */ -enum asrc_error_code asrc_initialise(struct comp_dev *dev, +enum asrc_error_code asrc_initialise(struct processing_module *mod, struct asrc_farrow *src_obj, int num_channels, int32_t fs_prim, @@ -286,7 +286,7 @@ enum asrc_error_code asrc_initialise(struct comp_dev *dev, * * @param[in] src_obj Pointer to the ias_src_farrow. */ -void asrc_free_polyphase_filter(struct asrc_farrow *src_obj); +void asrc_free_polyphase_filter(struct processing_module *mod, struct asrc_farrow *src_obj); /* * @brief Process the sample rate converter for one frame; the frame @@ -591,7 +591,7 @@ enum asrc_error_code asrc_update_fs_ratio(struct comp_dev *dev, * @param[in] fs_prim Primary sampling rate. * @param[in] fs_sec Secondary sampling rate. */ -enum asrc_error_code asrc_set_fs_ratio(struct comp_dev *dev, +enum asrc_error_code asrc_set_fs_ratio(struct processing_module *mod, struct asrc_farrow *src_obj, int32_t fs_prim, int32_t fs_sec); diff --git a/src/audio/asrc/asrc_ipc3.c b/src/audio/asrc/asrc_ipc3.c index 30dfbecddc6b..ca917318d7e5 100644 --- a/src/audio/asrc/asrc_ipc3.c +++ b/src/audio/asrc/asrc_ipc3.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include diff --git a/src/audio/asrc/asrc_ipc4.c b/src/audio/asrc/asrc_ipc4.c index 3e5d8bf7818f..1047799f207b 100644 --- a/src/audio/asrc/asrc_ipc4.c +++ b/src/audio/asrc/asrc_ipc4.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include From 9aa385d1dde31c45b83d6edab06de9b80a9095b7 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 7 Aug 2025 23:02:32 +0300 Subject: [PATCH 09/56] Audio: Copier: All memory allocations through module API Allocate all memory through module API mod_alloc() and friends and remove all redundant rfree() calls from module unload functions and init error branches. NOTE: copier_dai.c and copier_host.c still have their shared memory allocated through the old API. This is to be fixed once we have decided on how the shared memory allocations should work in user-space. Signed-off-by: Jyri Sarha --- src/audio/copier/copier.c | 68 +++++++++++--------------------- src/audio/copier/copier_host.c | 12 +++--- src/audio/copier/copier_ipcgtw.c | 15 +++---- src/audio/copier/host_copier.h | 2 +- src/audio/copier/ipcgtw_copier.h | 2 +- 5 files changed, 34 insertions(+), 65 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0e1db840db67..0331ed9231aa 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -82,13 +81,12 @@ static void mic_privacy_event(void *arg, enum notify_id type, void *data) } } -static int mic_privacy_configure(struct comp_dev *dev, struct copier_data *cd) +static int mic_privacy_configure(struct processing_module *mod, struct copier_data *cd) { struct mic_privacy_data *mic_priv_data; int ret; - mic_priv_data = rzalloc(SOF_MEM_FLAG_USER, - sizeof(struct mic_privacy_data)); + mic_priv_data = mod_zalloc(mod, sizeof(struct mic_privacy_data)); if (!mic_priv_data) return -ENOMEM; @@ -100,19 +98,15 @@ static int mic_privacy_configure(struct comp_dev *dev, struct copier_data *cd) uint32_t zeroing_wait_time = (mic_privacy_get_dma_zeroing_wait_time() * 1000) / ADSP_RTC_FREQUENCY; - ret = copier_gain_set_params(dev, &mic_priv_data->mic_priv_gain_params, + ret = copier_gain_set_params(mod->dev, &mic_priv_data->mic_priv_gain_params, zeroing_wait_time, SOF_DAI_INTEL_NONE); - if (ret != 0) { - rfree(mic_priv_data); + if (ret != 0) return ret; - } cd->mic_priv = mic_priv_data; ret = notifier_register(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, mic_privacy_event, 0); - if (ret != 0) - rfree(mic_priv_data); return ret; } @@ -123,8 +117,6 @@ static void mic_privacy_free(struct copier_data *cd) mic_privacy_enable_dmic_irq(false); notifier_unregister(cd->mic_priv, NULL, NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE); - - rfree(cd->mic_priv); } #endif @@ -144,7 +136,7 @@ __cold static int copier_init(struct processing_module *mod) assert_can_be_cold(); - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -154,10 +146,8 @@ __cold static int copier_init(struct processing_module *mod) * store it, it's only used during IPC processing, besides we haven't * allocated space for it, so don't "fix" this! */ - if (memcpy_s(&cd->config, sizeof(cd->config), copier, sizeof(*copier)) < 0) { - ret = -EINVAL; - goto error_cd; - } + if (memcpy_s(&cd->config, sizeof(cd->config), copier, sizeof(*copier)) < 0) + return -EINVAL; /* Allocate memory and store gateway_cfg in runtime. Gateway cfg has to * be kept even after copier is created e.g. during SET_PIPELINE_STATE @@ -166,18 +156,15 @@ __cold static int copier_init(struct processing_module *mod) */ if (copier->gtw_cfg.config_length) { gtw_cfg_size = copier->gtw_cfg.config_length << 2; - gtw_cfg = rmalloc(SOF_MEM_FLAG_USER, - gtw_cfg_size); - if (!gtw_cfg) { - ret = -ENOMEM; - goto error_cd; - } + gtw_cfg = mod_alloc(mod, gtw_cfg_size); + if (!gtw_cfg) + return -ENOMEM; ret = memcpy_s(gtw_cfg, gtw_cfg_size, &copier->gtw_cfg.config_data, gtw_cfg_size); if (ret) { comp_err(dev, "Unable to copy gateway config from copier blob"); - goto error; + return ret; } cd->gtw_cfg = gtw_cfg; @@ -191,8 +178,7 @@ __cold static int copier_init(struct processing_module *mod) IPC_COMP_IGNORE_REMOTE); if (!ipc_pipe) { comp_err(dev, "pipeline %d is not existed", config->pipeline_id); - ret = -EPIPE; - goto error; + return -EPIPE; } dev->pipeline = ipc_pipe->pipeline; @@ -205,18 +191,18 @@ __cold static int copier_init(struct processing_module *mod) switch (node_id.f.dma_type) { case ipc4_hda_host_output_class: case ipc4_hda_host_input_class: - ret = copier_host_create(dev, cd, copier, ipc_pipe->pipeline); + ret = copier_host_create(mod, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create host"); - goto error; + return ret; } #if CONFIG_INTEL_ADSP_MIC_PRIVACY if (cd->direction == SOF_IPC_STREAM_CAPTURE && node_id.f.dma_type == ipc4_hda_host_output_class) { - ret = mic_privacy_configure(dev, cd); + ret = mic_privacy_configure(mod, cd); if (ret < 0) { comp_err(dev, "unable to configure mic privacy"); - goto error; + return ret; } } #endif @@ -231,14 +217,14 @@ __cold static int copier_init(struct processing_module *mod) ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create dai"); - goto error; + return ret; } #if CONFIG_INTEL_ADSP_MIC_PRIVACY if (cd->direction == SOF_IPC_STREAM_CAPTURE) { - ret = mic_privacy_configure(dev, cd); + ret = mic_privacy_configure(mod, cd); if (ret < 0) { comp_err(dev, "unable to configure mic privacy"); - goto error; + return ret; } } #endif @@ -246,17 +232,16 @@ __cold static int copier_init(struct processing_module *mod) #if CONFIG_IPC4_GATEWAY case ipc4_ipc_output_class: case ipc4_ipc_input_class: - ret = copier_ipcgtw_create(dev, cd, copier, ipc_pipe->pipeline); + ret = copier_ipcgtw_create(mod, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create IPC gateway"); - goto error; + return ret; } break; #endif default: comp_err(dev, "unsupported dma type %x", (uint32_t)node_id.f.dma_type); - ret = -EINVAL; - goto error; + return -EINVAL; }; dev->direction_set = true; @@ -270,11 +255,6 @@ __cold static int copier_init(struct processing_module *mod) dev->direction = cd->direction; dev->state = COMP_STATE_READY; return 0; -error: - rfree(gtw_cfg); -error_cd: - rfree(cd); - return ret; } __cold static int copier_free(struct processing_module *mod) @@ -303,10 +283,6 @@ __cold static int copier_free(struct processing_module *mod) break; } - if (cd) - rfree(cd->gtw_cfg); - rfree(cd); - return 0; } diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index 8315ad4535e2..1fd7f4578aa0 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -131,11 +131,11 @@ __cold static int init_pipeline_reg(struct comp_dev *dev) * Sof host component can support this case so copier reuses host * component to support host gateway. */ -__cold int copier_host_create(struct comp_dev *dev, struct copier_data *cd, +__cold int copier_host_create(struct processing_module *mod, struct copier_data *cd, const struct ipc4_copier_module_cfg *copier_cfg, struct pipeline *pipeline) { - struct processing_module *mod = comp_mod(dev); + struct comp_dev *dev = mod->dev; struct comp_ipc_config *config = &dev->ipc_config; struct ipc_config_host ipc_host; struct host_data *hd; @@ -177,16 +177,17 @@ __cold int copier_host_create(struct comp_dev *dev, struct copier_data *cd, ipc_host.dma_buffer_size = copier_cfg->gtw_cfg.dma_buffer_size; ipc_host.feature_mask = copier_cfg->copier_feature_mask; - hd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*hd)); + hd = mod_zalloc(mod, sizeof(*hd)); if (!hd) return -ENOMEM; ret = host_common_new(hd, dev, &ipc_host, config->id); if (ret < 0) { comp_err(dev, "copier: host new failed with exit"); - goto e_data; + return ret; } #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION + /* NOTE: Should use goto e_conv this #if section, not direct return */ /* Size of a configuration without optional parameters. */ const uint32_t basic_size = sizeof(*copier_cfg) + (copier_cfg->gtw_cfg.config_length - 1) * sizeof(uint32_t); @@ -248,8 +249,6 @@ __cold int copier_host_create(struct comp_dev *dev, struct copier_data *cd, e_conv: host_common_free(hd); -e_data: - rfree(hd); return ret; } @@ -263,7 +262,6 @@ __cold void copier_host_free(struct copier_data *cd) delete_from_fpi_sync_group(cd->hd); #endif host_common_free(cd->hd); - rfree(cd->hd); } /* This is called by DMA driver every time when DMA completes its current diff --git a/src/audio/copier/copier_ipcgtw.c b/src/audio/copier/copier_ipcgtw.c index ea518b5e12f2..28d407b228c9 100644 --- a/src/audio/copier/copier_ipcgtw.c +++ b/src/audio/copier/copier_ipcgtw.c @@ -2,6 +2,7 @@ // // Copyright 2023 Intel Corporation. All rights reserved. +#include #include #include #include @@ -207,15 +208,15 @@ void copier_ipcgtw_reset(struct comp_dev *dev) } } -__cold int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, +__cold int copier_ipcgtw_create(struct processing_module *mod, struct copier_data *cd, const struct ipc4_copier_module_cfg *copier, struct pipeline *pipeline) { + struct comp_dev *dev = mod->dev; struct comp_ipc_config *config = &dev->ipc_config; struct ipcgtw_data *ipcgtw_data; const struct ipc4_copier_gateway_cfg *gtw_cfg; const struct ipc4_ipc_gateway_config_blob *blob; - int ret; assert_can_be_cold(); @@ -231,7 +232,7 @@ __cold int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, config->type = SOF_COMP_HOST; cd->gtw_type = ipc4_gtw_host; - ipcgtw_data = rzalloc(SOF_MEM_FLAG_USER, sizeof(*ipcgtw_data)); + ipcgtw_data = mod_zalloc(mod, sizeof(*ipcgtw_data)); if (!ipcgtw_data) return -ENOMEM; @@ -254,8 +255,7 @@ __cold int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, if (!cd->converter[IPC4_COPIER_GATEWAY_PIN]) { comp_err(dev, "failed to get converter for IPC gateway, dir %d", cd->direction); - ret = -EINVAL; - goto e_ipcgtw; + return -EINVAL; } if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { @@ -271,10 +271,6 @@ __cold int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, cd->endpoint_num++; return 0; - -e_ipcgtw: - rfree(ipcgtw_data); - return ret; } __cold void copier_ipcgtw_free(struct copier_data *cd) @@ -282,5 +278,4 @@ __cold void copier_ipcgtw_free(struct copier_data *cd) assert_can_be_cold(); list_item_del(&cd->ipcgtw_data->item); - rfree(cd->ipcgtw_data); } diff --git a/src/audio/copier/host_copier.h b/src/audio/copier/host_copier.h index e8f5fc58ca91..79d8d55f7fec 100644 --- a/src/audio/copier/host_copier.h +++ b/src/audio/copier/host_copier.h @@ -129,7 +129,7 @@ static inline int host_common_copy(struct host_data *hd, struct comp_dev *dev, c } void host_common_update(struct host_data *hd, struct comp_dev *dev, uint32_t bytes); void host_common_one_shot(struct host_data *hd, uint32_t bytes); -int copier_host_create(struct comp_dev *dev, struct copier_data *cd, +int copier_host_create(struct processing_module *mod, struct copier_data *cd, const struct ipc4_copier_module_cfg *copier_cfg, struct pipeline *pipeline); void copier_host_free(struct copier_data *cd); diff --git a/src/audio/copier/ipcgtw_copier.h b/src/audio/copier/ipcgtw_copier.h index ef42ede75ddd..b100ef47fe87 100644 --- a/src/audio/copier/ipcgtw_copier.h +++ b/src/audio/copier/ipcgtw_copier.h @@ -95,7 +95,7 @@ struct ipc4_ipc_gateway_cmd_data_reply { int copier_ipcgtw_process(const struct ipc4_ipcgtw_cmd *cmd, void *reply_payload, uint32_t *reply_payload_size); -int copier_ipcgtw_create(struct comp_dev *dev, struct copier_data *cd, +int copier_ipcgtw_create(struct processing_module *mod, struct copier_data *cd, const struct ipc4_copier_module_cfg *copier, struct pipeline *pipeline); #if CONFIG_IPC4_GATEWAY From 43b1f8350109e1b80e005257a7e976f3a250abd4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 5 Sep 2025 11:43:12 +0300 Subject: [PATCH 10/56] audio: copier: Fix resource leak from DMA sync code error handling The code within #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION should free host_common resources in case of failure. The commit fixes the issue. Signed-off-by: Jyri Sarha --- src/audio/copier/copier_host.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/audio/copier/copier_host.c b/src/audio/copier/copier_host.c index 1fd7f4578aa0..1216eedf71f2 100644 --- a/src/audio/copier/copier_host.c +++ b/src/audio/copier/copier_host.c @@ -187,7 +187,6 @@ __cold int copier_host_create(struct processing_module *mod, struct copier_data return ret; } #if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION - /* NOTE: Should use goto e_conv this #if section, not direct return */ /* Size of a configuration without optional parameters. */ const uint32_t basic_size = sizeof(*copier_cfg) + (copier_cfg->gtw_cfg.config_length - 1) * sizeof(uint32_t); @@ -206,14 +205,16 @@ __cold int copier_host_create(struct processing_module *mod, struct copier_data if (value_ptr) { struct ipc4_copier_sync_group *sync_group; - if (value_size != sizeof(struct ipc4_copier_sync_group)) - return -EINVAL; + if (value_size != sizeof(struct ipc4_copier_sync_group)) { + ret = -EINVAL; + goto e_conv; + } sync_group = (struct ipc4_copier_sync_group *)((void *)value_ptr); ret = add_to_fpi_sync_group(dev, hd, sync_group); if (ret < 0) - return ret; + goto e_conv; } } #endif From 8851c36957c43172613a957705e960f182ee4889 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 11 Aug 2025 18:21:35 +0300 Subject: [PATCH 11/56] Audio: crossover: All memory allocations through module API Allocate all memory through module API mod_alloc() and friends and remove all redundant rfree() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/crossover/crossover.c | 53 ++++++++----------- src/audio/multiband_drc/multiband_drc.c | 2 +- .../module/crossover/crossover_common.h | 18 ++++--- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/audio/crossover/crossover.c b/src/audio/crossover/crossover.c index d1c0eefa4d7f..cd820a2d1d50 100644 --- a/src/audio/crossover/crossover.c +++ b/src/audio/crossover/crossover.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -47,12 +46,13 @@ DECLARE_TR_CTX(crossover_tr, SOF_UUID(crossover_uuid), LOG_LEVEL_INFO); * \brief Reset the state (coefficients and delay) of the crossover filter * across all channels */ -static void crossover_reset_state(struct comp_data *cd) +static void crossover_reset_state(struct processing_module *mod, + struct comp_data *cd) { int i; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - crossover_reset_state_ch(&cd->state[i]); + crossover_reset_state_ch(mod, &cd->state[i]); } /** @@ -156,7 +156,8 @@ static int crossover_assign_sinks(struct processing_module *mod, * high/low pass filter. * \param[out] lr4 initialized struct */ -static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, +static int crossover_init_coef_lr4(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct iir_state_df1 *lr4) { int ret; @@ -169,8 +170,7 @@ static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, * in series due to identity. To maintain the structure of * iir_state_df1, it requires two copies of coefficients in a row. */ - lr4->coef = rzalloc(SOF_MEM_FLAG_USER, - sizeof(struct sof_eq_iir_biquad) * 2); + lr4->coef = mod_zalloc(mod, sizeof(struct sof_eq_iir_biquad) * 2); if (!lr4->coef) return -ENOMEM; @@ -189,8 +189,7 @@ static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, * delay[0..1] -> state for first biquad * delay[2..3] -> state for second biquad */ - lr4->delay = rzalloc(SOF_MEM_FLAG_USER, - sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); + lr4->delay = mod_zalloc(mod, sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); if (!lr4->delay) return -ENOMEM; @@ -203,7 +202,8 @@ static int crossover_init_coef_lr4(struct sof_eq_iir_biquad *coef, /** * \brief Initializes the crossover coefficients for one channel */ -int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, +int crossover_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct crossover_state *ch_state, int32_t num_sinks) { @@ -214,12 +214,12 @@ int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, for (i = 0; i < num_lr4s; i++) { /* Get the low pass coefficients */ - err = crossover_init_coef_lr4(&coef[j], + err = crossover_init_coef_lr4(mod, &coef[j], &ch_state->lowpass[i]); if (err < 0) return -EINVAL; /* Get the high pass coefficients */ - err = crossover_init_coef_lr4(&coef[j + 1], + err = crossover_init_coef_lr4(mod, &coef[j + 1], &ch_state->highpass[i]); if (err < 0) return -EINVAL; @@ -259,13 +259,13 @@ static int crossover_init_coef(struct processing_module *mod, int nch) /* Collect the coef array and assign it to every channel */ crossover = config->coef; for (ch = 0; ch < nch; ch++) { - err = crossover_init_coef_ch(crossover, &cd->state[ch], + err = crossover_init_coef_ch(mod, crossover, &cd->state[ch], config->num_sinks); /* Free all previously allocated blocks in case of an error */ if (err < 0) { comp_err(mod->dev, "crossover_init_coef(), could not assign coefficients to ch %d", ch); - crossover_reset_state(cd); + crossover_reset_state(mod, cd); return err; } } @@ -282,7 +282,7 @@ static int crossover_setup(struct processing_module *mod, int nch) int ret = 0; /* Reset any previous state */ - crossover_reset_state(cd); + crossover_reset_state(mod, cd); /* Assign LR4 coefficients from config */ ret = crossover_init_coef(mod, nch); @@ -312,40 +312,34 @@ static int crossover_init(struct processing_module *mod) return -ENOMEM; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } /* Get configuration data and reset Crossover state */ ret = comp_init_data_blob(cd->model_handler, bs, ipc_crossover->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto cd_fail; + return ret; } ret = crossover_output_pin_init(mod); if (ret < 0) { comp_err(dev, "crossover_init_output_pins() failed."); - goto cd_fail; + return ret; } - crossover_reset_state(cd); + crossover_reset_state(mod, cd); return 0; - -cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); - return ret; } /** @@ -357,11 +351,8 @@ static int crossover_free(struct processing_module *mod) comp_info(mod->dev, "crossover_free()"); - comp_data_blob_handler_free(cd->model_handler); - - crossover_reset_state(cd); + crossover_reset_state(mod, cd); - rfree(cd); return 0; } @@ -616,7 +607,7 @@ static int crossover_reset(struct processing_module *mod) comp_info(mod->dev, "crossover_reset()"); - crossover_reset_state(cd); + crossover_reset_state(mod, cd); cd->crossover_process = NULL; cd->crossover_split = NULL; diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index cca2850cfe12..ad11aab4d270 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -142,7 +142,7 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Crossover: collect the coef array and assign it to every channel */ crossover = config->crossover_coef; for (ch = 0; ch < nch; ch++) { - ret = crossover_init_coef_ch(crossover, &state->crossover[ch], + ret = crossover_init_coef_ch(mod, crossover, &state->crossover[ch], config->num_bands); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { diff --git a/src/include/module/crossover/crossover_common.h b/src/include/module/crossover/crossover_common.h index 28c6e8aa7775..d238ff7c1008 100644 --- a/src/include/module/crossover/crossover_common.h +++ b/src/include/module/crossover/crossover_common.h @@ -8,6 +8,7 @@ #ifndef __SOF_CROSSOVER_COMMON_H__ #define __SOF_CROSSOVER_COMMON_H__ +#include #include #include @@ -39,17 +40,19 @@ typedef void (*crossover_split)(int32_t in, int32_t out[], extern const crossover_split crossover_split_fnmap[]; /* crossover init function */ -int crossover_init_coef_ch(struct sof_eq_iir_biquad *coef, +int crossover_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct crossover_state *ch_state, int32_t num_sinks); /** * \brief Reset the state of an LR4 filter. */ -static inline void crossover_reset_state_lr4(struct iir_state_df1 *lr4) +static inline void crossover_reset_state_lr4(struct processing_module *mod, + struct iir_state_df1 *lr4) { - rfree(lr4->coef); - rfree(lr4->delay); + mod_free(mod, lr4->coef); + mod_free(mod, lr4->delay); lr4->coef = NULL; lr4->delay = NULL; @@ -59,13 +62,14 @@ static inline void crossover_reset_state_lr4(struct iir_state_df1 *lr4) * \brief Reset the state (coefficients and delay) of the crossover filter * of a single channel. */ -static inline void crossover_reset_state_ch(struct crossover_state *ch_state) +static inline void crossover_reset_state_ch(struct processing_module *mod, + struct crossover_state *ch_state) { int i; for (i = 0; i < CROSSOVER_MAX_LR4; i++) { - crossover_reset_state_lr4(&ch_state->lowpass[i]); - crossover_reset_state_lr4(&ch_state->highpass[i]); + crossover_reset_state_lr4(mod, &ch_state->lowpass[i]); + crossover_reset_state_lr4(mod, &ch_state->highpass[i]); } } From 680c025e38312a9607dee05e9fa9589256f5220c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 13 Aug 2025 16:10:33 +0300 Subject: [PATCH 12/56] Audio: multiband_drc: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/multiband_drc/multiband_drc.c | 61 ++++++++++--------------- src/audio/multiband_drc/multiband_drc.h | 7 +-- 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index ad11aab4d270..0426ab00e852 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -42,17 +42,18 @@ SOF_DEFINE_REG_UUID(multiband_drc); DECLARE_TR_CTX(multiband_drc_tr, SOF_UUID(multiband_drc_uuid), LOG_LEVEL_INFO); /* Called from multiband_drc_setup() from multiband_drc_process(), so cannot be __cold */ -static void multiband_drc_reset_state(struct multiband_drc_state *state) +static void multiband_drc_reset_state(struct processing_module *mod, + struct multiband_drc_state *state) { int i; /* Reset emphasis eq-iir state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - multiband_drc_iir_reset_state_ch(&state->emphasis[i]); + multiband_drc_iir_reset_state_ch(mod, &state->emphasis[i]); /* Reset crossover state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - crossover_reset_state_ch(&state->crossover[i]); + crossover_reset_state_ch(mod, &state->crossover[i]); /* Reset drc kernel state */ for (i = 0; i < SOF_MULTIBAND_DRC_MAX_BANDS; i++) @@ -60,10 +61,11 @@ static void multiband_drc_reset_state(struct multiband_drc_state *state) /* Reset deemphasis eq-iir state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) - multiband_drc_iir_reset_state_ch(&state->deemphasis[i]); + multiband_drc_iir_reset_state_ch(mod, &state->deemphasis[i]); } -static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, +static int multiband_drc_eq_init_coef_ch(struct processing_module *mod, + struct sof_eq_iir_biquad *coef, struct iir_state_df1 *eq) { int ret; @@ -72,8 +74,7 @@ static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, if (SOF_EMP_DEEMP_BIQUADS != SOF_IIR_DF1_4TH_NUM_BIQUADS) return -EINVAL; - eq->coef = rzalloc(SOF_MEM_FLAG_USER, - sizeof(struct sof_eq_iir_biquad) * SOF_EMP_DEEMP_BIQUADS); + eq->coef = mod_zalloc(mod, sizeof(struct sof_eq_iir_biquad) * SOF_EMP_DEEMP_BIQUADS); if (!eq->coef) return -ENOMEM; @@ -86,8 +87,7 @@ static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, * delay[0..1] -> state for first biquad * delay[2..3] -> state for second biquad */ - eq->delay = rzalloc(SOF_MEM_FLAG_USER, - sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); + eq->delay = mod_zalloc(mod, sizeof(uint64_t) * CROSSOVER_NUM_DELAYS_LR4); if (!eq->delay) return -ENOMEM; @@ -148,7 +148,7 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", ch); - goto err; + return ret; } } @@ -157,12 +157,12 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Emphasis: collect the coef array and assign it to every channel */ emphasis = config->emp_coef; for (ch = 0; ch < nch; ch++) { - ret = multiband_drc_eq_init_coef_ch(emphasis, &state->emphasis[ch]); + ret = multiband_drc_eq_init_coef_ch(mod, emphasis, &state->emphasis[ch]); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", ch); - goto err; + return ret; } } @@ -171,12 +171,12 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u /* Deemphasis: collect the coef array and assign it to every channel */ deemphasis = config->deemp_coef; for (ch = 0; ch < nch; ch++) { - ret = multiband_drc_eq_init_coef_ch(deemphasis, &state->deemphasis[ch]); + ret = multiband_drc_eq_init_coef_ch(mod, deemphasis, &state->deemphasis[ch]); /* Free all previously allocated blocks in case of an error */ if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", ch); - goto err; + return ret; } } @@ -188,22 +188,18 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not init pre delay buffers"); - goto err; + return ret; } ret = drc_set_pre_delay_time(&state->drc[i], cd->config->drc_coef[i].pre_delay_time, rate); if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not set pre delay time"); - goto err; + return ret; } } return 0; - -err: - multiband_drc_reset_state(state); - return ret; } /* Called from multiband_drc_process(), so cannot be __cold */ @@ -213,7 +209,7 @@ static int multiband_drc_setup(struct processing_module *mod, int16_t channels, struct multiband_drc_comp_data *cd = module_get_private_data(mod); /* Reset any previous state */ - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); /* Setup Crossover, Emphasis EQ, Deemphasis EQ, and DRC */ return multiband_drc_init_coef(mod, channels, rate); @@ -243,7 +239,7 @@ static int multiband_drc_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -258,40 +254,29 @@ static int multiband_drc_init(struct processing_module *mod) multiband_drc_process_enable(&cd->process_enabled); /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } /* Get configuration data and reset DRC state */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto cd_fail; + return ret; } - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); return 0; - -cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); - return ret; } __cold static int multiband_drc_free(struct processing_module *mod) { - struct multiband_drc_comp_data *cd = module_get_private_data(mod); - assert_can_be_cold(); comp_info(mod->dev, "multiband_drc_free()"); - comp_data_blob_handler_free(cd->model_handler); - - rfree(cd); return 0; } @@ -415,7 +400,7 @@ static int multiband_drc_reset(struct processing_module *mod) comp_info(mod->dev, "multiband_drc_reset()"); - multiband_drc_reset_state(&cd->state); + multiband_drc_reset_state(mod, &cd->state); cd->source_format = 0; cd->multiband_drc_func = NULL; diff --git a/src/audio/multiband_drc/multiband_drc.h b/src/audio/multiband_drc/multiband_drc.h index 20f939877209..6a99fda55cef 100644 --- a/src/audio/multiband_drc/multiband_drc.h +++ b/src/audio/multiband_drc/multiband_drc.h @@ -89,10 +89,11 @@ static inline multiband_drc_func multiband_drc_find_proc_func_pass(enum sof_ipc_ return NULL; } -static inline void multiband_drc_iir_reset_state_ch(struct iir_state_df1 *iir) +static inline void multiband_drc_iir_reset_state_ch(struct processing_module *mod, + struct iir_state_df1 *iir) { - rfree(iir->coef); - rfree(iir->delay); + mod_free(mod, iir->coef); + mod_free(mod, iir->delay); iir->coef = NULL; iir->delay = NULL; From 1e9f4d40894868e4016fd32ffcf599d2e0226134 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 13 Aug 2025 17:02:48 +0300 Subject: [PATCH 13/56] Audio: DRC: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/drc/drc.c | 43 ++++++++++--------------- src/audio/drc/drc_algorithm.h | 5 +-- src/audio/multiband_drc/multiband_drc.c | 5 +-- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/audio/drc/drc.c b/src/audio/drc/drc.c index 6219f54c8842..0cc8fdf0922b 100644 --- a/src/audio/drc/drc.c +++ b/src/audio/drc/drc.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -43,11 +42,11 @@ extern const struct sof_uuid drc_uuid; extern struct tr_ctx drc_tr; /* Called from drc_setup() from drc_process(), so cannot be __cold */ -void drc_reset_state(struct drc_state *state) +void drc_reset_state(struct processing_module *mod, struct drc_state *state) { int i; - rfree(state->pre_delay_buffers[0]); + mod_free(mod, state->pre_delay_buffers[0]); for (i = 0; i < PLATFORM_MAX_CHANNELS; ++i) { state->pre_delay_buffers[i] = NULL; } @@ -67,7 +66,8 @@ void drc_reset_state(struct drc_state *state) state->max_attack_compression_diff_db = INT32_MIN; } -int drc_init_pre_delay_buffers(struct drc_state *state, +int drc_init_pre_delay_buffers(struct processing_module *mod, + struct drc_state *state, size_t sample_bytes, int channels) { @@ -76,7 +76,7 @@ int drc_init_pre_delay_buffers(struct drc_state *state, int i; /* Allocate pre-delay (lookahead) buffers */ - state->pre_delay_buffers[0] = rballoc(SOF_MEM_FLAG_USER, bytes_total); + state->pre_delay_buffers[0] = mod_balloc(mod, bytes_total); if (!state->pre_delay_buffers[0]) return -ENOMEM; @@ -121,16 +121,17 @@ int drc_set_pre_delay_time(struct drc_state *state, } /* Called from drc_process(), so cannot be __cold */ -static int drc_setup(struct drc_comp_data *cd, uint16_t channels, uint32_t rate) +static int drc_setup(struct processing_module *mod, uint16_t channels, uint32_t rate) { + struct drc_comp_data *cd = module_get_private_data(mod); uint32_t sample_bytes = get_sample_bytes(cd->source_format); int ret; /* Reset any previous state */ - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); /* Allocate pre-delay buffers */ - ret = drc_init_pre_delay_buffers(&cd->state, (size_t)sample_bytes, (int)channels); + ret = drc_init_pre_delay_buffers(mod, &cd->state, (size_t)sample_bytes, (int)channels); if (ret < 0) return ret; @@ -164,28 +165,27 @@ __cold static int drc_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } /* Get configuration data and reset DRC state */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto cd_fail; + return ret; } - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); /* Initialize DRC to enabled. If defined by topology, a control may set * enabled to false before prepare() or during streaming with the switch @@ -194,21 +194,12 @@ __cold static int drc_init(struct processing_module *mod) cd->enabled = true; cd->enable_switch = true; return 0; - -cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); - return ret; } __cold static int drc_free(struct processing_module *mod) { - struct drc_comp_data *cd = module_get_private_data(mod); - assert_can_be_cold(); - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); return 0; } @@ -284,7 +275,7 @@ static int drc_process(struct processing_module *mod, /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = drc_setup(cd, audio_stream_get_channels(source), + ret = drc_setup(mod, audio_stream_get_channels(source), audio_stream_get_rate(source)); if (ret < 0) { comp_err(dev, "drc_copy(), failed DRC setup"); @@ -370,7 +361,7 @@ static int drc_prepare(struct processing_module *mod, comp_info(dev, "drc_prepare(), source_format=%d", cd->source_format); cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); if (cd->config) { - ret = drc_setup(cd, channels, rate); + ret = drc_setup(mod, channels, rate); if (ret < 0) { comp_err(dev, "drc_prepare() error: drc_setup failed."); return ret; @@ -403,7 +394,7 @@ static int drc_reset(struct processing_module *mod) { struct drc_comp_data *cd = module_get_private_data(mod); - drc_reset_state(&cd->state); + drc_reset_state(mod, &cd->state); return 0; } diff --git a/src/audio/drc/drc_algorithm.h b/src/audio/drc/drc_algorithm.h index c0a942b09622..8d9d759eb3a8 100644 --- a/src/audio/drc/drc_algorithm.h +++ b/src/audio/drc/drc_algorithm.h @@ -14,10 +14,11 @@ #include "drc.h" /* drc reset function */ -void drc_reset_state(struct drc_state *state); +void drc_reset_state(struct processing_module *mod, struct drc_state *state); /* drc init functions */ -int drc_init_pre_delay_buffers(struct drc_state *state, +int drc_init_pre_delay_buffers(struct processing_module *mod, + struct drc_state *state, size_t sample_bytes, int channels); int drc_set_pre_delay_time(struct drc_state *state, diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index 0426ab00e852..e1c796b5440b 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -57,7 +57,7 @@ static void multiband_drc_reset_state(struct processing_module *mod, /* Reset drc kernel state */ for (i = 0; i < SOF_MULTIBAND_DRC_MAX_BANDS; i++) - drc_reset_state(&state->drc[i]); + drc_reset_state(mod, &state->drc[i]); /* Reset deemphasis eq-iir state */ for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -184,7 +184,8 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u for (i = 0; i < num_bands; i++) { comp_info(dev, "multiband_drc_init_coef(), initializing drc band %d", i); - ret = drc_init_pre_delay_buffers(&state->drc[i], (size_t)sample_bytes, (int)nch); + ret = drc_init_pre_delay_buffers(mod, &state->drc[i], + (size_t)sample_bytes, (int)nch); if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not init pre delay buffers"); From 67a7749b3a15dffe5bbcdaadd8c01946af6d7fbd Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 19 Aug 2025 22:54:05 +0300 Subject: [PATCH 14/56] Audio: FIR: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/eq_fir/eq_fir.c | 44 +++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index ed946157ed4c..22e1653df3b3 100644 --- a/src/audio/eq_fir/eq_fir.c +++ b/src/audio/eq_fir/eq_fir.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -58,15 +57,16 @@ static void eq_fir_passthrough(struct fir_state_32x16 fir[], audio_stream_copy(source, 0, sink, 0, frames * audio_stream_get_channels(source)); } -static void eq_fir_free_delaylines(struct comp_data *cd) +static void eq_fir_free_delaylines(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); struct fir_state_32x16 *fir = cd->fir; int i = 0; /* Free the common buffer for all EQs and point then * each FIR channel delay line to NULL. */ - rfree(cd->fir_delay); + mod_free(mod, cd->fir_delay); cd->fir_delay = NULL; cd->fir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -198,12 +198,13 @@ static void eq_fir_init_delay(struct fir_state_32x16 *fir, } } -static int eq_fir_setup(struct comp_dev *dev, struct comp_data *cd, int nch) +static int eq_fir_setup(struct processing_module *mod, struct comp_data *cd, int nch) { + struct comp_dev *dev = mod->dev; int delay_size; /* Free existing FIR channels data if it was allocated */ - eq_fir_free_delaylines(cd); + eq_fir_free_delaylines(mod); /* Update number of channels */ cd->nch = nch; @@ -220,7 +221,7 @@ static int eq_fir_setup(struct comp_dev *dev, struct comp_data *cd, int nch) return 0; /* Allocate all FIR channels data in a big chunk and clear it */ - cd->fir_delay = rballoc(SOF_MEM_FLAG_USER, delay_size); + cd->fir_delay = mod_balloc(mod, delay_size); if (!cd->fir_delay) { comp_err(dev, "eq_fir_setup(), delay allocation failed for size %d", delay_size); return -ENOMEM; @@ -264,7 +265,7 @@ static int eq_fir_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -274,11 +275,10 @@ static int eq_fir_init(struct processing_module *mod) cd->nch = -1; /* component model data handler */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + comp_err(dev, "mod_data_blob_handler_new() failed."); + return -ENOMEM; } md->private = cd; @@ -289,32 +289,18 @@ static int eq_fir_init(struct processing_module *mod) ret = comp_init_data_blob(cd->model_handler, bs, cfg->init_data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto err_init; + return ret; } for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) fir_reset(&cd->fir[i]); return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); -err: - rfree(cd); - return ret; } static int eq_fir_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "eq_fir_free()"); - - eq_fir_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); - - rfree(cd); - return 0; } @@ -360,7 +346,7 @@ static int eq_fir_process(struct processing_module *mod, /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = eq_fir_setup(mod->dev, cd, audio_stream_get_channels(source)); + ret = eq_fir_setup(mod, cd, audio_stream_get_channels(source)); if (ret < 0) { comp_err(mod->dev, "eq_fir_process(), failed FIR setup"); return ret; @@ -437,7 +423,7 @@ static int eq_fir_prepare(struct processing_module *mod, cd->eq_fir_func = eq_fir_passthrough; cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); if (cd->config) { - ret = eq_fir_setup(dev, cd, channels); + ret = eq_fir_setup(mod, cd, channels); if (ret < 0) comp_err(dev, "eq_fir_setup failed."); else if (cd->fir_delay_size) @@ -464,7 +450,7 @@ static int eq_fir_reset(struct processing_module *mod) comp_data_blob_set_validator(cd->model_handler, NULL); - eq_fir_free_delaylines(cd); + eq_fir_free_delaylines(mod); cd->eq_fir_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) From 07ee21b0cd9f63c2a329139408f3762303f54f44 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 19 Aug 2025 23:43:48 +0300 Subject: [PATCH 15/56] Audio: IIR: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/eq_iir/eq_iir.c | 25 +++++++------------------ src/audio/eq_iir/eq_iir.h | 2 +- src/audio/eq_iir/eq_iir_generic.c | 10 +++++----- src/audio/eq_iir/eq_iir_ipc3.c | 1 - src/audio/eq_iir/eq_iir_ipc4.c | 1 - 5 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 4b70fe355c77..c26c166fb276 100644 --- a/src/audio/eq_iir/eq_iir.c +++ b/src/audio/eq_iir/eq_iir.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -60,18 +59,17 @@ static int eq_iir_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* component model data handler */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + comp_err(dev, "mod_data_blob_handler_new() failed."); + return -ENOMEM; } /* Allocate and make a copy of the coefficients blob and reset IIR. If @@ -80,27 +78,18 @@ static int eq_iir_init(struct processing_module *mod) ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed with error: %d", ret); - comp_data_blob_handler_free(cd->model_handler); - goto err; + return ret; } for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) iir_reset_df1(&cd->iir[i]); return 0; -err: - rfree(cd); - return ret; } static int eq_iir_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - - eq_iir_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); - - rfree(cd); + eq_iir_free_delaylines(mod); return 0; } @@ -234,7 +223,7 @@ static int eq_iir_reset(struct processing_module *mod) struct comp_data *cd = module_get_private_data(mod); int i; - eq_iir_free_delaylines(cd); + eq_iir_free_delaylines(mod); cd->eq_iir_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) diff --git a/src/audio/eq_iir/eq_iir.h b/src/audio/eq_iir/eq_iir.h index 7b6b6c247574..08462049f7b5 100644 --- a/src/audio/eq_iir/eq_iir.h +++ b/src/audio/eq_iir/eq_iir.h @@ -71,5 +71,5 @@ void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsou int eq_iir_setup(struct processing_module *mod, int nch); -void eq_iir_free_delaylines(struct comp_data *cd); +void eq_iir_free_delaylines(struct processing_module *mod); #endif /* __SOF_AUDIO_EQ_IIR_EQ_IIR_H__ */ diff --git a/src/audio/eq_iir/eq_iir_generic.c b/src/audio/eq_iir/eq_iir_generic.c index 4e7688b85004..66024c909852 100644 --- a/src/audio/eq_iir/eq_iir_generic.c +++ b/src/audio/eq_iir/eq_iir_generic.c @@ -285,15 +285,16 @@ static void eq_iir_init_delay(struct iir_state_df1 *iir, } } -void eq_iir_free_delaylines(struct comp_data *cd) +void eq_iir_free_delaylines(struct processing_module *mod) { + struct comp_data *cd = module_get_private_data(mod); struct iir_state_df1 *iir = cd->iir; int i = 0; /* Free the common buffer for all EQs and point then * each IIR channel delay line to NULL. */ - rfree(cd->iir_delay); + mod_free(mod, cd->iir_delay); cd->iir_delay = NULL; cd->iir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -315,7 +316,7 @@ int eq_iir_setup(struct processing_module *mod, int nch) int delay_size; /* Free existing IIR channels data if it was allocated */ - eq_iir_free_delaylines(cd); + eq_iir_free_delaylines(mod); /* Set coefficients for each channel EQ from coefficient blob */ delay_size = eq_iir_init_coef(mod, nch); @@ -329,8 +330,7 @@ int eq_iir_setup(struct processing_module *mod, int nch) return 0; /* Allocate all IIR channels data in a big chunk and clear it */ - cd->iir_delay = rzalloc(SOF_MEM_FLAG_USER, - delay_size); + cd->iir_delay = mod_zalloc(mod, delay_size); if (!cd->iir_delay) { comp_err(mod->dev, "eq_iir_setup(), delay allocation fail"); return -ENOMEM; diff --git a/src/audio/eq_iir/eq_iir_ipc3.c b/src/audio/eq_iir/eq_iir_ipc3.c index b8c5536f0d32..1c5019cbfdcc 100644 --- a/src/audio/eq_iir/eq_iir_ipc3.c +++ b/src/audio/eq_iir/eq_iir_ipc3.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/src/audio/eq_iir/eq_iir_ipc4.c b/src/audio/eq_iir/eq_iir_ipc4.c index ece765d3140b..325a371460ab 100644 --- a/src/audio/eq_iir/eq_iir_ipc4.c +++ b/src/audio/eq_iir/eq_iir_ipc4.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include From e0b85f6166216c9ea7cf76c7c68f25f3ea0c6624 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 19 Aug 2025 23:55:10 +0300 Subject: [PATCH 16/56] Audio: Google ctc: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). The change does not touch the google_ctc_audio_processing.h API or its mock implementation, that still uses rballoc() and rfree(). Signed-off-by: Jyri Sarha --- .../google/google_ctc_audio_processing.c | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/audio/google/google_ctc_audio_processing.c b/src/audio/google/google_ctc_audio_processing.c index 4b01feea1efa..5396be3dfdeb 100644 --- a/src/audio/google/google_ctc_audio_processing.c +++ b/src/audio/google/google_ctc_audio_processing.c @@ -245,13 +245,7 @@ static int ctc_free(struct processing_module *mod) comp_info(mod->dev, "ctc_free()"); - if (cd) { - rfree(cd->input); - rfree(cd->output); - GoogleCtcAudioProcessingFree(cd->state); - rfree(cd); - module_set_private_data(mod, NULL); - } + GoogleCtcAudioProcessingFree(cd->state); return 0; } @@ -265,10 +259,9 @@ static int ctc_init(struct processing_module *mod) comp_info(dev, "ctc_init()"); /* Create private component data */ - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { comp_err(dev, "Failed to create component data"); - ctc_free(mod); return -ENOMEM; } @@ -277,23 +270,20 @@ static int ctc_init(struct processing_module *mod) cd->chunk_frames = kChunkFrames; buf_size = cd->chunk_frames * sizeof(cd->input[0]) * kMaxChannels; - cd->input = rballoc(SOF_MEM_FLAG_USER, buf_size); + cd->input = mod_balloc(mod, buf_size); if (!cd->input) { comp_err(dev, "Failed to allocate input buffer"); - ctc_free(mod); return -ENOMEM; } - cd->output = rballoc(SOF_MEM_FLAG_USER, buf_size); + cd->output = mod_balloc(mod, buf_size); if (!cd->output) { comp_err(dev, "Failed to allocate output buffer"); - ctc_free(mod); return -ENOMEM; } - cd->tuning_handler = comp_data_blob_handler_new(dev); + cd->tuning_handler = mod_data_blob_handler_new(mod); if (!cd->tuning_handler) { comp_err(dev, "Failed to create tuning handler"); - ctc_free(mod); return -ENOMEM; } From 042b5a84a168a938e92bb880301840501018ccbb Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 20 Aug 2025 00:12:36 +0300 Subject: [PATCH 17/56] Audio: Google rtc: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The change does not touch the google_rtc_audio_processing.h API or its mock implementation, that still uses rballoc() and rfree(). Signed-off-by: Jyri Sarha --- src/audio/google/google_rtc_audio_processing.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/audio/google/google_rtc_audio_processing.c b/src/audio/google/google_rtc_audio_processing.c index 4e9a55f39516..dcc51c7d4c77 100644 --- a/src/audio/google/google_rtc_audio_processing.c +++ b/src/audio/google/google_rtc_audio_processing.c @@ -512,7 +512,7 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) comp_info(dev, "google_rtc_audio_processing_init()"); /* Create private component data */ - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { ret = -ENOMEM; goto fail; @@ -520,7 +520,7 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) md->private = cd; - cd->tuning_handler = comp_data_blob_handler_new(dev); + cd->tuning_handler = mod_data_blob_handler_new(mod); if (!cd->tuning_handler) { ret = -ENOMEM; goto fail; @@ -585,8 +585,6 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) GoogleRtcAudioProcessingFree(cd->state); } GoogleRtcAudioProcessingDetachMemoryBuffer(); - comp_data_blob_handler_free(cd->tuning_handler); - rfree(cd); } return ret; @@ -601,8 +599,6 @@ static int google_rtc_audio_processing_free(struct processing_module *mod) GoogleRtcAudioProcessingFree(cd->state); cd->state = NULL; GoogleRtcAudioProcessingDetachMemoryBuffer(); - comp_data_blob_handler_free(cd->tuning_handler); - rfree(cd); return 0; } From d378698966d39a9e0919df6d6e78f68562e35ae4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 20 Aug 2025 00:20:43 +0300 Subject: [PATCH 18/56] Audio: igo_nr: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/igo_nr/igo_nr.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index fd6d900eaf82..206b7a05bebf 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -421,7 +420,7 @@ static int igo_nr_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -429,60 +428,40 @@ static int igo_nr_init(struct processing_module *mod) ret = IgoLibGetInfo(&cd->igo_lib_info); if (ret != IGO_RET_OK) { comp_err(dev, "IgoLibGetInfo() Failed."); - ret = -EINVAL; - goto cd_fail; + return -EINVAL; } - cd->p_handle = rballoc(SOF_MEM_FLAG_USER, cd->igo_lib_info.handle_size); + cd->p_handle = mod_balloc(mod, cd->igo_lib_info.handle_size); if (!cd->p_handle) { - comp_err(dev, "igo_handle memory rballoc error for size %d", + comp_err(dev, "igo_handle memory mod_balloc error for size %d", cd->igo_lib_info.handle_size); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { - comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail2; + comp_err(dev, "mod_data_blob_handler_new() failed."); + return -ENOMEM; } /* Get configuration data */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - ret = -ENOMEM; - goto cd_fail3; + return -ENOMEM; } /* update downstream (playback) or upstream (capture) buffer parameters */ mod->verify_params_flags = BUFF_PARAMS_RATE; comp_info(dev, "igo_nr created"); return 0; - -cd_fail3: - comp_data_blob_handler_free(cd->model_handler); - -cd_fail2: - rfree(cd->p_handle); - -cd_fail: - rfree(cd); - return ret; } static int igo_nr_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "igo_nr_free()"); - comp_data_blob_handler_free(cd->model_handler); - - rfree(cd->p_handle); - rfree(cd); return 0; } From 148ed35bdcf2b23ac6b8c0ab5e69deac5bf9dcfc Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 21 Aug 2025 22:32:55 +0300 Subject: [PATCH 19/56] Math: Make mod_alloc() versions of all heap using functions Make mod_alloc() versions of all heap using functions. The new functions are simple copy-paste versions of the original, just using mod_alloc() and friend instead of rmalloc() friends. The idea is to get rid off the original versions once all the modules are converted to module API heap usage and the cmocka math tests have been fixed to work with mod_alloc() versions. Signed-off-by: Jyri Sarha --- src/include/sof/math/auditory.h | 2 + src/include/sof/math/dct.h | 1 + src/include/sof/math/fft.h | 4 + src/include/sof/math/matrix.h | 15 ++++ src/math/auditory/auditory.c | 126 ++++++++++++++++++++++++++++++++ src/math/dct.c | 48 ++++++++++++ src/math/fft/fft_common.c | 59 +++++++++++++++ 7 files changed, 255 insertions(+) diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index eef073092e22..0e082335f764 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -77,6 +77,8 @@ int16_t psy_mel_to_hz(int16_t mel); * \return Zero when success, otherwise error code. */ int psy_get_mel_filterbank(struct psy_mel_filterbank *mel_fb); +struct processing_module; +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); /** * \brief Convert linear complex spectra from FFT into Mel band energies in desired diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index bb3aca81b202..c1c5caa808a6 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -30,5 +30,6 @@ struct dct_plan_16 { }; int dct_initialize_16(struct dct_plan_16 *dct); +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/include/sof/math/fft.h b/src/include/sof/math/fft.h index 504465401cad..16ae9ca97669 100644 --- a/src/include/sof/math/fft.h +++ b/src/include/sof/math/fft.h @@ -53,8 +53,12 @@ struct fft_plan { /* interfaces of the library */ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits); +struct processing_module; +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits); void fft_execute_16(struct fft_plan *plan, bool ifft); void fft_execute_32(struct fft_plan *plan, bool ifft); void fft_plan_free(struct fft_plan *plan16); +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan16); #endif /* __SOF_FFT_H__ */ diff --git a/src/include/sof/math/matrix.h b/src/include/sof/math/matrix.h index 74899371038a..f48f1ca4960d 100644 --- a/src/include/sof/math/matrix.h +++ b/src/include/sof/math/matrix.h @@ -10,6 +10,7 @@ #ifndef __SOF_MATH_MATRIX_H__ #define __SOF_MATH_MATRIX_H__ +#include #include #include #include @@ -44,6 +45,20 @@ static inline struct mat_matrix_16b *mat_matrix_alloc_16b(int16_t rows, int16_t return mat; } +static inline struct mat_matrix_16b *mod_mat_matrix_alloc_16b(struct processing_module *mod, + int16_t rows, int16_t columns, + int16_t fractions) +{ + struct mat_matrix_16b *mat; + const int mat_size = sizeof(int16_t) * rows * columns + sizeof(struct mat_matrix_16b); + + mat = mod_zalloc(mod, mat_size); + if (mat) + mat_init_16b(mat, rows, columns, fractions); + + return mat; +} + static inline void mat_copy_from_linear_16b(struct mat_matrix_16b *mat, const int16_t *lin_data) { size_t bytes = sizeof(int16_t) * mat->rows * mat->columns; diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index dbfe47b1699c..a10d13bbfc99 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -210,3 +211,128 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) fb->scratch_data2, sizeof(int16_t) * fb->data_length); return 0; } + +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *fb) +{ + int32_t up_slope; + int32_t down_slope; + int32_t slope; + int32_t scale = ONE_Q16; + int32_t scale_inv = ONE_Q16; + int16_t *mel; + int16_t mel_start; + int16_t mel_end; + int16_t mel_step; + int16_t left_mel; + int16_t center_mel; + int16_t right_mel; + int16_t delta_cl; + int16_t delta_rc; + int16_t left_hz; + int16_t right_hz; + int16_t f; + int segment; + int i, j, idx; + int base_idx = 0; + int start_bin = 0; + int end_bin = 0; + + if (!fb) + return -ENOMEM; + + if (!fb->scratch_data1 || !fb->scratch_data2) + return -ENOMEM; + + /* Log power can be log, or log10 or dB, get multiply coef to convert + * log to desired format. + */ + switch (fb->mel_log_scale) { + case MEL_LOG: + fb->log_mult = ONE_OVER_LOG2E_Q29; + break; + case MEL_LOG10: + fb->log_mult = ONE_OVER_LOG2TEN_Q29; + break; + case MEL_DB: + fb->log_mult = TEN_OVER_LOG2TEN_Q29; + break; + default: + return -EINVAL; + } + + /* Use scratch area to hold vector of Mel values for each FFT frequency */ + if (fb->scratch_length1 < fb->half_fft_bins) + return -ENOMEM; + + fb->scale_log2 = 0; + + mel = fb->scratch_data1; + for (i = 0; i < fb->half_fft_bins; i++) { + f = fb->samplerate * i / fb->fft_bins; + mel[i] = psy_hz_to_mel(f); + } + + mel_start = psy_hz_to_mel(fb->start_freq); + mel_end = psy_hz_to_mel(fb->end_freq); + mel_step = (mel_end - mel_start) / (fb->mel_bins + 1); + for (i = 0; i < fb->mel_bins; i++) { + left_mel = mel_start + i * mel_step; + center_mel = mel_start + (i + 1) * mel_step; + right_mel = mel_start + (i + 2) * mel_step; + delta_cl = center_mel - left_mel; + delta_rc = right_mel - center_mel; + segment = 0; + idx = base_idx + 3; /* start of filter weight values */ + if (fb->slaney_normalize) { + left_hz = psy_mel_to_hz(left_mel); + right_hz = psy_mel_to_hz(right_mel); + scale = Q_SHIFT_RND(TWO_Q29 / (right_hz - left_hz), 29, 16); /* Q16.16*/ + if (i == 0) { + scale_inv = Q_SHIFT_LEFT(ONE_Q30 / scale, 14, 16); + fb->scale_log2 = base2_logarithm((uint32_t)scale) - LOG2_2P16; + } + + scale = Q_MULTSR_32X32((int64_t)scale, scale_inv, 16, 16, 16); + } + for (j = 0; j < fb->half_fft_bins; j++) { + up_slope = (((int32_t)mel[j] - left_mel) << 15) / delta_cl; /* Q17.15 */ + down_slope = (((int32_t)right_mel - mel[j]) << 15) / delta_rc; /* Q17.15 */ + slope = MIN(up_slope, down_slope); + slope = Q_MULTSR_32X32((int64_t)slope, scale, 15, 16, 15); + if (segment == 1 && slope <= 0) { + end_bin = j - 1; + break; + } + + if (segment == 0 && slope > 0) { + start_bin = j; + segment = 1; + } + + if (segment == 1) { + if (idx >= fb->scratch_length2) + return -EINVAL; + + fb->scratch_data2[idx++] = sat_int16(slope); + } + } + + if (idx + 2 >= fb->scratch_length2) + return -EINVAL; + + fb->scratch_data2[base_idx] = idx; /* index to next */ + fb->scratch_data2[base_idx + 1] = start_bin; + fb->scratch_data2[base_idx + 2] = end_bin - start_bin + 1; /* length */ + base_idx = idx; + } + + fb->data_length = &fb->scratch_data2[base_idx] - &fb->scratch_data2[0]; + fb->data = mod_zalloc(mod, sizeof(int16_t) * fb->data_length); + if (!fb->data) + return -ENOMEM; + + /* Copy the exact triangles data size to allocated buffer */ + memcpy_s(fb->data, sizeof(int16_t) * fb->data_length, + fb->scratch_data2, sizeof(int16_t) * fb->data_length); + return 0; +} diff --git a/src/math/dct.c b/src/math/dct.c index 15d23b67c7f9..db2d96525eea 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -77,3 +78,50 @@ int dct_initialize_16(struct dct_plan_16 *dct) return 0; } + +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct) +{ + int16_t dct_val; + int32_t arg; + int32_t cos; + int32_t c1; + int16_t c2; + int16_t nk; + int n; + int k; + + if (dct->type != DCT_II || dct->ortho != true) + return -EINVAL; + + if (dct->num_in < 1 || dct->num_out < 1) + return -EINVAL; + + if (dct->num_in > DCT_MATRIX_SIZE_MAX || dct->num_out > DCT_MATRIX_SIZE_MAX) + return -EINVAL; + + dct->matrix = mod_mat_matrix_alloc_16b(mod, dct->num_in, dct->num_out, 15); + if (!dct->matrix) + return -ENOMEM; + + c1 = PI_Q29 / dct->num_in; + arg = Q_SHIFT_RND(TWO_Q29 / dct->num_in, 29, 12); + c2 = sqrt_int16(arg); /* Q4.12 */ + for (n = 0; n < dct->num_in; n++) { + for (k = 0; k < dct->num_out; k++) { + /* Note: Current int16_t nk works up to DCT_MATRIX_SIZE_MAX = 91 */ + nk = (Q_SHIFT_LEFT(n, 0, 1) + HALF_Q1) * Q_SHIFT_LEFT(k, 0, 1); /*Q14.2 */ + arg = Q_MULTSR_32X32((int64_t)c1, nk, 29, 2, 24); /* Q8.24 */ + /* Note: Q8.24 works up to DCT_MATRIX_SIZE_MAX = 42 */ + arg %= TWO_PI_Q24; + cos = cos_fixed_32b(Q_SHIFT_LEFT(arg, 24, 28)); /* Q1.31 */ + dct_val = Q_MULTSR_32X32((int64_t)cos, c2, 31, 12, 15); /* Q1.15 */ + if (k == 0) + dct_val = Q_MULTSR_32X32((int64_t)dct_val, + ONE_OVER_SQRT_TWO, 15, 31, 15); + + mat_set_scalar_16b(dct->matrix, n, k, dct_val); + } + } + + return 0; +} diff --git a/src/math/fft/fft_common.c b/src/math/fft/fft_common.c index a2afd09cf127..182bbb623078 100644 --- a/src/math/fft/fft_common.c +++ b/src/math/fft/fft_common.c @@ -5,6 +5,7 @@ // Author: Amery Song // Keyon Jie +#include #include #include #include @@ -63,6 +64,55 @@ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits) return plan; } +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits) +{ + struct fft_plan *plan; + int lim = 1; + int len = 0; + int i; + + if (!inb || !outb) + return NULL; + + plan = mod_zalloc(mod, sizeof(struct fft_plan)); + if (!plan) + return NULL; + + switch (bits) { + case 16: + plan->inb16 = inb; + plan->outb16 = outb; + break; + case 32: + plan->inb32 = inb; + plan->outb32 = outb; + break; + default: + return NULL; + } + + /* calculate the exponent of 2 */ + while (lim < size) { + lim <<= 1; + len++; + } + + plan->size = lim; + plan->len = len; + + plan->bit_reverse_idx = mod_zalloc(mod, plan->size * sizeof(uint16_t)); + if (!plan->bit_reverse_idx) + return NULL; + + /* set up the bit reverse index */ + for (i = 1; i < plan->size; ++i) + plan->bit_reverse_idx[i] = (plan->bit_reverse_idx[i >> 1] >> 1) | + ((i & 1) << (len - 1)); + + return plan; +} + void fft_plan_free(struct fft_plan *plan) { if (!plan) @@ -71,3 +121,12 @@ void fft_plan_free(struct fft_plan *plan) rfree(plan->bit_reverse_idx); rfree(plan); } + +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan) +{ + if (!plan) + return; + + mod_free(mod, plan->bit_reverse_idx); + mod_free(mod, plan); +} From 1b07960f869e4c23489e10d3a0d7f06242ffe530 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 21 Aug 2025 23:16:17 +0300 Subject: [PATCH 20/56] Audio: mfcc: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/mfcc/mfcc.c | 22 ++------ src/audio/mfcc/mfcc_setup.c | 77 ++++++++++---------------- src/include/sof/audio/mfcc/mfcc_comp.h | 2 +- 3 files changed, 34 insertions(+), 67 deletions(-) diff --git a/src/audio/mfcc/mfcc.c b/src/audio/mfcc/mfcc.c index da1fa9f3414e..d5a6ebb8fbc3 100644 --- a/src/audio/mfcc/mfcc.c +++ b/src/audio/mfcc/mfcc.c @@ -88,44 +88,32 @@ static int mfcc_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; /* Handler for configuration data */ md->private = cd; - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + return -ENOMEM; } /* Get configuration data */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->init_data); if (ret < 0) { comp_err(mod->dev, "comp_init_data_blob() failed."); - goto err_init; + return ret; } return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); - -err: - rfree(cd); - return ret; } static int mfcc_free(struct processing_module *mod) { - struct mfcc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "mfcc_free()"); - comp_data_blob_handler_free(cd->model_handler); - mfcc_free_buffers(cd); - rfree(cd); + mfcc_free_buffers(mod); return 0; } diff --git a/src/audio/mfcc/mfcc_setup.c b/src/audio/mfcc/mfcc_setup.c index 802ea058bb6f..33d6577f9d38 100644 --- a/src/audio/mfcc/mfcc_setup.c +++ b/src/audio/mfcc/mfcc_setup.c @@ -65,7 +65,7 @@ static int mfcc_get_window(struct mfcc_state *state, enum sof_mfcc_fft_window_ty * coef[i] = 1.0 + 0.5 * lifter * sin(pi * i / lifter), i = 0 to num_ceps-1 */ -static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) +static int mfcc_get_cepstral_lifter(struct processing_module *mod, struct mfcc_cepstral_lifter *cl) { int32_t inv_cepstral_lifter; int32_t val; @@ -75,7 +75,7 @@ static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) if (cl->num_ceps > DCT_MATRIX_SIZE_MAX) return -EINVAL; - cl->matrix = mat_matrix_alloc_16b(1, cl->num_ceps, 9); /* Use Q7.9 */ + cl->matrix = mod_mat_matrix_alloc_16b(mod, 1, cl->num_ceps, 9); /* Use Q7.9 */ if (!cl->matrix) return -ENOMEM; @@ -171,12 +171,10 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i comp_info(dev, "mfcc_setup(), buffer_size = %d, prev_size = %d", state->buffer_size, state->prev_data_size); - state->buffers = rzalloc(SOF_MEM_FLAG_USER, - state->sample_buffers_size); + state->buffers = mod_zalloc(mod, state->sample_buffers_size); if (!state->buffers) { comp_err(dev, "Failed buffer allocate"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } mfcc_init_buffer(&state->buf, state->buffers, state->buffer_size); @@ -189,29 +187,26 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i #else fft->fft_buffer_size = fft->fft_padded_size * sizeof(struct icomplex32); #endif - fft->fft_buf = rzalloc(SOF_MEM_FLAG_USER, fft->fft_buffer_size); + fft->fft_buf = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_buf) { comp_err(dev, "Failed FFT buffer allocate"); - ret = -ENOMEM; - goto free_buffers; + return -ENOMEM; } - fft->fft_out = rzalloc(SOF_MEM_FLAG_USER, fft->fft_buffer_size); + fft->fft_out = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_out) { comp_err(dev, "Failed FFT output allocate"); - ret = -ENOMEM; - goto free_fft_buf; + return -ENOMEM; } fft->fft_fill_start_idx = 0; /* From config pad_type */ /* Setup FFT */ - fft->fft_plan = fft_plan_new(fft->fft_buf, fft->fft_out, fft->fft_padded_size, - MFCC_FFT_BITS); + fft->fft_plan = mod_fft_plan_new(mod, fft->fft_buf, fft->fft_out, fft->fft_padded_size, + MFCC_FFT_BITS); if (!fft->fft_plan) { comp_err(dev, "Failed FFT init"); - ret = -EINVAL; - goto free_fft_out; + return -EINVAL; } comp_info(dev, "mfcc_setup(), window = %d, num_mel_bins = %d, num_ceps = %d, norm = %d", @@ -223,7 +218,7 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i ret = mfcc_get_window(state, config->window); if (ret < 0) { comp_err(dev, "Failed Window function"); - goto free_fft_out; + return ret; } /* Setup Mel auditory filterbank. FFT input and output buffers are used @@ -242,10 +237,10 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i fb->scratch_data2 = (int16_t *)fft->fft_out; fb->scratch_length1 = fft->fft_buffer_size / sizeof(int16_t); fb->scratch_length2 = fft->fft_buffer_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(fb); + ret = mod_psy_get_mel_filterbank(mod, fb); if (ret < 0) { comp_err(dev, "Failed Mel filterbank"); - goto free_fft_out; + return ret; } /* Setup DCT */ @@ -253,18 +248,18 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i dct->num_out = config->num_ceps; dct->type = (enum dct_type)config->dct; dct->ortho = true; - ret = dct_initialize_16(dct); + ret = mod_dct_initialize_16(mod, dct); if (ret < 0) { comp_err(dev, "Failed DCT init"); - goto free_melfb_data; + return ret; } state->lifter.num_ceps = config->num_ceps; state->lifter.cepstral_lifter = config->cepstral_lifter; /* Q7.9 max 64.0*/ - ret = mfcc_get_cepstral_lifter(&state->lifter); + ret = mfcc_get_cepstral_lifter(mod, &state->lifter); if (ret < 0) { comp_err(dev, "Failed cepstral lifter"); - goto free_dct_matrix; + return ret; } /* Scratch overlay during runtime @@ -297,33 +292,17 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i comp_dbg(dev, "mfcc_setup(), done"); return 0; - -free_dct_matrix: - rfree(state->dct.matrix); - -free_melfb_data: - rfree(fb->data); - -free_fft_out: - rfree(fft->fft_out); - -free_fft_buf: - rfree(fft->fft_buf); - -free_buffers: - rfree(state->buffers); - -exit: - return ret; } -void mfcc_free_buffers(struct mfcc_comp_data *cd) +void mfcc_free_buffers(struct processing_module *mod) { - fft_plan_free(cd->state.fft.fft_plan); - rfree(cd->state.fft.fft_buf); - rfree(cd->state.fft.fft_out); - rfree(cd->state.buffers); - rfree(cd->state.melfb.data); - rfree(cd->state.dct.matrix); - rfree(cd->state.lifter.matrix); + struct mfcc_comp_data *cd = module_get_private_data(mod); + + mod_fft_plan_free(mod, cd->state.fft.fft_plan); + mod_free(mod, cd->state.fft.fft_buf); + mod_free(mod, cd->state.fft.fft_out); + mod_free(mod, cd->state.buffers); + mod_free(mod, cd->state.melfb.data); + mod_free(mod, cd->state.dct.matrix); + mod_free(mod, cd->state.lifter.matrix); } diff --git a/src/include/sof/audio/mfcc/mfcc_comp.h b/src/include/sof/audio/mfcc/mfcc_comp.h index bbc01030e157..ec5cc90eb40c 100644 --- a/src/include/sof/audio/mfcc/mfcc_comp.h +++ b/src/include/sof/audio/mfcc/mfcc_comp.h @@ -154,7 +154,7 @@ static inline int16_t *mfcc_buffer_wrap(struct mfcc_buffer *buffer, int16_t *ptr int mfcc_setup(struct processing_module *mod, int max_frames, int rate, int channels); -void mfcc_free_buffers(struct mfcc_comp_data *cd); +void mfcc_free_buffers(struct processing_module *mod); void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames); From 8ed8f8052936b536e42e10884c3eec0d2b16fde0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 22 Aug 2025 12:19:03 +0300 Subject: [PATCH 21/56] cmocka: Add mocks for mod_balloc_align() and mod_alloc_align() Add mocks for mod_balloc_align() and mod_alloc_align(). These dummy versions do not keep track of the allocated memory or provide real control over alignment. They just forward the calls to regular malloc() and free(). Signed-off-by: Jyri Sarha --- test/cmocka/src/common_mocks.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/cmocka/src/common_mocks.c b/test/cmocka/src/common_mocks.c index 1450af20ddfd..fca1d6300656 100644 --- a/test/cmocka/src/common_mocks.c +++ b/test/cmocka/src/common_mocks.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,39 @@ void WEAK rfree(void *ptr) free(ptr); } +void WEAK *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + void *ret; + (void)mod; + (void)alignment; + + ret = malloc(size); + + assert(ret); + + return ret; +} + +void WEAK *mod_alloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + void *ret; + (void)mod; + (void)alignment; + + ret = malloc(size); + + assert(ret); + + return ret; +} + +int WEAK mod_free(struct processing_module *mod, const void *ptr) +{ + (void)mod; + free((void *)ptr); + return 0; +} + int WEAK memcpy_s(void *dest, size_t dest_size, const void *src, size_t count) { From 76a08e25efe9b60a11ca1b15ace120aa6769c966 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sat, 23 Aug 2025 12:04:18 +0300 Subject: [PATCH 22/56] cmocka: math: Test using module memory API math function Convert auditory, dct, fft, and matrix math tests to use module heap API functions instead of the old version using rmalloc() and friends directly. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/auditory/auditory.c | 7 +++++-- test/cmocka/src/math/dct/dct.c | 4 +++- test/cmocka/src/math/fft/fft.c | 23 +++++++++++++---------- test/cmocka/src/math/matrix/matrix.c | 9 ++++++--- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/test/cmocka/src/math/auditory/auditory.c b/test/cmocka/src/math/auditory/auditory.c index 1e3e903fb5fb..65be2e0dcfce 100644 --- a/test/cmocka/src/math/auditory/auditory.c +++ b/test/cmocka/src/math/auditory/auditory.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "ref_hz_to_mel.h" @@ -38,6 +39,8 @@ #undef DEBUGFILES /* Change this to #define to get output data files for debugging */ +struct processing_module dummy; + static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, const int16_t *ref_mel_log, int num_fft_bins, int num_mel_bins, int norm_slaney, @@ -87,7 +90,7 @@ static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; @@ -190,7 +193,7 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; diff --git a/test/cmocka/src/math/dct/dct.c b/test/cmocka/src/math/dct/dct.c index 4cfe38ef803b..fd7b2f64d0b5 100644 --- a/test/cmocka/src/math/dct/dct.c +++ b/test/cmocka/src/math/dct/dct.c @@ -22,6 +22,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 2.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 1.1 +struct processing_module dummy; + static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, enum dct_type type, bool ortho) { @@ -41,7 +43,7 @@ static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, dct.num_out = num_out; dct.type = type; dct.ortho = ortho; - ret = dct_initialize_16(&dct); + ret = mod_dct_initialize_16(&dummy, &dct); if (ret) { fprintf(stderr, "Failed to initialize DCT.\n"); exit(EXIT_FAILURE); diff --git a/test/cmocka/src/math/fft/fft.c b/test/cmocka/src/math/fft/fft.c index 34f59cc656fb..06cd92a1c427 100644 --- a/test/cmocka/src/math/fft/fft.c +++ b/test/cmocka/src/math/fft/fft.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #define MIN_SNR_512 125.0 #define MIN_SNR_1024 119.0 +struct processing_module dummy; + /** * \brief Doing Fast Fourier Transform (FFT) for mono real input buffers. * \param[in] src - pointer to input buffer. @@ -68,7 +71,7 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -85,7 +88,7 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -123,7 +126,7 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -140,7 +143,7 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -181,7 +184,7 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -210,7 +213,7 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, (outb[size - i].real - outb[i].real) / 2; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -498,7 +501,7 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -515,7 +518,7 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -553,7 +556,7 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -570,7 +573,7 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); diff --git a/test/cmocka/src/math/matrix/matrix.c b/test/cmocka/src/math/matrix/matrix.c index 66200bc3e632..8806344dce09 100644 --- a/test/cmocka/src/math/matrix/matrix.c +++ b/test/cmocka/src/math/matrix/matrix.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -23,6 +24,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 1.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 0.5 +struct processing_module dummy; + static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, const int16_t *c_ref, int elementwise, int a_rows, int a_columns, int b_rows, int b_columns, int c_rows, int c_columns, @@ -38,17 +41,17 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons int16_t x; int i, j, k; - a_matrix = mat_matrix_alloc_16b(a_rows, a_columns, a_frac); + a_matrix = mod_mat_matrix_alloc_16b(&dummy, a_rows, a_columns, a_frac); if (!a_matrix) exit(EXIT_FAILURE); - b_matrix = mat_matrix_alloc_16b(b_rows, b_columns, b_frac); + b_matrix = mod_mat_matrix_alloc_16b(&dummy, b_rows, b_columns, b_frac); if (!b_matrix) { free(a_matrix); exit(EXIT_FAILURE); } - c_matrix = mat_matrix_alloc_16b(c_rows, c_columns, c_frac); + c_matrix = mod_mat_matrix_alloc_16b(&dummy, c_rows, c_columns, c_frac); if (!c_matrix) { free(a_matrix); free(b_matrix); From 0605018598538db0dfec3d7eec59a433430e0ec4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 24 Aug 2025 21:10:07 +0300 Subject: [PATCH 23/56] Math: Remove directly heap using math functions Both unit tests and modules should now use the module API heap allocation functions, so we can now remove the directly heap using versions. Signed-off-by: Jyri Sarha --- src/include/sof/math/auditory.h | 1 - src/include/sof/math/dct.h | 1 - src/math/auditory/auditory.c | 126 -------------------------------- src/math/dct.c | 47 ------------ 4 files changed, 175 deletions(-) diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index 0e082335f764..997c1a6c4a58 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -76,7 +76,6 @@ int16_t psy_mel_to_hz(int16_t mel); * filter coefficients. * \return Zero when success, otherwise error code. */ -int psy_get_mel_filterbank(struct psy_mel_filterbank *mel_fb); struct processing_module; int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index c1c5caa808a6..21cdd8ba817f 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -29,7 +29,6 @@ struct dct_plan_16 { bool ortho; }; -int dct_initialize_16(struct dct_plan_16 *dct); int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index a10d13bbfc99..56cd6f99a24e 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -86,132 +86,6 @@ int16_t psy_mel_to_hz(int16_t mel) return hz; } -int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) -{ - int32_t up_slope; - int32_t down_slope; - int32_t slope; - int32_t scale = ONE_Q16; - int32_t scale_inv = ONE_Q16; - int16_t *mel; - int16_t mel_start; - int16_t mel_end; - int16_t mel_step; - int16_t left_mel; - int16_t center_mel; - int16_t right_mel; - int16_t delta_cl; - int16_t delta_rc; - int16_t left_hz; - int16_t right_hz; - int16_t f; - int segment; - int i, j, idx; - int base_idx = 0; - int start_bin = 0; - int end_bin = 0; - - if (!fb) - return -ENOMEM; - - if (!fb->scratch_data1 || !fb->scratch_data2) - return -ENOMEM; - - /* Log power can be log, or log10 or dB, get multiply coef to convert - * log to desired format. - */ - switch (fb->mel_log_scale) { - case MEL_LOG: - fb->log_mult = ONE_OVER_LOG2E_Q29; - break; - case MEL_LOG10: - fb->log_mult = ONE_OVER_LOG2TEN_Q29; - break; - case MEL_DB: - fb->log_mult = TEN_OVER_LOG2TEN_Q29; - break; - default: - return -EINVAL; - } - - /* Use scratch area to hold vector of Mel values for each FFT frequency */ - if (fb->scratch_length1 < fb->half_fft_bins) - return -ENOMEM; - - fb->scale_log2 = 0; - - mel = fb->scratch_data1; - for (i = 0; i < fb->half_fft_bins; i++) { - f = fb->samplerate * i / fb->fft_bins; - mel[i] = psy_hz_to_mel(f); - } - - mel_start = psy_hz_to_mel(fb->start_freq); - mel_end = psy_hz_to_mel(fb->end_freq); - mel_step = (mel_end - mel_start) / (fb->mel_bins + 1); - for (i = 0; i < fb->mel_bins; i++) { - left_mel = mel_start + i * mel_step; - center_mel = mel_start + (i + 1) * mel_step; - right_mel = mel_start + (i + 2) * mel_step; - delta_cl = center_mel - left_mel; - delta_rc = right_mel - center_mel; - segment = 0; - idx = base_idx + 3; /* start of filter weight values */ - if (fb->slaney_normalize) { - left_hz = psy_mel_to_hz(left_mel); - right_hz = psy_mel_to_hz(right_mel); - scale = Q_SHIFT_RND(TWO_Q29 / (right_hz - left_hz), 29, 16); /* Q16.16*/ - if (i == 0) { - scale_inv = Q_SHIFT_LEFT(ONE_Q30 / scale, 14, 16); - fb->scale_log2 = base2_logarithm((uint32_t)scale) - LOG2_2P16; - } - - scale = Q_MULTSR_32X32((int64_t)scale, scale_inv, 16, 16, 16); - } - for (j = 0; j < fb->half_fft_bins; j++) { - up_slope = (((int32_t)mel[j] - left_mel) << 15) / delta_cl; /* Q17.15 */ - down_slope = (((int32_t)right_mel - mel[j]) << 15) / delta_rc; /* Q17.15 */ - slope = MIN(up_slope, down_slope); - slope = Q_MULTSR_32X32((int64_t)slope, scale, 15, 16, 15); - if (segment == 1 && slope <= 0) { - end_bin = j - 1; - break; - } - - if (segment == 0 && slope > 0) { - start_bin = j; - segment = 1; - } - - if (segment == 1) { - if (idx >= fb->scratch_length2) - return -EINVAL; - - fb->scratch_data2[idx++] = sat_int16(slope); - } - } - - if (idx + 2 >= fb->scratch_length2) - return -EINVAL; - - fb->scratch_data2[base_idx] = idx; /* index to next */ - fb->scratch_data2[base_idx + 1] = start_bin; - fb->scratch_data2[base_idx + 2] = end_bin - start_bin + 1; /* length */ - base_idx = idx; - } - - fb->data_length = &fb->scratch_data2[base_idx] - &fb->scratch_data2[0]; - fb->data = rzalloc(SOF_MEM_FLAG_USER, - sizeof(int16_t) * fb->data_length); - if (!fb->data) - return -ENOMEM; - - /* Copy the exact triangles data size to allocated buffer */ - memcpy_s(fb->data, sizeof(int16_t) * fb->data_length, - fb->scratch_data2, sizeof(int16_t) * fb->data_length); - return 0; -} - int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *fb) { int32_t up_slope; diff --git a/src/math/dct.c b/src/math/dct.c index db2d96525eea..192846e6a082 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -32,53 +32,6 @@ * multiply with the returned matrix. * \param[in,out] dct In input provide DCT type and size, in output the DCT matrix */ -int dct_initialize_16(struct dct_plan_16 *dct) -{ - int16_t dct_val; - int32_t arg; - int32_t cos; - int32_t c1; - int16_t c2; - int16_t nk; - int n; - int k; - - if (dct->type != DCT_II || dct->ortho != true) - return -EINVAL; - - if (dct->num_in < 1 || dct->num_out < 1) - return -EINVAL; - - if (dct->num_in > DCT_MATRIX_SIZE_MAX || dct->num_out > DCT_MATRIX_SIZE_MAX) - return -EINVAL; - - dct->matrix = mat_matrix_alloc_16b(dct->num_in, dct->num_out, 15); - if (!dct->matrix) - return -ENOMEM; - - c1 = PI_Q29 / dct->num_in; - arg = Q_SHIFT_RND(TWO_Q29 / dct->num_in, 29, 12); - c2 = sqrt_int16(arg); /* Q4.12 */ - for (n = 0; n < dct->num_in; n++) { - for (k = 0; k < dct->num_out; k++) { - /* Note: Current int16_t nk works up to DCT_MATRIX_SIZE_MAX = 91 */ - nk = (Q_SHIFT_LEFT(n, 0, 1) + HALF_Q1) * Q_SHIFT_LEFT(k, 0, 1); /*Q14.2 */ - arg = Q_MULTSR_32X32((int64_t)c1, nk, 29, 2, 24); /* Q8.24 */ - /* Note: Q8.24 works up to DCT_MATRIX_SIZE_MAX = 42 */ - arg %= TWO_PI_Q24; - cos = cos_fixed_32b(Q_SHIFT_LEFT(arg, 24, 28)); /* Q1.31 */ - dct_val = Q_MULTSR_32X32((int64_t)cos, c2, 31, 12, 15); /* Q1.15 */ - if (k == 0) - dct_val = Q_MULTSR_32X32((int64_t)dct_val, - ONE_OVER_SQRT_TWO, 15, 31, 15); - - mat_set_scalar_16b(dct->matrix, n, k, dct_val); - } - } - - return 0; -} - int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct) { int16_t dct_val; From 203d33ea38ab717928b19aac42baf678d4a204c0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 24 Aug 2025 21:23:05 +0300 Subject: [PATCH 24/56] audio: mixer: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/mixer/mixer.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/audio/mixer/mixer.c b/src/audio/mixer/mixer.c index 703e87ecee43..2a4deb51157f 100644 --- a/src/audio/mixer/mixer.c +++ b/src/audio/mixer/mixer.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -47,7 +46,7 @@ static int mixer_init(struct processing_module *mod) comp_dbg(dev, "mixer_init()"); - md = rzalloc(SOF_MEM_FLAG_USER, sizeof(*md)); + md = mod_zalloc(mod, sizeof(*md)); if (!md) return -ENOMEM; @@ -61,13 +60,10 @@ static int mixer_init(struct processing_module *mod) static int mixer_free(struct processing_module *mod) { - struct mixer_data *md = module_get_private_data(mod); struct comp_dev *dev = mod->dev; comp_dbg(dev, "mixer_free()"); - rfree(md); - return 0; } From e2a7f39fcbec821088f0287732f8aa38ffbe9075 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 24 Aug 2025 21:27:33 +0300 Subject: [PATCH 25/56] Audio: mixin_mixout: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/mixin_mixout/mixin_mixout.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index ec473baf6e58..304bb9ee1fde 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -141,7 +140,7 @@ static int mixin_init(struct processing_module *mod) comp_dbg(dev, "entry"); - md = rzalloc(SOF_MEM_FLAG_USER, sizeof(*md)); + md = mod_zalloc(mod, sizeof(*md)); if (!md) return -ENOMEM; @@ -168,7 +167,7 @@ static int mixout_init(struct processing_module *mod) comp_dbg(dev, "entry"); - mo_data = rzalloc(SOF_MEM_FLAG_USER, sizeof(*mo_data)); + mo_data = mod_zalloc(mod, sizeof(*mo_data)); if (!mo_data) return -ENOMEM; @@ -182,17 +181,11 @@ static int mixout_init(struct processing_module *mod) static int mixin_free(struct processing_module *mod) { - struct mixin_data *md = module_get_private_data(mod); - - rfree(md); - return 0; } static int mixout_free(struct processing_module *mod) { - rfree(module_get_private_data(mod)); - return 0; } From cf10334857b8d819b3547d0f7d24326020852f2f Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 24 Aug 2025 21:35:29 +0300 Subject: [PATCH 26/56] Audio: Mux: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/mux/mux.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index bbcf1b544e90..99545f4629a1 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -94,36 +93,27 @@ static int mux_demux_common_init(struct processing_module *mod, enum sof_comp_ty return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, - sizeof(*cd) + MUX_BLOB_STREAMS_SIZE); + cd = mod_zalloc(mod, sizeof(*cd) + MUX_BLOB_STREAMS_SIZE); if (!cd) return -ENOMEM; - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + return -ENOMEM; } module_data->private = cd; ret = comp_init_data_blob(cd->model_handler, cfg->size, cfg->init_data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto err_init; + return ret; } mod->verify_params_flags = BUFF_PARAMS_CHANNELS; mod->no_pause = true; cd->comp_type = type; return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); - -err: - rfree(cd); - return ret; } static int mux_init(struct processing_module *mod) @@ -135,12 +125,8 @@ static int mux_init(struct processing_module *mod) static int mux_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "mux_free()"); - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); return 0; } From b31f45004212db5239bdac8024de5229d5597b33 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 15:22:57 +0300 Subject: [PATCH 27/56] Audio: NXP: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The rballoc() calls are converted to mod_balloc(), except module pdata is allocated with mod_alloc() as its obviously not an audio buffer. Signed-off-by: Jyri Sarha --- src/audio/nxp/eap.c | 45 +++++++++------------------------------------ 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/src/audio/nxp/eap.c b/src/audio/nxp/eap.c index 4e6e2c5eb535..aec6aea1ded6 100644 --- a/src/audio/nxp/eap.c +++ b/src/audio/nxp/eap.c @@ -5,7 +5,6 @@ // Author: Daniel Baluta #include -#include #include #include #include @@ -93,7 +92,7 @@ static int nxp_eap_init(struct processing_module *mod) tr_info(mod->dev, "NXP EAP library, platform: %s version:%s", info.pPlatform, info.pVersionNumber); - eap = rballoc(SOF_MEM_FLAG_USER, sizeof(*eap)); + eap = mod_alloc(mod, sizeof(*eap)); if (!eap) { comp_err(dev, "nxp_eap_init() failed to allocate module private data"); return -ENOMEM; @@ -106,7 +105,6 @@ static int nxp_eap_init(struct processing_module *mod) lvm_ret = LVM_GetMemoryTable(LVM_NULL, &eap->mem_tab, &eap->inst_params); if (lvm_ret != LVM_SUCCESS) { comp_err(dev, "nxp_eap_init() failed to get memory table %d", lvm_ret); - rfree(eap); return -EINVAL; } @@ -115,54 +113,31 @@ static int nxp_eap_init(struct processing_module *mod) eap->mem_tab.Region[i].pBaseAddress = NULL; for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { - eap->mem_tab.Region[i].pBaseAddress = rballoc(SOF_MEM_FLAG_USER, - eap->mem_tab.Region[i].Size); + eap->mem_tab.Region[i].pBaseAddress = mod_balloc(mod, eap->mem_tab.Region[i].Size); if (!eap->mem_tab.Region[i].pBaseAddress) { comp_err(dev, "nxp_eap_init() failed to allocate memory for region %d", i); - ret = -ENOMEM; - goto free_mem; + return -ENOMEM; } } lvm_ret = LVM_GetInstanceHandle(&eap->instance, &eap->mem_tab, &eap->inst_params); if (lvm_ret != LVM_SUCCESS) { comp_err(dev, "nxp_eap_init() failed to get instance handle err: %d", lvm_ret); - ret = -EINVAL; - goto free_mem; + return -EINVAL; } /* default parameters, no effects */ memcpy(&eap->ctrl_params, &ControlParamSet_allEffectOff, sizeof(eap->ctrl_params)); return 0; - -free_mem: - for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { - if (eap->mem_tab.Region[i].pBaseAddress) { - rfree(eap->mem_tab.Region[i].pBaseAddress); - eap->mem_tab.Region[i].pBaseAddress = NULL; - } - } - rfree(eap); - return ret; } static int nxp_eap_free(struct processing_module *mod) { struct comp_dev *dev = mod->dev; - struct nxp_eap_data *eap = module_get_private_data(mod); comp_dbg(dev, "nxp_eap_free()"); - for (int i = 0; i < LVM_NR_MEMORY_REGIONS; i++) { - if (eap->mem_tab.Region[i].pBaseAddress) { - rfree(eap->mem_tab.Region[i].pBaseAddress); - eap->mem_tab.Region[i].pBaseAddress = NULL; - } - } - - rfree(eap); - return 0; } @@ -189,15 +164,13 @@ static int nxp_eap_prepare(struct processing_module *mod, */ eap->buffer_bytes = NXP_EAP_DEFAULT_MAX_BLOCK_SIZE; - md->mpd.in_buff = rballoc_align(SOF_MEM_FLAG_USER, eap->buffer_bytes, 32); + md->mpd.in_buff = mod_balloc_align(mod, eap->buffer_bytes, 32); if (!md->mpd.in_buff) return -ENOMEM; - md->mpd.out_buff = rballoc_align(SOF_MEM_FLAG_USER, eap->buffer_bytes, 32); - if (!md->mpd.out_buff) { - rfree(md->mpd.in_buff); + md->mpd.out_buff = mod_balloc_align(mod, eap->buffer_bytes, 32); + if (!md->mpd.out_buff) return -ENOMEM; - } md->mpd.in_buff_size = eap->buffer_bytes; md->mpd.out_buff_size = eap->buffer_bytes; @@ -213,13 +186,13 @@ static int nxp_eap_reset(struct processing_module *mod) comp_dbg(dev, "nxp_eap_reset"); if (md->mpd.in_buff) { - rfree(md->mpd.in_buff); + mod_free(mod, md->mpd.in_buff); md->mpd.in_buff = NULL; md->mpd.in_buff_size = 0; } if (md->mpd.out_buff) { - rfree(md->mpd.out_buff); + mod_free(mod, md->mpd.out_buff); md->mpd.out_buff = NULL; md->mpd.out_buff_size = 0; } From 8c3cb8b41e70d2c9551a65e923a959631998e6b4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 21:58:00 +0300 Subject: [PATCH 28/56] Audio: RTNR: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. However, the rtnr_stub's heap access, rtk_alloc() and rtk_free() still use heap directly like before. Signed-off-by: Jyri Sarha --- src/audio/rtnr/rtnr.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/audio/rtnr/rtnr.c b/src/audio/rtnr/rtnr.c index 541f985753a1..7dd99302dbed 100644 --- a/src/audio/rtnr/rtnr.c +++ b/src/audio/rtnr/rtnr.c @@ -241,7 +241,7 @@ static int rtnr_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -250,17 +250,16 @@ static int rtnr_init(struct processing_module *mod) cd->process_enable = true; /* Handler for component data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } ret = comp_init_data_blob(cd->model_handler, bs, ipc_rtnr->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed with error: %d", ret); - goto cd_fail; + return ret; } /* Component defaults */ @@ -269,8 +268,7 @@ static int rtnr_init(struct processing_module *mod) cd->rtk_agl = RTKMA_API_Context_Create(cd->process_sample_rate); if (cd->rtk_agl == 0) { comp_err(dev, "RTKMA_API_Context_Create failed."); - ret = -EINVAL; - goto cd_fail; + return -EINVAL; } comp_info(dev, "RTKMA_API_Context_Create succeeded."); @@ -283,11 +281,6 @@ static int rtnr_init(struct processing_module *mod) /* Done. */ return 0; - -cd_fail: - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); - return ret; } static int rtnr_free(struct processing_module *mod) @@ -296,11 +289,8 @@ static int rtnr_free(struct processing_module *mod) comp_info(mod->dev, "rtnr_free()"); - comp_data_blob_handler_free(cd->model_handler); - RTKMA_API_Context_Free(cd->rtk_agl); - rfree(cd); return 0; } From 948abc3d6785d93845cbaa1a9871e9032460553e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 22:09:36 +0300 Subject: [PATCH 29/56] Audio: Selector: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The IPC3 implementation of selector uses the component interface directly and can not use the new module API. Signed-off-by: Jyri Sarha --- src/audio/selector/selector.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 201ed9fa6567..e7663ad8286b 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -613,7 +613,7 @@ static int selector_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -729,12 +729,8 @@ static int selector_verify_params(struct processing_module *mod, */ static int selector_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - comp_dbg(mod->dev, "selector_free()"); - rfree(cd); - return 0; } From 74c8aef24c2cf258f44de420094f26ca75dd22b8 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 22:47:55 +0300 Subject: [PATCH 30/56] Audio: TDFB: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The one rballoc() call is converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/tdfb/tdfb.c | 32 +++++++++++--------------------- src/audio/tdfb/tdfb_comp.h | 3 +-- src/audio/tdfb/tdfb_direction.c | 30 +++++++----------------------- src/audio/tdfb/tdfb_ipc3.c | 2 +- 4 files changed, 20 insertions(+), 47 deletions(-) diff --git a/src/audio/tdfb/tdfb.c b/src/audio/tdfb/tdfb.c index 9fc04820ff75..8363d1ee6c84 100644 --- a/src/audio/tdfb/tdfb.c +++ b/src/audio/tdfb/tdfb.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -261,15 +260,16 @@ static inline int set_pass_func(struct processing_module *mod, enum sof_ipc_fram * Control code functions next. The processing is in fir_ C modules. */ -static void tdfb_free_delaylines(struct tdfb_comp_data *cd) +static void tdfb_free_delaylines(struct processing_module *mod) { + struct tdfb_comp_data *cd = module_get_private_data(mod); struct fir_state_32x16 *fir = cd->fir; int i = 0; /* Free the common buffer for all EQs and point then * each FIR channel delay line to NULL. */ - rfree(cd->fir_delay); + mod_free(mod, cd->fir_delay); cd->fir_delay = NULL; cd->fir_delay_size = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) @@ -511,10 +511,10 @@ static int tdfb_setup(struct processing_module *mod, int source_nch, int sink_nc if (delay_size > cd->fir_delay_size) { /* Free existing FIR channels data if it was allocated */ - tdfb_free_delaylines(cd); + tdfb_free_delaylines(mod); /* Allocate all FIR channels data in a big chunk and clear it */ - cd->fir_delay = rballoc(SOF_MEM_FLAG_USER, delay_size); + cd->fir_delay = mod_balloc(mod, delay_size); if (!cd->fir_delay) { comp_err(mod->dev, "tdfb_setup(), delay allocation failed for size %d", delay_size); @@ -554,7 +554,7 @@ static int tdfb_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -571,10 +571,10 @@ static int tdfb_init(struct processing_module *mod) /* Initialize IPC for direction of arrival estimate update */ ret = tdfb_ipc_notification_init(mod); if (ret) - goto err_free_cd; + return ret; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); ret = -ENOMEM; @@ -598,14 +598,8 @@ static int tdfb_init(struct processing_module *mod) return 0; err: - /* These are null if not used for IPC version */ - rfree(cd->ctrl_data); ipc_msg_free(cd->msg); - -err_free_cd: - rfree(cd); return ret; - } static int tdfb_free(struct processing_module *mod) @@ -615,11 +609,7 @@ static int tdfb_free(struct processing_module *mod) comp_dbg(mod->dev, "tdfb_free()"); ipc_msg_free(cd->msg); - tdfb_free_delaylines(cd); - comp_data_blob_handler_free(cd->model_handler); - tdfb_direction_free(cd); - rfree(cd->ctrl_data); - rfree(cd); + return 0; } @@ -780,7 +770,7 @@ static int tdfb_prepare(struct processing_module *mod, comp_dbg(dev, "dev_frames = %d, max_frames = %d", dev->frames, cd->max_frames); /* Initialize tracking */ - ret = tdfb_direction_init(cd, rate, source_channels); + ret = tdfb_direction_init(mod, rate, source_channels); if (!ret) { comp_info(dev, "max_lag = %d, xcorr_size = %zu", cd->direction.max_lag, cd->direction.d_size); @@ -803,7 +793,7 @@ static int tdfb_reset(struct processing_module *mod) comp_dbg(mod->dev, "tdfb_reset()"); - tdfb_free_delaylines(cd); + tdfb_free_delaylines(mod); cd->tdfb_func = NULL; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) diff --git a/src/audio/tdfb/tdfb_comp.h b/src/audio/tdfb/tdfb_comp.h index e2d5075e06b5..8c5689da1e65 100644 --- a/src/audio/tdfb/tdfb_comp.h +++ b/src/audio/tdfb/tdfb_comp.h @@ -118,10 +118,9 @@ void tdfb_fir_s32(struct tdfb_comp_data *cd, struct output_stream_buffer *bsink, int frames); #endif -int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int channels); +int tdfb_direction_init(struct processing_module *mod, int32_t fs, int channels); void tdfb_direction_copy_emphasis(struct tdfb_comp_data *cd, int channels, int *channel, int32_t x); void tdfb_direction_estimate(struct tdfb_comp_data *cd, int frames, int channels); -void tdfb_direction_free(struct tdfb_comp_data *cd); static inline void tdfb_cinc_s16(int16_t **ptr, int16_t *end, size_t size) { diff --git a/src/audio/tdfb/tdfb_direction.c b/src/audio/tdfb/tdfb_direction.c index 640fe4eaa06e..1f2f1e27944a 100644 --- a/src/audio/tdfb/tdfb_direction.c +++ b/src/audio/tdfb/tdfb_direction.c @@ -8,7 +8,6 @@ #include "tdfb_comp.h" #include -#include #include #include #include @@ -176,8 +175,9 @@ static bool line_array_mode_check(struct tdfb_comp_data *cd) return true; } -int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) +int tdfb_direction_init(struct processing_module *mod, int32_t fs, int ch_count) { + struct tdfb_comp_data *cd = module_get_private_data(mod); struct sof_eq_iir_header *filt; int32_t *delay; int32_t d_max; @@ -200,7 +200,7 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) /* Allocate delay lines for IIR filters and initialize them */ size = ch_count * iir_delay_size_df1(filt); - delay = rzalloc(SOF_MEM_FLAG_USER, size); + delay = mod_zalloc(mod, size); if (!delay) return -ENOMEM; @@ -225,9 +225,9 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) cd->direction.max_lag = Q_MULTSR_32X32((int64_t)fs, t_max, 0, 15, 0) + 1; n = (cd->max_frames + (2 * cd->direction.max_lag + 1)) * ch_count; cd->direction.d_size = n * sizeof(int16_t); - cd->direction.d = rzalloc(SOF_MEM_FLAG_USER, cd->direction.d_size); + cd->direction.d = mod_zalloc(mod, cd->direction.d_size); if (!cd->direction.d) - goto err_free_iir; + return -ENOMEM; /* Set needed pointers to xcorr delay line, advance write pointer by max_lag to keep read * always behind write @@ -238,9 +238,9 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) /* xcorr result is temporary but too large for stack so it is allocated here */ cd->direction.r_size = (2 * cd->direction.max_lag + 1) * sizeof(int32_t); - cd->direction.r = rzalloc(SOF_MEM_FLAG_USER, cd->direction.r_size); + cd->direction.r = mod_zalloc(mod, cd->direction.r_size); if (!cd->direction.r) - goto err_free_all; + return -ENOMEM; /* Check for line array mode */ cd->direction.line_array = line_array_mode_check(cd); @@ -249,22 +249,6 @@ int tdfb_direction_init(struct tdfb_comp_data *cd, int32_t fs, int ch_count) cd->direction.az = 0; cd->direction.step_sign = 1; return 0; - -err_free_all: - rfree(cd->direction.d); - cd->direction.d = NULL; - -err_free_iir: - rfree(cd->direction.df1_delay); - cd->direction.df1_delay = NULL; - return -ENOMEM; -} - -void tdfb_direction_free(struct tdfb_comp_data *cd) -{ - rfree(cd->direction.df1_delay); - rfree(cd->direction.d); - rfree(cd->direction.r); } /* Measure level of one channel */ diff --git a/src/audio/tdfb/tdfb_ipc3.c b/src/audio/tdfb/tdfb_ipc3.c index 52662a141e56..d39002bec44c 100644 --- a/src/audio/tdfb/tdfb_ipc3.c +++ b/src/audio/tdfb/tdfb_ipc3.c @@ -30,7 +30,7 @@ static int init_get_ctl_ipc(struct processing_module *mod) struct tdfb_comp_data *cd = module_get_private_data(mod); int comp_id = dev_comp_id(mod->dev); - cd->ctrl_data = rzalloc(SOF_MEM_FLAG_USER, TDFB_GET_CTRL_DATA_SIZE); + cd->ctrl_data = mod_zalloc(mod, TDFB_GET_CTRL_DATA_SIZE); if (!cd->ctrl_data) return -ENOMEM; From 99bc09a7a671e5fb030b82a6682dd678e03a5726 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 23:08:12 +0300 Subject: [PATCH 31/56] Audio: Template_comp: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/template/template.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/audio/template/template.c b/src/audio/template/template.c index 20911df27bb2..38d11e7d2bfe 100644 --- a/src/audio/template/template.c +++ b/src/audio/template/template.c @@ -40,7 +40,7 @@ __cold static int template_init(struct processing_module *mod) comp_info(dev, "template_init()"); - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -168,12 +168,9 @@ static int template_reset(struct processing_module *mod) */ __cold static int template_free(struct processing_module *mod) { - struct template_comp_data *cd = module_get_private_data(mod); - assert_can_be_cold(); comp_dbg(mod->dev, "template_free()"); - rfree(cd); return 0; } From a67449fed62222b65e228519646803275ca28752 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 23:18:59 +0300 Subject: [PATCH 32/56] modules: tensorflow: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/tensorflow/tflm-classify.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/audio/tensorflow/tflm-classify.c b/src/audio/tensorflow/tflm-classify.c index 29b4b6a1af74..b8474e3c4e92 100644 --- a/src/audio/tensorflow/tflm-classify.c +++ b/src/audio/tensorflow/tflm-classify.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -61,25 +60,24 @@ __cold static int tflm_init(struct processing_module *mod) comp_info(dev, "tflm_init()"); - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; md->private = cd; /* Handler for configuration data */ - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto cd_fail; + return -ENOMEM; } /* Get configuration data and reset DRC state */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->data); if (ret < 0) { comp_err(dev, "comp_init_data_blob() failed."); - goto cd_fail; + return ret; } /* hard coded atm */ @@ -100,20 +98,12 @@ __cold static int tflm_init(struct processing_module *mod) } return ret; - -cd_fail: - rfree(cd); - return ret; } __cold static int tflm_free(struct processing_module *mod) { - struct tflm_comp_data *cd = module_get_private_data(mod); - assert_can_be_cold(); - comp_data_blob_handler_free(cd->model_handler); - rfree(cd); return 0; } From 58edf476661abdbfcfdac3898db24b59812e1b7c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 23:27:37 +0300 Subject: [PATCH 33/56] Audio: up_down_mixer: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. The two rballoc() calls are converted to mod_balloc(). Signed-off-by: Jyri Sarha --- src/audio/up_down_mixer/up_down_mixer.c | 28 +++++++------------------ 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index 3cc8308ad62d..af06d9b770f9 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -324,12 +323,6 @@ static int init_mix(struct processing_module *mod, static int up_down_mixer_free(struct processing_module *mod) { - struct up_down_mixer_data *cd = module_get_private_data(mod); - - rfree(cd->buf_in); - rfree(cd->buf_out); - rfree(cd); - return 0; } @@ -342,7 +335,7 @@ static int up_down_mixer_init(struct processing_module *mod) struct up_down_mixer_data *cd; int ret; - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) { comp_free(dev); return -ENOMEM; @@ -350,12 +343,10 @@ static int up_down_mixer_init(struct processing_module *mod) mod_data->private = cd; - cd->buf_in = rballoc(SOF_MEM_FLAG_USER, mod->priv.cfg.base_cfg.ibs); - cd->buf_out = rballoc(SOF_MEM_FLAG_USER, mod->priv.cfg.base_cfg.obs); - if (!cd->buf_in || !cd->buf_out) { - ret = -ENOMEM; - goto err; - } + cd->buf_in = mod_balloc(mod, mod->priv.cfg.base_cfg.ibs); + cd->buf_out = mod_balloc(mod, mod->priv.cfg.base_cfg.obs); + if (!cd->buf_in || !cd->buf_out) + return -ENOMEM; switch (up_down_mixer->coefficients_select) { case DEFAULT_COEFFICIENTS: @@ -380,20 +371,15 @@ static int up_down_mixer_init(struct processing_module *mod) break; default: comp_err(dev, "unsupported coefficient type"); - ret = -EINVAL; - break; + return -EINVAL; } if (ret < 0) { comp_err(dev, "failed to initialize up_down_mix"); - goto err; + return ret; } return 0; - -err: - up_down_mixer_free(mod); - return ret; } static int From c1a139e462d612974446191916de4e19d5ff9138 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 23:37:18 +0300 Subject: [PATCH 34/56] audio: volume: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/volume/volume.c | 5 ----- src/audio/volume/volume_ipc3.c | 8 ++------ src/audio/volume/volume_ipc4.c | 11 +++-------- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/audio/volume/volume.c b/src/audio/volume/volume.c index 9f8aff265226..e0cf5ffe1271 100644 --- a/src/audio/volume/volume.c +++ b/src/audio/volume/volume.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -775,11 +774,7 @@ static int volume_free(struct processing_module *mod) struct vol_data *cd = module_get_private_data(mod); comp_dbg(mod->dev, "volume_free()"); - volume_peak_free(cd); - rfree(cd->vol); - rfree(cd); - return 0; } diff --git a/src/audio/volume/volume_ipc3.c b/src/audio/volume/volume_ipc3.c index e83ebf25cff1..9e8d018f1d8e 100644 --- a/src/audio/volume/volume_ipc3.c +++ b/src/audio/volume/volume_ipc3.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -81,7 +80,7 @@ int volume_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct vol_data)); + cd = mod_zalloc(mod, sizeof(struct vol_data)); if (!cd) return -ENOMEM; @@ -89,9 +88,8 @@ int volume_init(struct processing_module *mod) * malloc memory to store current volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->vol = rmalloc(SOF_MEM_FLAG_USER, vol_size); + cd->vol = mod_alloc(mod, vol_size); if (!cd->vol) { - rfree(cd); comp_err(dev, "Failed to allocate %zu", vol_size); return -ENOMEM; } @@ -158,8 +156,6 @@ int volume_init(struct processing_module *mod) break; default: comp_err(dev, "invalid ramp type %d", vol->ramp); - rfree(cd); - rfree(cd->vol); return -EINVAL; } diff --git a/src/audio/volume/volume_ipc4.c b/src/audio/volume/volume_ipc4.c index 889008657e8e..fc70358df90e 100644 --- a/src/audio/volume/volume_ipc4.c +++ b/src/audio/volume/volume_ipc4.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -128,7 +127,7 @@ int volume_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct vol_data)); + cd = mod_zalloc(mod, sizeof(struct vol_data)); if (!cd) return -ENOMEM; @@ -136,9 +135,8 @@ int volume_init(struct processing_module *mod) * malloc memory to store current volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->vol = rmalloc(SOF_MEM_FLAG_USER, vol_size); + cd->vol = mod_alloc(mod, vol_size); if (!cd->vol) { - rfree(cd); comp_err(dev, "Failed to allocate %d", vol_size); return -ENOMEM; } @@ -146,10 +144,8 @@ int volume_init(struct processing_module *mod) /* malloc memory to store temp peak volume 4 times to ensure the address * is 8-byte aligned for multi-way xtensa intrinsic operations. */ - cd->peak_vol = rzalloc(SOF_MEM_FLAG_USER, vol_size); + cd->peak_vol = mod_zalloc(mod, vol_size); if (!cd->peak_vol) { - rfree(cd->vol); - rfree(cd); comp_err(dev, "Failed to allocate %d for peak_vol", vol_size); return -ENOMEM; } @@ -196,7 +192,6 @@ void volume_peak_free(struct vol_data *cd) /* clear mailbox */ memset_s(®s, sizeof(regs), 0, sizeof(regs)); mailbox_sw_regs_write(cd->mailbox_offset, ®s, sizeof(regs)); - rfree(cd->peak_vol); } static int volume_set_volume(struct processing_module *mod, const uint8_t *data, int data_size) From 9e7da6479e06a948c8cd7bdd9f2528f896eec4e0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 16:30:40 +0300 Subject: [PATCH 35/56] Math: auditory: Add mod_psy_free_mel_filterbank() Add mod_psy_free_mel_filterbank() for freeing the allocated memory. Signed-off-by: Jyri Sarha --- src/include/sof/math/auditory.h | 1 + src/math/auditory/auditory.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index 997c1a6c4a58..b09017786e36 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -78,6 +78,7 @@ int16_t psy_mel_to_hz(int16_t mel); */ struct processing_module; int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); +int mod_psy_free_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); /** * \brief Convert linear complex spectra from FFT into Mel band energies in desired diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index 56cd6f99a24e..57641c46aa5a 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -210,3 +210,8 @@ int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_fil fb->scratch_data2, sizeof(int16_t) * fb->data_length); return 0; } + +int mod_psy_free_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb) +{ + return mod_free(mod, mel_fb->data); +} From d8ac86fe1e1e6ef736382c38adde625a47593762 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 16:32:55 +0300 Subject: [PATCH 36/56] cmocka: math: auditiory: Fix memory leaks Fix memory leaks from auditory cmocka test. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/auditory/auditory.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/cmocka/src/math/auditory/auditory.c b/test/cmocka/src/math/auditory/auditory.c index 65be2e0dcfce..2f8df53e8c6a 100644 --- a/test/cmocka/src/math/auditory/auditory.c +++ b/test/cmocka/src/math/auditory/auditory.c @@ -131,6 +131,10 @@ static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, assert_true(error_rms < MEL_FB16_MAX_ERROR_RMS); assert_true(delta_max < MEL_FB16_MAX_ERROR_ABS); + free(mel_log); + free(fft_buf); + free(fft_out); + mod_psy_free_mel_filterbank(&dummy, &fb); return; err_get_filterbank: @@ -234,6 +238,10 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, assert_true(error_rms < MEL_FB32_MAX_ERROR_RMS); assert_true(delta_max < MEL_FB32_MAX_ERROR_ABS); + free(mel_log); + free(fft_buf); + free(fft_out); + mod_psy_free_mel_filterbank(&dummy, &fb); return; err_get_filterbank: From bbbc38e54c7a7d82ff2c11601fe315b204e8ae58 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 17:54:08 +0300 Subject: [PATCH 37/56] cmocka: math: fft: Fix memory leaks Fix all memory leaks found from fft test when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/fft/fft.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/cmocka/src/math/fft/fft.c b/test/cmocka/src/math/fft/fft.c index 06cd92a1c427..1415b12d756c 100644 --- a/test/cmocka/src/math/fft/fft.c +++ b/test/cmocka/src/math/fft/fft.c @@ -303,6 +303,9 @@ static void test_math_fft_256(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_256, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_512(void **state) @@ -345,6 +348,9 @@ static void test_math_fft_512(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_512, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024(void **state) @@ -387,6 +393,9 @@ static void test_math_fft_1024(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_1024, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_ifft(void **state) @@ -428,6 +437,10 @@ static void test_math_fft_1024_ifft(void **state) db = 10 * log10((float)signal / noise); printf("%s: SNR: %6.2f dB\n", __func__, db); assert_int_equal(db < FFT_DB_TH, 0); + + buffer_free(source); + buffer_free(intm); + buffer_free(sink); } static void test_math_fft_512_2ch(void **state) @@ -470,6 +483,10 @@ static void test_math_fft_512_2ch(void **state) /* the peak should be in range i +/-1 */ assert_in_range(r, i - 1, i + 1); + + buffer_free(source); + buffer_free(sink1); + buffer_free(sink2); } /** @@ -663,6 +680,9 @@ static void test_math_fft_256_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_256_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_512_16(void **state) @@ -705,6 +725,9 @@ static void test_math_fft_512_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_512_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_16(void **state) @@ -747,6 +770,9 @@ static void test_math_fft_1024_16(void **state) snr = 10 * log10(signal / noise); printf("%s: SNR %5.2f dB\n", __func__, snr); assert_int_equal(snr < MIN_SNR_1024_16, 0); + + buffer_free(source); + buffer_free(sink); } static void test_math_fft_1024_ifft_16(void **state) @@ -787,6 +813,10 @@ static void test_math_fft_1024_ifft_16(void **state) db = 10 * log10((float)signal / noise); printf("%s: SNR: %6.2f dB\n", __func__, db); assert_int_equal(db < FFT_DB_TH_16, 0); + + buffer_free(source); + buffer_free(intm); + buffer_free(sink); } int main(void) From 90c29afe3494862aaff8327446a25fa4470bbcc8 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 18:19:10 +0300 Subject: [PATCH 38/56] cmocka: math: matrix: Fix memory leaks Fix all memory leaks found from matrix test when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/matrix/matrix.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/cmocka/src/math/matrix/matrix.c b/test/cmocka/src/math/matrix/matrix.c index 8806344dce09..63632ba58c4b 100644 --- a/test/cmocka/src/math/matrix/matrix.c +++ b/test/cmocka/src/math/matrix/matrix.c @@ -47,14 +47,14 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons b_matrix = mod_mat_matrix_alloc_16b(&dummy, b_rows, b_columns, b_frac); if (!b_matrix) { - free(a_matrix); + mod_free(&dummy, a_matrix); exit(EXIT_FAILURE); } c_matrix = mod_mat_matrix_alloc_16b(&dummy, c_rows, c_columns, c_frac); if (!c_matrix) { - free(a_matrix); - free(b_matrix); + mod_free(&dummy, a_matrix); + mod_free(&dummy, b_matrix); exit(EXIT_FAILURE); } @@ -86,6 +86,10 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons assert_true(error_rms < MATRIX_MULT_16_MAX_ERROR_RMS); assert_true(delta_max < MATRIX_MULT_16_MAX_ERROR_ABS); + + mod_free(&dummy, a_matrix); + mod_free(&dummy, b_matrix); + mod_free(&dummy, c_matrix); } static void test_matrix_mult_16_test1(void **state) From d4994031952950fc76f2488502a60b3bd5a59f46 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 18:29:04 +0300 Subject: [PATCH 39/56] Math: DCT: Add mod_dct_free_16() Add mod_dct_free_16() to free memory allocated by mod_dct_initialize_16(). Signed-off-by: Jyri Sarha --- src/include/sof/math/dct.h | 2 ++ src/math/dct.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index 21cdd8ba817f..7c754f448c21 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -31,4 +31,6 @@ struct dct_plan_16 { int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); +int mod_dct_free_16(struct processing_module *mod, struct dct_plan_16 *dct); + #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/math/dct.c b/src/math/dct.c index 192846e6a082..de27cab4471e 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -78,3 +78,8 @@ int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct return 0; } + +int mod_dct_free_16(struct processing_module *mod, struct dct_plan_16 *dct) +{ + return mod_free(mod, dct->matrix); +} From 7f90a49a41415916ed6f3b9ba7d9c09e5c1cf70c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 18:30:48 +0300 Subject: [PATCH 40/56] cmocka: math: dct: Fix memory leaks Fix memory leaks found by running the tests with Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/dct/dct.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cmocka/src/math/dct/dct.c b/test/cmocka/src/math/dct/dct.c index fd7b2f64d0b5..ea35d170e66e 100644 --- a/test/cmocka/src/math/dct/dct.c +++ b/test/cmocka/src/math/dct/dct.c @@ -71,6 +71,8 @@ static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, assert_true(error_rms < MATRIX_MULT_16_MAX_ERROR_RMS); assert_true(delta_max < MATRIX_MULT_16_MAX_ERROR_ABS); + + mod_dct_free_16(&dummy, &dct); } static void test_dct_matrix_16_test1(void **state) From 137de514d1842fa9a397cb13c8a588ed02d3fb90 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 19:01:32 +0300 Subject: [PATCH 41/56] cmocka: module_adapter_test: Fix memory freeing error Fix memory freeing error from module_adapter_test_free(). Use free_test_source() for sources, not free_test_sink(). Signed-off-by: Jyri Sarha --- test/cmocka/src/audio/module_adapter_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cmocka/src/audio/module_adapter_test.c b/test/cmocka/src/audio/module_adapter_test.c index 29140e4581e9..81ec6cadc1b7 100644 --- a/test/cmocka/src/audio/module_adapter_test.c +++ b/test/cmocka/src/audio/module_adapter_test.c @@ -77,7 +77,7 @@ void module_adapter_test_free(struct processing_module_test_data *test_data) } for (i = 0; i < test_data->num_sources; i++) { - free_test_sink(test_data->sources[i]); + free_test_source(test_data->sources[i]); test_free(test_data->input_buffers[i]); } From 4e34f3bd0ba10555bcc2f85962b94048a7964648 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 19:03:51 +0300 Subject: [PATCH 42/56] cmocka: volume: Fix memory leaks Fix all memory leaks found from volume test when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/audio/volume/volume_process.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/cmocka/src/audio/volume/volume_process.c b/test/cmocka/src/audio/volume/volume_process.c index 10afdd1276a3..389a4e75a503 100644 --- a/test/cmocka/src/audio/volume/volume_process.c +++ b/test/cmocka/src/audio/volume/volume_process.c @@ -315,7 +315,7 @@ int main(void) struct vol_test_parameters *parameters; uint32_t volume_values[] = {VOL_MAX, VOL_ZERO_DB, VOL_MINUS_80DB}; int num_tests = ARRAY_SIZE(test_parameters) * ARRAY_SIZE(volume_values); - int i, j; + int i, j, ret; parameters = test_calloc(num_tests, sizeof(struct vol_test_parameters)); for (i = 0; i < ARRAY_SIZE(test_parameters); i++) { @@ -338,5 +338,9 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); - return cmocka_run_group_tests(tests, NULL, NULL); + ret = cmocka_run_group_tests(tests, NULL, NULL); + + test_free(parameters); + + return ret; } From 2ab641c3dc5d32aa43b37763d4abaf9244ba3e53 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 19:28:00 +0300 Subject: [PATCH 43/56] cmocka: mux_copy: Fix memory leaks Fix all memory leaks found from mux_copy test when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/audio/mux/mux_copy.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/cmocka/src/audio/mux/mux_copy.c b/test/cmocka/src/audio/mux/mux_copy.c index 97b7be7b9076..66b21b0df27c 100644 --- a/test/cmocka/src/audio/mux/mux_copy.c +++ b/test/cmocka/src/audio/mux/mux_copy.c @@ -211,6 +211,9 @@ static int teardown_test_case(void **state) struct test_data *td = *((struct test_data **)state); int i; + rfree(td->mod->input_buffers); + rfree(td->mod->output_buffers); + for (i = 0; i < MUX_MAX_STREAMS; ++i) free_test_source(td->sources[i]); @@ -357,8 +360,10 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); ret = cmocka_run_group_tests(tests, setup_group, NULL); - for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) + for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) { free(tests[ti].initial_state); + free((void *)tests[ti].name); + } return ret; } From 6be199d1c53e2cdb1dc5d6b3e534c6bfeadb02a2 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 19:36:04 +0300 Subject: [PATCH 44/56] cmocka: demux_copy: Fix memory leaks Fix all memory leaks found from demux_copy test when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- test/cmocka/src/audio/mux/demux_copy.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/cmocka/src/audio/mux/demux_copy.c b/test/cmocka/src/audio/mux/demux_copy.c index 4934ab6dbdaa..8e331446bbf4 100644 --- a/test/cmocka/src/audio/mux/demux_copy.c +++ b/test/cmocka/src/audio/mux/demux_copy.c @@ -188,6 +188,9 @@ static int teardown_test_case(void **state) struct test_data *td = *((struct test_data **)state); int i; + rfree(td->mod->input_buffers); + rfree(td->mod->output_buffers); + free_test_source(td->source); for (i = 0; i < MUX_MAX_STREAMS; ++i) @@ -339,8 +342,10 @@ int main(void) cmocka_set_message_output(CM_OUTPUT_TAP); ret = cmocka_run_group_tests(tests, setup_group, NULL); - for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) + for (ti = 0; ti < ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks); ti++) { free(tests[ti].initial_state); + free((void *)tests[ti].name); + } return ret; } From a040c24c6d83b356918bc3072041c3623e8bc62d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 22:12:53 +0300 Subject: [PATCH 45/56] cmocka: pipeline: Fix memory leaks Fix all memory leaks found from all pipeline tests when tests were run under Valgrind. Signed-off-by: Jyri Sarha --- .../src/audio/pipeline/pipeline_connect_upstream.c | 1 + .../src/audio/pipeline/pipeline_connection_mocks.c | 13 ++++++++++--- .../src/audio/pipeline/pipeline_connection_mocks.h | 1 + test/cmocka/src/audio/pipeline/pipeline_free.c | 1 + test/cmocka/src/audio/pipeline/pipeline_new.c | 4 ++++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c b/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c index dea28ce65401..e911f0238162 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c +++ b/test/cmocka/src/audio/pipeline/pipeline_connect_upstream.c @@ -24,6 +24,7 @@ static int setup(void **state) static int teardown(void **state) { + free_standard_connect_objects(*state); free(*state); return 0; } diff --git a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c index 35899b14b297..de05f8e3b284 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c +++ b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.c @@ -30,7 +30,7 @@ struct pipeline_connect_data *get_standard_connect_objects(void) struct pipeline_connect_data *pipeline_connect_data = calloc (sizeof(struct pipeline_connect_data), 1); - struct pipeline *pipe = calloc(sizeof(struct pipeline), 1); + struct pipeline *pipe = &pipeline_connect_data->p; pipe->frames_per_sched = 5; pipe->pipeline_id = PIPELINE_ID_SAME; @@ -83,7 +83,14 @@ struct pipeline_connect_data *get_standard_connect_objects(void) comp_buffer_reset_source_list(buffer_2); pipeline_connect_data->b2 = buffer_2; - pipeline_connect_data->p = *pipe; - return pipeline_connect_data; } + +void free_standard_connect_objects(struct pipeline_connect_data *data) +{ + free(data->p.pipe_task); + free(data->p.sched_comp); + free(data->second); + free(data->b1); + free(data->b2); +} diff --git a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h index 6a8c0fce1a12..60eedabbd43b 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h +++ b/test/cmocka/src/audio/pipeline/pipeline_connection_mocks.h @@ -32,6 +32,7 @@ struct pipeline_connect_data { }; struct pipeline_connect_data *get_standard_connect_objects(void); +void free_standard_connect_objects(struct pipeline_connect_data *data); void cleanup_test_data(struct pipeline_connect_data *data); diff --git a/test/cmocka/src/audio/pipeline/pipeline_free.c b/test/cmocka/src/audio/pipeline/pipeline_free.c index d4d441012a29..6d76fde9a145 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_free.c +++ b/test/cmocka/src/audio/pipeline/pipeline_free.c @@ -36,6 +36,7 @@ static int setup(void **state) static int teardown(void **state) { + free_standard_connect_objects(*state); free(*state); return 0; } diff --git a/test/cmocka/src/audio/pipeline/pipeline_new.c b/test/cmocka/src/audio/pipeline/pipeline_new.c index dda5d1a5c020..c08e499a5a05 100644 --- a/test/cmocka/src/audio/pipeline/pipeline_new.c +++ b/test/cmocka/src/audio/pipeline/pipeline_new.c @@ -55,6 +55,10 @@ static void test_audio_pipeline_pipeline_new_creation(void **state) /*Pipeline should have been created so pointer can't be null*/ assert_non_null(result); + + rfree(result->msg->tx_data); + rfree(result->msg); + rfree(result); } int main(void) From 5f4b1139274fe7b44fe8394420491dd4d6d8e009 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 15 Oct 2025 16:30:46 +0100 Subject: [PATCH 46/56] vregions: refactor and rename API. To be squashed. Signed-off-by: Liam Girdwood --- src/audio/module_adapter/module/generic.c | 30 +- src/audio/module_adapter/module_adapter.c | 100 ++++- src/audio/pipeline/pipeline-graph.c | 27 +- src/include/module/module/base.h | 17 +- src/include/sof/audio/pipeline.h | 4 +- src/schedule/zephyr_dp_schedule.c | 25 +- zephyr/CMakeLists.txt | 19 +- zephyr/Kconfig | 16 +- zephyr/include/sof/lib/pacovr.h | 114 ----- zephyr/include/sof/lib/{vpage.h => vpages.h} | 6 +- zephyr/include/sof/lib/vregion.h | 90 ++++ zephyr/lib/pacovr.c | 255 ----------- zephyr/lib/vpages.c | 12 +- zephyr/lib/vregion.c | 434 +++++++++++++++++++ 14 files changed, 721 insertions(+), 428 deletions(-) delete mode 100644 zephyr/include/sof/lib/pacovr.h rename zephyr/include/sof/lib/{vpage.h => vpages.h} (91%) create mode 100644 zephyr/include/sof/lib/vregion.h delete mode 100644 zephyr/lib/pacovr.c create mode 100644 zephyr/lib/vregion.c diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 44af38769a64..cc965b84bd1a 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -188,14 +188,15 @@ void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignm return NULL; } -#if CONFIG_SOF_PACOVR +#if CONFIG_SOF_VREGIONS /* do we need to use the dynamic heap or the static heap? */ + struct vregion *vregion = module_get_vregion(mod); if (mod->priv.state != MODULE_INITIALIZED) { - /* static allocator */ - ptr = pacovr_static_alloc(mod->dev->pipeline->pacovr, size); + /* lifetime allocator */ + ptr = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME, size, alignment); } else { - /* dynamic allocator */ - ptr = pacovr_dynamic_alloc_align(mod->dev->pipeline->pacovr, size, alignment); + /* interim allocator */ + ptr = vregion_alloc_align(vregion, VREGION_MEM_TYPE_INTERIM, size, alignment); } #else /* Allocate memory for module */ @@ -249,14 +250,15 @@ void *mod_alloc_align(struct processing_module *mod, size_t size, size_t alignme return NULL; } -#if CONFIG_SOF_PACOVR +#if CONFIG_SOF_VREGIONS /* do we need to use the dynamic heap or the static heap? */ + struct vregion *vregion = module_get_vregion(mod); if (mod->priv.state != MODULE_INITIALIZED) { /* static allocator */ - ptr = pacovr_static_alloc(mod->dev->pipeline->pacovr, size); + ptr = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME, size, alignment); } else { /* dynamic allocator */ - ptr = pacovr_dynamic_alloc_align(mod->dev->pipeline->pacovr, size, alignment); + ptr = vregion_alloc_align(vregion, VREGION_MEM_TYPE_INTERIM, size, alignment); } #else /* Allocate memory for module */ @@ -362,15 +364,9 @@ static int free_contents(struct processing_module *mod, struct module_resource * switch (container->type) { case MOD_RES_HEAP: -#if CONFIG_SOF_PACOVR - /* do we need to use the scratch heap or the batch heap? */ - if (mod->priv.state != MODULE_INITIALIZED) { - /* static allocator */ - pacovr_static_free(mod->dev->pipeline->pacovr, container->ptr); - } else { - /* dynamic allocator */ - pacovr_dynamic_free(mod->dev->pipeline->pacovr, container->ptr); - } +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(mod); + vregion_free(vregion, container->ptr); #else rfree(container->ptr); #endif diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 77777727efba..175430e4475b 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -64,7 +64,10 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, struct comp_dev *dev; struct processing_module *mod; struct module_config *dst; + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); const struct module_interface *const interface = drv->adapter_ops; + struct vregion *vregion = NULL; comp_cl_dbg(drv, "start"); @@ -81,6 +84,42 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, } dev->ipc_config = *config; + /* set pipeline for module */ + ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, + config->pipeline_id, + IPC_COMP_IGNORE_REMOTE); + if (!ipc_pipe) { + comp_err(dev, "pipeline %d does not exist", config->pipeline_id); + goto err_pipe; + } + dev->pipeline = ipc_pipe->pipeline; +#if CONFIG_SOF_VREGIONS + + /* TODO: determine if our user domain is different from the LL pipeline domain */ + if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) { + // TODO: get the text, heap, stack and shared sizes from topology too + /* create a vregion region for all resources */ + size_t interim_size = 0x4000; /* 16kB scratch */ + size_t lifetime_size = 0x20000; /* 128kB batch */ + size_t shared_size = 0x4000; /* 16kB shared */ + size_t text_size = 0x4000; /* 16kB text */ + vregion = vregion_create(lifetime_size, interim_size, shared_size, 0, text_size); + if (!vregion) { + comp_err(dev, "failed to create vregion for DP module"); + goto err_pipe; + } + } else { + vregion = dev->pipeline->vregion; + } + + /* allocate module in correct vregion*/ + //TODO: add coherent flag for cross core DP modules + mod = vregion_alloc(vregion, VREGION_MEM_TYPE_LIFETIME, sizeof(*mod)); + if (!mod) { + comp_err(dev, "failed to allocate memory for module"); + goto err_pipe; + } +#else /* allocate module information. * for DP shared modules this struct must be accessible from all cores * Unfortunately at this point there's no information of components the module @@ -95,7 +134,9 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, comp_err(dev, "failed to allocate memory for module"); goto err; } - +#endif + memset(mod, 0, sizeof(*mod)); + mod->vregion = vregion; dst = &mod->priv.cfg; module_set_private_data(mod, mod_priv); @@ -165,6 +206,7 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, rfree(mod->priv.cfg.input_pins); #endif rfree(mod); +err_pipe: rfree(dev); return NULL; } @@ -345,8 +387,15 @@ int module_adapter_prepare(struct comp_dev *dev) memory_flags = user_get_buffer_memory_region(dev->drv); /* allocate memory for input buffers */ if (mod->max_sources) { + //TODO: check if shared memory is needed + struct vregion *vregion = module_get_vregion(mod); mod->input_buffers = +#if CONFIG_SOF_VREGIONS + vregion_alloc(vregion, VREGION_MEM_TYPE_LIFETIME_SHARED, + sizeof(*mod->input_buffers) * mod->max_sources); +#else rzalloc(memory_flags, sizeof(*mod->input_buffers) * mod->max_sources); +#endif if (!mod->input_buffers) { comp_err(dev, "failed to allocate input buffers"); return -ENOMEM; @@ -354,11 +403,19 @@ int module_adapter_prepare(struct comp_dev *dev) } else { mod->input_buffers = NULL; } + memset(mod->input_buffers, 0, sizeof(*mod->input_buffers) * mod->max_sources); /* allocate memory for output buffers */ + //TODO: check if shared memory is needed if (mod->max_sinks) { + struct vregion *vregion = module_get_vregion(mod); mod->output_buffers = +#if CONFIG_SOF_VREGIONS + vregion_alloc(vregion, VREGION_MEM_TYPE_LIFETIME_SHARED, + sizeof(*mod->output_buffers) * mod->max_sinks); +#else rzalloc(memory_flags, sizeof(*mod->output_buffers) * mod->max_sinks); +#endif if (!mod->output_buffers) { comp_err(dev, "failed to allocate output buffers"); ret = -ENOMEM; @@ -367,6 +424,7 @@ int module_adapter_prepare(struct comp_dev *dev) } else { mod->output_buffers = NULL; } + memset(mod->output_buffers, 0, sizeof(*mod->output_buffers) * mod->max_sinks); /* * no need to allocate intermediate sink buffers if the module produces only period bytes @@ -423,8 +481,15 @@ int module_adapter_prepare(struct comp_dev *dev) /* allocate memory for input buffer data */ size_t size = MAX(mod->deep_buff_bytes, mod->period_bytes); + // TODO: check if shared memory is needed list_for_item(blist, &dev->bsource_list) { +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(mod); + mod->input_buffers[i].data = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME_SHARED, + size, 0); +#else mod->input_buffers[i].data = rballoc(memory_flags, size); +#endif if (!mod->input_buffers[i].data) { comp_err(mod->dev, "Failed to alloc input buffer data"); ret = -ENOMEM; @@ -436,7 +501,13 @@ int module_adapter_prepare(struct comp_dev *dev) /* allocate memory for output buffer data */ i = 0; list_for_item(blist, &dev->bsink_list) { +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(mod); + mod->output_buffers[i].data = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME_SHARED, + size, 0); +#else mod->output_buffers[i].data = rballoc(memory_flags, md->mpd.out_buff_size); +#endif if (!mod->output_buffers[i].data) { comp_err(mod->dev, "Failed to alloc output buffer data"); ret = -ENOMEM; @@ -1213,17 +1284,32 @@ int module_adapter_reset(struct comp_dev *dev) return ret; } +#if CONFIG_SOF_VREGIONS + if (IS_PROCESSING_MODE_RAW_DATA(mod)) { + struct vregion *vregion = module_get_vregion(mod); + for (i = 0; i < mod->num_of_sinks; i++) + vregion_free(vregion, (__sparse_force void *)mod->output_buffers[i].data); + for (i = 0; i < mod->num_of_sources; i++) + vregion_free(vregion, (__sparse_force void *)mod->input_buffers[i].data); + } +#else if (IS_PROCESSING_MODE_RAW_DATA(mod)) { for (i = 0; i < mod->num_of_sinks; i++) rfree((__sparse_force void *)mod->output_buffers[i].data); for (i = 0; i < mod->num_of_sources; i++) rfree((__sparse_force void *)mod->input_buffers[i].data); } +#endif if (IS_PROCESSING_MODE_RAW_DATA(mod) || IS_PROCESSING_MODE_AUDIO_STREAM(mod)) { +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(mod); + vregion_free(vregion, mod->output_buffers); + vregion_free(vregion, mod->input_buffers); +#else rfree(mod->output_buffers); rfree(mod->input_buffers); - +#endif mod->num_of_sources = 0; mod->num_of_sinks = 0; } @@ -1276,7 +1362,17 @@ void module_adapter_free(struct comp_dev *dev) #endif rfree(mod->stream_params); +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(mod); + vregion_free(vregion, (__sparse_force void *)mod); + + /* free the vregion if its a separate instance from the pipeline */ + if (dev->pipeline->vregion != vregion) + vregion_destroy(vregion); +#else + rfree(mod); +#endif rfree(dev); } EXPORT_SYMBOL(module_adapter_free); diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 105c2c7bd1da..62e8086c0cb9 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -128,14 +128,17 @@ struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t return NULL; } -#if CONFIG_SOF_PACOVR - /* create a pacovr region for all resources */ - // TODO: make batch and scratch sizes configurable from topology - size_t scratch_size = 0x4000; /* 16kB scratch */ - size_t batch_size = 0x20000; /* 128kB batch */ - p->pacovr = pacovr_create(batch_size, scratch_size); - if (!p->pacovr) { - pipe_err(p, "pipeline_new(): pacovr_create() failed."); +#if CONFIG_SOF_VREGIONS + /* create a vregion region for all resources */ + // TODO: make lifetime_size and interim sizes configurable from topology + // TODO: get the text and shared size from topology too + size_t lifetime_size = 0x20000; /* 128kB lifetime */ + size_t interim_size = 0x4000; /* 16kB interim */ + size_t shared_size = 0x4000; /* 16kB shared */ + + p->vregion = vregion_create(lifetime_size, interim_size, shared_size, 0, 0); + if (!p->vregion) { + pipe_err(p, "pipeline_new(): vregion_create() failed."); goto free; } #endif @@ -249,9 +252,9 @@ int pipeline_free(struct pipeline *p) pipeline_posn_offset_put(p->posn_offset); -#if CONFIG_SOF_PACOVR - /* free pacovr region */ - pacovr_destroy(p->pacovr); +#if CONFIG_SOF_VREGIONS + /* free vregion region */ + vregion_destroy(p->vregion); #endif /* now free the pipeline */ rfree(p); diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index ed116681afd2..58aaf95fb6ef 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -81,12 +81,17 @@ struct processing_module { struct module_data priv; /**< module private data */ uint32_t period_bytes; /** pipeline period bytes */ + /* virtual region iff not using the parent pipeline region. + * i.e. a DP module in a different memory domain from rest of pipeline. + */ + struct vregion *vregion; + /* * Fields below can only be accessed by the SOF and must be moved to a new structure. * Below #ifdef is a temporary solution used until work on separating a common interface * for loadable modules is completed. */ -#ifdef SOF_MODULE_API_PRIVATE +//#ifdef SOF_MODULE_API_PRIVATE struct sof_ipc_stream_params *stream_params; /* list of sink buffers to save produced output, to be used in Raw data * processing mode @@ -185,7 +190,15 @@ struct processing_module { #if CONFIG_USERSPACE struct userspace_context *user_ctx; #endif /* CONFIG_USERSPACE */ -#endif /* SOF_MODULE_PRIVATE */ +//#endif /* SOF_MODULE_PRIVATE */ }; +static inline struct vregion *module_get_vregion(struct processing_module *mod) +{ + if (mod->vregion) + return mod->vregion; + else + return mod->dev->pipeline->vregion; +} + #endif /* __MODULE_MODULE_BASE__ */ diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 5f9f2d13000c..8462135bc3bc 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -66,7 +66,7 @@ struct pipeline { uint32_t attributes; /**< pipeline attributes from IPC extension msg/ */ /* pipeline resource management */ - struct pacovr *pacovr; + struct vregion *vregion; /* runtime status */ int32_t xrun_bytes; /* last xrun length */ diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index c4f3aaedeb37..1bba1332e085 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -547,6 +547,7 @@ int scheduler_dp_task_init(struct task **task, { void __sparse_cache *p_stack = NULL; struct sys_heap *const user_heap = mod->dev->drv->user_heap; + struct vregion *vregion; /* memory allocation helper structure */ struct { @@ -559,6 +560,28 @@ int scheduler_dp_task_init(struct task **task, /* must be called on the same core the task will be binded to */ assert(cpu_get_id() == core); +#if CONFIG_SOF_VREGIONS1 + + /* if module has its own vregion, use it otherwise use pipeline vregion */ + if (mod->vregion) { + vregion = mod->vregion; + } else { + /* otherwise use pipeline vregion */ + vregion = mod->dev->pipeline->vregion; + } + + //TODO: add check if vregion is in correct memory domain/coherent + task_memory = vregion_static_alloc(vregion, sizeof(*task_memory)); + if (!task_memory) { + tr_err(&dp_tr, "vregion task memory alloc failed"); + return -ENOMEM; + } + p_stack = vregion_static_alloc(vregion, stack_size); + if (!p_stack) { + tr_err(&dp_tr, "vregion stack alloc failed"); + return -ENOMEM; + } +#else /* * allocate memory * to avoid multiple malloc operations allocate all required memory as a single structure @@ -580,7 +603,7 @@ int scheduler_dp_task_init(struct task **task, ret = -ENOMEM; goto err; } - +#endif /* CONFIG_SOF_VREGION */ /* internal SOF task init */ ret = schedule_task_init(&task_memory->task, uid, SOF_SCHEDULE_DP, 0, ops->run, mod, core, options); diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index c47695e8081d..695c7c1e47b9 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -289,14 +289,17 @@ if (CONFIG_SOC_SERIES_INTEL_ADSP_ACE) # Sources for virtual heap management # Virtual memory support is required and can be enabled with - # either VMH or PACOVR. - zephyr_library_sources_ifdef(CONFIG_SOF_PACOVR - lib/vpages.c - lib/pacovr.c - ) - zephyr_library_sources_ifndef(CONFIG_SOF_PACOVR, - lib/regions_mm.c - ) + # either VMH or Virtual pages and regions. + if (CONFIG_SOF_VREGIONS) + zephyr_library_sources( + lib/vpages.c + lib/vregion.c + ) + else() + zephyr_library_sources( + lib/regions_mm.c + ) + endif() zephyr_library_sources_ifdef(CONFIG_CAVS_LPS ${SOF_PLATFORM_PATH}/intel/ace/lps_wait.c diff --git a/zephyr/Kconfig b/zephyr/Kconfig index cf5d28750c27..0be21f5afdfd 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -76,15 +76,19 @@ config SOF_ZEPHYR_USERSPACE_MODULE_HEAP_SIZE module has its own independent heap to which only it has access. This heap is shared between instances of the same module. -config SOF_PACOVR - bool "Enable PACOVR memory allocator" +config SOF_VREGIONS + bool "Enable virtual memory regions" default y if ACE default n depends on ACE help - Enable the PACOVR memory allocator for pipeline resource management. - PACOVR provides a way to manage memory resources for audio pipelines, - including both batch and scratch allocations. + Enable the virtual regions memory allocator for pipeline resource management. + This provides a way to manage memory resources for audio pipelines, + including + 1) multiple pipeline static lifetime allocations. + 2) runtime pipeline allocations. + 3) pipeline shared memory allocations. + 4) module text allocation. config SOF_VPAGE_ELEMS int "Number of virtual memory allocation elements" @@ -169,7 +173,7 @@ config SOF_ZEPHYR_NO_SOF_CLOCK config VIRTUAL_HEAP bool "Use virtual memory heap to allocate a buffers" - default y if ACE + default n if ACE depends on ACE help Enabling this option will use the virtual memory heap allocator to allocate buffers. diff --git a/zephyr/include/sof/lib/pacovr.h b/zephyr/include/sof/lib/pacovr.h deleted file mode 100644 index db6d52ba0faa..000000000000 --- a/zephyr/include/sof/lib/pacovr.h +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// Copyright(c) 2025 Intel Corporation. - -/* Pre Allocated Contiguous Virtual Region */ -#ifndef __SOF_LIB_PACOVR_H__ -#define __SOF_LIB_PACOVR_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct pacovr; - -/** - * @brief Create a new PACOVR instance. - * - * Create a new PACOVR instance with specified batch and scratch sizes. Total - * size is the sum of batch and scratch sizes. - * - * @param[in] batch_size Size of the PACOVR batch region. - * @param[in] scratch_size Size of the scratch heap. - * @return struct pacovr* Pointer to the new PACOVR instance, or NULL on failure. - */ -struct pacovr *pacovr_create(size_t batch_size, size_t scratch_size); - -/** - * @brief Destroy a PACOVR instance. - * - * Free all associated resources and deallocate the PACOVR instance. - * - * @param[in] p Pointer to the PACOVR instance to destroy. - */ -void pacovr_destroy(struct pacovr *p); - -/** - * @brief Allocate memory from the PACOVR dynamic heap. - * - * Allocate memory from the PACOVR dynamic heap. Intended use for temporary - * allocations during audio processing. i.e. change of parameters or kcontrols. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_dynamic_alloc(struct pacovr *p, size_t size); - -/** - * @brief Allocate memory with alignment from the PACOVR dynamic heap. - * - * Allocate memory with alignment from the PACOVR dynamic heap. Intended use for - * temporary allocations during audio processing. i.e. change of parameters or - * kcontrols. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @param[in] align Alignment of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_dynamic_alloc_align(struct pacovr *p, size_t size, size_t align); - -/** - * @brief Free memory from the PACOVR dynamic heap. - * - * Free memory from the PACOVR dynamic heap. Intended use for temporary - * allocations during audio processing. i.e. change of parameters or - * kcontrols. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] ptr Pointer to the memory to free. - */ -void pacovr_dynamic_free(struct pacovr *p, void *ptr); - -/** - * @brief Allocate memory from the PACOVR static allocator. - * - * Allocate memory from the PACOVR static allocator. Intended use for - * allocations that persist for the lifetime of the audio processing pipeline. - * i.e. component data, buffers, etc. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @param[in] align Alignment of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_static_alloc(struct pacovr *p, size_t size); - -/** - * @brief Free memory from the PACOVR static allocator. - * - * Free memory from the PACOVR static allocator. This is a no-op and is - * intended for tuning and tracking only. Static allocations are freed - * when the PACOVR instance is destroyed. Any call to this function usually - * means the allocation should have been from the dynamic heap. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] ptr Pointer to the memory to free. - */ -void pacovr_static_free(struct pacovr *p, void *ptr); - -/** - * @brief Log PACOVR memory usage. - * - * @param[in] p Pointer to the PACOVR instance. - */ -void pacovr_info(struct pacovr *p); - -#ifdef __cplusplus -} -#endif - -#endif /* __SOF_LIB_PACOVR_H__ */ diff --git a/zephyr/include/sof/lib/vpage.h b/zephyr/include/sof/lib/vpages.h similarity index 91% rename from zephyr/include/sof/lib/vpage.h rename to zephyr/include/sof/lib/vpages.h index 0aea2fdeda97..ef290f75b02a 100644 --- a/zephyr/include/sof/lib/vpage.h +++ b/zephyr/include/sof/lib/vpages.h @@ -20,7 +20,7 @@ extern "C" { * * @return Pointer to the allocated virtual memory region, or NULL on failure. */ -void *vpage_alloc(uint32_t pages); +void *alloc_vpages(uint32_t pages); /** * @brief Free virtual pages @@ -28,7 +28,7 @@ void *vpage_alloc(uint32_t pages); * * @param[in] ptr Pointer to the memory pages to free. */ -void vpage_free(void *ptr); +void free_vpages(void *ptr); /** * @brief Initialize virtual page allocator @@ -39,7 +39,7 @@ void vpage_free(void *ptr); * @retval 0 if successful. * @retval -ENOMEM on creation failure. */ -int vpage_init(void); +int init_vpages(void); #ifdef __cplusplus } diff --git a/zephyr/include/sof/lib/vregion.h b/zephyr/include/sof/lib/vregion.h new file mode 100644 index 000000000000..87b61851c382 --- /dev/null +++ b/zephyr/include/sof/lib/vregion.h @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright(c) 2025 Intel Corporation. + +/* Pre Allocated Contiguous Virtual Region */ +#ifndef __SOF_LIB_VREGION_H__ +#define __SOF_LIB_VREGION_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct vregion; + +/** + * @brief Create a new virtual region instance. + * + * Create a new virtual region instance with specified static, dynamic, and shared static sizes + * plus an optional read-only text partition and optional shared static partition. + * Total size is the sum of static, dynamic, shared static, and text sizes. + * + * @param[in] lifetime_size Size of the virtual region lifetime partition. + * @param[in] interim_size Size of the virtual region interim partition. + * @param[in] lifetime_shared_size Size of the virtual region shared lifetime partition. + * @param[in] interim_shared_size Size of the virtual region shared interim partition. + * @param[in] text_size Size of the optional read-only text partition. + * @return struct vregion* Pointer to the new virtual region instance, or NULL on failure. + */ +struct vregion *vregion_create(size_t lifetime_size, size_t interim_size, + size_t lifetime_shared_size, size_t interim_shared_size, + size_t text_size); + +/** + * @brief Destroy a virtual region instance. + * + * Free all associated resources and deallocate the virtual region instance. + * + * @param[in] vr Pointer to the virtual region instance to destroy. + */ +void vregion_destroy(struct vregion *vr); + +/** + * @brief Memory types for virtual region allocations. + * Used to specify the type of memory allocation within a virtual region. + */ +enum vregion_mem_type { + VREGION_MEM_TYPE_INTERIM, /* interim allocation that can be freed */ + VREGION_MEM_TYPE_LIFETIME, /* lifetime allocation */ + VREGION_MEM_TYPE_INTERIM_SHARED, /* shared interim allocation */ + VREGION_MEM_TYPE_LIFETIME_SHARED /* shared lifetime allocation */ +}; +void *vregion_alloc(struct vregion *vr, enum vregion_mem_type type, size_t size); + +/** + * @brief Allocate aligned memory from the specified virtual region. + * + * Allocate aligned memory from the specified virtual region based on the memory type. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] type Type of memory to allocate (static, dynamic, or shared static). + * @param[in] size Size of memory to allocate in bytes. + * @param[in] alignment Alignment of memory to allocate in bytes. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc_align(struct vregion *vr, enum vregion_mem_type type, size_t size, size_t alignment); + +/** + * @brief Free memory allocated from the specified virtual region. + * + * Free memory previously allocated from the specified virtual region. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] ptr Pointer to the memory to free. + */ +void vregion_free(struct vregion *vr, void *ptr); + +/** + * @brief Log virtual region memory usage. + * + * @param[in] vr Pointer to the virtual region instance. + */ +void vregion_info(struct vregion *vr); + +#ifdef __cplusplus +} +#endif + +#endif /* __SOF_LIB_VREGION_H__ */ diff --git a/zephyr/lib/pacovr.c b/zephyr/lib/pacovr.c deleted file mode 100644 index 087737487fe4..000000000000 --- a/zephyr/lib/pacovr.c +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Copyright(c) 2025 Intel Corporation. - * - * Author: Liam Girdwood - */ - -#include -#include -#include -#include -#include -#include -#include - -LOG_MODULE_REGISTER(pacovr, CONFIG_SOF_LOG_LEVEL); - -/* - * Pre Allocated COntiguous Virtual memory Region - PACOVR. - * - * This allocator manages a pre-allocated virtual memory region that uses the - * virtual page allocator to allocate and free memory pages. - * - * It is designed for use cases where a contiguous virtual memory region - * is required, such as for batched allocation of audio pipelines and modules. - * - * New pipelines will create a new PACOVR that will contain a dynamic heap at - * the start of the region and above the dynamic heap will be a simple static - * linear incrementing allocator for audio pipeline modules. - * - * The dynamic heap is used for temporary allocations during audio processing whilst - * the static allocator is used for long term allocations that are freed when the - * pipeline is destroyed. - * - * TODO: Pipeline/module reset() could reset the dynamic heap. - */ - -/** - * @brief PACOVR memory region structure. - * - * This structure represents a PACOVR memory region, which includes - * information about the base address, size, and allocation status - * of the region. - * The PACOVR memory region is divided into two main areas: - * 1. Dynamic Heap: A dynamic memory area used for multiple temporary allocations - * and frees over the lifetime of the audio processing pipeline. - * 2. Static Allocator: A simple incrementing allocator used for long-term static - * allocations that persist for the lifetime of the audio processing pipeline. - */ -struct pacovr { - uint8_t *base; /* base address of region */ - size_t size; /* size of whole region in bytes */ - size_t static_used; /* used bytes in static heap */ - size_t dynamic_size; /* size of dynamic heap */ - size_t static_size; /* size of static heap */ - size_t pages; /* size of region in pages */ - struct k_heap dynamic; /* dynamic heap */ - uint8_t *static_ptr; /* current static alloc pointer */ - int static_free_count; /* number of static frees - tuning only */ -}; - -/** - * @brief Create a new PACOVR instance. - * @param[in] static_size Size of the PACOVR static region. - * @param[in] dynamic_size Size of the dynamic heap. - * @return struct pacovr* Pointer to the new PACOVR instance, or NULL on failure. - */ -struct pacovr *pacovr_create(size_t static_size, size_t dynamic_size) -{ - struct pacovr *p; - uint32_t pages; - size_t total_size; - - if (!static_size || !dynamic_size) { - LOG_ERR("error: invalid pacovr static size %d or dynamic size %d", - static_size, dynamic_size); - return NULL; - } - - /* align up static size and dynamic size to nearest page */ - static_size = ALIGN_UP(static_size, CONFIG_MM_DRV_PAGE_SIZE); - dynamic_size = ALIGN_UP(dynamic_size, CONFIG_MM_DRV_PAGE_SIZE); - total_size = static_size + dynamic_size; - - /* allocate pacovr structure in userspace */ - p = rzalloc(SOF_MEM_FLAG_USER, sizeof(*p)); - if (!p) - return NULL; - - /* allocate pages for pacovr */ - pages = (static_size + dynamic_size) / CONFIG_MM_DRV_PAGE_SIZE; - p->base = vpage_alloc(pages); - if (!p->base) { - rfree(p); - return NULL; - } - - /* init pacovr */ - p->size = total_size; - p->dynamic_size = dynamic_size; - p->static_size = static_size; - p->pages = pages; - p->static_ptr = p->base + dynamic_size; - - /* init dynamic heap */ - sys_heap_init(&p->dynamic.heap, p->base, dynamic_size); - - LOG_INF("pacovr created at base %p total size 0x%x pages %d dynamic 0x%x static 0x%x", - (void *)p->base, total_size, pages, dynamic_size, static_size); - - return p; -} - -/** - * @brief Destroy a PACOVR instance. - * - * @param[in] p Pointer to the PACOVR instance to destroy. - */ -void pacovr_destroy(struct pacovr *p) -{ - if (!p) - return; - LOG_INF("pacovr destroy base %p size 0x%x pages %d static used 0x%x free count %d", - (void *)p->base, p->size, p->pages, p->static_used, p->static_free_count); - vpage_free(p->base); - rfree(p); -} - -/** - * @brief Allocate memory from the PACOVR dynamic heap. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_dynamic_alloc(struct pacovr *p, size_t size) -{ - void *ptr; - - if (!p || !size) - return NULL; - - ptr = sys_heap_alloc(&p->dynamic.heap, size); - if (!ptr) { - LOG_ERR("error: pacovr dynamic alloc failed"); - return NULL; - } - - return ptr; -} - -/** - * @brief Allocate memory with alignment from the PACOVR dynamic heap. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @param[in] align Alignment of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_dynamic_alloc_align(struct pacovr *p, size_t size, size_t align) -{ - void *ptr; - - if (!p || !size) - return NULL; - - /* align up size to 4 bytes - force aligned loads and stores */ - if (!align) - align = sizeof(uint32_t); - - ptr = sys_heap_aligned_alloc(&p->dynamic.heap, size, align); - if (!ptr) { - LOG_ERR("error: pacovr dynamic alloc failed"); - return NULL; - } - - return ptr; -} - -/** - * @brief Free memory from the PACOVR dynamic heap. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] ptr Pointer to the memory to free. - */ -void pacovr_dynamic_free(struct pacovr *p, void *ptr) -{ - if (!p || !ptr) - return; - - sys_heap_free(&p->dynamic.heap, ptr); -} - -/** - * @brief Allocate memory from the PACOVR static allocator. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] size Size of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *pacovr_static_alloc(struct pacovr *p, size_t size) -{ - void *ptr; - - if (!p || !size) - return NULL; - - /* align up size to 4 bytes - force aligned loads and stores */ - size = ALIGN_UP(size, 4); - - /* check we have enough static space left */ - if (p->static_used + size > p->static_size) { - LOG_ERR("error: pacovr static alloc failed for %d bytes, only %d bytes free", - size, p->static_size - p->static_used); - return NULL; - } - - /* allocate memory */ - ptr = p->static_ptr; - p->static_ptr += size; - p->static_used += size; - return ptr; -} - -/** - * @brief Free memory from the PACOVR static allocator. - * - * @param[in] p Pointer to the PACOVR instance. - * @param[in] ptr Pointer to the memory to free. - */ -void pacovr_static_free(struct pacovr *p, void *ptr) -{ - if (!p || !ptr) - return; - - /* simple free, just increment free count, this is for tuning only */ - p->static_free_count++; - - LOG_DBG("pacovr static free %p count %d", ptr, p->static_free_count); -} - -/** - * @brief Log PACOVR memory usage. - * - * @param[in] p Pointer to the PACOVR instance. - */ -void pacovr_info(struct pacovr *p) -{ - if (!p) - return; - - LOG_INF("pacovr info base %p size 0x%x pages %d static used 0x%x free count %d", - (void *)p->base, p->size, p->pages, p->static_used, p->static_free_count); -} -EXPORT_SYMBOL(pacovr_info); diff --git a/zephyr/lib/vpages.c b/zephyr/lib/vpages.c index 491b184001a7..c7b63f307961 100644 --- a/zephyr/lib/vpages.c +++ b/zephyr/lib/vpages.c @@ -35,7 +35,7 @@ LOG_MODULE_REGISTER(vpage, CONFIG_SOF_LOG_LEVEL); struct valloc_elem { uint16_t pages; /* number of 4kB pages allocated in contiguous block */ uint16_t vpage; /* virtual page number from start of region */ -}; +} __packed; /* * Virtual page table structure @@ -150,7 +150,7 @@ static int vpages_alloc_and_map(uint32_t pages, void **ptr) * @retval ptr to allocated pages if successful. * @retval NULL on allocation failure. */ -void *vpage_alloc(uint32_t pages) +void *alloc_vpages(uint32_t pages) { void *ptr; int err; @@ -241,13 +241,13 @@ static int vpages_free_and_unmap(uintptr_t *ptr) * * @param ptr */ -void vpage_free(void *ptr) +void free_vpages(void *ptr) { k_mutex_lock(&page_context.lock, K_FOREVER); vpages_free_and_unmap((uintptr_t *)ptr); assert(!ret); /* should never fail */ k_mutex_unlock(&page_context.lock); - LOG_INF("vpage_free done ptr %p free pages %d/%d", ptr, page_context.free_pages, + LOG_INF("vptr %p free/total pages %d/%d", ptr, page_context.free_pages, page_context.total_pages); } @@ -260,7 +260,7 @@ void vpage_free(void *ptr) * @retval 0 if successful. * @retval -ENOMEM on creation failure. */ -static int vpage_init(void) +static int init_vpages(void) { const struct sys_mm_drv_region *virtual_memory_regions; const struct sys_mm_drv_region *region; @@ -337,5 +337,5 @@ static int vpage_init(void) return 0; } -SYS_INIT(vpage_init, POST_KERNEL, 1); +SYS_INIT(init_vpages, POST_KERNEL, 1); diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c new file mode 100644 index 000000000000..d097805167bd --- /dev/null +++ b/zephyr/lib/vregion.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2025 Intel Corporation. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(vregion, CONFIG_SOF_LOG_LEVEL); + +/* + * Pre Allocated Contiguous Virtual Memory Region Allocator + * + * This allocator manages a pre-allocated virtual memory region that uses the + * virtual page allocator to allocate and free memory pages. + * + * It is designed for use cases where a contiguous virtual memory region + * is required, such as for batched allocation of audio pipelines and modules. + * + * New pipelines will create a new virtual region that will contain a dynamic heap at + * the start of the region and above the dynamic heap will be a simple static + * linear incrementing allocator for audio pipeline modules. + * + * The dynamic heap is used for temporary allocations during audio processing whilst + * the static allocator is used for long term allocations that are freed when the + * pipeline is destroyed. + * + * The shared static allocator is used for short term audio buffers that can be + * shared between multiple pipelines and is reset when the pipeline is stopped. + * + * An optional read-only text region can be created at the start of the region + * that can be used to hold read-only data or executable code. + * + * TODO: Pipeline/module reset() could reset the dynamic heap. + */ + +/** + * @brief virtual region memory region structure. + * + * This structure represents a virtual region memory region, which includes + * information about the base address, size, and allocation status + * of the region. + * + * The virtual region memory region can be partitioned into four main areas + * (two are optional), listed here from base to top: + * + * 1. Text Region (optional): A read-only and executable region that can be used + * to store code or constant data. This region is optional and only present + * if the virtual region is created with a text size. It is page aligned and located + * at the start of the virtual region region. Main use case would be DP modules. + * + * 2. Dynamic Heap: A dynamic memory area used for multiple temporary allocations + * and frees over the lifetime of the audio processing pipeline. + * + * 3. Static Allocator: A simple incrementing allocator used for long-term static + * allocations that persist for the lifetime of the audio processing pipeline. + * + * 4. Shared Static Allocator (optional): A simple incrementing allocator used for long + * term static allocations that can be shared between multiple audio processing pipelines. This + * area is optional and only present if the virtual region is created with shared static size. + * It is page aligned and located after the dynamic heap and before the static allocator. + */ + +struct vlinear_heap { + uint8_t *base; /* base address of linear allocator */ + uint8_t *ptr; /* current alloc pointer */ + size_t size; /* size of linear allocator in bytes */ + size_t used; /* used bytes in linear allocator */ + int free_count; /* number of frees - tuning only */ +}; + +struct zephyr_heap { + struct sys_heap heap; + uint8_t *base; /* base address of linear allocator */ + size_t size; /* size of heap in bytes */ +}; + +struct vregion { + /* region context */ + uint8_t *base; /* base address of entire region */ + size_t size; /* size of whole region in bytes */ + size_t pages; /* size of whole region in pages */ + + /* optional text region - RO and Executable */ + struct vlinear_heap text; /* text linear heap */ + + /* interim heap */ + struct zephyr_heap interim; /* interim heap */ + + /* interim shared */ + struct zephyr_heap interim_shared; /* shared interim heap */ + + /* lifetime heap */ + struct vlinear_heap lifetime; /* lifetime linear heap */ + + /* optional shared static buffer heap */ + struct vlinear_heap lifetime_shared; /* shared lifetime linear heap */ +}; + +/** + * @brief Create a new virtual region instance with shared pages. + * + * Create a new VIRTUAL REGION instance with specified static, dynamic, and shared static sizes. + * Total size is the sum of static, dynamic, and shared static sizes. + * + * @param[in] lifetime_size Size of the virtual region lifetime partition. + * @param[in] interim_size Size of the virtual region interim partition. + * @param[in] lifetime_shared_size Size of the virtual region shared lifetime partition. + * @param[in] interim_shared_size Size of the virtual region shared interim partition. + * @param[in] text_size Size of the optional read-only text partition. + * @return struct vregion* Pointer to the new virtual region instance, or NULL on failure. + */ +struct vregion *vregion_create(size_t lifetime_size, size_t interim_size, + size_t lifetime_shared_size, size_t interim_shared_size, + size_t text_size) +{ + struct vregion *vr; + uint32_t pages; + size_t total_size; + + if (!lifetime_size || !interim_size) { + LOG_ERR("error: invalid vregion lifetime size %d or interim size %d", + lifetime_size, interim_size); + return NULL; + } + + /* align up lifetime size and interim size to nearest page */ + lifetime_size = ALIGN_UP(lifetime_size, CONFIG_MM_DRV_PAGE_SIZE); + interim_size = ALIGN_UP(interim_size, CONFIG_MM_DRV_PAGE_SIZE); + if (lifetime_shared_size) + lifetime_shared_size = ALIGN_UP(lifetime_shared_size, CONFIG_MM_DRV_PAGE_SIZE); + if (interim_shared_size) + interim_shared_size = ALIGN_UP(interim_shared_size, CONFIG_MM_DRV_PAGE_SIZE); + if (text_size) + text_size = ALIGN_UP(text_size, CONFIG_MM_DRV_PAGE_SIZE); + total_size = lifetime_size + interim_size + + lifetime_shared_size + interim_shared_size + text_size; + + /* allocate vregion structure in userspace */ + vr = rzalloc(SOF_MEM_FLAG_USER, sizeof(*vr)); + if (!vr) + return NULL; + + /* allocate pages for vregion */ + pages = total_size / CONFIG_MM_DRV_PAGE_SIZE; + vr->base = alloc_vpages(pages); + if (!vr->base) { + rfree(vr); + return NULL; + } + + /* init vregion */ + vr->size = total_size; + vr->pages = pages; + + /* set partition sizes */ + vr->interim.size = interim_size; + vr->interim_shared.size = interim_shared_size; + vr->lifetime.size = lifetime_size; + vr->lifetime_shared.size = lifetime_shared_size; + vr->text.size = text_size; + + /* set base addresses for partitions */ + vr->text.base = vr->base; + vr->interim.base = vr->text.base + text_size; + vr->lifetime.base = vr->interim.base + interim_size; + vr->lifetime_shared.base = vr->lifetime.base + lifetime_size; + vr->interim_shared.base = vr->lifetime_shared.base + lifetime_shared_size; + + /* set alloc ptr addresses for lifetime linear partitions */ + vr->text.ptr = vr->text.base; + vr->lifetime.ptr = vr->lifetime.base; + vr->lifetime_shared.ptr = vr->lifetime_shared.base; + + /* init interim heaps */ + sys_heap_init(&vr->interim.heap, vr->interim.base, interim_size); + if (interim_shared_size) { + sys_heap_init(&vr->interim_shared.heap, vr->interim_shared.base, + interim_shared_size); + } + + LOG_INF("new at %p size 0x%x pages %d", + (void *)vr->base, total_size, pages); + LOG_INF(" interim size 0x%x at %p", interim_size, (void *)vr->interim.base); + LOG_INF(" lifetime size 0x%x at %p", lifetime_size, (void *)vr->lifetime.base); + if (interim_shared_size) + LOG_INF(" interim shared size 0x%x at %p", interim_shared_size, + (void *)vr->interim_shared.base); + if (lifetime_shared_size) + LOG_INF(" lifetime shared size 0x%x at %p", lifetime_shared_size, + (void *)vr->lifetime_shared.base); + if (text_size) + LOG_INF(" text size 0x%x at %p", text_size, (void *)vr->text.base); + + return vr; +} + +/** + * @brief Destroy a virtual region instance. + * + * @param[in] vr Pointer to the virtual region instance to destroy. + */ +void vregion_destroy(struct vregion *vr) +{ + if (!vr) + return; + + LOG_INF("destroy %p size 0x%x pages %d", + (void *)vr->base, vr->size, vr->pages); + LOG_INF(" lifetime used %d free count %d", + vr->lifetime.used, vr->lifetime.free_count); + if (vr->lifetime_shared.size) + LOG_INF(" lifetime shared used %d free count %d", + vr->lifetime_shared.used, vr->lifetime_shared.free_count); + free_vpages(vr->base); + rfree(vr); +} + + +/** + * @brief Allocate memory with alignment from the virtual region dynamic heap. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] heap Pointer to the heap to use. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +static void *interim_alloc(struct vregion *vr, struct zephyr_heap *heap, + size_t size, size_t align) +{ + void *ptr; + + /* align up size to 4 bytes - force aligned loads and stores */ + if (!align) + align = sizeof(uint32_t); + + ptr = sys_heap_aligned_alloc(&heap->heap, size, align); + if (!ptr) { + LOG_ERR("error: interim alloc failed for %d bytes align %d", + size, align); + return NULL; + } + + return ptr; +} + +/** + * @brief Free memory from the virtual region interim heap. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] heap Pointer to the heap to use. + * @param[in] ptr Pointer to the memory to free. + */ +static void interim_free(struct vregion *vr, struct zephyr_heap *heap, void *ptr) +{ + sys_heap_free(&heap->heap, ptr); +} + +/** + * @brief Allocate memory from the virtual region lifetime allocator. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] heap Pointer to the linear heap to use. + * @param[in] size Size of the allocation. + * @param[in] align Alignment of the allocation. + * @param[in] align_size If non-zero also align up size to D$ line size. + * + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +static void *lifetime_alloc(struct vregion *vr, struct vlinear_heap *heap, + size_t size, size_t align, size_t align_size) +{ + void *ptr; + uint8_t *aligned_ptr; + size_t heap_obj_size; + + /* align up size to 4 bytes - force aligned loads and stores */ + if (!align) + align = sizeof(uint32_t); + + /* align heap pointer to alignment */ + aligned_ptr = UINT_TO_POINTER(ALIGN_UP(POINTER_TO_UINT(heap->ptr), align)); + + /* also align up size to D$ bytes if asked - allocation head and tail aligned */ + if (align_size && align_size < CONFIG_DCACHE_LINE_SIZE) + size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); + + /* calculate new heap object size for object and alignments */ + heap_obj_size = aligned_ptr - heap->ptr + size; + + /* check we have enough shared static space left */ + if (heap_obj_size + heap->used > heap->size) { + LOG_ERR("error: shared alloc failed for object %d heap %d bytes free %d", + size, heap_obj_size, heap->size - heap->used); + return NULL; + } + + /* allocate memory */ + ptr = aligned_ptr; + heap->ptr += heap_obj_size; + heap->used += heap_obj_size; + return ptr; +} + +/** + * @brief Free memory from the virtual region lifetime allocator. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] ptr Pointer to the memory to free. + */ +void lifetime_free(struct vregion *vr, struct vlinear_heap *heap, void *ptr) +{ + /* simple free, just increment free count, this is for tuning only */ + heap->free_count++; + + LOG_DBG("lifetime free %p count %d", ptr, heap->free_count); +} + +/** + * @brief Free memory from the virtual region. + * + * @param vr Pointer to the virtual region instance. + * @param ptr Pointer to the memory to free. + */ +void vregion_free(struct vregion *vr, void *ptr) +{ + if (!vr || !ptr) + return; + + /* check if pointer is in interim heap */ + if (ptr >= (void *)vr->interim.base && + ptr < (void *)(vr->interim.base + vr->interim.size)) { + interim_free(vr, &vr->interim, ptr); + return; + } + + /* check if pointer is in interim shared heap */ + if (vr->interim_shared.size && + ptr >= (void *)vr->interim_shared.base && + ptr < (void *)(vr->interim_shared.base + vr->interim_shared.size)) { + interim_free(vr, &vr->interim_shared, ptr); + return; + } + + /* check if pointer is in lifetime heap */ + if (ptr >= (void *)vr->lifetime.base && + ptr < (void *)(vr->lifetime.base + vr->lifetime.size)) { + lifetime_free(vr, &vr->lifetime, ptr); + return; + } + + /* check if pointer is in lifetime shared heap */ + if (vr->lifetime_shared.size && + ptr >= (void *)vr->lifetime_shared.base && + ptr < (void *)(vr->lifetime_shared.base + vr->lifetime_shared.size)) { + lifetime_free(vr, &vr->lifetime_shared, ptr); + return; + } + + LOG_ERR("error: vregion free invalid pointer %p", ptr); +} + +/** + * @brief Allocate memory type from the virtual region. + * + * @param[in] vr Pointer to the virtual region instance. + * @param[in] type Memory type to allocate. + * @param[in] size Size of the allocation. + * @param[in] alignment Alignment of the allocation. + * + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc_align(struct vregion *vr, enum vregion_mem_type type, + size_t size, size_t alignment) +{ + if (!vr || !size) + return NULL; + + switch (type) { + case VREGION_MEM_TYPE_INTERIM: + return interim_alloc(vr, &vr->interim, size, alignment); + case VREGION_MEM_TYPE_LIFETIME: + return lifetime_alloc(vr, &vr->lifetime, size, alignment, 0); + case VREGION_MEM_TYPE_INTERIM_SHARED: + return interim_alloc(vr, &vr->interim_shared, size, alignment); + case VREGION_MEM_TYPE_LIFETIME_SHARED: + return lifetime_alloc(vr, &vr->lifetime_shared, size, + alignment < CONFIG_DCACHE_LINE_SIZE ? CONFIG_DCACHE_LINE_SIZE : alignment, + CONFIG_DCACHE_LINE_SIZE); + default: + LOG_ERR("error: invalid memory type %d", type); + return NULL; + } +} + +/** + * @brief Allocate memory from the virtual region. + * @param[in] vr Pointer to the virtual region instance. + * @param[in] type Memory type to allocate. + * @param[in] size Size of the allocation. + * @return void* Pointer to the allocated memory, or NULL on failure. + */ +void *vregion_alloc(struct vregion *vr, enum vregion_mem_type type, size_t size) +{ + return vregion_alloc_align(vr, type, size, 0); +} + +/** + * @brief Log virtual region memory usage. + * + * @param[in] vr Pointer to the virtual region instance. + */ +void vregion_info(struct vregion *vr) +{ + if (!vr) + return; + + LOG_INF("base %p size 0x%x pages %d", + (void *)vr->base, vr->size, vr->pages); + LOG_INF("lifetime used 0x%x free count %d", + vr->lifetime.used, vr->lifetime.free_count); + LOG_INF("lifetime shared used 0x%x free count %d", + vr->lifetime_shared.used, vr->lifetime_shared.free_count); +} +EXPORT_SYMBOL(vregion_info); From d81de38562ffcb460ec9c8e6b8e9d213763be8cb Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 15 Oct 2025 19:38:52 +0100 Subject: [PATCH 47/56] vregions: dp schedule update Signed-off-by: Liam Girdwood --- src/schedule/zephyr_dp_schedule.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 1bba1332e085..a669b4d948e9 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -357,7 +357,13 @@ static int scheduler_dp_task_free(void *data, struct task *task) #endif /* free task stack */ +#if CONFIG_SOF_VREGIONS + struct vregion *vregion = module_get_vregion(pdata->mod); + vregion_free(vregion, (__sparse_force void *)pdata->p_stack); + ret = 0; +#else ret = user_stack_free((__sparse_force void *)pdata->p_stack); +#endif pdata->p_stack = NULL; /* all other memory has been allocated as a single malloc, will be freed later by caller */ @@ -547,7 +553,7 @@ int scheduler_dp_task_init(struct task **task, { void __sparse_cache *p_stack = NULL; struct sys_heap *const user_heap = mod->dev->drv->user_heap; - struct vregion *vregion; + struct vregion *vregion = module_get_vregion(mod); /* memory allocation helper structure */ struct { @@ -560,23 +566,16 @@ int scheduler_dp_task_init(struct task **task, /* must be called on the same core the task will be binded to */ assert(cpu_get_id() == core); -#if CONFIG_SOF_VREGIONS1 - - /* if module has its own vregion, use it otherwise use pipeline vregion */ - if (mod->vregion) { - vregion = mod->vregion; - } else { - /* otherwise use pipeline vregion */ - vregion = mod->dev->pipeline->vregion; - } - +#if CONFIG_SOF_VREGIONS //TODO: add check if vregion is in correct memory domain/coherent - task_memory = vregion_static_alloc(vregion, sizeof(*task_memory)); + task_memory = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME_SHARED, + sizeof(*task_memory), CONFIG_DCACHE_LINE_SIZE); if (!task_memory) { tr_err(&dp_tr, "vregion task memory alloc failed"); return -ENOMEM; } - p_stack = vregion_static_alloc(vregion, stack_size); + p_stack = vregion_alloc_align(vregion, VREGION_MEM_TYPE_LIFETIME, + stack_size, CONFIG_DCACHE_LINE_SIZE); if (!p_stack) { tr_err(&dp_tr, "vregion stack alloc failed"); return -ENOMEM; From 6eedcc89f45ae209708004a98ed8d017655906df Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 8 Oct 2025 16:44:02 +0300 Subject: [PATCH 48/56] zephyr/lib/vpages.c: Compile fix, remove idle assert on non existing ret variable --- zephyr/lib/vpages.c | 1 - 1 file changed, 1 deletion(-) diff --git a/zephyr/lib/vpages.c b/zephyr/lib/vpages.c index c7b63f307961..1f2d0fdbfa89 100644 --- a/zephyr/lib/vpages.c +++ b/zephyr/lib/vpages.c @@ -245,7 +245,6 @@ void free_vpages(void *ptr) { k_mutex_lock(&page_context.lock, K_FOREVER); vpages_free_and_unmap((uintptr_t *)ptr); - assert(!ret); /* should never fail */ k_mutex_unlock(&page_context.lock); LOG_INF("vptr %p free/total pages %d/%d", ptr, page_context.free_pages, page_context.total_pages); From e7ca28cafed3ed62551626d15874feba5617e8f3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 8 Oct 2025 08:20:55 -0700 Subject: [PATCH 49/56] audio: module_adapter: Set the pipeline pointer during module init Set the pipeline pointer during init for all modules and remove the code from copier init. Signed-off-by: Ranjani Sridharan --- src/audio/copier/copier.c | 19 +++---------------- src/audio/module_adapter/module_adapter.c | 11 +++++++++++ 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0331ed9231aa..bc51d8e37d39 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -123,13 +123,10 @@ static void mic_privacy_free(struct copier_data *cd) __cold static int copier_init(struct processing_module *mod) { union ipc4_connector_node_id node_id; - struct ipc_comp_dev *ipc_pipe; - struct ipc *ipc = ipc_get(); struct copier_data *cd; struct comp_dev *dev = mod->dev; struct module_data *md = &mod->priv; struct ipc4_copier_module_cfg *copier = (struct ipc4_copier_module_cfg *)md->cfg.init_data; - struct comp_ipc_config *config = &dev->ipc_config; void *gtw_cfg = NULL; size_t gtw_cfg_size; int i, ret = 0; @@ -173,16 +170,6 @@ __cold static int copier_init(struct processing_module *mod) for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) cd->out_fmt[i] = cd->config.out_fmt; - ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, - config->pipeline_id, - IPC_COMP_IGNORE_REMOTE); - if (!ipc_pipe) { - comp_err(dev, "pipeline %d is not existed", config->pipeline_id); - return -EPIPE; - } - - dev->pipeline = ipc_pipe->pipeline; - node_id = copier->gtw_cfg.node_id; /* copier is linked to gateway */ if (node_id.dw != IPC4_INVALID_NODE_ID) { @@ -191,7 +178,7 @@ __cold static int copier_init(struct processing_module *mod) switch (node_id.f.dma_type) { case ipc4_hda_host_output_class: case ipc4_hda_host_input_class: - ret = copier_host_create(mod, cd, copier, ipc_pipe->pipeline); + ret = copier_host_create(mod, cd, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create host"); return ret; @@ -214,7 +201,7 @@ __cold static int copier_init(struct processing_module *mod) case ipc4_i2s_link_input_class: case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: - ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline); + ret = copier_dai_create(dev, cd, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create dai"); return ret; @@ -232,7 +219,7 @@ __cold static int copier_init(struct processing_module *mod) #if CONFIG_IPC4_GATEWAY case ipc4_ipc_output_class: case ipc4_ipc_input_class: - ret = copier_ipcgtw_create(mod, cd, copier, ipc_pipe->pipeline); + ret = copier_ipcgtw_create(mod, cd, copier, dev->pipeline); if (ret < 0) { comp_err(dev, "unable to create IPC gateway"); return ret; diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 175430e4475b..ba6d4d0321fa 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -166,6 +166,17 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, else goto err; +#if CONFIG_IPC_MAJOR_4 + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); + + /* set the pipeline pointer if ipc_pipe is valid */ + ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id, + IPC_COMP_IGNORE_REMOTE); + if (ipc_pipe) + dev->pipeline = ipc_pipe->pipeline; +#endif + /* Init processing module */ ret = module_init(mod); if (ret) { From 24474652197957e8726fc41ffa7d9a5f7edb91f5 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 10 Oct 2025 12:39:37 +0300 Subject: [PATCH 50/56] src/audio/src/src_ipc4.c: comp_dgb > info --- src/audio/src/src_ipc4.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/audio/src/src_ipc4.c b/src/audio/src/src_ipc4.c index 1240a86bd48e..aff251ae0acc 100644 --- a/src/audio/src/src_ipc4.c +++ b/src/audio/src/src_ipc4.c @@ -48,6 +48,9 @@ DECLARE_TR_CTX(src_tr, SOF_UUID(src4_uuid), LOG_LEVEL_INFO); LOG_MODULE_DECLARE(src, CONFIG_SOF_LOG_LEVEL); +#undef comp_dbg +#define comp_dbg comp_info + int src_rate_check(const void *spec) { const struct ipc4_config_src *ipc_src = spec; From 655374dcd3cf94feb18f8eb01ddd6d401cd8abdc Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 16 Oct 2025 17:09:49 +0300 Subject: [PATCH 51/56] module_adapter: generic: Introduce mod_generic_init Factor out resource initialization so that it can be reused. While at it get rid of md variable. Signed-off-by: Daniel Baluta --- src/audio/module_adapter/module/generic.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index cc965b84bd1a..7a339a77b199 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -71,10 +71,20 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) return ret; } +static void mod_resource_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + /* Init memory list */ + list_init(&md->resources.res_list); + list_init(&md->resources.free_cont_list); + list_init(&md->resources.cont_chunk_list); + md->resources.heap_usage = 0; + md->resources.heap_high_water_mark = 0; +} + int module_init(struct processing_module *mod) { int ret; - struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; const struct module_interface *const interface = dev->drv->adapter_ops; @@ -99,14 +109,9 @@ int module_init(struct processing_module *mod) return -EIO; } - /* Init memory list */ - list_init(&md->resources.res_list); - list_init(&md->resources.free_cont_list); - list_init(&md->resources.cont_chunk_list); - md->resources.heap_usage = 0; - md->resources.heap_high_water_mark = 0; + mod_resource_init(mod); #if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) - md->resources.rsrc_mngr = k_current_get(); + mod->priv.resources.rsrc_mngr = k_current_get(); #endif /* Now we can proceed with module specific initialization */ ret = interface->init(mod); @@ -117,7 +122,7 @@ int module_init(struct processing_module *mod) comp_dbg(dev, "done"); #if CONFIG_IPC_MAJOR_3 - md->state = MODULE_INITIALIZED; + mod->priv.state = MODULE_INITIALIZED; #endif return 0; From 3c9c05f54dab5ae6d5b27b9d27bd1c61d7e3fc08 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sun, 12 Oct 2025 20:56:16 +0300 Subject: [PATCH 52/56] module_adapter: generic: Fix use after free Remove any containers from the free container list so that we don't keep pointers to containers that are no longer used and will be freed when container chunks are released below. Leaving those nodes in the free container list would cause use-after-free on subsequent allocations. While at it, make sure all resource lists are reset. Signed-off-by: Daniel Baluta --- src/audio/module_adapter/module/generic.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 7a339a77b199..19dc9cbd8296 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -628,6 +628,13 @@ void mod_free_all(struct processing_module *mod) list_item_del(&container->list); } + list_for_item_safe(list, _list, &res->free_cont_list) { + struct module_resource *container = + container_of(list, struct module_resource, list); + + list_item_del(&container->list); + } + list_for_item_safe(list, _list, &res->cont_chunk_list) { struct container_chunk *chunk = container_of(list, struct container_chunk, chunk_list); @@ -635,6 +642,9 @@ void mod_free_all(struct processing_module *mod) list_item_del(&chunk->chunk_list); rfree(chunk); } + + /* Make sure resource lists and accounting are reset */ + mod_resource_init(mod); } EXPORT_SYMBOL(mod_free_all); From 9bb77f5f49a116fa041695b23413748f9b02529c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 22 Oct 2025 22:33:12 +0300 Subject: [PATCH 53/56] Revert "audio: module_adapter: Set the pipeline pointer during module init" This reverts commit e7ca28cafed3ed62551626d15874feba5617e8f3. --- src/audio/copier/copier.c | 19 ++++++++++++++++--- src/audio/module_adapter/module_adapter.c | 11 ----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index bc51d8e37d39..0331ed9231aa 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -123,10 +123,13 @@ static void mic_privacy_free(struct copier_data *cd) __cold static int copier_init(struct processing_module *mod) { union ipc4_connector_node_id node_id; + struct ipc_comp_dev *ipc_pipe; + struct ipc *ipc = ipc_get(); struct copier_data *cd; struct comp_dev *dev = mod->dev; struct module_data *md = &mod->priv; struct ipc4_copier_module_cfg *copier = (struct ipc4_copier_module_cfg *)md->cfg.init_data; + struct comp_ipc_config *config = &dev->ipc_config; void *gtw_cfg = NULL; size_t gtw_cfg_size; int i, ret = 0; @@ -170,6 +173,16 @@ __cold static int copier_init(struct processing_module *mod) for (i = 0; i < IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT; i++) cd->out_fmt[i] = cd->config.out_fmt; + ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, + config->pipeline_id, + IPC_COMP_IGNORE_REMOTE); + if (!ipc_pipe) { + comp_err(dev, "pipeline %d is not existed", config->pipeline_id); + return -EPIPE; + } + + dev->pipeline = ipc_pipe->pipeline; + node_id = copier->gtw_cfg.node_id; /* copier is linked to gateway */ if (node_id.dw != IPC4_INVALID_NODE_ID) { @@ -178,7 +191,7 @@ __cold static int copier_init(struct processing_module *mod) switch (node_id.f.dma_type) { case ipc4_hda_host_output_class: case ipc4_hda_host_input_class: - ret = copier_host_create(mod, cd, copier, dev->pipeline); + ret = copier_host_create(mod, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create host"); return ret; @@ -201,7 +214,7 @@ __cold static int copier_init(struct processing_module *mod) case ipc4_i2s_link_input_class: case ipc4_alh_link_output_class: case ipc4_alh_link_input_class: - ret = copier_dai_create(dev, cd, copier, dev->pipeline); + ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create dai"); return ret; @@ -219,7 +232,7 @@ __cold static int copier_init(struct processing_module *mod) #if CONFIG_IPC4_GATEWAY case ipc4_ipc_output_class: case ipc4_ipc_input_class: - ret = copier_ipcgtw_create(mod, cd, copier, dev->pipeline); + ret = copier_ipcgtw_create(mod, cd, copier, ipc_pipe->pipeline); if (ret < 0) { comp_err(dev, "unable to create IPC gateway"); return ret; diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index ba6d4d0321fa..175430e4475b 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -166,17 +166,6 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, else goto err; -#if CONFIG_IPC_MAJOR_4 - struct ipc_comp_dev *ipc_pipe; - struct ipc *ipc = ipc_get(); - - /* set the pipeline pointer if ipc_pipe is valid */ - ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id, - IPC_COMP_IGNORE_REMOTE); - if (ipc_pipe) - dev->pipeline = ipc_pipe->pipeline; -#endif - /* Init processing module */ ret = module_init(mod); if (ret) { From 79f5155d031a3262c7e8a61d07d1ee057a6fa77a Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 22 Oct 2025 00:09:23 +0300 Subject: [PATCH 54/56] module_adapter: generic: Call mod_free_all() if module_init() fails Call mod_free_all() if module specific init fails. This fixes a resource leak in case the module initialization fails in module specific init. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 19dc9cbd8296..8b22f4137c51 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -117,6 +117,7 @@ int module_init(struct processing_module *mod) ret = interface->init(mod); if (ret) { comp_err(dev, "error %d: module specific init failed", ret); + mod_free_all(mod); return ret; } From afbcb129626338c812a5f6d7c20e0946547d0ded Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 21 Oct 2025 00:52:08 +0300 Subject: [PATCH 55/56] module_adapter: generic: Clean up and optimize mod_free_all() Rewrite misleading copy-pasted comment and remove unnecessary container removals from res->res_list and res->cont_chunk_list. All the containers are anyway freed when the container chunks are freed and the list heads are reinitialized when mod_resource_init() is called. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 8b22f4137c51..afad8fdca276 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -620,22 +620,20 @@ void mod_free_all(struct processing_module *mod) struct list_item *_list; MEM_API_CHECK_THREAD(res); - /* Find which container keeps this memory */ - list_for_item_safe(list, _list, &res->res_list) { + /* Free all contents found in used containers */ + list_for_item(list, &res->res_list) { struct module_resource *container = container_of(list, struct module_resource, list); free_contents(mod, container); - list_item_del(&container->list); - } - - list_for_item_safe(list, _list, &res->free_cont_list) { - struct module_resource *container = - container_of(list, struct module_resource, list); - - list_item_del(&container->list); } + /* + * We do not need to remove the containers from res_list in + * the loop above or go through free_cont_list as all the + * containers are anyway freed in the loop below, and the list + * heads are reinitialized when mod_resource_init() is called. + */ list_for_item_safe(list, _list, &res->cont_chunk_list) { struct container_chunk *chunk = container_of(list, struct container_chunk, chunk_list); From eded27a9fd84127e0f9e1f014f5ed37ef002f419 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 22 Oct 2025 18:23:27 +0300 Subject: [PATCH 56/56] common.h: Make IS_ALIGNED() safe for testing with alignment == 0 Make IS_ALIGNED() safe for testing with alignment == 0. Without this fix the DSP will crash if alignemnet is 0. Signed-off-by: Jyri Sarha --- src/include/sof/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/sof/common.h b/src/include/sof/common.h index 4bb279b039aa..8c81d3b091a8 100644 --- a/src/include/sof/common.h +++ b/src/include/sof/common.h @@ -20,7 +20,7 @@ /* Align the number to the nearest alignment value */ #ifndef IS_ALIGNED -#define IS_ALIGNED(size, alignment) ((size) % (alignment) == 0) +#define IS_ALIGNED(size, alignment) (!(alignment) || (size) % (alignment) == 0) #endif /* Treat zero as a special case because it wraps around */