From 3685833d9217095f20ed0c14c85d396dee37aa34 Mon Sep 17 00:00:00 2001 From: Jaroslaw Stelter Date: Wed, 19 Jul 2023 16:52:56 +0300 Subject: [PATCH] lib-manager: Support for two stage library loading The hardware programming flow dictates that the DSP side should set the GEN bit first followed by the host setting the EN bit. We cannot assume that the GEN bit is already enabled (and it would in fact will leave the DMA on the DSP side wrongly configured at best). To support the currently used flow (single step) and add support for the correct programming flow, the proposed solution is to use the lib_id as indication of the method the host software is going to use. Two stage flow: The first LOAD_LIBRARY_PREPARE with valid dma_id - just allocate and set the GEN bit Second LOAD_LIBRARY with valid lib_id and dma_id - proceed to the loading of the library via host DMA to local buffer Single stage flow (currently supported) LOAD_LIBRARY with valid lib_id and dma_id - allocate, set GEN bit and proceed to loading the library Signed-off-by: Peter Ujfalusi Signed-off-by: Jaroslaw Stelter --- src/include/ipc4/header.h | 2 + src/include/sof/lib_manager.h | 6 +- src/ipc/ipc4/handler.c | 11 ++- src/library_manager/lib_manager.c | 141 +++++++++++++++++++----------- 4 files changed, 107 insertions(+), 53 deletions(-) diff --git a/src/include/ipc4/header.h b/src/include/ipc4/header.h index 567b1be29c08..4a91b1a8cb13 100644 --- a/src/include/ipc4/header.h +++ b/src/include/ipc4/header.h @@ -81,6 +81,8 @@ enum ipc4_message_type { SOF_IPC4_GLB_RESTORE_PIPELINE = 23, /**< Loads library */ SOF_IPC4_GLB_LOAD_LIBRARY = 24, + /**< Loads library prepare */ + SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE = 25, /**< Internal FW message */ SOF_IPC4_GLB_INTERNAL_MESSAGE = 26, /**< Notification (FW to SW driver) */ diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index 279513f7bb96..5e0e47fdacb7 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -84,6 +84,8 @@ struct ext_library { uint32_t mods_exec_load_cnt; struct ipc_lib_msg *lib_notif_pool; uint32_t lib_notif_count; + + void *runtime_data; }; /* lib manager context, used by lib_notification */ @@ -150,12 +152,14 @@ int lib_manager_free_module(const struct comp_driver *drv, * * param[in] dma_id - channel used to transfer binary from host * param[in] lib_id + * param[in] type - ipc command type + * (SOF_IPC4_GLB_LOAD_LIBRARY or SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE) * * Function will load library manifest into temporary buffer. * Then it will read library parameters, allocate memory for library and load it into * destination memory region. */ -int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id); +int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type); /* * \brief Initialize message diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 8e572c636709..51ee1f693742 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -499,10 +499,16 @@ static int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) static int ipc4_load_library(struct ipc4_message_request *ipc4) { struct ipc4_module_load_library library; + int ret; library.header.dat = ipc4->primary.dat; - return lib_manager_load_library(library.header.r.dma_id, library.header.r.lib_id); + ret = lib_manager_load_library(library.header.r.dma_id, library.header.r.lib_id, + ipc4->primary.r.type); + if (ret != 0) + return (ret == -EINVAL) ? IPC4_ERROR_INVALID_PARAM : IPC4_FAILURE; + + return IPC4_SUCCESS; } #endif @@ -649,6 +655,9 @@ static int ipc4_process_glb_message(struct ipc4_message_request *ipc4) case SOF_IPC4_GLB_LOAD_LIBRARY: ret = ipc4_load_library(ipc4); break; + case SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE: + ret = ipc4_load_library(ipc4); + break; #endif case SOF_IPC4_GLB_INTERNAL_MESSAGE: ipc_cmd_err(&ipc_tr, "not implemented ipc message type %d", type); diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index 6b45f79d02ac..7b1fb03710e6 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -41,6 +41,7 @@ struct lib_manager_dma_ext { struct dma *dma; struct dma_chan_data *chan; uintptr_t dma_addr; /**< buffer start pointer */ + uint32_t addr_align; }; static struct ext_library loader_ext_lib; @@ -416,13 +417,14 @@ int lib_manager_register_module(struct sof_man_fw_desc *desc, int module_id) #endif /* CONFIG_INTEL_MODULES */ static int lib_manager_dma_buffer_alloc(struct lib_manager_dma_ext *dma_ext, - uint32_t size, uint32_t align) + uint32_t size) { /* * allocate new buffer: this is the actual DMA buffer but we * traditionally allocate a cached address for it */ - dma_ext->dma_addr = (uintptr_t)rballoc_align(0, SOF_MEM_CAPS_DMA, size, align); + dma_ext->dma_addr = (uintptr_t)rballoc_align(0, SOF_MEM_CAPS_DMA, size, + dma_ext->addr_align); if (!dma_ext->dma_addr) { tr_err(&lib_manager_tr, "lib_manager_dma_buffer_alloc(): alloc failed"); return -ENOMEM; @@ -564,7 +566,7 @@ static void __sparse_cache *lib_manager_allocate_store_mem(uint32_t size, static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, void __sparse_cache *man_buffer, - uint32_t lib_id, uint32_t addr_align) + uint32_t lib_id) { void __sparse_cache *library_base_address; struct sof_man_fw_desc *man_desc = (struct sof_man_fw_desc *) @@ -598,8 +600,10 @@ static int lib_manager_store_library(struct lib_manager_dma_ext *dma_ext, return 0; } -int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id) +static int lib_manager_setup(uint32_t dma_id) { + struct ext_library *_ext_lib = ext_lib_get(); + struct lib_manager_dma_ext *dma_ext; struct dma_block_config dma_block_cfg = { .block_size = MAN_MAX_SIZE_V1_8, .flow_control_mode = 1, @@ -611,44 +615,30 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id) .block_count = 1, .head_block = &dma_block_cfg, }; - struct lib_manager_dma_ext dma_ext; - uint32_t addr_align; - int ret, ret2; - void __sparse_cache *man_tmp_buffer = NULL; + int ret; - if (!lib_id || lib_id >= LIB_MANAGER_MAX_LIBS) { - tr_err(&lib_manager_tr, - "lib_manager_load_library(): invalid lib_id: %u", lib_id); - return -EINVAL; - } + if (_ext_lib->runtime_data) + return 0; - lib_manager_init(); + dma_ext = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, + sizeof(*dma_ext)); + if (!dma_ext) + return -ENOMEM; - ret = lib_manager_dma_init(&dma_ext, dma_id); + ret = lib_manager_dma_init(dma_ext, dma_id); if (ret < 0) - return ret; + goto err_dma_init; -#if CONFIG_ZEPHYR_NATIVE_DRIVERS - ret = dma_get_attribute(dma_ext.dma->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, - &addr_align); -#else - ret = dma_get_attribute_legacy(dma_ext.dma, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, - &addr_align); -#endif + ret = dma_get_attribute(dma_ext->dma->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, + &dma_ext->addr_align); if (ret < 0) - goto e_init; + goto err_dma_init; - /* allocate temporary manifest buffer */ - man_tmp_buffer = (__sparse_force void __sparse_cache *)rballoc_align(0, SOF_MEM_CAPS_DMA, - MAN_MAX_SIZE_V1_8, addr_align); - if (!man_tmp_buffer) { - ret = -ENOMEM; - goto e_init; - } - - ret = lib_manager_dma_buffer_alloc(&dma_ext, MAN_MAX_SIZE_V1_8, addr_align); + ret = lib_manager_dma_buffer_alloc(dma_ext, MAN_MAX_SIZE_V1_8); if (ret < 0) - goto e_buf; + goto err_dma_buffer; + + dma_block_cfg.dest_address = dma_ext->dma_addr; /* * make sure that the DSP is running full speed for the duration of @@ -656,27 +646,78 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id) */ ret = core_kcps_adjust(cpu_get_id(), CLK_MAX_CPU_HZ / 1000); if (ret < 0) - goto cleanup; + goto err_dma_buffer; - dma_block_cfg.dest_address = dma_ext.dma_addr; - - ret = dma_config(dma_ext.chan->dma->z_dev, dma_ext.chan->index, &config); + ret = dma_config(dma_ext->chan->dma->z_dev, dma_ext->chan->index, &config); if (ret < 0) - goto kcps_rollback; + goto err_dma; - ret = dma_start(dma_ext.chan->dma->z_dev, dma_ext.chan->index); + ret = dma_start(dma_ext->chan->dma->z_dev, dma_ext->chan->index); if (ret < 0) + goto err_dma; + + _ext_lib->runtime_data = dma_ext; + + return 0; + +err_dma: + core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); + +err_dma_buffer: + lib_manager_dma_deinit(dma_ext, dma_id); + +err_dma_init: + rfree(dma_ext); + return ret; +} + +int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type) +{ + void __sparse_cache *man_tmp_buffer; + struct lib_manager_dma_ext *dma_ext; + struct ext_library *_ext_lib; + int ret, ret2; + + if (type == SOF_IPC4_GLB_LOAD_LIBRARY && + (lib_id == 0 || lib_id >= LIB_MANAGER_MAX_LIBS)) { + tr_err(&lib_manager_tr, + "lib_manager_load_library(): invalid lib_id: %u", lib_id); + return -EINVAL; + } + + lib_manager_init(); + + _ext_lib = ext_lib_get(); + + if (type == SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE || !_ext_lib->runtime_data) { + ret = lib_manager_setup(dma_id); + if (ret) + return ret; + + if (type == SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE) + return 0; + } + + dma_ext = _ext_lib->runtime_data; + + /* allocate temporary manifest buffer */ + man_tmp_buffer = (__sparse_force void __sparse_cache *) + rballoc_align(0, SOF_MEM_CAPS_DMA, + MAN_MAX_SIZE_V1_8, dma_ext->addr_align); + if (!man_tmp_buffer) { + ret = -ENOMEM; goto cleanup; + } /* Load manifest to temporary buffer. */ - ret = lib_manager_store_data(&dma_ext, man_tmp_buffer, MAN_MAX_SIZE_V1_8); + ret = lib_manager_store_data(dma_ext, man_tmp_buffer, MAN_MAX_SIZE_V1_8); if (ret < 0) goto stop_dma; - ret = lib_manager_store_library(&dma_ext, man_tmp_buffer, lib_id, addr_align); + ret = lib_manager_store_library(dma_ext, man_tmp_buffer, lib_id); stop_dma: - ret2 = dma_stop(dma_ext.chan->dma->z_dev, dma_ext.chan->index); + ret2 = dma_stop(dma_ext->chan->dma->z_dev, dma_ext->chan->index); if (ret2 < 0) { tr_err(&lib_manager_tr, "lib_manager_load_library(): error stopping DMA: %d", ret); @@ -684,16 +725,14 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id) ret = ret2; } -kcps_rollback: - core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); + rfree((__sparse_force void *)man_tmp_buffer); cleanup: - rfree((void *)dma_ext.dma_addr); - -e_buf: - rfree((__sparse_force void *)man_tmp_buffer); -e_init: - lib_manager_dma_deinit(&dma_ext, dma_id); + core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000)); + rfree((void *)dma_ext->dma_addr); + lib_manager_dma_deinit(dma_ext, dma_id); + rfree(dma_ext); + _ext_lib->runtime_data = NULL; if (!ret) tr_info(&ipc_tr, "loaded library id: %u", lib_id);