@@ -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
267266release :
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 );
273270free_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+
279361struct sof_ipc4_fw_module * sof_ipc4_find_module_by_uuid (struct snd_sof_dev * sdev ,
280362 const guid_t * uuid )
281363{
0 commit comments