From 1664690206d456d326fd71b526887dfb27ebefb3 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 3 Dec 2024 16:44:45 +0200 Subject: [PATCH] ASoC: SOF: ipc4: Add support for modular firmware releases A modular SOF release consists of a base firmware and two libraries: -openmodules.ri for processing (audio) modules -debug.ri for debug and developer modules To handle this new release model add infrastructure to try to load the two library after boot optionally. This approach will allow flexibility on handling platforms in sof-bin with monolithic or modular configuration: Monolithic release: base firmware only Modular release: base firmware + openmodules + debug The files for the modular firmware are located at the firmware directory. Signed-off-by: Peter Ujfalusi --- sound/soc/sof/ipc4-loader.c | 116 +++++++++++++++++++++++++++--------- sound/soc/sof/ipc4-priv.h | 1 + sound/soc/sof/ipc4.c | 8 ++- 3 files changed, 96 insertions(+), 29 deletions(-) diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index 456b9885d06ca1..6363bf68e80a92 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -178,21 +178,14 @@ static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev) return payload_offset; } -static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, - unsigned long lib_id, const guid_t *uuid) +static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long *lib_id, + const char *lib_filename, bool optional) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_fw_library *fw_lib; - const char *fw_filename; ssize_t payload_offset; int ret, i, err; - if (!sdev->pdata->fw_lib_prefix) { - dev_err(sdev->dev, - "Library loading is not supported due to not set library path\n"); - return -EINVAL; - } - if (!ipc4_data->load_library) { dev_err(sdev->dev, "Library loading is not supported on this platform\n"); return -EOPNOTSUPP; @@ -202,21 +195,28 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (!fw_lib) return -ENOMEM; - fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", - sdev->pdata->fw_lib_prefix, uuid); - if (!fw_filename) { - ret = -ENOMEM; - goto free_fw_lib; - } - - ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename); - goto free_filename; + if (optional) { + ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + dev_dbg(sdev->dev, "Library file '%s' is not present\n", + lib_filename); + /* optional library, override the error */ + ret = 0; + goto free_fw_lib; + } } else { - dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename); + ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "Library file '%s' is missing\n", + lib_filename); + goto free_fw_lib; + } } + dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename); + payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib); if (payload_offset <= 0) { if (!payload_offset) @@ -228,11 +228,11 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, } fw_lib->sof_fw.payload_offset = payload_offset; - fw_lib->id = lib_id; + fw_lib->id = *lib_id; /* Fix up the module ID numbers within the library */ for (i = 0; i < fw_lib->num_modules; i++) - fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT); + fw_lib->modules[i].man4_module_entry.id |= (*lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT); /* * Make sure that the DSP is booted and stays up while attempting the @@ -256,26 +256,86 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (ret) goto release; - ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL); + ret = xa_insert(&ipc4_data->fw_lib_xa, *lib_id, fw_lib, GFP_KERNEL); if (unlikely(ret)) goto release; - kfree(fw_filename); - + (*lib_id)++; return 0; release: release_firmware(fw_lib->sof_fw.fw); /* Allocated within sof_ipc4_fw_parse_ext_man() */ devm_kfree(sdev->dev, fw_lib->modules); -free_filename: - kfree(fw_filename); free_fw_lib: devm_kfree(sdev->dev, fw_lib); return ret; } +int sof_ipc4_load_library_bundles(struct snd_sof_dev *sdev) +{ + static const char * const lib_bundle[] = { "openmodules", "debug" }; + const char *fw_filename = sdev->pdata->fw_filename; + const char *lib_filename, *p; + unsigned long lib_id = 1; + char *lib_name_base; + int ret, i; + + p = strstr(fw_filename, ".ri"); + if (!p || strlen(p) != 3) { + dev_info(sdev->dev, + "%s: Cannot parse firmware name '%s', missing .ri extension\n", + __func__, fw_filename); + return 0; + } + + lib_name_base = kzalloc(strlen(fw_filename) - 2, GFP_KERNEL); + strscpy(lib_name_base, fw_filename, sizeof(lib_name_base)); + + for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) { + lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri", + sdev->pdata->fw_filename_prefix, + lib_name_base, lib_bundle[i]); + if (!lib_filename) + return -ENOMEM; + + ret = sof_ipc4_load_library(sdev, &lib_id, lib_filename, true); + + kfree(lib_filename); + if (ret) + break; + } + + kfree(lib_name_base); + + return ret; +} + +static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, + unsigned long lib_id, const guid_t *uuid) +{ + const char *lib_filename; + int ret; + + if (!sdev->pdata->fw_lib_prefix) { + dev_err(sdev->dev, + "Library loading is not supported due to not set library path\n"); + return -EINVAL; + } + + lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", + sdev->pdata->fw_lib_prefix, uuid); + if (!lib_filename) + return -ENOMEM; + + ret = sof_ipc4_load_library(sdev, &lib_id, lib_filename, false); + + kfree(lib_filename); + + return ret; +} + struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid) { diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index ea3323b90343df..ffd9403414118a 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -102,6 +102,7 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 s int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev); +int sof_ipc4_load_library_bundles(struct snd_sof_dev *sdev); int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid); diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 4386cbae16d4ed..7e8ff28f1e613f 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -825,8 +825,14 @@ static void sof_ipc4_exit(struct snd_sof_dev *sdev) static int sof_ipc4_post_boot(struct snd_sof_dev *sdev) { - if (sdev->first_boot) + if (sdev->first_boot) { + int ret = sof_ipc4_load_library_bundles(sdev); + + if (ret) + return ret; + return sof_ipc4_query_fw_configuration(sdev); + } return sof_ipc4_reload_fw_libraries(sdev); }