Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>
Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20250206085237.19214-1-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Peter Ujfalusi and committed by
Mark Brown
4c751806 2466b622

+126 -26
+118 -25
sound/soc/sof/ipc4-loader.c
··· 169 169 return payload_offset; 170 170 } 171 171 172 - static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, 173 - unsigned long lib_id, const guid_t *uuid) 172 + static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id, 173 + const char *lib_filename, bool optional) 174 174 { 175 175 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 176 176 struct sof_ipc4_fw_library *fw_lib; 177 - const char *fw_filename; 178 177 ssize_t payload_offset; 179 178 int ret, i, err; 180 - 181 - if (!sdev->pdata->fw_lib_prefix) { 182 - dev_err(sdev->dev, 183 - "Library loading is not supported due to not set library path\n"); 184 - return -EINVAL; 185 - } 186 179 187 180 if (!ipc4_data->load_library) { 188 181 dev_err(sdev->dev, "Library loading is not supported on this platform\n"); ··· 186 193 if (!fw_lib) 187 194 return -ENOMEM; 188 195 189 - fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", 190 - sdev->pdata->fw_lib_prefix, uuid); 191 - if (!fw_filename) { 192 - ret = -ENOMEM; 193 - goto free_fw_lib; 196 + if (optional) { 197 + ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename, 198 + sdev->dev); 199 + if (ret < 0) { 200 + /* optional library, override the error */ 201 + ret = 0; 202 + goto free_fw_lib; 203 + } 204 + } else { 205 + ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename, 206 + sdev->dev); 207 + if (ret < 0) { 208 + dev_err(sdev->dev, "Library file '%s' is missing\n", 209 + lib_filename); 210 + goto free_fw_lib; 211 + } 194 212 } 195 213 196 - ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev); 197 - if (ret < 0) { 198 - dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename); 199 - goto free_filename; 200 - } else { 201 - dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename); 202 - } 214 + dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename); 203 215 204 216 payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib); 205 217 if (payload_offset <= 0) { ··· 249 251 if (unlikely(ret)) 250 252 goto release; 251 253 252 - kfree(fw_filename); 253 - 254 254 return 0; 255 255 256 256 release: 257 257 release_firmware(fw_lib->sof_fw.fw); 258 258 /* Allocated within sof_ipc4_fw_parse_ext_man() */ 259 259 devm_kfree(sdev->dev, fw_lib->modules); 260 - free_filename: 261 - kfree(fw_filename); 262 260 free_fw_lib: 263 261 devm_kfree(sdev->dev, fw_lib); 262 + 263 + return ret; 264 + } 265 + 266 + /** 267 + * sof_ipc4_complete_split_release - loads the library parts of a split firmware 268 + * @sdev: SOF device 269 + * 270 + * With IPC4 the firmware can be a single binary or a split release. 271 + * - single binary: only the basefw 272 + * - split release: basefw and two libraries (openmodules, debug) 273 + * 274 + * With split firmware release it is also allowed that for example only the 275 + * debug library is present (the openmodules content is built in the basefw). 276 + * 277 + * To handle the permutations try to load the openmodules then the debug 278 + * libraries as optional ones after the basefw boot. 279 + * 280 + * The libraries for the split release are stored alongside the basefw on the 281 + * filesystem. 282 + */ 283 + int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev) 284 + { 285 + static const char * const lib_bundle[] = { "openmodules", "debug" }; 286 + const char *fw_filename = sdev->pdata->fw_filename; 287 + const char *lib_filename, *p; 288 + size_t lib_name_base_size; 289 + unsigned long lib_id = 1; 290 + char *lib_name_base; 291 + int i; 292 + 293 + p = strstr(fw_filename, ".ri"); 294 + if (!p || strlen(p) != 3) { 295 + dev_info(sdev->dev, 296 + "%s: Firmware name '%s' is missing .ri extension\n", 297 + __func__, fw_filename); 298 + return 0; 299 + } 300 + 301 + /* Space for the firmware basename + '\0', without the extension */ 302 + lib_name_base_size = strlen(fw_filename) - 2; 303 + lib_name_base = kzalloc(lib_name_base_size, GFP_KERNEL); 304 + if (!lib_name_base) 305 + return -ENOMEM; 306 + 307 + /* 308 + * strscpy will 0 terminate the copied string, removing the '.ri' from 309 + * the end of the fw_filename, for example: 310 + * fw_filename: "sof-ptl.ri\0" 311 + * lib_name_base: "sof-ptl\0" 312 + */ 313 + strscpy(lib_name_base, fw_filename, lib_name_base_size); 314 + 315 + for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) { 316 + int ret; 317 + 318 + lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri", 319 + sdev->pdata->fw_filename_prefix, 320 + lib_name_base, lib_bundle[i]); 321 + if (!lib_filename) { 322 + kfree(lib_name_base); 323 + return -ENOMEM; 324 + } 325 + 326 + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, true); 327 + if (ret) 328 + dev_warn(sdev->dev, "%s: Failed to load %s: %d\n", 329 + __func__, lib_filename, ret); 330 + else 331 + lib_id++; 332 + 333 + kfree(lib_filename); 334 + } 335 + 336 + kfree(lib_name_base); 337 + 338 + return 0; 339 + } 340 + 341 + static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, 342 + unsigned long lib_id, const guid_t *uuid) 343 + { 344 + const char *lib_filename; 345 + int ret; 346 + 347 + if (!sdev->pdata->fw_lib_prefix) { 348 + dev_err(sdev->dev, 349 + "Library loading is not supported due to not set library path\n"); 350 + return -EINVAL; 351 + } 352 + 353 + lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", 354 + sdev->pdata->fw_lib_prefix, uuid); 355 + if (!lib_filename) 356 + return -ENOMEM; 357 + 358 + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, false); 359 + 360 + kfree(lib_filename); 264 361 265 362 return ret; 266 363 }
+1
sound/soc/sof/ipc4-priv.h
··· 101 101 int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state); 102 102 int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); 103 103 104 + int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev); 104 105 int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev); 105 106 int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); 106 107 struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
+7 -1
sound/soc/sof/ipc4.c
··· 825 825 826 826 static int sof_ipc4_post_boot(struct snd_sof_dev *sdev) 827 827 { 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 + 829 834 return sof_ipc4_query_fw_configuration(sdev); 835 + } 830 836 831 837 return sof_ipc4_reload_fw_libraries(sdev); 832 838 }