Skip to content

Commit 1475854

Browse files
ujfalusiranj063
authored andcommitted
ASoC: SOF: ipc4: Add support for split firmware releases
A split 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 single or split configuration: single release: base firmware only split release: base firmware + openmodules + debug The files for the split firmware are located at the firmware directory. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent 638fb42 commit 1475854

3 files changed

Lines changed: 126 additions & 26 deletions

File tree

sound/soc/sof/ipc4-loader.c

Lines changed: 118 additions & 25 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,26 @@ 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+
/* optional library, override the error */
203+
ret = 0;
204+
goto free_fw_lib;
205+
}
216206
} else {
217-
dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
207+
ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename,
208+
sdev->dev);
209+
if (ret < 0) {
210+
dev_err(sdev->dev, "Library file '%s' is missing\n",
211+
lib_filename);
212+
goto free_fw_lib;
213+
}
218214
}
219215

216+
dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename);
217+
220218
payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
221219
if (payload_offset <= 0) {
222220
if (!payload_offset)
@@ -260,22 +258,117 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
260258
if (unlikely(ret))
261259
goto release;
262260

263-
kfree(fw_filename);
264-
265261
return 0;
266262

267263
release:
268264
release_firmware(fw_lib->sof_fw.fw);
269265
/* Allocated within sof_ipc4_fw_parse_ext_man() */
270266
devm_kfree(sdev->dev, fw_lib->modules);
271-
free_filename:
272-
kfree(fw_filename);
273267
free_fw_lib:
274268
devm_kfree(sdev->dev, fw_lib);
275269

276270
return ret;
277271
}
278272

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

sound/soc/sof/ipc4-priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
101101
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state);
102102
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
103103

104+
int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev);
104105
int sof_ipc4_query_fw_configuration(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,

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_complete_split_release(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)