From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
To: lgirdwood@gmail.com, broonie@kernel.org
Cc: chao.song@intel.com, alsa-devel@alsa-project.org,
pierre-louis.bossart@linux.intel.com,
kai.vehmanen@linux.intel.com, ranjani.sridharan@linux.intel.com
Subject: [PATCH 19/19] ASoC: SOF: ipc4-loader: Support for loading external libraries
Date: Tue, 18 Oct 2022 15:09:16 +0300 [thread overview]
Message-ID: <20221018120916.19820-20-peter.ujfalusi@linux.intel.com> (raw)
In-Reply-To: <20221018120916.19820-1-peter.ujfalusi@linux.intel.com>
In case the requested module is not available among the loaded libraries,
try to load it as external library.
The kernel will try to load the file from <fw_lib_prefix>/<module_uuid>.bin
If the file found, then the ext manifest of it is parsed, placed it under
XArray and the pointer to the module is returned to the caller.
Releasing the firmware will be done on ipc cleanup time.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Chao Song <chao.song@intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
---
sound/soc/sof/ipc4-loader.c | 155 ++++++++++++++++++++++++++++++++++--
sound/soc/sof/ipc4-priv.h | 2 +
sound/soc/sof/ipc4.c | 2 +-
3 files changed, 153 insertions(+), 6 deletions(-)
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index dbe3ee4ef08c..af0018b38cf0 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -14,6 +14,9 @@
#include "sof-priv.h"
#include "ops.h"
+/* The module ID includes the id of the library it is part of at offset 12 */
+#define SOF_IPC4_MOD_LIB_ID_SHIFT 12
+
static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib)
{
@@ -71,17 +74,18 @@ static size_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
return -EINVAL;
}
- dev_info(sdev->dev, "Loaded firmware version: %u.%u.%u.%u\n",
- fw_header->major_version, fw_header->minor_version,
+ dev_info(sdev->dev, "Loaded firmware library: %s, version: %u.%u.%u.%u\n",
+ fw_header->name, fw_header->major_version, fw_header->minor_version,
fw_header->hotfix_version, fw_header->build_version);
- dev_dbg(sdev->dev, "Firmware name: %s, header length: %u, module count: %u\n",
- fw_header->name, fw_header->len, fw_header->num_module_entries);
+ dev_dbg(sdev->dev, "Header length: %u, module count: %u\n",
+ fw_header->len, fw_header->num_module_entries);
fw_lib->modules = devm_kmalloc_array(sdev->dev, fw_header->num_module_entries,
sizeof(*fw_module), GFP_KERNEL);
if (!fw_lib->modules)
return -ENOMEM;
+ fw_lib->name = fw_header->name;
fw_lib->num_modules = fw_header->num_module_entries;
fw_module = fw_lib->modules;
@@ -160,13 +164,111 @@ 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)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ const char *fw_filename;
+ size_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;
+ }
+
+ fw_lib = devm_kzalloc(sdev->dev, sizeof(*fw_lib), GFP_KERNEL);
+ 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;
+ } else {
+ dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
+ }
+
+ payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
+ if (payload_offset <= 0) {
+ if (!payload_offset)
+ ret = -EINVAL;
+ else
+ ret = payload_offset;
+
+ goto release;
+ }
+
+ fw_lib->sof_fw.payload_offset = payload_offset;
+ 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);
+
+ /*
+ * Make sure that the DSP is booted and stays up while attempting the
+ * loading the library for the first time
+ */
+ ret = pm_runtime_resume_and_get(sdev->dev);
+ if (ret < 0 && ret != -EACCES) {
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime resume failed: %d\n",
+ __func__, ret);
+ goto release;
+ }
+
+ ret = ipc4_data->load_library(sdev, fw_lib, false);
+
+ pm_runtime_mark_last_busy(sdev->dev);
+ err = pm_runtime_put_autosuspend(sdev->dev);
+ if (err < 0)
+ dev_err_ratelimited(sdev->dev, "%s: pm_runtime idle failed: %d\n",
+ __func__, err);
+
+ if (ret)
+ goto release;
+
+ ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL);
+ if (unlikely(ret))
+ goto release;
+
+ kfree(fw_filename);
+
+ 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;
+}
+
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
const guid_t *uuid)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_ipc4_fw_library *fw_lib;
unsigned long lib_id;
- int i;
+ int i, ret;
if (guid_is_null(uuid))
return NULL;
@@ -178,6 +280,30 @@ struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev
}
}
+ /*
+ * Do not attempt to load external library in case the maximum number of
+ * firmware libraries have been already loaded
+ */
+ if ((lib_id + 1) == ipc4_data->max_libs_count) {
+ dev_err(sdev->dev,
+ "%s: Maximum allowed number of libraries reached (%u)\n",
+ __func__, ipc4_data->max_libs_count);
+ return NULL;
+ }
+
+ /* The module cannot be found, try to load it as a library */
+ ret = sof_ipc4_load_library_by_uuid(sdev, lib_id + 1, uuid);
+ if (ret)
+ return NULL;
+
+ /* Look for the module in the newly loaded library, it should be available now */
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, lib_id) {
+ for (i = 0; i < fw_lib->num_modules; i++) {
+ if (guid_equal(uuid, &fw_lib->modules[i].man4_module_entry.uuid))
+ return &fw_lib->modules[i];
+ }
+ }
+
return NULL;
}
@@ -270,6 +396,25 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
return ret;
}
+int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ struct sof_ipc4_fw_library *fw_lib;
+ unsigned long lib_id;
+ int ret = 0;
+
+ xa_for_each_start(&ipc4_data->fw_lib_xa, lib_id, fw_lib, 1) {
+ ret = ipc4_data->load_library(sdev, fw_lib, true);
+ if (ret) {
+ dev_err(sdev->dev, "%s: Failed to reload library: %s, %d\n",
+ __func__, fw_lib->name, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
.validate = sof_ipc4_validate_firmware,
.parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index e4bd6d93fb0f..d6f35004c4b7 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -50,6 +50,7 @@ struct sof_ipc4_fw_module {
*/
struct sof_ipc4_fw_library {
struct sof_firmware sof_fw;
+ const char *name;
u32 id;
int num_modules;
struct sof_ipc4_fw_module *modules;
@@ -91,6 +92,7 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state);
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_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);
#endif
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index f1e5875675db..3e81bc5d7d44 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -692,7 +692,7 @@ static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
if (sdev->first_boot)
return sof_ipc4_query_fw_configuration(sdev);
- return 0;
+ return sof_ipc4_reload_fw_libraries(sdev);
}
const struct sof_ipc_ops ipc4_ops = {
--
2.38.0
prev parent reply other threads:[~2022-10-18 12:15 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-18 12:08 [PATCH 00/19] ASoC: SOF: Intel/IPC4: Support for external firmware libraries Peter Ujfalusi
2022-10-18 12:08 ` [PATCH 01/19] ASoC: SOF: loader: Set complete state before post_fw_run op Peter Ujfalusi
2022-10-18 12:08 ` [PATCH 02/19] ASoC: SOF: Introduce container struct for SOF firmware Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 03/19] ASoC: SOF: amd: Use the basefw firmware container directly Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 04/19] ASoC: SOF: Intel: hda-loader: " Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 05/19] ASoC: SOF: Intel: hda-loader-skl: " Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 06/19] ASoC: SOF: Drop the firmware and fw_offset from snd_sof_pdata Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 07/19] ASoC: SOF: ipc: ops: Add support for optional init and exit callbacks Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 08/19] ASoC: SOF: ipc4-loader: Save the maximum number of libraries supported Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 09/19] ASoC: SOF: ipc4: Convert the firmware handling (loader) to library convention Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 10/19] ASoC: SOF: IPC4: Add helper for looking up module by UUID Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 11/19] ASoC: SOF: Add path definition for external firmware libraries Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 12/19] ASoC: SOF: Intel: Set the default firmware library path for IPC4 Peter Ujfalusi
2022-10-18 12:38 ` Amadeusz Sławiński
2022-10-18 13:49 ` Péter Ujfalusi
2022-10-18 15:46 ` Cezary Rojewski
2022-10-18 16:37 ` Pierre-Louis Bossart
2022-10-18 17:18 ` Cezary Rojewski
2022-10-19 9:51 ` Cezary Rojewski
2022-10-19 11:16 ` Péter Ujfalusi
2022-10-19 11:58 ` Cezary Rojewski
2022-10-19 12:21 ` Péter Ujfalusi
2022-10-18 12:09 ` [PATCH 13/19] ASoC: SOF: ipc4: Define platform dependent library loading callback Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 14/19] ASoC: SOF: Intel: hda: Add flag to indicate that the firmware is IMR booted Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 15/19] ASoC: SOF: Intel: Add ipc4 library loading implementation Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 16/19] ASoC: SOF: loader: Add support for IPC dependent post firmware boot ops Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 17/19] ASoC: SOF: ipc4: Stop using the query_fw_configuration fw_loader ops Peter Ujfalusi
2022-10-18 12:09 ` [PATCH 18/19] ASoC: SOF: loader: Remove the query_fw_configuration ops Peter Ujfalusi
2022-10-18 12:09 ` Peter Ujfalusi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221018120916.19820-20-peter.ujfalusi@linux.intel.com \
--to=peter.ujfalusi@linux.intel.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=chao.song@intel.com \
--cc=kai.vehmanen@linux.intel.com \
--cc=lgirdwood@gmail.com \
--cc=pierre-louis.bossart@linux.intel.com \
--cc=ranjani.sridharan@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox