diff --git a/src/audio/eq_fir/eq_fir.c b/src/audio/eq_fir/eq_fir.c index 0269c783a331..8cfbbd262b2e 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_alloc(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++) diff --git a/src/audio/eq_iir/eq_iir.c b/src/audio/eq_iir/eq_iir.c index 0e7d3a9b541d..9828997365f9 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 diff --git a/src/audio/google/google_ctc_audio_processing.c b/src/audio/google/google_ctc_audio_processing.c index 3e3e12224457..a93b888a145a 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_alloc(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_alloc(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; } diff --git a/src/audio/google/google_rtc_audio_processing.c b/src/audio/google/google_rtc_audio_processing.c index f98b2de7322c..c7ade653d9de 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; } diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index 5ab5424cdff3..c25ef14f380e 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_alloc(mod, cd->igo_lib_info.handle_size); if (!cd->p_handle) { comp_err(dev, "igo_handle memory rballoc 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; } diff --git a/src/audio/module_adapter/Kconfig b/src/audio/module_adapter/Kconfig index bb9081812271..3c762c73f7f8 100644 --- a/src/audio/module_adapter/Kconfig +++ b/src/audio/module_adapter/Kconfig @@ -3,6 +3,27 @@ menu "Processing modules" visible if COMP_MODULE_ADAPTER + config MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE + int "Number of memory containers to allocate at once" + default 16 + help + The per module resource containers are allocated in + chunks. The unused containers are kept in free + list. When the free list is empty the amount of + containers to allocate at once is selected by this + config option. + + config MODULE_MEMORY_API_DEBUG + bool "Turn on memory API thread safety checks" + default y if DEBUG + help + The Module Memory API structures are not protected + by locks. This is because the initialization, + allocation, and freeing of resources should always + be done in the same thread. This option adds an + assert to make sure no other thread makes such + operations. + config CADENCE_CODEC bool "Cadence codec" default n diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 03a345552f71..cb4ea2e3d5ae 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -14,6 +14,16 @@ #include #include +#include +#include + +/* The __ZEPHYR__ condition is to keep cmocka tests working */ +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) +#define MEM_API_CHECK_THREAD(res) __ASSERT((res)->rsrc_mngr == k_current_get(), \ + "Module memory API operation from wrong thread") +#else +#define MEM_API_CHECK_THREAD(res) +#endif LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); @@ -92,8 +102,14 @@ int module_init(struct processing_module *mod) } /* Init memory list */ - list_init(&md->memory.mem_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; +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) + md->resources.rsrc_mngr = k_current_get(); +#endif /* Now we can proceed with module specific initialization */ ret = interface->init(mod); if (ret) { @@ -110,6 +126,42 @@ int module_init(struct processing_module *mod) return 0; } +struct container_chunk { + struct list_item chunk_list; + struct module_resource containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; +}; + +static struct module_resource *container_get(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + + if (list_is_empty(&res->free_cont_list)) { + struct container_chunk *chunk = rzalloc(SOF_MEM_FLAG_USER, sizeof(*chunk)); + int i; + + if (!chunk) { + comp_err(mod->dev, "allocating more containers failed"); + return NULL; + } + + list_item_append(&chunk->chunk_list, &res->cont_chunk_list); + for (i = 0; i < ARRAY_SIZE(chunk->containers); i++) + list_item_append(&chunk->containers[i].list, &res->free_cont_list); + } + + container = list_first_item(&res->free_cont_list, struct module_resource, list); + list_item_del(&container->list); + return container; +} + +static void container_put(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; + + list_item_append(&container->list, &res->free_cont_list); +} + /** * Allocates aligned memory block for module. * @param mod Pointer to the module this memory block is allocatd for. @@ -121,20 +173,17 @@ int module_init(struct processing_module *mod) */ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment) { - struct comp_dev *dev = mod->dev; - struct module_memory *container; + struct module_resource *container = container_get(mod); + struct module_resources *res = &mod->priv.resources; void *ptr; - if (!size) { - comp_err(dev, "mod_alloc: requested allocation of 0 bytes."); + MEM_API_CHECK_THREAD(res); + if (!container) return NULL; - } - /* Allocate memory container */ - container = rzalloc(SOF_MEM_FLAG_USER, - sizeof(struct module_memory)); - if (!container) { - comp_err(dev, "mod_alloc: failed to allocate memory container."); + if (!size) { + comp_err(mod->dev, "mod_alloc: requested allocation of 0 bytes."); + container_put(mod, container); return NULL; } @@ -145,15 +194,20 @@ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t ali ptr = rballoc(SOF_MEM_FLAG_USER, size); if (!ptr) { - comp_err(dev, "mod_alloc: failed to allocate memory for comp %x.", - dev_comp_id(dev)); - rfree(container); + comp_err(mod->dev, "mod_alloc: failed to allocate memory for comp %x.", + dev_comp_id(mod->dev)); + container_put(mod, container); return NULL; } /* Store reference to allocated memory */ container->ptr = ptr; container->size = size; - list_item_prepend(&container->mem_list, &mod->priv.memory.mem_list); + container->type = MOD_RES_HEAP; + list_item_prepend(&container->list, &res->res_list); + + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; return ptr; } @@ -193,28 +247,124 @@ void *mod_zalloc(struct processing_module *mod, uint32_t size) } EXPORT_SYMBOL(mod_zalloc); +/** + * Creates a blob handler and releases it when the module is unloaded + * @param mod Pointer to module this memory block is allocated for. + * @return Pointer to the created data blob handler + * + * Like comp_data_blob_handler_new() but the handler is automatically freed. + */ +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler * +mod_data_blob_handler_new(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container = container_get(mod); + struct comp_data_blob_handler *bhp; + + MEM_API_CHECK_THREAD(res); + if (!container) + return NULL; + + bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); + if (!bhp) { + container_put(mod, container); + return NULL; + } + + container->bhp = bhp; + container->size = 0; + container->type = MOD_RES_BLOB_HANDLER; + list_item_prepend(&container->list, &res->res_list); + + return bhp; +} +EXPORT_SYMBOL(mod_data_blob_handler_new); +#endif + +/** + * Make a module associated shared SRAM copy of DRAM read-only data. + * @param mod Pointer to module this copy is allocated for. + * @return Pointer to the SRAM copy. + * + * Like fast_get() but the handler is automatically freed. + */ +#if CONFIG_FAST_GET +const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container = container_get(mod); + const void *ptr; + + MEM_API_CHECK_THREAD(res); + if (!container) + return NULL; + + ptr = fast_get(dram_ptr, size); + if (!ptr) { + container_put(mod, container); + return NULL; + } + + container->sram_ptr = ptr; + container->size = 0; + container->type = MOD_RES_FAST_GET; + list_item_prepend(&container->list, &res->res_list); + + return ptr; +} +EXPORT_SYMBOL(mod_fast_get); +#endif + +static int free_contents(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; + + switch (container->type) { + case MOD_RES_HEAP: + rfree(container->ptr); + res->heap_usage -= container->size; + return 0; +#if CONFIG_COMP_BLOB + case MOD_RES_BLOB_HANDLER: + comp_data_blob_handler_free(container->bhp); + return 0; +#endif +#if CONFIG_FAST_GET + case MOD_RES_FAST_GET: + fast_put(container->sram_ptr); + return 0; +#endif + default: + comp_err(mod->dev, "Unknown resource type: %d", container->type); + } + return -EINVAL; +} + /** * Frees the memory block removes it from module's book keeping. * @param mod Pointer to module this memory block was allocated for. * @param ptr Pointer to the memory block. */ -int mod_free(struct processing_module *mod, void *ptr) +int mod_free(struct processing_module *mod, const void *ptr) { - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + struct list_item *res_list; + MEM_API_CHECK_THREAD(res); if (!ptr) return 0; /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); - if (mem->ptr == ptr) { - rfree(mem->ptr); - list_item_del(&mem->mem_list); - rfree(mem); - return 0; + list_for_item(res_list, &res->res_list) { + container = container_of(res_list, struct module_resource, list); + if (container->ptr == ptr) { + int ret = free_contents(mod, container); + + list_item_del(&container->list); + container_put(mod, container); + return ret; } } @@ -225,6 +375,22 @@ int mod_free(struct processing_module *mod, void *ptr) } EXPORT_SYMBOL(mod_free); +#if CONFIG_COMP_BLOB +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh) +{ + mod_free(mod, (void *)dbh); +} +EXPORT_SYMBOL(mod_data_blob_handler_free); +#endif + +#if CONFIG_FAST_GET +void mod_fast_put(struct processing_module *mod, const void *sram_ptr) +{ + mod_free(mod, sram_ptr); +} +EXPORT_SYMBOL(mod_fast_put); +#endif + int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -396,23 +562,33 @@ int module_reset(struct processing_module *mod) } /** - * Frees all the memory allocated for this module - * @param mod Pointer to module this memory block was allocated for. + * Frees all the resources registered for this module + * @param mod Pointer to module that should have its resource freed. * * This function is called automatically when the module is unloaded. */ void mod_free_all(struct processing_module *mod) { - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resources *res = &mod->priv.resources; + struct list_item *list; + struct list_item *_list; + MEM_API_CHECK_THREAD(res); /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); - rfree(mem->ptr); - list_item_del(&mem->mem_list); - rfree(mem); + list_for_item_safe(list, _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->cont_chunk_list) { + struct container_chunk *chunk = + container_of(list, struct container_chunk, chunk_list); + + list_item_del(&chunk->chunk_list); + rfree(chunk); } } EXPORT_SYMBOL(mod_free_all); diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index da0353d892ab..10f722fd9bbd 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1289,18 +1289,14 @@ void module_adapter_free(struct comp_dev *dev) } EXPORT_SYMBOL(module_adapter_free); -size_t module_adapter_heap_usage(struct processing_module *mod) +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm) { - struct list_item *mem_list, *_mem_list; - size_t size = 0; + struct module_resources *res = &mod->priv.resources; - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - struct module_memory *mem = container_of(mem_list, struct module_memory, mem_list); + if (hwm) + *hwm = res->heap_high_water_mark; - size += mem->size; - } - - return size; + return res->heap_usage; } EXPORT_SYMBOL(module_adapter_heap_usage); diff --git a/src/audio/src/src_common.c b/src/audio/src/src_common.c index f96b3bc6e358..6331a6b9180e 100644 --- a/src/audio/src/src_common.c +++ b/src/audio/src/src_common.c @@ -627,12 +627,11 @@ int src_allocate_copy_stages(struct processing_module *mod, struct src_param *pr return -EINVAL; } - stage_dst[0].coefs = fast_get(stage_src1->coefs, coef_size[0]); - stage_dst[1].coefs = fast_get(stage_src2->coefs, coef_size[1]); + stage_dst[0].coefs = mod_fast_get(mod, stage_src1->coefs, coef_size[0]); + stage_dst[1].coefs = mod_fast_get(mod, stage_src2->coefs, coef_size[1]); if (!stage_dst[0].coefs || !stage_dst[1].coefs) { comp_err(mod->dev, "failed to allocate coefficients"); - fast_put(stage_dst[0].coefs); return -ENOMEM; } @@ -708,12 +707,5 @@ __cold int src_free(struct processing_module *mod) comp_info(mod->dev, "src_free()"); -#if CONFIG_FAST_GET - struct comp_data *cd = module_get_private_data(mod); - if (cd->param.stage1) { - fast_put(cd->param.stage1->coefs); - fast_put(cd->param.stage2->coefs); - } -#endif return 0; } diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index 2371d77124f5..881e74a2d108 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -59,7 +59,7 @@ struct module_data { enum module_state state; size_t new_cfg_size; /**< size of new module config data */ void *runtime_params; - struct module_memory memory; /**< memory allocated by module */ + struct module_resources resources; /**< resources allocated by module */ struct module_processing_data mpd; /**< shared data comp <-> module */ #endif /* SOF_MODULE_PRIVATE */ }; diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 1001c4ba450c..ced9fc710b11 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -19,6 +19,11 @@ #include #include "module_interface.h" +/* The __ZEPHYR__ condition is to keep cmocka tests working */ +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) +#include +#endif + /* * helpers to determine processing type * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE @@ -116,13 +121,42 @@ struct module_param { }; /** - * \struct module_memory - * \brief module memory block - used for every memory allocated by module + * \struct module_resources + * \brief module resources block - used for module allocation records + * The allocations are recorded so that they can be automatically freed + * when the module unloads. */ -struct module_memory { - void *ptr; /**< A pointr to particular memory block */ - struct list_item mem_list; /**< list of memory allocated by module */ - size_t size; +struct module_resources { + struct list_item res_list; /**< Allocad resource containers */ + struct list_item free_cont_list; /**< Unused memory containers */ + struct list_item cont_chunk_list; /**< Memory container chunks */ + size_t heap_usage; + size_t heap_high_water_mark; +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) + k_tid_t rsrc_mngr; +#endif +}; + +enum mod_resource_type { + MOD_RES_UNINITIALIZED = 0, + MOD_RES_HEAP, + MOD_RES_BLOB_HANDLER, + MOD_RES_FAST_GET, +}; + +/** + * \struct module_resource + * \brief module memory container - used for every memory allocated by module + */ +struct module_resource { + union { + void *ptr; /**< Pointer to heap allocated memory */ + struct comp_data_blob_handler *bhp; /**< Blob handler ptr */ + const void *sram_ptr; /**< SRAM ptr from fast_get() */ + }; + struct list_item list; /**< list element */ + size_t size; /**< Size of allocated heap memory, 0 if not from heap */ + enum mod_resource_type type; /**< Resource type */ }; /** @@ -157,7 +191,15 @@ int module_init(struct processing_module *mod); void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment); void *mod_alloc(struct processing_module *mod, uint32_t size); void *mod_zalloc(struct processing_module *mod, uint32_t size); -int mod_free(struct processing_module *mod, void *ptr); +int mod_free(struct processing_module *mod, const void *ptr); +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod); +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh); +#endif +#if CONFIG_FAST_GET +const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size); +void mod_fast_put(struct processing_module *mod, const void *sram_ptr); +#endif void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, @@ -223,7 +265,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd); void module_adapter_free(struct comp_dev *dev); int module_adapter_reset(struct comp_dev *dev); -size_t module_adapter_heap_usage(struct processing_module *mod); +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm); #if CONFIG_IPC_MAJOR_3 static inline diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt index 723cb091ff61..ea8cad0bd79e 100644 --- a/test/cmocka/src/audio/mixer/CMakeLists.txt +++ b/test/cmocka/src/audio/mixer/CMakeLists.txt @@ -25,6 +25,7 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-schedule.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-stream.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-xrun.c + ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c diff --git a/zephyr/sof_shell.c b/zephyr/sof_shell.c index 60785c4eb5c4..f10a2c9275b5 100644 --- a/zephyr/sof_shell.c +++ b/zephyr/sof_shell.c @@ -55,13 +55,15 @@ static int cmd_sof_module_heap_usage(const struct shell *sh, } list_for_item_safe(clist, _clist, &ipc->comp_list) { + size_t usage, hwm; + icd = container_of(clist, struct ipc_comp_dev, list); if (icd->type != COMP_TYPE_COMPONENT) continue; - shell_print(sh, "comp id 0x%08x\t%8zu bytes\t(%zu max)", icd->id, - module_adapter_heap_usage(comp_mod(icd->cd)), - comp_mod(icd->cd)->priv.cfg.heap_bytes); + usage = module_adapter_heap_usage(comp_mod(icd->cd), &hwm); + shell_print(sh, "comp id 0x%08x%9zu usage%9zu hwm %9zu max\tbytes", + icd->id, usage, hwm, comp_mod(icd->cd)->priv.cfg.heap_bytes); } return 0; }