From 37385b3799420d22aa48b96d67a1462e220878bf Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 4 Jun 2025 14:38:44 +0200 Subject: [PATCH 01/10] buf: extend module bind call API_CALL Currently bind api call passes IPC4 header only. This commit extends API by adding pointers to sink/source of the entity that is being bound. Note that in pipeline 2.0 there's a possibility to bind a module to a module, therefore pointers to sink/src need to be provided instead of a pointer to a buffer Signed-off-by: Marcin Szkudlinski --- src/audio/copier/copier.c | 4 +-- src/audio/kpb.c | 6 ++-- src/audio/mixin_mixout/mixin_mixout.c | 6 ++-- src/audio/module_adapter/module/generic.c | 4 +-- .../module_adapter/module_adapter_ipc4.c | 4 +-- src/debug/tester/tester.c | 4 +-- src/debug/tester/tester.h | 2 +- src/idc/idc.c | 4 +-- src/include/module/module/interface.h | 3 +- src/include/sof/audio/component.h | 36 ++++++++++++++++++- src/include/sof/audio/component_ext.h | 10 +++--- .../sof/audio/module_adapter/module/generic.h | 6 ++-- src/ipc/ipc4/helper.c | 10 ++++-- 13 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index bc6f92db62df..bb0c334644c9 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1173,9 +1173,9 @@ __cold static int copier_get_hw_params(struct comp_dev *dev, struct sof_ipc_stre return dai_common_get_hw_params(dd, dev, params, dir); } -__cold static int copier_bind(struct processing_module *mod, void *data) +__cold static int copier_bind(struct processing_module *mod, struct bind_info *bind_data) { - const struct ipc4_module_bind_unbind *const bu = (struct ipc4_module_bind_unbind *)data; + const struct ipc4_module_bind_unbind *const bu = bind_data->ipc4_data; const uint32_t src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); const uint32_t src_queue_id = bu->extension.r.src_queue; struct copier_data *cd = module_get_private_data(mod); diff --git a/src/audio/kpb.c b/src/audio/kpb.c index 61f85c34bca3..465f3b9fcd9e 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -333,10 +333,10 @@ static int kpb_get_attribute(struct comp_dev *dev, /** * \brief Initialize KPB sinks when binding. * \param[in] dev - component device pointer. - * \param[in] data - ipc4 bind/unbind data. + * \param[in] bind_data - bind/unbind data. * \return: none. */ -static int kpb_bind(struct comp_dev *dev, void *data) +static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data) { struct comp_data *kpb = comp_get_drvdata(dev); struct ipc4_module_bind_unbind *bu; @@ -345,7 +345,7 @@ static int kpb_bind(struct comp_dev *dev, void *data) comp_dbg(dev, "kpb_bind()"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = bind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); /* We're assuming here that KPB Real Time sink (kpb->sel_sink) is diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 0bbceebba3c1..4279da644d63 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -784,7 +784,7 @@ static int mixout_prepare(struct processing_module *mod, return 0; } -static int mixout_bind(struct processing_module *mod, void *data) +static int mixout_bind(struct processing_module *mod, struct bind_info *bind_data) { struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; @@ -792,9 +792,7 @@ static int mixout_bind(struct processing_module *mod, void *data) int src_id; struct mixout_data *mixout_data; - comp_dbg(mod->dev, "mixout_bind() %p", data); - - bu = (struct ipc4_module_bind_unbind *)data; + bu = bind_data->ipc4_data; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); /* we are only interested in bind for mixin -> mixout pair */ diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index f81fd42d3766..b303658f30af 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -493,12 +493,12 @@ int module_set_configuration(struct processing_module *mod, } EXPORT_SYMBOL(module_set_configuration); -int module_bind(struct processing_module *mod, void *data) +int module_bind(struct processing_module *mod, struct bind_info *bind_data) { const struct module_interface *const ops = mod->dev->drv->adapter_ops; if (ops->bind) - return ops->bind(mod, data); + return ops->bind(mod, bind_data); return 0; } diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index fb7642212f4f..f732b949bdc9 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -242,12 +242,12 @@ static bool module_adapter_multi_sink_source_prepare(struct comp_dev *dev) return false; } -int module_adapter_bind(struct comp_dev *dev, void *data) +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) { struct processing_module *mod = comp_mod(dev); int ret; - ret = module_bind(mod, data); + ret = module_bind(mod, bind_data); if (ret < 0) return ret; diff --git a/src/debug/tester/tester.c b/src/debug/tester/tester.c index bcbda904fcf7..a8f3a81770f0 100644 --- a/src/debug/tester/tester.c +++ b/src/debug/tester/tester.c @@ -188,13 +188,13 @@ static int tester_free(struct processing_module *mod) return ret; } -static int tester_bind(struct processing_module *mod, void *data) +static int tester_bind(struct processing_module *mod, struct bind_info *bind_data) { struct tester_module_data *cd = module_get_private_data(mod); int ret = 0; if (cd->tester_case_interface->bind) - ret = cd->tester_case_interface->bind(cd->test_case_ctx, mod, data); + ret = cd->tester_case_interface->bind(cd->test_case_ctx, mod, bind_data); return ret; } diff --git a/src/debug/tester/tester.h b/src/debug/tester/tester.h index ccfb8fabdc5a..8f759dc8ac56 100644 --- a/src/debug/tester/tester.h +++ b/src/debug/tester/tester.h @@ -75,7 +75,7 @@ struct tester_test_case_interface { /** * copy of module bind method, with additional ctx param */ - int (*bind)(void *ctx, struct processing_module *mod, void *data); + int (*bind)(void *ctx, struct processing_module *mod, struct bind_info *bind_data); /** * copy of module unbind method, with additional ctx param diff --git a/src/idc/idc.c b/src/idc/idc.c index 68efb2ee2f75..95477f1a93f3 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -86,14 +86,14 @@ static int idc_ipc4_bind(uint32_t comp_id) { struct ipc_comp_dev *ipc_dev; struct idc_payload *payload; - struct ipc4_module_bind_unbind *bu; + struct bind_info *bu; ipc_dev = ipc_get_comp_by_id(ipc_get(), comp_id); if (!ipc_dev) return -ENODEV; payload = idc_payload_get(*idc_get(), cpu_get_id()); - bu = (struct ipc4_module_bind_unbind *)payload; + bu = (struct bind_info *)payload; return comp_bind(ipc_dev->cd, bu); } diff --git a/src/include/module/module/interface.h b/src/include/module/module/interface.h index 75b4621c716c..1384b32d5540 100644 --- a/src/include/module/module/interface.h +++ b/src/include/module/module/interface.h @@ -65,6 +65,7 @@ struct output_stream_buffer { struct processing_module; struct sof_source; struct sof_sink; +struct bind_info; /* * This structure may be used by modules to carry short 16bit parameters. @@ -266,7 +267,7 @@ struct module_interface { * (optional) Module specific bind procedure, called when modules are bound with each other. * Usually can be __cold */ - int (*bind)(struct processing_module *mod, void *data); + int (*bind)(struct processing_module *mod, struct bind_info *bind_data); /** * (optional) Module specific unbind procedure, called when modules are disconnected from diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 0091419cc442..ff3f222214d9 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -271,6 +271,40 @@ enum comp_copy_type { struct comp_driver; struct comp_ipc_config; union ipc_config_specific; +struct ipc4_module_bind_unbind; + +enum bind_type { + COMP_BIND_TYPE_SOURCE, + COMP_BIND_TYPE_SINK +}; + +struct bind_info { + /* pointer to IPC4 bind data */ + struct ipc4_module_bind_unbind *ipc4_data; + + /* type of binding + * bind call will be called twice for every component, first when binding a data source, + * than when binding data sink. + * + * bind_type is indicating type of binding + */ + enum bind_type bind_type; + + /* pointers to sink or source API of the data provider/consumer + * that is being bound to the module + * + * if bind_type == COMP_BIND_TYPE_SOURCE, the pointer below points to source + * if bind_type == COMP_BIND_TYPE_SINK, the pointer below points to sink + * + * NOTE! As in pipeline2.0 there may be a binding between modules, + * without a buffer in between, it cannot be a pointer to any buffer type, module should + * use sink/source API + */ + union { + struct sof_source *source; + struct sof_sink *sink; + }; +}; /** * Audio component operations. @@ -481,7 +515,7 @@ struct comp_ops { * * Usually can be __cold. */ - int (*bind)(struct comp_dev *dev, void *data); + int (*bind)(struct comp_dev *dev, struct bind_info *bind_data); /** * Unbind, atomic - used to notify component of unbind event. diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index d66854f4b27d..54242077c469 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -432,29 +432,29 @@ static inline struct comp_driver_list *comp_drivers_get(void) } #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_bind_remote(struct comp_dev *dev, void *data) +static inline int comp_ipc4_bind_remote(struct comp_dev *dev, struct bind_info *bind_data) { struct idc_msg msg = { IDC_MSG_BIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, - sizeof(struct ipc4_module_bind_unbind), data}; + sizeof(*bind_data), bind_data}; return idc_send_msg(&msg, IDC_BLOCKING); } #endif -static inline int comp_bind(struct comp_dev *dev, void *data) +static inline int comp_bind(struct comp_dev *dev, struct bind_info *bind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.bind) return cpu_is_me(dev->ipc_config.core) ? - dev->drv->ops.bind(dev, data) : comp_ipc4_bind_remote(dev, data); + dev->drv->ops.bind(dev, bind_data) : comp_ipc4_bind_remote(dev, bind_data); return 0; #else int ret = 0; if (dev->drv->ops.bind) - ret = dev->drv->ops.bind(dev, data); + ret = dev->drv->ops.bind(dev, bind_data); return ret; #endif diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 60906685a21a..3dfb3f1f2edd 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -205,7 +205,7 @@ int module_set_configuration(struct processing_module *mod, enum module_cfg_fragment_position pos, size_t data_offset_size, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size); -int module_bind(struct processing_module *mod, void *data); +int module_bind(struct processing_module *mod, struct bind_info *bind_data); int module_unbind(struct processing_module *mod, void *data); struct comp_dev *module_adapter_new(const struct comp_driver *drv, @@ -246,7 +246,7 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ } static inline -int module_adapter_bind(struct comp_dev *dev, void *data) +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) { return 0; } @@ -281,7 +281,7 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ bool last_block, uint32_t *data_offset, char *data); int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value); int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value); -int module_adapter_bind(struct comp_dev *dev, void *data); +int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data); int module_adapter_unbind(struct comp_dev *dev, void *data); uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input); diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 09de3e448aa2..1f71373f5326 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -476,6 +476,7 @@ static int ll_wait_finished_on_core(struct comp_dev *dev) __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) { struct ipc4_module_bind_unbind *bu; + struct bind_info bind_data; struct comp_buffer *buffer; struct comp_dev *source; struct comp_dev *sink; @@ -652,11 +653,16 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) } /* these might call comp_ipc4_bind_remote() if necessary */ - ret = comp_bind(source, bu); + bind_data.ipc4_data = bu; + bind_data.bind_type = COMP_BIND_TYPE_SINK; + bind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + ret = comp_bind(source, &bind_data); if (ret < 0) goto e_src_bind; - ret = comp_bind(sink, bu); + bind_data.bind_type = COMP_BIND_TYPE_SOURCE; + bind_data.source = audio_buffer_get_source(&buffer->audio_buffer); + ret = comp_bind(sink, &bind_data); if (ret < 0) goto e_sink_bind; From 4a0a6e41519448582c0f1822b717fb5f9fe23140 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 4 Jun 2025 15:43:33 +0200 Subject: [PATCH 02/10] buf: extend module unbind call API_CALL Currently unbind api call passes IPC4 header only. This commit extends API by adding pointers to sink/source of the entity that is being bound. Note that in pipeline 2.0 there's a possibility to bind a module to a module, therefore pointers to sink/src need to be provided instead of a pointer to a buffer Signed-off-by: Marcin Szkudlinski --- src/audio/copier/copier.c | 4 ++-- src/audio/copier/dai_copier.h | 2 +- src/audio/dai-zephyr.c | 5 +++-- src/audio/kpb.c | 4 ++-- src/audio/mixin_mixout/mixin_mixout.c | 4 ++-- src/audio/module_adapter/module/generic.c | 4 ++-- src/audio/module_adapter/module_adapter_ipc4.c | 4 ++-- src/debug/tester/tester.c | 4 ++-- src/debug/tester/tester.h | 2 +- src/idc/idc.c | 4 ++-- src/include/module/module/interface.h | 3 ++- src/include/sof/audio/component.h | 8 ++++---- src/include/sof/audio/component_ext.h | 11 ++++++----- .../sof/audio/module_adapter/module/generic.h | 6 +++--- src/ipc/ipc4/helper.c | 16 +++++++++++++--- 15 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index bb0c334644c9..5d4b47a1d5fc 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1202,7 +1202,7 @@ __cold static int copier_bind(struct processing_module *mod, struct bind_info *b return -ENODEV; } -__cold static int copier_unbind(struct processing_module *mod, void *data) +__cold static int copier_unbind(struct processing_module *mod, struct bind_info *unbind_data) { struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; @@ -1212,7 +1212,7 @@ __cold static int copier_unbind(struct processing_module *mod, void *data) if (dev->ipc_config.type == SOF_COMP_DAI) { struct dai_data *dd = cd->dd[0]; - return dai_zephyr_unbind(dd, dev, data); + return dai_zephyr_unbind(dd, dev, unbind_data); } return 0; diff --git a/src/audio/copier/dai_copier.h b/src/audio/copier/dai_copier.h index a03970288b1b..0ec7f04ae6ac 100644 --- a/src/audio/copier/dai_copier.h +++ b/src/audio/copier/dai_copier.h @@ -69,7 +69,7 @@ static inline int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, v int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, struct comp_buffer *multi_endpoint_buffer, int num_endpoints); -int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data); +int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data); #endif diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index c36a89a9c57b..3d9ac2212158 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1961,14 +1961,15 @@ static uint64_t dai_get_processed_data(struct comp_dev *dev, uint32_t stream_no, } #ifdef CONFIG_IPC_MAJOR_4 -__cold int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data) +__cold +int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data) { struct ipc4_module_bind_unbind *bu; int buf_id; assert_can_be_cold(); - bu = (struct ipc4_module_bind_unbind *)data; + bu = unbind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); if (dd && dd->local_buffer) { diff --git a/src/audio/kpb.c b/src/audio/kpb.c index 465f3b9fcd9e..28a7423786fb 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -383,7 +383,7 @@ static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data) * \param[in] data - ipc4 bind/unbind data. * \return: none. */ -static int kpb_unbind(struct comp_dev *dev, void *data) +static int kpb_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { struct comp_data *kpb = comp_get_drvdata(dev); struct ipc4_module_bind_unbind *bu; @@ -391,7 +391,7 @@ static int kpb_unbind(struct comp_dev *dev, void *data) comp_dbg(dev, "kpb_bind()"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = unbind_data->ipc4_data; buf_id = IPC4_COMP_ID(bu->extension.r.src_queue, bu->extension.r.dst_queue); /* Reset sinks when unbinding */ diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 4279da644d63..82ff7acfb030 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -831,7 +831,7 @@ static int mixout_bind(struct processing_module *mod, struct bind_info *bind_dat return 0; } -static int mixout_unbind(struct processing_module *mod, void *data) +static int mixout_unbind(struct processing_module *mod, struct bind_info *unbind_data) { struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; @@ -841,7 +841,7 @@ static int mixout_unbind(struct processing_module *mod, void *data) comp_dbg(mod->dev, "mixout_unbind()"); - bu = (struct ipc4_module_bind_unbind *)data; + bu = unbind_data->ipc4_data; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); /* we are only interested in unbind for mixin -> mixout pair */ diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index b303658f30af..cab35e7925a2 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -502,12 +502,12 @@ int module_bind(struct processing_module *mod, struct bind_info *bind_data) return 0; } -int module_unbind(struct processing_module *mod, void *data) +int module_unbind(struct processing_module *mod, struct bind_info *unbind_data) { const struct module_interface *const ops = mod->dev->drv->adapter_ops; if (ops->unbind) - return ops->unbind(mod, data); + return ops->unbind(mod, unbind_data); return 0; } diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index f732b949bdc9..a50b78ff7714 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -257,12 +257,12 @@ int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) } EXPORT_SYMBOL(module_adapter_bind); -int module_adapter_unbind(struct comp_dev *dev, void *data) +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { struct processing_module *mod = comp_mod(dev); int ret; - ret = module_unbind(mod, data); + ret = module_unbind(mod, unbind_data); if (ret < 0) return ret; diff --git a/src/debug/tester/tester.c b/src/debug/tester/tester.c index a8f3a81770f0..575e339646a8 100644 --- a/src/debug/tester/tester.c +++ b/src/debug/tester/tester.c @@ -199,13 +199,13 @@ static int tester_bind(struct processing_module *mod, struct bind_info *bind_dat return ret; } -static int tester_unbind(struct processing_module *mod, void *data) +static int tester_unbind(struct processing_module *mod, struct bind_info *unbind_data) { struct tester_module_data *cd = module_get_private_data(mod); int ret = 0; if (cd->tester_case_interface->unbind) - ret = cd->tester_case_interface->unbind(cd->test_case_ctx, mod, data); + ret = cd->tester_case_interface->unbind(cd->test_case_ctx, mod, unbind_data); return ret; } diff --git a/src/debug/tester/tester.h b/src/debug/tester/tester.h index 8f759dc8ac56..79a65b65a7b2 100644 --- a/src/debug/tester/tester.h +++ b/src/debug/tester/tester.h @@ -80,7 +80,7 @@ struct tester_test_case_interface { /** * copy of module unbind method, with additional ctx param */ - int (*unbind)(void *ctx, struct processing_module *mod, void *data); + int (*unbind)(void *ctx, struct processing_module *mod, struct bind_info *unbind_data); /** * copy of module trigger method, with additional ctx param diff --git a/src/idc/idc.c b/src/idc/idc.c index 95477f1a93f3..8250175bfcb7 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -102,14 +102,14 @@ static int idc_ipc4_unbind(uint32_t comp_id) { struct ipc_comp_dev *ipc_dev; struct idc_payload *payload; - struct ipc4_module_bind_unbind *bu; + struct bind_info *bu; ipc_dev = ipc_get_comp_by_id(ipc_get(), comp_id); if (!ipc_dev) return -ENODEV; payload = idc_payload_get(*idc_get(), cpu_get_id()); - bu = (struct ipc4_module_bind_unbind *)payload; + bu = (struct bind_info *)payload; return comp_unbind(ipc_dev->cd, bu); } diff --git a/src/include/module/module/interface.h b/src/include/module/module/interface.h index 1384b32d5540..26c176aee9b1 100644 --- a/src/include/module/module/interface.h +++ b/src/include/module/module/interface.h @@ -66,6 +66,7 @@ struct processing_module; struct sof_source; struct sof_sink; struct bind_info; +struct bind_info; /* * This structure may be used by modules to carry short 16bit parameters. @@ -273,7 +274,7 @@ struct module_interface { * (optional) Module specific unbind procedure, called when modules are disconnected from * one another. Usually can be __cold */ - int (*unbind)(struct processing_module *mod, void *data); + int (*unbind)(struct processing_module *mod, struct bind_info *unbind_data); /** * (optional) Module specific trigger procedure, called when modules are triggered. Usually diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index ff3f222214d9..337730ccae7d 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -279,7 +279,7 @@ enum bind_type { }; struct bind_info { - /* pointer to IPC4 bind data */ + /* pointer to IPC4 bind/unbind data */ struct ipc4_module_bind_unbind *ipc4_data; /* type of binding @@ -293,8 +293,8 @@ struct bind_info { /* pointers to sink or source API of the data provider/consumer * that is being bound to the module * - * if bind_type == COMP_BIND_TYPE_SOURCE, the pointer below points to source - * if bind_type == COMP_BIND_TYPE_SINK, the pointer below points to sink + * if bind_type == COMP_BIND_TYPE_SOURCE, the pointer points to source being bound/unbound + * if bind_type == COMP_BIND_TYPE_SINK, the pointer points to sink being bound/unbound * * NOTE! As in pipeline2.0 there may be a binding between modules, * without a buffer in between, it cannot be a pointer to any buffer type, module should @@ -524,7 +524,7 @@ struct comp_ops { * * Usually can be __cold. */ - int (*unbind)(struct comp_dev *dev, void *data); + int (*unbind)(struct comp_dev *dev, struct bind_info *unbind_data); /** * Gets config in component. diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 54242077c469..c33f792f075a 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -461,29 +461,30 @@ static inline int comp_bind(struct comp_dev *dev, struct bind_info *bind_data) } #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, void *data) +static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, struct bind_info *unbind_data) { struct idc_msg msg = { IDC_MSG_UNBIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, - sizeof(struct ipc4_module_bind_unbind), data}; + sizeof(*unbind_data), unbind_data}; return idc_send_msg(&msg, IDC_BLOCKING); } #endif -static inline int comp_unbind(struct comp_dev *dev, void *data) +static inline int comp_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.unbind) return cpu_is_me(dev->ipc_config.core) ? - dev->drv->ops.unbind(dev, data) : comp_ipc4_unbind_remote(dev, data); + dev->drv->ops.unbind(dev, unbind_data) : + comp_ipc4_unbind_remote(dev, unbind_data); return 0; #else int ret = 0; if (dev->drv->ops.unbind) - ret = dev->drv->ops.unbind(dev, data); + ret = dev->drv->ops.unbind(dev, unbind_data); return ret; #endif diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 3dfb3f1f2edd..fb7f4ca02202 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -206,7 +206,7 @@ int module_set_configuration(struct processing_module *mod, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size); int module_bind(struct processing_module *mod, struct bind_info *bind_data); -int module_unbind(struct processing_module *mod, void *data); +int module_unbind(struct processing_module *mod, struct bind_info *unbind_data); struct comp_dev *module_adapter_new(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec); @@ -252,7 +252,7 @@ int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) } static inline -int module_adapter_unbind(struct comp_dev *dev, void *data) +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) { return 0; } @@ -282,7 +282,7 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value); int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value); int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data); -int module_adapter_unbind(struct comp_dev *dev, void *data); +int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data); uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input); diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 1f71373f5326..b2c84f7f5edd 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -683,7 +683,10 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_SUCCESS; e_sink_bind: - comp_unbind(source, bu); + /* sink bind was already called */ + bind_data.bind_type = COMP_BIND_TYPE_SINK; + bind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + comp_unbind(source, &bind_data); e_src_bind: pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); e_sink_connect: @@ -710,6 +713,7 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) uint32_t flags = 0; int ret, ret1; bool cross_core_unbind; + struct bind_info unbind_data; assert_can_be_cold(); @@ -779,8 +783,14 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) pipeline_disconnect(src, buffer, PPL_CONN_DIR_COMP_TO_BUFFER); pipeline_disconnect(sink, buffer, PPL_CONN_DIR_BUFFER_TO_COMP); /* these might call comp_ipc4_bind_remote() if necessary */ - ret = comp_unbind(src, bu); - ret1 = comp_unbind(sink, bu); + unbind_data.ipc4_data = bu; + unbind_data.bind_type = COMP_BIND_TYPE_SINK; + unbind_data.sink = audio_buffer_get_sink(&buffer->audio_buffer); + ret = comp_unbind(src, &unbind_data); + + unbind_data.bind_type = COMP_BIND_TYPE_SOURCE; + unbind_data.source = audio_buffer_get_source(&buffer->audio_buffer); + ret1 = comp_unbind(sink, &unbind_data); ll_unblock(cross_core_unbind, flags); From e47ec84a3c190d6106c9c3d41af2c9985f54703b Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 4 Jun 2025 16:34:39 +0200 Subject: [PATCH 03/10] mod: add bind/unbind hook to sink/source API This commit adds bind/unbind hook to sink/source API It is guaranteed that the hooks will be called on core that the API will be / was used on, what makes them a perfect place for cache operations needed at start/end of usage. Note that free method is not a good place for this, as in case of shared buffers it may happen on either of the cores the buffer connects Signed-off-by: Marcin Szkudlinski --- src/audio/module_adapter/module/generic.c | 38 +++++++++++++-- src/include/module/audio/sink_api.h | 57 ++++++++++++++++++++++ src/include/module/audio/source_api.h | 58 ++++++++++++++++++++++- 3 files changed, 148 insertions(+), 5 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index cab35e7925a2..1e806a1d4915 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -495,20 +495,50 @@ EXPORT_SYMBOL(module_set_configuration); int module_bind(struct processing_module *mod, struct bind_info *bind_data) { + int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; + switch (bind_data->bind_type) { + case COMP_BIND_TYPE_SINK: + ret = sink_bind(bind_data->sink, mod); + break; + case COMP_BIND_TYPE_SOURCE: + ret = source_bind(bind_data->source, mod); + break; + default: + ret = -EINVAL; + } + if (ret) + return ret; + if (ops->bind) - return ops->bind(mod, bind_data); - return 0; + ret = ops->bind(mod, bind_data); + + return ret; } int module_unbind(struct processing_module *mod, struct bind_info *unbind_data) { + int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; + switch (unbind_data->bind_type) { + case COMP_BIND_TYPE_SINK: + ret = sink_unbind(unbind_data->sink); + break; + case COMP_BIND_TYPE_SOURCE: + ret = source_unbind(unbind_data->source); + break; + default: + ret = -EINVAL; + } + if (ret) + return ret; + if (ops->unbind) - return ops->unbind(mod, unbind_data); - return 0; + ret = ops->unbind(mod, unbind_data); + + return ret; } void module_update_buffer_position(struct input_stream_buffer *input_buffers, diff --git a/src/include/module/audio/sink_api.h b/src/include/module/audio/sink_api.h index 839111abc536..527fd1dc11c6 100644 --- a/src/include/module/audio/sink_api.h +++ b/src/include/module/audio/sink_api.h @@ -51,6 +51,7 @@ struct sof_sink; struct sof_audio_stream_params; struct sof_ipc_stream_params; +struct processing_module; /** * this is a definition of internals of sink API @@ -101,6 +102,14 @@ struct sink_ops { int (*set_alignment_constants)(struct sof_sink *sink, const uint32_t byte_align, const uint32_t frame_align_req); + + /** + * OPTIONAL + * events called when a module is starting / finishing using of the API + * on the core that the module and API will executed on + */ + int (*on_bind)(struct sof_sink *sink, struct processing_module *module); + int (*on_unbind)(struct sof_sink *sink); }; /** internals of sink API. NOT TO BE MODIFIED OUTSIDE OF sink_api.c */ @@ -111,6 +120,7 @@ struct sof_sink { size_t min_free_space; /** minimum buffer space required by the module using sink * it is module's OBS as declared in module bind IPC */ + struct processing_module *bound_module; /* a pointer module that is using sink API */ struct sof_audio_stream_params *audio_stream_params; /** pointer to audio params */ }; @@ -291,4 +301,51 @@ static inline uint32_t sink_get_pipeline_id(struct sof_sink *sink) return sink->audio_stream_params->pipeline_id; } +/** + * @brief hook to be called when a module connects to the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int sink_bind(struct sof_sink *sink, struct processing_module *module) +{ + int ret = 0; + + if (sink->bound_module) + return -EBUSY; + + if (sink->ops->on_bind) + ret = sink->ops->on_bind(sink, module); + + if (!ret) + sink->bound_module = module; + + return ret; +} + +/** + * @brief hook to be called when a module disconnects from the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int sink_unbind(struct sof_sink *sink) +{ + int ret = 0; + + if (!sink->bound_module) + return -EINVAL; + + if (sink->ops->on_unbind) + ret = sink->ops->on_unbind(sink); + + if (!ret) + sink->bound_module = NULL; + + return ret; +} + +static inline struct processing_module *sink_get_bound_module(struct sof_sink *sink) +{ + return sink->bound_module; +} + #endif /* __MODULE_AUDIO_SINK_API_H__ */ diff --git a/src/include/module/audio/source_api.h b/src/include/module/audio/source_api.h index cb82cab457f3..336535e1be26 100644 --- a/src/include/module/audio/source_api.h +++ b/src/include/module/audio/source_api.h @@ -51,6 +51,7 @@ struct sof_source; struct sof_audio_stream_params; struct sof_ipc_stream_params; +struct processing_module; /** * this is a definition of internals of source API @@ -101,6 +102,14 @@ struct source_ops { int (*set_alignment_constants)(struct sof_source *source, const uint32_t byte_align, const uint32_t frame_align_req); + + /** + * OPTIONAL + * events called when a module is starting / finishing using of the API + * on the core that the module and API will executed on + */ + int (*on_bind)(struct sof_source *source, struct processing_module *module); + int (*on_unbind)(struct sof_source *source); }; /** internals of source API. NOT TO BE MODIFIED OUTSIDE OF source_api.c */ @@ -112,7 +121,7 @@ struct sof_source { * source * it is module's IBS as declared in module bind IPC */ - + struct processing_module *bound_module; /* a pointer module that is using source API */ struct sof_audio_stream_params *audio_stream_params; }; @@ -267,4 +276,51 @@ static inline uint32_t source_get_pipeline_id(struct sof_source *source) return source->audio_stream_params->pipeline_id; } +/** + * @brief hook to be called when a module connects to the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int source_bind(struct sof_source *source, struct processing_module *module) +{ + int ret = 0; + + if (source->bound_module) + return -EBUSY; + + if (source->ops->on_bind) + ret = source->ops->on_bind(source, module); + + if (!ret) + source->bound_module = module; + + return ret; +} + +/** + * @brief hook to be called when a module disconnects from the API + * + * NOTE! it MUST be called at core that a module is bound to + */ +static inline int source_unbind(struct sof_source *source) +{ + int ret = 0; + + if (!source->bound_module) + return -EINVAL; + + if (source->ops->on_unbind) + ret = source->ops->on_unbind(source); + + if (!ret) + source->bound_module = NULL; + + return ret; +} + +static inline struct processing_module *source_get_bound_module(struct sof_source *source) +{ + return source->bound_module; +} + #endif /* __MODULE_AUDIO_SOURCE_API_H__ */ From d1ae44876c73ad6f09cc2c31550c43793ec588dd Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Thu, 5 Jun 2025 12:49:10 +0200 Subject: [PATCH 04/10] ipc: propagate unbind event in all cases Unbind used to be ignored for components in the same pipeline But there are some code that depends on the event and need to have it in all situations, i.e. dai_zephyr_unbind or cross-core DP connections in the same pipeline Propagate the event in all cases Signed-off-by: Marcin Szkudlinski --- src/ipc/ipc4/helper.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index b2c84f7f5edd..ed4fff79fb2d 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -727,11 +727,6 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) return IPC4_INVALID_RESOURCE_ID; } - if (src->pipeline == sink->pipeline) { - tr_warn(&ipc_tr, "ignoring unbinding of src %x and dst %x", src_id, sink_id); - return 0; - } - cross_core_unbind = src->ipc_config.core != sink->ipc_config.core; /* Pass IPC to target core if both modules has the same target core, From 0ea4145e9c425f9c1e3ad83f2cbba8b797c45d99 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Thu, 5 Jun 2025 15:09:48 +0200 Subject: [PATCH 05/10] buf: add cache invalidation on unbind unbind hook in buffer is guaranteed to be called on the core that was using the API. Free, however, may be called on other core Add cache invalidation, that must be called on core that was producing data (user of sink API) in unbind hook. Signed-off-by: Marcin Szkudlinski --- src/audio/buffers/ring_buffer.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/audio/buffers/ring_buffer.c b/src/audio/buffers/ring_buffer.c index 52acc91a11f4..ec6005b5d1e2 100644 --- a/src/audio/buffers/ring_buffer.c +++ b/src/audio/buffers/ring_buffer.c @@ -239,6 +239,21 @@ static int ring_buffer_release_data(struct sof_source *source, size_t free_size) return 0; } +int ring_buffer_module_unbind(struct sof_sink *sink) +{ + struct ring_buffer *ring_buffer = ring_buffer_from_sink(sink); + + CORE_CHECK_STRUCT(&ring_buffer->audio_buffer); + + /* in case of disconnection, invalidate all cache. This method is guaranteed be called on + * core that have been using sink API + */ + ring_buffer_invalidate_shared(ring_buffer, ring_buffer->_data_buffer, + ring_buffer->data_buffer_size); + + return 0; +} + static struct source_ops ring_buffer_source_ops = { .get_data_available = ring_buffer_get_data_available, .get_data = ring_buffer_get_data, @@ -249,6 +264,7 @@ static struct sink_ops ring_buffer_sink_ops = { .get_free_size = ring_buffer_get_free_size, .get_buffer = ring_buffer_get_buffer, .commit_buffer = ring_buffer_commit_buffer, + .on_unbind = ring_buffer_module_unbind, }; static const struct audio_buffer_ops audio_buffer_ops = { From 6aabe882df7ffd8e7efead034e6fbbde733be74a Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Mon, 16 Jun 2025 08:40:51 +0200 Subject: [PATCH 06/10] mem: move struct vmh_heap to c file for privacy struct vmh_heap is a private structure and should not be used outside of regions_mm.c file structure moved Signed-off-by: Marcin Szkudlinski --- zephyr/include/sof/lib/regions_mm.h | 27 --------------------------- zephyr/lib/alloc.c | 1 + zephyr/lib/regions_mm.c | 27 +++++++++++++++++++++++++++ zephyr/test/vmh.c | 1 + 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/zephyr/include/sof/lib/regions_mm.h b/zephyr/include/sof/lib/regions_mm.h index 3cc8766f4d78..fb310a8c9174 100644 --- a/zephyr/include/sof/lib/regions_mm.h +++ b/zephyr/include/sof/lib/regions_mm.h @@ -44,33 +44,6 @@ */ #define DEFAULT_CONFIG_ALOCATORS_COUNT 5 -/** @struct vmh_heap - * - * @brief This structure holds all information about virtual memory heap - * it aggregates information about its allocations and - * physical mappings. - * - * @var node generic list member used for list operations - * @var virtual_region pointer to virtual region information, it holds its - * attributes size and beginning ptr provided by zephyr. - * @var physical_blocks_allocators[] a table of block allocators - * each representing a virtual regions part in blocks of a given size - * governed by sys_mem_blocks API. - * @var allocation_sizes[] a table of bit arrays representing sizes of allocations - * made in physical_blocks_allocators directly related to physical_blocks_allocators - * @var core_id id of the core that heap was created on - * @var allocating_continuously configuration value deciding if heap allocations - * will be contiguous or single block. - */ -struct vmh_heap { - struct list_item node; - const struct sys_mm_drv_region *virtual_region; - struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; - struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; - int core_id; - bool allocating_continuously; -}; - /** @struct vmh_block_bundle_descriptor * * @brief This is a struct describing one bundle of blocks diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index 3cfc6eb97296..11d867991655 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -21,6 +21,7 @@ #if CONFIG_VIRTUAL_HEAP #include +struct vmh_heap; struct vmh_heap *virtual_buffers_heap[CONFIG_MP_MAX_NUM_CPUS]; struct k_spinlock vmh_lock; diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index b921b9c24a96..d07c2582664a 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -13,6 +13,33 @@ /* list of vmh_heap objects created */ static struct list_item vmh_list = LIST_INIT(vmh_list); +/** @struct vmh_heap + * + * @brief This structure holds all information about virtual memory heap + * it aggregates information about its allocations and + * physical mappings. + * + * @var node generic list member used for list operations + * @var virtual_region pointer to virtual region information, it holds its + * attributes size and beginning ptr provided by zephyr. + * @var physical_blocks_allocators[] a table of block allocators + * each representing a virtual regions part in blocks of a given size + * governed by sys_mem_blocks API. + * @var allocation_sizes[] a table of bit arrays representing sizes of allocations + * made in physical_blocks_allocators directly related to physical_blocks_allocators + * @var core_id id of the core that heap was created on + * @var allocating_continuously configuration value deciding if heap allocations + * will be contiguous or single block. + */ +struct vmh_heap { + struct list_item node; + const struct sys_mm_drv_region *virtual_region; + struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; + struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; + int core_id; + bool allocating_continuously; +}; + /** * @brief Initialize new heap * diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c index c7d3d1882cc6..e3ef103accf5 100644 --- a/zephyr/test/vmh.c +++ b/zephyr/test/vmh.c @@ -17,6 +17,7 @@ #include LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); +struct vmh_heap; /* Test creating and freeing a virtual memory heap */ static void test_vmh_init_and_free_heap(int memory_region_attribute, From ff221378ba2d4cabeaac614e942eb3fa11ddfec0 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Mon, 16 Jun 2025 10:48:58 +0200 Subject: [PATCH 07/10] mem: use single cross-core virtual heap In case of cross core buffers a buffer may be allocated and freed by different core, depending on which component is deleted second. As all control structures of virtual heaps are stored in uncached aliases, there's no technical problems with allowing virtual heaps to work cross core. The only consideration is that in case of cross core allocate/free the cache invalidation MUST be performed on the core that was storing data. It is up to the memory user to ensure this Signed-off-by: Marcin Szkudlinski --- zephyr/include/sof/lib/regions_mm.h | 6 +- zephyr/lib/alloc.c | 26 ++----- zephyr/lib/regions_mm.c | 116 ++-------------------------- zephyr/test/vmh.c | 50 ++---------- 4 files changed, 23 insertions(+), 175 deletions(-) diff --git a/zephyr/include/sof/lib/regions_mm.h b/zephyr/include/sof/lib/regions_mm.h index fb310a8c9174..fcd738414470 100644 --- a/zephyr/include/sof/lib/regions_mm.h +++ b/zephyr/include/sof/lib/regions_mm.h @@ -77,16 +77,12 @@ struct vmh_heap_config { struct vmh_block_bundle_descriptor block_bundles_table[MAX_MEMORY_ALLOCATORS_COUNT]; }; -struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, - int memory_region_attribute, int core_id, bool allocating_continuously); +struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocating_continuously); void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size); int vmh_free_heap(struct vmh_heap *heap); int vmh_free(struct vmh_heap *heap, void *ptr); -struct vmh_heap *vmh_reconfigure_heap(struct vmh_heap *heap, - struct vmh_heap_config *cfg, int core_id, bool allocating_continuously); void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, struct vmh_heap_config *cfg); -struct vmh_heap *vmh_get_heap_by_attribute(uint32_t attr, uint32_t core_id); /** * @brief Checks if ptr is in range of given memory range * diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index 11d867991655..dcc9da3c7163 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -22,7 +22,7 @@ #include struct vmh_heap; -struct vmh_heap *virtual_buffers_heap[CONFIG_MP_MAX_NUM_CPUS]; +struct vmh_heap *virtual_buffers_heap; struct k_spinlock vmh_lock; #undef HEAPMEM_SIZE @@ -252,12 +252,11 @@ static bool is_virtual_heap_pointer(void *ptr) static void virtual_heap_free(void *ptr) { - struct vmh_heap *const heap = virtual_buffers_heap[cpu_get_id()]; int ret; ptr = (__sparse_force void *)sys_cache_cached_ptr_get(ptr); - ret = vmh_free(heap, ptr); + ret = vmh_free(virtual_buffers_heap, ptr); if (ret) { tr_err(&zephyr_tr, "Unable to free %p! %d", ptr, ret); k_panic(); @@ -280,17 +279,12 @@ static const struct vmh_heap_config static_hp_buffers = { static int virtual_heap_init(void) { - int core; - k_spinlock_init(&vmh_lock); - for (core = 0; core < CONFIG_MP_MAX_NUM_CPUS; core++) { - struct vmh_heap *heap = vmh_init_heap(&static_hp_buffers, MEM_REG_ATTR_CORE_HEAP, - core, false); - if (!heap) - tr_err(&zephyr_tr, "Unable to init virtual heap for core %d!", core); - - virtual_buffers_heap[core] = heap; + virtual_buffers_heap = vmh_init_heap(&static_hp_buffers, false); + if (!virtual_buffers_heap) { + tr_err(&zephyr_tr, "Unable to init virtual heap"); + return -ENOMEM; } return 0; @@ -491,9 +485,6 @@ EXPORT_SYMBOL(rzalloc); void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, uint32_t align) { -#if CONFIG_VIRTUAL_HEAP - struct vmh_heap *virtual_heap; -#endif struct k_heap *heap; /* choose a heap */ @@ -511,9 +502,8 @@ void *rballoc_align(uint32_t flags, uint32_t caps, size_t bytes, #if CONFIG_VIRTUAL_HEAP /* Use virtual heap if it is available */ - virtual_heap = virtual_buffers_heap[cpu_get_id()]; - if (virtual_heap) - return virtual_heap_alloc(virtual_heap, flags, caps, bytes, align); + if (virtual_buffers_heap) + return virtual_heap_alloc(virtual_buffers_heap, flags, caps, bytes, align); #endif /* CONFIG_VIRTUAL_HEAP */ if (flags & SOF_MEM_FLAG_COHERENT) diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index d07c2582664a..7ff912b49b26 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -10,8 +10,6 @@ #if defined(CONFIG_MM_DRV) #include -/* list of vmh_heap objects created */ -static struct list_item vmh_list = LIST_INIT(vmh_list); /** @struct vmh_heap * @@ -19,7 +17,6 @@ static struct list_item vmh_list = LIST_INIT(vmh_list); * it aggregates information about its allocations and * physical mappings. * - * @var node generic list member used for list operations * @var virtual_region pointer to virtual region information, it holds its * attributes size and beginning ptr provided by zephyr. * @var physical_blocks_allocators[] a table of block allocators @@ -27,16 +24,13 @@ static struct list_item vmh_list = LIST_INIT(vmh_list); * governed by sys_mem_blocks API. * @var allocation_sizes[] a table of bit arrays representing sizes of allocations * made in physical_blocks_allocators directly related to physical_blocks_allocators - * @var core_id id of the core that heap was created on * @var allocating_continuously configuration value deciding if heap allocations * will be contiguous or single block. */ struct vmh_heap { - struct list_item node; const struct sys_mm_drv_region *virtual_region; struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; - int core_id; bool allocating_continuously; }; @@ -47,49 +41,32 @@ struct vmh_heap { * and config. The heap size overall must be aligned to physical page * size. * @param cfg Configuration structure with block structure for the heap - * @param memory_region_attribute A zephyr defined virtual region identifier - * @param core_id Core id of a heap that will be created * @param allocating_continuously Flag deciding if heap can do contiguous allocation. * * @retval ptr to a new heap if successful. * @retval NULL on creation failure. */ -struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, - int memory_region_attribute, int core_id, bool allocating_continuously) +struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocating_continuously) { const struct sys_mm_drv_region *virtual_memory_regions = sys_mm_drv_query_memory_regions(); int i; - /* Check if we haven't created heap for this region already */ - if (vmh_get_heap_by_attribute(memory_region_attribute, core_id)) - return NULL; - struct vmh_heap *new_heap = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*new_heap)); if (!new_heap) return NULL; - new_heap->core_id = core_id; - list_init(&new_heap->node); struct vmh_heap_config new_config = {0}; - /* Search for matching attribute so we place heap on right - * virtual region. - * In case of core heaps regions we count theme from 0 to max - * available cores - */ - if (memory_region_attribute == MEM_REG_ATTR_CORE_HEAP) { - new_heap->virtual_region = &virtual_memory_regions[core_id]; - } else { - for (i = CONFIG_MP_MAX_NUM_CPUS; - i < CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; i++) { + /* Search for matching attribute so we place heap on shared virtual region */ + for (i = CONFIG_MP_MAX_NUM_CPUS; + i < CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; i++) { - if (memory_region_attribute == virtual_memory_regions[i].attr) { - new_heap->virtual_region = &virtual_memory_regions[i]; - break; - } + if (virtual_memory_regions[i].attr == MEM_REG_ATTR_SHARED_HEAP) { + new_heap->virtual_region = &virtual_memory_regions[i]; + break; } } @@ -220,9 +197,6 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, new_heap->allocating_continuously = allocating_continuously; - /* Save the new heap pointer to a linked list */ - list_item_append(&vmh_list, &new_heap->node); - return new_heap; fail: for (i = 0; i < MAX_MEMORY_ALLOCATORS_COUNT; i++) { @@ -419,9 +393,6 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) { if (!alloc_size) return NULL; - /* Only operations on the same core are allowed */ - if (heap->core_id != cpu_get_id()) - return NULL; void *ptr = NULL; int mem_block_iterator, allocation_error_code = -ENOMEM; @@ -566,7 +537,6 @@ int vmh_free_heap(struct vmh_heap *heap) rfree(heap->allocation_sizes[i]); } } - list_item_del(&heap->node); rfree(heap); return 0; } @@ -587,9 +557,6 @@ int vmh_free(struct vmh_heap *heap, void *ptr) { int retval; - if (heap->core_id != cpu_get_id()) - return -EINVAL; - size_t mem_block_iter, i, size_to_free, block_size, ptr_bit_array_offset, ptr_bit_array_position, blocks_to_free; bool ptr_range_found; @@ -703,32 +670,6 @@ int vmh_free(struct vmh_heap *heap, void *ptr) size_to_free); } -/** - * @brief Reconfigure heap with given config - * - * This will destroy the heap from the pointer and recreate it - * using provided config. Individual region attribute is the - * "anchor" to the virtual space we use. - * - * @param heap Ptr to the heap that should be reconfigured - * @param cfg heap blocks configuration - * @param allocating_continuously allow contiguous on the reconfigured heap - * - * @retval heap_pointer Returns new heap pointer on success - * @retval NULL when reconfiguration failed - */ -struct vmh_heap *vmh_reconfigure_heap( - struct vmh_heap *heap, struct vmh_heap_config *cfg, - int core_id, bool allocating_continuously) -{ - uint32_t region_attribute = heap->virtual_region->attr; - - if (vmh_free_heap(heap)) - return NULL; - - return vmh_init_heap(cfg, region_attribute, core_id, allocating_continuously); -} - /** * @brief Get default configuration for heap * @@ -757,47 +698,4 @@ void vmh_get_default_heap_config(const struct sys_mm_drv_region *region, } } -/** - * @brief Gets pointer to already created heap identified by - * provided attribute. - * - * @param attr Virtual memory region attribute. - * @param core_id id of the core that heap was created for (core heap specific). - * - * @retval heap ptr on success - * @retval NULL if there was no heap created fitting the attr. - */ -struct vmh_heap *vmh_get_heap_by_attribute(uint32_t attr, uint32_t core_id) -{ - struct list_item *vm_heaps_iterator; - struct vmh_heap *retval; - - if (attr == MEM_REG_ATTR_CORE_HEAP) { - /* if we look up cpu heap we need to match its cpuid with addr - * we know that regions keep cpu heaps from 0 to max so we match - * the region of the cpu id with lists one to find match - */ - const struct sys_mm_drv_region *virtual_memory_region = - sys_mm_drv_query_memory_regions(); - /* we move ptr to cpu vmr */ - virtual_memory_region = &virtual_memory_region[core_id]; - - list_for_item(vm_heaps_iterator, &vmh_list) { - retval = - CONTAINER_OF(vm_heaps_iterator, struct vmh_heap, node); - - if (retval->virtual_region->addr == virtual_memory_region->addr) - return retval; - } - } else { - list_for_item(vm_heaps_iterator, &vmh_list) { - retval = - CONTAINER_OF(vm_heaps_iterator, struct vmh_heap, node); - if (retval->virtual_region->attr == attr) - return retval; - } - } - return NULL; -} - #endif /* if defined (CONFIG_MM_DRV) */ diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c index e3ef103accf5..26e044a2d9f0 100644 --- a/zephyr/test/vmh.c +++ b/zephyr/test/vmh.c @@ -20,14 +20,11 @@ LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); struct vmh_heap; /* Test creating and freeing a virtual memory heap */ -static void test_vmh_init_and_free_heap(int memory_region_attribute, - struct vmh_heap_config *config, - int core_id, +static void test_vmh_init_and_free_heap(struct vmh_heap_config *config, bool allocating_continuously, bool expect_success) { - struct vmh_heap *heap = vmh_init_heap(config, memory_region_attribute, - core_id, allocating_continuously); + struct vmh_heap *heap = vmh_init_heap(config, allocating_continuously); if (expect_success) { zassert_not_null(heap, "Heap initialization expected to succeed but failed"); @@ -147,7 +144,7 @@ static void test_vmh_multiple_allocs(struct vmh_heap *heap, int num_allocs, static void test_vmh_alloc_multiple_times(bool allocating_continuously) { struct vmh_heap *heap = - vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(NULL, allocating_continuously); zassert_not_null(heap, "Heap initialization failed"); @@ -171,7 +168,7 @@ static void test_vmh_alloc_multiple_times(bool allocating_continuously) static void test_vmh_alloc_free(bool allocating_continuously) { struct vmh_heap *heap = - vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(NULL, allocating_continuously); zassert_not_null(heap, "Heap initialization failed"); @@ -195,7 +192,7 @@ static void test_vmh_alloc_free(bool allocating_continuously) /* Test case for vmh_alloc and vmh_free with and without config */ static void test_heap_creation(void) { - test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, NULL, 0, false, true); + test_vmh_init_and_free_heap(NULL, 0, false, true); /* Try to setup with pre defined heap config */ struct vmh_heap_config config = {0}; @@ -208,7 +205,7 @@ static void test_heap_creation(void) config.block_bundles_table[1].number_of_blocks = 512; - test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, &config, 0, false, true); + test_vmh_init_and_free_heap(&config, 0, false, true); } /* Test case for alloc/free on configured heap */ @@ -224,7 +221,7 @@ static void test_alloc_on_configured_heap(bool allocating_continuously) /* Create continuous allocation heap for success test */ struct vmh_heap *heap = - vmh_init_heap(&config, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + vmh_init_heap(&config, allocating_continuously); /* Will succeed on continuous and fail with single block alloc */ test_vmh_alloc_free_check(heap, 512, allocating_continuously); @@ -234,42 +231,9 @@ static void test_alloc_on_configured_heap(bool allocating_continuously) zassert_equal(ret, 0, "Failed to free heap"); } -/* Test cases for initializing heaps on all available regions */ -static void test_vmh_init_all_heaps(void) -{ - int num_regions = CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; - int i; - const struct sys_mm_drv_region *virtual_memory_region = - sys_mm_drv_query_memory_regions(); - - /* Test initializing all types of heaps */ - for (i = 0; i < num_regions; i++) { - - /* Zeroed size symbolizes end of regions table */ - if (!virtual_memory_region[i].size) - break; - - struct vmh_heap *heap = vmh_init_heap(NULL, virtual_memory_region[i].attr, - i, true); - - zassert_not_null(heap, "Heap initialization expected to succeed but failed"); - - /* Test if it fails when heap already exists */ - test_vmh_init_and_free_heap(virtual_memory_region[i].attr, NULL, i, true, - false); - - if (heap) { - int ret = vmh_free_heap(heap); - - zassert_equal(ret, 0, "Failed to free heap"); - } - } -} - ZTEST(sof_boot, virtual_memory_heap) { test_heap_creation(); - test_vmh_init_all_heaps(); test_alloc_on_configured_heap(true); test_alloc_on_configured_heap(false); test_vmh_alloc_free(true); From 767a836cadfdbc9a25e8ffee8827555f21ec385a Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Mon, 16 Jun 2025 10:49:37 +0200 Subject: [PATCH 08/10] mem: add mutex protection for alloc and free virtual heap may be called from multiple threads, all operations should be protected my mutex Signed-off-by: Marcin Szkudlinski --- zephyr/lib/alloc.c | 3 --- zephyr/lib/regions_mm.c | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/zephyr/lib/alloc.c b/zephyr/lib/alloc.c index dcc9da3c7163..899730e312e0 100644 --- a/zephyr/lib/alloc.c +++ b/zephyr/lib/alloc.c @@ -23,7 +23,6 @@ struct vmh_heap; struct vmh_heap *virtual_buffers_heap; -struct k_spinlock vmh_lock; #undef HEAPMEM_SIZE /* Buffers are allocated from virtual space so we can safely reduce the heap size. @@ -279,8 +278,6 @@ static const struct vmh_heap_config static_hp_buffers = { static int virtual_heap_init(void) { - k_spinlock_init(&vmh_lock); - virtual_buffers_heap = vmh_init_heap(&static_hp_buffers, false); if (!virtual_buffers_heap) { tr_err(&zephyr_tr, "Unable to init virtual heap"); diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index 7ff912b49b26..5d99564ca060 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -28,6 +28,7 @@ * will be contiguous or single block. */ struct vmh_heap { + struct k_mutex lock; const struct sys_mm_drv_region *virtual_region; struct sys_mem_blocks *physical_blocks_allocators[MAX_MEMORY_ALLOCATORS_COUNT]; struct sys_bitarray *allocation_sizes[MAX_MEMORY_ALLOCATORS_COUNT]; @@ -58,6 +59,7 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocatin if (!new_heap) return NULL; + k_mutex_init(&new_heap->lock); struct vmh_heap_config new_config = {0}; /* Search for matching attribute so we place heap on shared virtual region */ @@ -378,7 +380,7 @@ static int vmh_unmap_region(struct sys_mem_blocks *region, void *ptr, size_t siz } /** - * @brief Alloc function + * @brief Alloc function, not reentrant * * Allocates memory on heap from provided heap pointer. * Check if we need to map physical memory for given allocation @@ -389,7 +391,7 @@ static int vmh_unmap_region(struct sys_mem_blocks *region, void *ptr, size_t siz * @retval ptr to allocated memory if successful * @retval NULL on allocation failure */ -void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) +static void *_vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) { if (!alloc_size) return NULL; @@ -507,6 +509,20 @@ void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) return ptr; } +/** + * @brief Alloc function, reentrant + * see _vmh_alloc comment for details + */ +void *vmh_alloc(struct vmh_heap *heap, uint32_t alloc_size) +{ + k_mutex_lock(&heap->lock, K_FOREVER); + + void *ret = _vmh_alloc(heap, alloc_size); + + k_mutex_unlock(&heap->lock); + return ret; +} + /** * @brief Free virtual memory heap * @@ -542,7 +558,7 @@ int vmh_free_heap(struct vmh_heap *heap) } /** - * @brief Free ptr allocated on given heap + * @brief Free ptr allocated on given heap, not reentrant * * Free the ptr allocation. After free action is complete * check if any physical memory block can be freed up as @@ -553,7 +569,7 @@ int vmh_free_heap(struct vmh_heap *heap) * @retval 0 on success; * @retval -ENOTEMPTY on heap having active allocations. */ -int vmh_free(struct vmh_heap *heap, void *ptr) +static int _vmh_free(struct vmh_heap *heap, void *ptr) { int retval; @@ -670,6 +686,20 @@ int vmh_free(struct vmh_heap *heap, void *ptr) size_to_free); } +/** + * @brief Free ptr function, reentrant + * see _vmh_free comment for details + */ +int vmh_free(struct vmh_heap *heap, void *ptr) +{ + k_mutex_lock(&heap->lock, K_FOREVER); + + int ret = _vmh_free(heap, ptr); + + k_mutex_unlock(&heap->lock); + return ret; +} + /** * @brief Get default configuration for heap * From f7d9991f57066ab034e63f5787c76c769d18db7d Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Wed, 11 Jun 2025 16:06:38 +0200 Subject: [PATCH 09/10] buf: buffer free "virtual destructor" struct sof_audio_buffer is a "base class" in a meaning of C++ of all buffers in SOF (currently comp_buffer and ring_buffer). Freeing of memory was based on indirect assumption that struct sof_audio_buffer is a very first field of the buffer structure this commit moves freeing of buffer to a method specific for each buffer type, enforcing that proper pointer will be used regardless of buffer structure Signed-off-by: Marcin Szkudlinski --- src/audio/buffers/audio_buffer.c | 7 ++++--- src/audio/buffers/comp_buffer.c | 1 + src/audio/buffers/ring_buffer.c | 1 + src/include/sof/audio/audio_buffer.h | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/audio/buffers/audio_buffer.c b/src/audio/buffers/audio_buffer.c index af882accaae8..f63a9a7c93b6 100644 --- a/src/audio/buffers/audio_buffer.c +++ b/src/audio/buffers/audio_buffer.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -92,9 +93,8 @@ void audio_buffer_free(struct sof_audio_buffer *buffer) audio_buffer_free(buffer->secondary_buffer_sink); audio_buffer_free(buffer->secondary_buffer_source); #endif /* CONFIG_PIPELINE_2_0 */ - if (buffer->ops->free) - buffer->ops->free(buffer); - rfree(buffer); + /* "virtual destructor": free the buffer internals and buffer memory */ + buffer->ops->free(buffer); } static @@ -196,6 +196,7 @@ void audio_buffer_init(struct sof_audio_buffer *buffer, uint32_t buffer_type, bo CORE_CHECK_STRUCT_INIT(&buffer, is_shared); buffer->buffer_type = buffer_type; buffer->ops = audio_buffer_ops; + assert(audio_buffer_ops->free); buffer->audio_stream_params = audio_stream_params; buffer->is_shared = is_shared; diff --git a/src/audio/buffers/comp_buffer.c b/src/audio/buffers/comp_buffer.c index 02b44e5dcdce..232e26cbec8a 100644 --- a/src/audio/buffers/comp_buffer.c +++ b/src/audio/buffers/comp_buffer.c @@ -158,6 +158,7 @@ static void comp_buffer_free(struct sof_audio_buffer *audio_buffer) notifier_unregister_all(NULL, buffer); rfree(buffer->stream.addr); + rfree(buffer); } static struct source_ops comp_buffer_source_ops = { diff --git a/src/audio/buffers/ring_buffer.c b/src/audio/buffers/ring_buffer.c index ec6005b5d1e2..d7bd251b3c23 100644 --- a/src/audio/buffers/ring_buffer.c +++ b/src/audio/buffers/ring_buffer.c @@ -96,6 +96,7 @@ static void ring_buffer_free(struct sof_audio_buffer *audio_buffer) container_of(audio_buffer, struct ring_buffer, audio_buffer); rfree((__sparse_force void *)ring_buffer->_data_buffer); + rfree(ring_buffer); } static void ring_buffer_reset(struct sof_audio_buffer *audio_buffer) diff --git a/src/include/sof/audio/audio_buffer.h b/src/include/sof/audio/audio_buffer.h index 4984c3dee99a..e7fc6e7e1c5d 100644 --- a/src/include/sof/audio/audio_buffer.h +++ b/src/include/sof/audio/audio_buffer.h @@ -21,8 +21,8 @@ struct sof_audio_buffer; struct audio_buffer_ops { /** * @brief this method must free all structures allocated by buffer implementation - * it must not free the buffer memory itself - * OPTIONAL + * and the buffer itself + * OBLIGATORY */ void (*free)(struct sof_audio_buffer *buffer); From 419f90cc7cb511a4e41e0b5f3317eab528ed1a71 Mon Sep 17 00:00:00 2001 From: Marcin Szkudlinski Date: Tue, 24 Jun 2025 12:23:15 +0200 Subject: [PATCH 10/10] mem: use Zephyr's macro for virtual memory regions iteration Zephyr provides a special macro, SYS_MM_DRV_MEMORY_REGION_FOREACH for iteration through all memory regions. This commit use this macro instead of a for loop that requires information about number of virtual memory regions provided by Zephyr. Signed-off-by: Marcin Szkudlinski --- zephyr/lib/regions_mm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/zephyr/lib/regions_mm.c b/zephyr/lib/regions_mm.c index 5d99564ca060..797e49d45af8 100644 --- a/zephyr/lib/regions_mm.c +++ b/zephyr/lib/regions_mm.c @@ -61,17 +61,14 @@ struct vmh_heap *vmh_init_heap(const struct vmh_heap_config *cfg, bool allocatin k_mutex_init(&new_heap->lock); struct vmh_heap_config new_config = {0}; + const struct sys_mm_drv_region *region; - /* Search for matching attribute so we place heap on shared virtual region */ - for (i = CONFIG_MP_MAX_NUM_CPUS; - i < CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; i++) { - - if (virtual_memory_regions[i].attr == MEM_REG_ATTR_SHARED_HEAP) { - new_heap->virtual_region = &virtual_memory_regions[i]; + SYS_MM_DRV_MEMORY_REGION_FOREACH(virtual_memory_regions, region) { + if (region->attr == MEM_REG_ATTR_SHARED_HEAP) { + new_heap->virtual_region = region; break; } } - if (!new_heap->virtual_region) goto fail;