Skip to content

Commit

Permalink
ASoC: SOF: ipc4: Add support for modular firmware releases
Browse files Browse the repository at this point in the history
A modular SOF release consists of a base firmware and two libraries:
<fw_filename>-openmodules.ri for processing (audio) modules
<fw_filename>-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

Signed-off-by: Peter Ujfalusi <[email protected]>
  • Loading branch information
ujfalusi committed Dec 13, 2024
1 parent 0c8300c commit 36acd21
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 23 deletions.
104 changes: 82 additions & 22 deletions sound/soc/sof/ipc4-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,12 +178,11 @@ 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;

Expand All @@ -202,21 +201,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)
Expand All @@ -228,11 +234,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
Expand All @@ -256,26 +262,80 @@ 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_lib_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;

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)
{
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/ipc4-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 7 additions & 1 deletion sound/soc/sof/ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 36acd21

Please sign in to comment.