xref: /openbmc/linux/sound/soc/sof/loader.c (revision fb574682)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
7 //
8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
9 //
10 // Generic firmware loader.
11 //
12 
13 #include <linux/firmware.h>
14 #include <sound/sof.h>
15 #include <sound/sof/ext_manifest.h>
16 #include "ops.h"
17 
18 static int get_ext_windows(struct snd_sof_dev *sdev,
19 			   const struct sof_ipc_ext_data_hdr *ext_hdr)
20 {
21 	const struct sof_ipc_window *w =
22 		container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
23 	size_t w_size = struct_size(w, window, w->num_windows);
24 
25 	if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
26 		return -EINVAL;
27 
28 	if (sdev->info_window) {
29 		if (memcmp(sdev->info_window, w, w_size)) {
30 			dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox");
31 			return -EINVAL;
32 		}
33 		return 0;
34 	}
35 
36 	/* keep a local copy of the data */
37 	sdev->info_window = kmemdup(w, w_size, GFP_KERNEL);
38 	if (!sdev->info_window)
39 		return -ENOMEM;
40 
41 	return 0;
42 }
43 
44 static int get_cc_info(struct snd_sof_dev *sdev,
45 		       const struct sof_ipc_ext_data_hdr *ext_hdr)
46 {
47 	int ret;
48 
49 	const struct sof_ipc_cc_version *cc =
50 		container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr);
51 
52 	if (sdev->cc_version) {
53 		if (memcmp(sdev->cc_version, cc, cc->ext_hdr.hdr.size)) {
54 			dev_err(sdev->dev, "error: receive diverged cc_version descriptions");
55 			return -EINVAL;
56 		}
57 		return 0;
58 	}
59 
60 	dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n",
61 		cc->name, cc->major, cc->minor, cc->micro, cc->desc,
62 		cc->optim);
63 
64 	/* create read-only cc_version debugfs to store compiler version info */
65 	/* use local copy of the cc_version to prevent data corruption */
66 	if (sdev->first_boot) {
67 		sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size,
68 						GFP_KERNEL);
69 
70 		if (!sdev->cc_version)
71 			return -ENOMEM;
72 
73 		memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size);
74 		ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version,
75 					       cc->ext_hdr.hdr.size,
76 					       "cc_version", 0444);
77 
78 		/* errors are only due to memory allocation, not debugfs */
79 		if (ret < 0) {
80 			dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
81 			return ret;
82 		}
83 	}
84 
85 	return 0;
86 }
87 
88 /* parse the extended FW boot data structures from FW boot message */
89 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
90 {
91 	struct sof_ipc_ext_data_hdr *ext_hdr;
92 	void *ext_data;
93 	int ret = 0;
94 
95 	ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
96 	if (!ext_data)
97 		return -ENOMEM;
98 
99 	/* get first header */
100 	snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
101 			       sizeof(*ext_hdr));
102 	ext_hdr = ext_data;
103 
104 	while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
105 		/* read in ext structure */
106 		snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
107 				   (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
108 				   ext_hdr->hdr.size - sizeof(*ext_hdr));
109 
110 		dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
111 			ext_hdr->type, ext_hdr->hdr.size);
112 
113 		/* process structure data */
114 		switch (ext_hdr->type) {
115 		case SOF_IPC_EXT_WINDOW:
116 			ret = get_ext_windows(sdev, ext_hdr);
117 			break;
118 		case SOF_IPC_EXT_CC_INFO:
119 			ret = get_cc_info(sdev, ext_hdr);
120 			break;
121 		default:
122 			dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
123 				 ext_hdr->type, ext_hdr->hdr.size);
124 			ret = 0;
125 			break;
126 		}
127 
128 		if (ret < 0) {
129 			dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
130 				ext_hdr->type);
131 			break;
132 		}
133 
134 		/* move to next header */
135 		offset += ext_hdr->hdr.size;
136 		snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
137 				       sizeof(*ext_hdr));
138 		ext_hdr = ext_data;
139 	}
140 
141 	kfree(ext_data);
142 	return ret;
143 }
144 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
145 
146 static int ext_man_get_fw_version(struct snd_sof_dev *sdev,
147 				  const struct sof_ext_man_elem_header *hdr)
148 {
149 	const struct sof_ext_man_fw_version *v =
150 		container_of(hdr, struct sof_ext_man_fw_version, hdr);
151 
152 	memcpy(&sdev->fw_ready.version, &v->version, sizeof(v->version));
153 	sdev->fw_ready.flags = v->flags;
154 
155 	/* log ABI versions and check FW compatibility */
156 	return snd_sof_ipc_valid(sdev);
157 }
158 
159 static int ext_man_get_windows(struct snd_sof_dev *sdev,
160 			       const struct sof_ext_man_elem_header *hdr)
161 {
162 	const struct sof_ext_man_window *w;
163 
164 	w = container_of(hdr, struct sof_ext_man_window, hdr);
165 
166 	return get_ext_windows(sdev, &w->ipc_window.ext_hdr);
167 }
168 
169 static int ext_man_get_cc_info(struct snd_sof_dev *sdev,
170 			       const struct sof_ext_man_elem_header *hdr)
171 {
172 	const struct sof_ext_man_cc_version *cc;
173 
174 	cc = container_of(hdr, struct sof_ext_man_cc_version, hdr);
175 
176 	return get_cc_info(sdev, &cc->cc_version.ext_hdr);
177 }
178 
179 static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
180 {
181 	const struct sof_ext_man_header *head;
182 
183 	head = (struct sof_ext_man_header *)fw->data;
184 
185 	/*
186 	 * assert fw size is big enough to contain extended manifest header,
187 	 * it prevents from reading unallocated memory from `head` in following
188 	 * step.
189 	 */
190 	if (fw->size < sizeof(*head))
191 		return -EINVAL;
192 
193 	/*
194 	 * When fw points to extended manifest,
195 	 * then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER.
196 	 */
197 	if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
198 		return head->full_size;
199 
200 	/* otherwise given fw don't have an extended manifest */
201 	return 0;
202 }
203 
204 /* parse extended FW manifest data structures */
205 static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
206 				    const struct firmware *fw)
207 {
208 	const struct sof_ext_man_elem_header *elem_hdr;
209 	const struct sof_ext_man_header *head;
210 	ssize_t ext_man_size;
211 	ssize_t remaining;
212 	uintptr_t iptr;
213 	int ret = 0;
214 
215 	head = (struct sof_ext_man_header *)fw->data;
216 	remaining = head->full_size - head->header_size;
217 	ext_man_size = snd_sof_ext_man_size(fw);
218 
219 	/* Assert firmware starts with extended manifest */
220 	if (ext_man_size <= 0)
221 		return ext_man_size;
222 
223 	/* incompatible version */
224 	if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION,
225 					     head->header_version)) {
226 		dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n",
227 			head->header_version, SOF_EXT_MAN_VERSION);
228 		return -EINVAL;
229 	}
230 
231 	/* get first extended manifest element header */
232 	iptr = (uintptr_t)fw->data + head->header_size;
233 
234 	while (remaining > sizeof(*elem_hdr)) {
235 		elem_hdr = (struct sof_ext_man_elem_header *)iptr;
236 
237 		dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n",
238 			elem_hdr->type, elem_hdr->size);
239 
240 		if (elem_hdr->size < sizeof(*elem_hdr) ||
241 		    elem_hdr->size > remaining) {
242 			dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n",
243 				elem_hdr->type, elem_hdr->size);
244 			return -EINVAL;
245 		}
246 
247 		/* process structure data */
248 		switch (elem_hdr->type) {
249 		case SOF_EXT_MAN_ELEM_FW_VERSION:
250 			ret = ext_man_get_fw_version(sdev, elem_hdr);
251 			break;
252 		case SOF_EXT_MAN_ELEM_WINDOW:
253 			ret = ext_man_get_windows(sdev, elem_hdr);
254 			break;
255 		case SOF_EXT_MAN_ELEM_CC_VERSION:
256 			ret = ext_man_get_cc_info(sdev, elem_hdr);
257 			break;
258 		default:
259 			dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
260 				 elem_hdr->type, elem_hdr->size);
261 			break;
262 		}
263 
264 		if (ret < 0) {
265 			dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n",
266 				elem_hdr->type, elem_hdr->size);
267 			return ret;
268 		}
269 
270 		remaining -= elem_hdr->size;
271 		iptr += elem_hdr->size;
272 	}
273 
274 	if (remaining) {
275 		dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n");
276 		return -EINVAL;
277 	}
278 
279 	return ext_man_size;
280 }
281 
282 /*
283  * IPC Firmware ready.
284  */
285 static void sof_get_windows(struct snd_sof_dev *sdev)
286 {
287 	struct sof_ipc_window_elem *elem;
288 	u32 outbox_offset = 0;
289 	u32 stream_offset = 0;
290 	u32 inbox_offset = 0;
291 	u32 outbox_size = 0;
292 	u32 stream_size = 0;
293 	u32 inbox_size = 0;
294 	int window_offset;
295 	int bar;
296 	int i;
297 
298 	if (!sdev->info_window) {
299 		dev_err(sdev->dev, "error: have no window info\n");
300 		return;
301 	}
302 
303 	bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
304 	if (bar < 0) {
305 		dev_err(sdev->dev, "error: have no bar mapping\n");
306 		return;
307 	}
308 
309 	for (i = 0; i < sdev->info_window->num_windows; i++) {
310 		elem = &sdev->info_window->window[i];
311 
312 		window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
313 		if (window_offset < 0) {
314 			dev_warn(sdev->dev, "warn: no offset for window %d\n",
315 				 elem->id);
316 			continue;
317 		}
318 
319 		switch (elem->type) {
320 		case SOF_IPC_REGION_UPBOX:
321 			inbox_offset = window_offset + elem->offset;
322 			inbox_size = elem->size;
323 			snd_sof_debugfs_io_item(sdev,
324 						sdev->bar[bar] +
325 						inbox_offset,
326 						elem->size, "inbox",
327 						SOF_DEBUGFS_ACCESS_D0_ONLY);
328 			break;
329 		case SOF_IPC_REGION_DOWNBOX:
330 			outbox_offset = window_offset + elem->offset;
331 			outbox_size = elem->size;
332 			snd_sof_debugfs_io_item(sdev,
333 						sdev->bar[bar] +
334 						outbox_offset,
335 						elem->size, "outbox",
336 						SOF_DEBUGFS_ACCESS_D0_ONLY);
337 			break;
338 		case SOF_IPC_REGION_TRACE:
339 			snd_sof_debugfs_io_item(sdev,
340 						sdev->bar[bar] +
341 						window_offset +
342 						elem->offset,
343 						elem->size, "etrace",
344 						SOF_DEBUGFS_ACCESS_D0_ONLY);
345 			break;
346 		case SOF_IPC_REGION_DEBUG:
347 			snd_sof_debugfs_io_item(sdev,
348 						sdev->bar[bar] +
349 						window_offset +
350 						elem->offset,
351 						elem->size, "debug",
352 						SOF_DEBUGFS_ACCESS_D0_ONLY);
353 			break;
354 		case SOF_IPC_REGION_STREAM:
355 			stream_offset = window_offset + elem->offset;
356 			stream_size = elem->size;
357 			snd_sof_debugfs_io_item(sdev,
358 						sdev->bar[bar] +
359 						stream_offset,
360 						elem->size, "stream",
361 						SOF_DEBUGFS_ACCESS_D0_ONLY);
362 			break;
363 		case SOF_IPC_REGION_REGS:
364 			snd_sof_debugfs_io_item(sdev,
365 						sdev->bar[bar] +
366 						window_offset +
367 						elem->offset,
368 						elem->size, "regs",
369 						SOF_DEBUGFS_ACCESS_D0_ONLY);
370 			break;
371 		case SOF_IPC_REGION_EXCEPTION:
372 			sdev->dsp_oops_offset = window_offset + elem->offset;
373 			snd_sof_debugfs_io_item(sdev,
374 						sdev->bar[bar] +
375 						window_offset +
376 						elem->offset,
377 						elem->size, "exception",
378 						SOF_DEBUGFS_ACCESS_D0_ONLY);
379 			break;
380 		default:
381 			dev_err(sdev->dev, "error: get illegal window info\n");
382 			return;
383 		}
384 	}
385 
386 	if (outbox_size == 0 || inbox_size == 0) {
387 		dev_err(sdev->dev, "error: get illegal mailbox window\n");
388 		return;
389 	}
390 
391 	snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
392 				 outbox_offset, outbox_size);
393 	sdev->stream_box.offset = stream_offset;
394 	sdev->stream_box.size = stream_size;
395 
396 	dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
397 		inbox_offset, inbox_size);
398 	dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
399 		outbox_offset, outbox_size);
400 	dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
401 		stream_offset, stream_size);
402 }
403 
404 /* check for ABI compatibility and create memory windows on first boot */
405 int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
406 {
407 	struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
408 	int offset;
409 	int bar;
410 	int ret;
411 
412 	/* mailbox must be on 4k boundary */
413 	offset = snd_sof_dsp_get_mailbox_offset(sdev);
414 	if (offset < 0) {
415 		dev_err(sdev->dev, "error: have no mailbox offset\n");
416 		return offset;
417 	}
418 
419 	bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
420 	if (bar < 0) {
421 		dev_err(sdev->dev, "error: have no bar mapping\n");
422 		return -EINVAL;
423 	}
424 
425 	dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
426 		msg_id, offset);
427 
428 	/* no need to re-check version/ABI for subsequent boots */
429 	if (!sdev->first_boot)
430 		return 0;
431 
432 	/* copy data from the DSP FW ready offset */
433 	sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
434 
435 	/* make sure ABI version is compatible */
436 	ret = snd_sof_ipc_valid(sdev);
437 	if (ret < 0)
438 		return ret;
439 
440 	/* now check for extended data */
441 	snd_sof_fw_parse_ext_data(sdev, bar, offset +
442 				  sizeof(struct sof_ipc_fw_ready));
443 
444 	sof_get_windows(sdev);
445 
446 	return 0;
447 }
448 EXPORT_SYMBOL(sof_fw_ready);
449 
450 /* generic module parser for mmaped DSPs */
451 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
452 				struct snd_sof_mod_hdr *module)
453 {
454 	struct snd_sof_blk_hdr *block;
455 	int count, bar;
456 	u32 offset;
457 	size_t remaining;
458 
459 	dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
460 		module->size, module->num_blocks, module->type);
461 
462 	block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
463 
464 	/* module->size doesn't include header size */
465 	remaining = module->size;
466 	for (count = 0; count < module->num_blocks; count++) {
467 		/* check for wrap */
468 		if (remaining < sizeof(*block)) {
469 			dev_err(sdev->dev, "error: not enough data remaining\n");
470 			return -EINVAL;
471 		}
472 
473 		/* minus header size of block */
474 		remaining -= sizeof(*block);
475 
476 		if (block->size == 0) {
477 			dev_warn(sdev->dev,
478 				 "warning: block %d size zero\n", count);
479 			dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
480 				 block->type, block->offset);
481 			continue;
482 		}
483 
484 		switch (block->type) {
485 		case SOF_FW_BLK_TYPE_RSRVD0:
486 		case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
487 			continue;	/* not handled atm */
488 		case SOF_FW_BLK_TYPE_IRAM:
489 		case SOF_FW_BLK_TYPE_DRAM:
490 		case SOF_FW_BLK_TYPE_SRAM:
491 			offset = block->offset;
492 			bar = snd_sof_dsp_get_bar_index(sdev, block->type);
493 			if (bar < 0) {
494 				dev_err(sdev->dev,
495 					"error: no BAR mapping for block type 0x%x\n",
496 					block->type);
497 				return bar;
498 			}
499 			break;
500 		default:
501 			dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
502 				block->type, count);
503 			return -EINVAL;
504 		}
505 
506 		dev_dbg(sdev->dev,
507 			"block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
508 			count, block->type, block->size, offset);
509 
510 		/* checking block->size to avoid unaligned access */
511 		if (block->size % sizeof(u32)) {
512 			dev_err(sdev->dev, "error: invalid block size 0x%x\n",
513 				block->size);
514 			return -EINVAL;
515 		}
516 		snd_sof_dsp_block_write(sdev, bar, offset,
517 					block + 1, block->size);
518 
519 		if (remaining < block->size) {
520 			dev_err(sdev->dev, "error: not enough data remaining\n");
521 			return -EINVAL;
522 		}
523 
524 		/* minus body size of block */
525 		remaining -= block->size;
526 		/* next block */
527 		block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
528 			+ block->size);
529 	}
530 
531 	return 0;
532 }
533 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
534 
535 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
536 			size_t fw_offset)
537 {
538 	struct snd_sof_fw_header *header;
539 	size_t fw_size = fw->size - fw_offset;
540 
541 	if (fw->size <= fw_offset) {
542 		dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
543 		return -EINVAL;
544 	}
545 
546 	/* Read the header information from the data pointer */
547 	header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
548 
549 	/* verify FW sig */
550 	if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
551 		dev_err(sdev->dev, "error: invalid firmware signature\n");
552 		return -EINVAL;
553 	}
554 
555 	/* check size is valid */
556 	if (fw_size != header->file_size + sizeof(*header)) {
557 		dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
558 			fw_size, header->file_size + sizeof(*header));
559 		return -EINVAL;
560 	}
561 
562 	dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
563 		header->file_size, header->num_modules,
564 		header->abi, sizeof(*header));
565 
566 	return 0;
567 }
568 
569 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
570 			size_t fw_offset)
571 {
572 	struct snd_sof_fw_header *header;
573 	struct snd_sof_mod_hdr *module;
574 	int (*load_module)(struct snd_sof_dev *sof_dev,
575 			   struct snd_sof_mod_hdr *hdr);
576 	int ret, count;
577 	size_t remaining;
578 
579 	header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
580 	load_module = sof_ops(sdev)->load_module;
581 	if (!load_module)
582 		return -EINVAL;
583 
584 	/* parse each module */
585 	module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
586 					    sizeof(*header));
587 	remaining = fw->size - sizeof(*header) - fw_offset;
588 	/* check for wrap */
589 	if (remaining > fw->size) {
590 		dev_err(sdev->dev, "error: fw size smaller than header size\n");
591 		return -EINVAL;
592 	}
593 
594 	for (count = 0; count < header->num_modules; count++) {
595 		/* check for wrap */
596 		if (remaining < sizeof(*module)) {
597 			dev_err(sdev->dev, "error: not enough data remaining\n");
598 			return -EINVAL;
599 		}
600 
601 		/* minus header size of module */
602 		remaining -= sizeof(*module);
603 
604 		/* module */
605 		ret = load_module(sdev, module);
606 		if (ret < 0) {
607 			dev_err(sdev->dev, "error: invalid module %d\n", count);
608 			return ret;
609 		}
610 
611 		if (remaining < module->size) {
612 			dev_err(sdev->dev, "error: not enough data remaining\n");
613 			return -EINVAL;
614 		}
615 
616 		/* minus body size of module */
617 		remaining -=  module->size;
618 		module = (struct snd_sof_mod_hdr *)((u8 *)module
619 			+ sizeof(*module) + module->size);
620 	}
621 
622 	return 0;
623 }
624 
625 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
626 {
627 	struct snd_sof_pdata *plat_data = sdev->pdata;
628 	const char *fw_filename;
629 	ssize_t ext_man_size;
630 	int ret;
631 
632 	/* Don't request firmware again if firmware is already requested */
633 	if (plat_data->fw)
634 		return 0;
635 
636 	fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
637 				plat_data->fw_filename_prefix,
638 				plat_data->fw_filename);
639 	if (!fw_filename)
640 		return -ENOMEM;
641 
642 	ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
643 
644 	if (ret < 0) {
645 		dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
646 			fw_filename, ret);
647 		goto err;
648 	} else {
649 		dev_dbg(sdev->dev, "request_firmware %s successful\n",
650 			fw_filename);
651 	}
652 
653 	/* check for extended manifest */
654 	ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
655 	if (ext_man_size > 0) {
656 		/* when no error occurred, drop extended manifest */
657 		plat_data->fw_offset = ext_man_size;
658 	} else if (!ext_man_size) {
659 		/* No extended manifest, so nothing to skip during FW load */
660 		dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
661 	} else {
662 		ret = ext_man_size;
663 		dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
664 			fw_filename, ret);
665 	}
666 
667 err:
668 	kfree(fw_filename);
669 
670 	return ret;
671 }
672 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
673 
674 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
675 {
676 	struct snd_sof_pdata *plat_data = sdev->pdata;
677 	int ret;
678 
679 	ret = snd_sof_load_firmware_raw(sdev);
680 	if (ret < 0)
681 		return ret;
682 
683 	/* make sure the FW header and file is valid */
684 	ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
685 	if (ret < 0) {
686 		dev_err(sdev->dev, "error: invalid FW header\n");
687 		goto error;
688 	}
689 
690 	/* prepare the DSP for FW loading */
691 	ret = snd_sof_dsp_reset(sdev);
692 	if (ret < 0) {
693 		dev_err(sdev->dev, "error: failed to reset DSP\n");
694 		goto error;
695 	}
696 
697 	/* parse and load firmware modules to DSP */
698 	ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
699 	if (ret < 0) {
700 		dev_err(sdev->dev, "error: invalid FW modules\n");
701 		goto error;
702 	}
703 
704 	return 0;
705 
706 error:
707 	release_firmware(plat_data->fw);
708 	plat_data->fw = NULL;
709 	return ret;
710 
711 }
712 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
713 
714 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
715 {
716 	dev_dbg(sdev->dev, "loading firmware\n");
717 
718 	if (sof_ops(sdev)->load_firmware)
719 		return sof_ops(sdev)->load_firmware(sdev);
720 	return 0;
721 }
722 EXPORT_SYMBOL(snd_sof_load_firmware);
723 
724 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
725 {
726 	int ret;
727 	int init_core_mask;
728 
729 	init_waitqueue_head(&sdev->boot_wait);
730 
731 	/* create read-only fw_version debugfs to store boot version info */
732 	if (sdev->first_boot) {
733 		ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
734 					       sizeof(sdev->fw_version),
735 					       "fw_version", 0444);
736 		/* errors are only due to memory allocation, not debugfs */
737 		if (ret < 0) {
738 			dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
739 			return ret;
740 		}
741 	}
742 
743 	/* perform pre fw run operations */
744 	ret = snd_sof_dsp_pre_fw_run(sdev);
745 	if (ret < 0) {
746 		dev_err(sdev->dev, "error: failed pre fw run op\n");
747 		return ret;
748 	}
749 
750 	dev_dbg(sdev->dev, "booting DSP firmware\n");
751 
752 	/* boot the firmware on the DSP */
753 	ret = snd_sof_dsp_run(sdev);
754 	if (ret < 0) {
755 		dev_err(sdev->dev, "error: failed to reset DSP\n");
756 		return ret;
757 	}
758 
759 	init_core_mask = ret;
760 
761 	/*
762 	 * now wait for the DSP to boot. There are 3 possible outcomes:
763 	 * 1. Boot wait times out indicating FW boot failure.
764 	 * 2. FW boots successfully and fw_ready op succeeds.
765 	 * 3. FW boots but fw_ready op fails.
766 	 */
767 	ret = wait_event_timeout(sdev->boot_wait,
768 				 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
769 				 msecs_to_jiffies(sdev->boot_timeout));
770 	if (ret == 0) {
771 		dev_err(sdev->dev, "error: firmware boot failure\n");
772 		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
773 			SOF_DBG_TEXT | SOF_DBG_PCI);
774 		sdev->fw_state = SOF_FW_BOOT_FAILED;
775 		return -EIO;
776 	}
777 
778 	if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
779 		dev_dbg(sdev->dev, "firmware boot complete\n");
780 	else
781 		return -EIO; /* FW boots but fw_ready op failed */
782 
783 	/* perform post fw run operations */
784 	ret = snd_sof_dsp_post_fw_run(sdev);
785 	if (ret < 0) {
786 		dev_err(sdev->dev, "error: failed post fw run op\n");
787 		return ret;
788 	}
789 
790 	/* fw boot is complete. Update the active cores mask */
791 	sdev->enabled_cores_mask = init_core_mask;
792 
793 	return 0;
794 }
795 EXPORT_SYMBOL(snd_sof_run_firmware);
796 
797 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
798 {
799 	/* TODO: support module unloading at runtime */
800 }
801 EXPORT_SYMBOL(snd_sof_fw_unload);
802