Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASoC: SOF: ipc4: Add support for split firmware releases #5270

Open
wants to merge 1 commit into
base: topic/sof-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 111 additions & 28 deletions sound/soc/sof/ipc4-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -202,21 +195,26 @@ 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) {
/* 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 +226,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 +254,111 @@ 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;
}

/**
* sof_ipc4_complete_split_release - loads the library parts of a split firmware
* @sdev: SOF device
*
* With IPC4 the firmware can be a single binary or a split release.
* - single binary: only the basefw
* - split release: basefw and two libraries (openmodules, debug)
*
* With split firmware release it is also allowed that for example only the
* debug library is present (the openmodules content is built in the basefw).
*
* To handle the permutations try to load the openmodules then the debug
* libraries as optional ones after the basefw boot.
*
* The libraries for the split release are stored alongside the basefw on the
* filesystem.
*/
int sof_ipc4_complete_split_release(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 i;

p = strstr(fw_filename, ".ri");
if (!p || strlen(p) != 3) {
dev_info(sdev->dev,
"%s: Firmware name '%s' is missing .ri extension\n",
__func__, fw_filename);
return 0;
}

lib_name_base = kzalloc(strlen(fw_filename) - 2, GFP_KERNEL);
if (!lib_name_base)
return -ENOMEM;

strscpy(lib_name_base, fw_filename, sizeof(lib_name_base));

for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) {
int ret;

lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri",
sdev->pdata->fw_filename_prefix,
lib_name_base, lib_bundle[i]);
if (!lib_filename) {
kfree(lib_name_base);
return -ENOMEM;
}

ret = sof_ipc4_load_library(sdev, &lib_id, lib_filename, true);
if (ret)
dev_warn(sdev->dev, "%s: Failed to load %s: %d\n",
__func__, lib_filename, ret);

kfree(lib_filename);
}

kfree(lib_name_base);

return 0;
}

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)
{
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 @@ -101,6 +101,7 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state);
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);

int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev);
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,
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_complete_split_release(sdev);

if (ret)
return ret;

return sof_ipc4_query_fw_configuration(sdev);
}

return sof_ipc4_reload_fw_libraries(sdev);
}
Expand Down
Loading