@@ -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
267263release :
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 );
273267free_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+
279372struct sof_ipc4_fw_module * sof_ipc4_find_module_by_uuid (struct snd_sof_dev * sdev ,
280373 const guid_t * uuid )
281374{
0 commit comments