Skip to content

Commit d09062a

Browse files
committed
ASoC: SOF: ipc4: Add support for modular firmware releases
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 The files for the modular firmware are located at the firmware directory. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 2b55d42 commit d09062a

File tree

3 files changed

+118
-29
lines changed

3 files changed

+118
-29
lines changed

sound/soc/sof/ipc4-loader.c

Lines changed: 110 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -178,21 +178,14 @@ static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev)
178178
return payload_offset;
179179
}
180180

181-
static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
182-
unsigned long lib_id, const guid_t *uuid)
181+
static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long *lib_id,
182+
const char *lib_filename, bool optional)
183183
{
184184
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
185185
struct sof_ipc4_fw_library *fw_lib;
186-
const char *fw_filename;
187186
ssize_t payload_offset;
188187
int ret, i, err;
189188

190-
if (!sdev->pdata->fw_lib_prefix) {
191-
dev_err(sdev->dev,
192-
"Library loading is not supported due to not set library path\n");
193-
return -EINVAL;
194-
}
195-
196189
if (!ipc4_data->load_library) {
197190
dev_err(sdev->dev, "Library loading is not supported on this platform\n");
198191
return -EOPNOTSUPP;
@@ -202,21 +195,28 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
202195
if (!fw_lib)
203196
return -ENOMEM;
204197

205-
fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
206-
sdev->pdata->fw_lib_prefix, uuid);
207-
if (!fw_filename) {
208-
ret = -ENOMEM;
209-
goto free_fw_lib;
210-
}
211-
212-
ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev);
213-
if (ret < 0) {
214-
dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename);
215-
goto free_filename;
198+
if (optional) {
199+
ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename,
200+
sdev->dev);
201+
if (ret < 0) {
202+
dev_dbg(sdev->dev, "Library file '%s' is not present\n",
203+
lib_filename);
204+
/* optional library, override the error */
205+
ret = 0;
206+
goto free_fw_lib;
207+
}
216208
} else {
217-
dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
209+
ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename,
210+
sdev->dev);
211+
if (ret < 0) {
212+
dev_err(sdev->dev, "Library file '%s' is missing\n",
213+
lib_filename);
214+
goto free_fw_lib;
215+
}
218216
}
219217

218+
dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename);
219+
220220
payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
221221
if (payload_offset <= 0) {
222222
if (!payload_offset)
@@ -228,11 +228,11 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
228228
}
229229

230230
fw_lib->sof_fw.payload_offset = payload_offset;
231-
fw_lib->id = lib_id;
231+
fw_lib->id = *lib_id;
232232

233233
/* Fix up the module ID numbers within the library */
234234
for (i = 0; i < fw_lib->num_modules; i++)
235-
fw_lib->modules[i].man4_module_entry.id |= (lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
235+
fw_lib->modules[i].man4_module_entry.id |= (*lib_id << SOF_IPC4_MOD_LIB_ID_SHIFT);
236236

237237
/*
238238
* Make sure that the DSP is booted and stays up while attempting the
@@ -256,26 +256,108 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
256256
if (ret)
257257
goto release;
258258

259-
ret = xa_insert(&ipc4_data->fw_lib_xa, lib_id, fw_lib, GFP_KERNEL);
259+
ret = xa_insert(&ipc4_data->fw_lib_xa, *lib_id, fw_lib, GFP_KERNEL);
260260
if (unlikely(ret))
261261
goto release;
262262

263-
kfree(fw_filename);
264-
263+
(*lib_id)++;
265264
return 0;
266265

267266
release:
268267
release_firmware(fw_lib->sof_fw.fw);
269268
/* Allocated within sof_ipc4_fw_parse_ext_man() */
270269
devm_kfree(sdev->dev, fw_lib->modules);
271-
free_filename:
272-
kfree(fw_filename);
273270
free_fw_lib:
274271
devm_kfree(sdev->dev, fw_lib);
275272

276273
return ret;
277274
}
278275

276+
/**
277+
* sof_ipc4_load_library_bundles - loads the library parts of a modular firmware
278+
* @sdev: SOF device
279+
*
280+
* With IPC4 the firmware can be monolithic or modular release.
281+
* - monolithic: only the basefw
282+
* - modular: basefw and two libraries (openmodules, debug)
283+
*
284+
* With modular release it is also allowed that the for example only the debug
285+
* library is present (the openmodules content is built in the basefw).
286+
*
287+
* To handle the permutations try to load the openmodules then the debug
288+
* libraries as optional ones after the basefw boot.
289+
*
290+
* The libraries for the modular release are stored alongside of the basefw on
291+
* the filesystem.
292+
*/
293+
int sof_ipc4_load_library_bundles(struct snd_sof_dev *sdev)
294+
{
295+
static const char * const lib_bundle[] = { "openmodules", "debug" };
296+
const char *fw_filename = sdev->pdata->fw_filename;
297+
const char *lib_filename, *p;
298+
unsigned long lib_id = 1;
299+
char *lib_name_base;
300+
int ret, i;
301+
302+
p = strstr(fw_filename, ".ri");
303+
if (!p || strlen(p) != 3) {
304+
dev_info(sdev->dev,
305+
"%s: Firmware name '%s' is missing .ri extension\n",
306+
__func__, fw_filename);
307+
return 0;
308+
}
309+
310+
lib_name_base = kzalloc(strlen(fw_filename) - 2, GFP_KERNEL);
311+
if (!lib_name_base)
312+
return -ENOMEM;
313+
314+
strscpy(lib_name_base, fw_filename, sizeof(lib_name_base));
315+
316+
for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) {
317+
lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri",
318+
sdev->pdata->fw_filename_prefix,
319+
lib_name_base, lib_bundle[i]);
320+
if (!lib_filename) {
321+
ret = -ENOMEM;
322+
break;
323+
}
324+
325+
ret = sof_ipc4_load_library(sdev, &lib_id, lib_filename, true);
326+
327+
kfree(lib_filename);
328+
if (ret)
329+
break;
330+
}
331+
332+
kfree(lib_name_base);
333+
334+
return ret;
335+
}
336+
337+
static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
338+
unsigned long lib_id, const guid_t *uuid)
339+
{
340+
const char *lib_filename;
341+
int ret;
342+
343+
if (!sdev->pdata->fw_lib_prefix) {
344+
dev_err(sdev->dev,
345+
"Library loading is not supported due to not set library path\n");
346+
return -EINVAL;
347+
}
348+
349+
lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
350+
sdev->pdata->fw_lib_prefix, uuid);
351+
if (!lib_filename)
352+
return -ENOMEM;
353+
354+
ret = sof_ipc4_load_library(sdev, &lib_id, lib_filename, false);
355+
356+
kfree(lib_filename);
357+
358+
return ret;
359+
}
360+
279361
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
280362
const guid_t *uuid)
281363
{

sound/soc/sof/ipc4-priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 s
102102
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
103103

104104
int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
105+
int sof_ipc4_load_library_bundles(struct snd_sof_dev *sdev);
105106
int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
106107
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
107108
const guid_t *uuid);

sound/soc/sof/ipc4.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,14 @@ static void sof_ipc4_exit(struct snd_sof_dev *sdev)
825825

826826
static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
827827
{
828-
if (sdev->first_boot)
828+
if (sdev->first_boot) {
829+
int ret = sof_ipc4_load_library_bundles(sdev);
830+
831+
if (ret)
832+
return ret;
833+
829834
return sof_ipc4_query_fw_configuration(sdev);
835+
}
830836

831837
return sof_ipc4_reload_fw_libraries(sdev);
832838
}

0 commit comments

Comments
 (0)