xref: /openbmc/linux/sound/soc/sof/loader.c (revision b96c0546)
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 
24 	if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
25 		return -EINVAL;
26 
27 	if (sdev->info_window) {
28 		if (memcmp(sdev->info_window, w, ext_hdr->hdr.size)) {
29 			dev_err(sdev->dev, "error: mismatch between window descriptor from extended manifest and mailbox");
30 			return -EINVAL;
31 		}
32 		return 0;
33 	}
34 
35 	/* keep a local copy of the data */
36 	sdev->info_window = devm_kmemdup(sdev->dev, w, ext_hdr->hdr.size,
37 					 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 int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev,
180 				    const struct sof_ext_man_elem_header *hdr)
181 {
182 	const struct ext_man_dbg_abi *dbg_abi =
183 		container_of(hdr, struct ext_man_dbg_abi, hdr);
184 
185 	if (sdev->first_boot)
186 		dev_dbg(sdev->dev,
187 			"Firmware: DBG_ABI %d:%d:%d\n",
188 			SOF_ABI_VERSION_MAJOR(dbg_abi->dbg_abi.abi_dbg_version),
189 			SOF_ABI_VERSION_MINOR(dbg_abi->dbg_abi.abi_dbg_version),
190 			SOF_ABI_VERSION_PATCH(dbg_abi->dbg_abi.abi_dbg_version));
191 
192 	return 0;
193 }
194 
195 static ssize_t snd_sof_ext_man_size(const struct firmware *fw)
196 {
197 	const struct sof_ext_man_header *head;
198 
199 	head = (struct sof_ext_man_header *)fw->data;
200 
201 	/*
202 	 * assert fw size is big enough to contain extended manifest header,
203 	 * it prevents from reading unallocated memory from `head` in following
204 	 * step.
205 	 */
206 	if (fw->size < sizeof(*head))
207 		return -EINVAL;
208 
209 	/*
210 	 * When fw points to extended manifest,
211 	 * then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER.
212 	 */
213 	if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
214 		return head->full_size;
215 
216 	/* otherwise given fw don't have an extended manifest */
217 	return 0;
218 }
219 
220 /* parse extended FW manifest data structures */
221 static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev,
222 				    const struct firmware *fw)
223 {
224 	const struct sof_ext_man_elem_header *elem_hdr;
225 	const struct sof_ext_man_header *head;
226 	ssize_t ext_man_size;
227 	ssize_t remaining;
228 	uintptr_t iptr;
229 	int ret = 0;
230 
231 	head = (struct sof_ext_man_header *)fw->data;
232 	remaining = head->full_size - head->header_size;
233 	ext_man_size = snd_sof_ext_man_size(fw);
234 
235 	/* Assert firmware starts with extended manifest */
236 	if (ext_man_size <= 0)
237 		return ext_man_size;
238 
239 	/* incompatible version */
240 	if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION,
241 					     head->header_version)) {
242 		dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n",
243 			head->header_version, SOF_EXT_MAN_VERSION);
244 		return -EINVAL;
245 	}
246 
247 	/* get first extended manifest element header */
248 	iptr = (uintptr_t)fw->data + head->header_size;
249 
250 	while (remaining > sizeof(*elem_hdr)) {
251 		elem_hdr = (struct sof_ext_man_elem_header *)iptr;
252 
253 		dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n",
254 			elem_hdr->type, elem_hdr->size);
255 
256 		if (elem_hdr->size < sizeof(*elem_hdr) ||
257 		    elem_hdr->size > remaining) {
258 			dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n",
259 				elem_hdr->type, elem_hdr->size);
260 			return -EINVAL;
261 		}
262 
263 		/* process structure data */
264 		switch (elem_hdr->type) {
265 		case SOF_EXT_MAN_ELEM_FW_VERSION:
266 			ret = ext_man_get_fw_version(sdev, elem_hdr);
267 			break;
268 		case SOF_EXT_MAN_ELEM_WINDOW:
269 			ret = ext_man_get_windows(sdev, elem_hdr);
270 			break;
271 		case SOF_EXT_MAN_ELEM_CC_VERSION:
272 			ret = ext_man_get_cc_info(sdev, elem_hdr);
273 			break;
274 		case SOF_EXT_MAN_ELEM_DBG_ABI:
275 			ret = ext_man_get_dbg_abi_info(sdev, elem_hdr);
276 			break;
277 		default:
278 			dev_warn(sdev->dev, "warning: unknown sof_ext_man header type %d size 0x%X\n",
279 				 elem_hdr->type, elem_hdr->size);
280 			break;
281 		}
282 
283 		if (ret < 0) {
284 			dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n",
285 				elem_hdr->type, elem_hdr->size);
286 			return ret;
287 		}
288 
289 		remaining -= elem_hdr->size;
290 		iptr += elem_hdr->size;
291 	}
292 
293 	if (remaining) {
294 		dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n");
295 		return -EINVAL;
296 	}
297 
298 	return ext_man_size;
299 }
300 
301 /*
302  * IPC Firmware ready.
303  */
304 static void sof_get_windows(struct snd_sof_dev *sdev)
305 {
306 	struct sof_ipc_window_elem *elem;
307 	u32 outbox_offset = 0;
308 	u32 stream_offset = 0;
309 	u32 inbox_offset = 0;
310 	u32 outbox_size = 0;
311 	u32 stream_size = 0;
312 	u32 inbox_size = 0;
313 	u32 debug_size = 0;
314 	u32 debug_offset = 0;
315 	int window_offset;
316 	int bar;
317 	int i;
318 
319 	if (!sdev->info_window) {
320 		dev_err(sdev->dev, "error: have no window info\n");
321 		return;
322 	}
323 
324 	bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
325 	if (bar < 0) {
326 		dev_err(sdev->dev, "error: have no bar mapping\n");
327 		return;
328 	}
329 
330 	for (i = 0; i < sdev->info_window->num_windows; i++) {
331 		elem = &sdev->info_window->window[i];
332 
333 		window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
334 		if (window_offset < 0) {
335 			dev_warn(sdev->dev, "warn: no offset for window %d\n",
336 				 elem->id);
337 			continue;
338 		}
339 
340 		switch (elem->type) {
341 		case SOF_IPC_REGION_UPBOX:
342 			inbox_offset = window_offset + elem->offset;
343 			inbox_size = elem->size;
344 			snd_sof_debugfs_io_item(sdev,
345 						sdev->bar[bar] +
346 						inbox_offset,
347 						elem->size, "inbox",
348 						SOF_DEBUGFS_ACCESS_D0_ONLY);
349 			break;
350 		case SOF_IPC_REGION_DOWNBOX:
351 			outbox_offset = window_offset + elem->offset;
352 			outbox_size = elem->size;
353 			snd_sof_debugfs_io_item(sdev,
354 						sdev->bar[bar] +
355 						outbox_offset,
356 						elem->size, "outbox",
357 						SOF_DEBUGFS_ACCESS_D0_ONLY);
358 			break;
359 		case SOF_IPC_REGION_TRACE:
360 			snd_sof_debugfs_io_item(sdev,
361 						sdev->bar[bar] +
362 						window_offset +
363 						elem->offset,
364 						elem->size, "etrace",
365 						SOF_DEBUGFS_ACCESS_D0_ONLY);
366 			break;
367 		case SOF_IPC_REGION_DEBUG:
368 			debug_offset = window_offset + elem->offset;
369 			debug_size = elem->size;
370 			snd_sof_debugfs_io_item(sdev,
371 						sdev->bar[bar] +
372 						window_offset +
373 						elem->offset,
374 						elem->size, "debug",
375 						SOF_DEBUGFS_ACCESS_D0_ONLY);
376 			break;
377 		case SOF_IPC_REGION_STREAM:
378 			stream_offset = window_offset + elem->offset;
379 			stream_size = elem->size;
380 			snd_sof_debugfs_io_item(sdev,
381 						sdev->bar[bar] +
382 						stream_offset,
383 						elem->size, "stream",
384 						SOF_DEBUGFS_ACCESS_D0_ONLY);
385 			break;
386 		case SOF_IPC_REGION_REGS:
387 			snd_sof_debugfs_io_item(sdev,
388 						sdev->bar[bar] +
389 						window_offset +
390 						elem->offset,
391 						elem->size, "regs",
392 						SOF_DEBUGFS_ACCESS_D0_ONLY);
393 			break;
394 		case SOF_IPC_REGION_EXCEPTION:
395 			sdev->dsp_oops_offset = window_offset + elem->offset;
396 			snd_sof_debugfs_io_item(sdev,
397 						sdev->bar[bar] +
398 						window_offset +
399 						elem->offset,
400 						elem->size, "exception",
401 						SOF_DEBUGFS_ACCESS_D0_ONLY);
402 			break;
403 		default:
404 			dev_err(sdev->dev, "error: get illegal window info\n");
405 			return;
406 		}
407 	}
408 
409 	if (outbox_size == 0 || inbox_size == 0) {
410 		dev_err(sdev->dev, "error: get illegal mailbox window\n");
411 		return;
412 	}
413 
414 	snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
415 				 outbox_offset, outbox_size);
416 	sdev->stream_box.offset = stream_offset;
417 	sdev->stream_box.size = stream_size;
418 
419 	sdev->debug_box.offset = debug_offset;
420 	sdev->debug_box.size = debug_size;
421 
422 	dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
423 		inbox_offset, inbox_size);
424 	dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
425 		outbox_offset, outbox_size);
426 	dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
427 		stream_offset, stream_size);
428 	dev_dbg(sdev->dev, " debug region 0x%x - size 0x%x\n",
429 		debug_offset, debug_size);
430 }
431 
432 /* check for ABI compatibility and create memory windows on first boot */
433 int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
434 {
435 	struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
436 	int offset;
437 	int bar;
438 	int ret;
439 
440 	/* mailbox must be on 4k boundary */
441 	offset = snd_sof_dsp_get_mailbox_offset(sdev);
442 	if (offset < 0) {
443 		dev_err(sdev->dev, "error: have no mailbox offset\n");
444 		return offset;
445 	}
446 
447 	bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
448 	if (bar < 0) {
449 		dev_err(sdev->dev, "error: have no bar mapping\n");
450 		return -EINVAL;
451 	}
452 
453 	dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
454 		msg_id, offset);
455 
456 	/* no need to re-check version/ABI for subsequent boots */
457 	if (!sdev->first_boot)
458 		return 0;
459 
460 	/* copy data from the DSP FW ready offset */
461 	sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
462 
463 	/* make sure ABI version is compatible */
464 	ret = snd_sof_ipc_valid(sdev);
465 	if (ret < 0)
466 		return ret;
467 
468 	/* now check for extended data */
469 	snd_sof_fw_parse_ext_data(sdev, bar, offset +
470 				  sizeof(struct sof_ipc_fw_ready));
471 
472 	sof_get_windows(sdev);
473 
474 	return 0;
475 }
476 EXPORT_SYMBOL(sof_fw_ready);
477 
478 /* generic module parser for mmaped DSPs */
479 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
480 				struct snd_sof_mod_hdr *module)
481 {
482 	struct snd_sof_blk_hdr *block;
483 	int count, bar;
484 	u32 offset;
485 	size_t remaining;
486 
487 	dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
488 		module->size, module->num_blocks, module->type);
489 
490 	block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
491 
492 	/* module->size doesn't include header size */
493 	remaining = module->size;
494 	for (count = 0; count < module->num_blocks; count++) {
495 		/* check for wrap */
496 		if (remaining < sizeof(*block)) {
497 			dev_err(sdev->dev, "error: not enough data remaining\n");
498 			return -EINVAL;
499 		}
500 
501 		/* minus header size of block */
502 		remaining -= sizeof(*block);
503 
504 		if (block->size == 0) {
505 			dev_warn(sdev->dev,
506 				 "warning: block %d size zero\n", count);
507 			dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
508 				 block->type, block->offset);
509 			continue;
510 		}
511 
512 		switch (block->type) {
513 		case SOF_FW_BLK_TYPE_RSRVD0:
514 		case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
515 			continue;	/* not handled atm */
516 		case SOF_FW_BLK_TYPE_IRAM:
517 		case SOF_FW_BLK_TYPE_DRAM:
518 		case SOF_FW_BLK_TYPE_SRAM:
519 			offset = block->offset;
520 			bar = snd_sof_dsp_get_bar_index(sdev, block->type);
521 			if (bar < 0) {
522 				dev_err(sdev->dev,
523 					"error: no BAR mapping for block type 0x%x\n",
524 					block->type);
525 				return bar;
526 			}
527 			break;
528 		default:
529 			dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
530 				block->type, count);
531 			return -EINVAL;
532 		}
533 
534 		dev_dbg(sdev->dev,
535 			"block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
536 			count, block->type, block->size, offset);
537 
538 		/* checking block->size to avoid unaligned access */
539 		if (block->size % sizeof(u32)) {
540 			dev_err(sdev->dev, "error: invalid block size 0x%x\n",
541 				block->size);
542 			return -EINVAL;
543 		}
544 		snd_sof_dsp_block_write(sdev, bar, offset,
545 					block + 1, block->size);
546 
547 		if (remaining < block->size) {
548 			dev_err(sdev->dev, "error: not enough data remaining\n");
549 			return -EINVAL;
550 		}
551 
552 		/* minus body size of block */
553 		remaining -= block->size;
554 		/* next block */
555 		block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
556 			+ block->size);
557 	}
558 
559 	return 0;
560 }
561 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
562 
563 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw,
564 			size_t fw_offset)
565 {
566 	struct snd_sof_fw_header *header;
567 	size_t fw_size = fw->size - fw_offset;
568 
569 	if (fw->size <= fw_offset) {
570 		dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n");
571 		return -EINVAL;
572 	}
573 
574 	/* Read the header information from the data pointer */
575 	header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
576 
577 	/* verify FW sig */
578 	if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
579 		dev_err(sdev->dev, "error: invalid firmware signature\n");
580 		return -EINVAL;
581 	}
582 
583 	/* check size is valid */
584 	if (fw_size != header->file_size + sizeof(*header)) {
585 		dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
586 			fw_size, header->file_size + sizeof(*header));
587 		return -EINVAL;
588 	}
589 
590 	dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
591 		header->file_size, header->num_modules,
592 		header->abi, sizeof(*header));
593 
594 	return 0;
595 }
596 
597 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw,
598 			size_t fw_offset)
599 {
600 	struct snd_sof_fw_header *header;
601 	struct snd_sof_mod_hdr *module;
602 	int (*load_module)(struct snd_sof_dev *sof_dev,
603 			   struct snd_sof_mod_hdr *hdr);
604 	int ret, count;
605 	size_t remaining;
606 
607 	header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
608 	load_module = sof_ops(sdev)->load_module;
609 	if (!load_module)
610 		return -EINVAL;
611 
612 	/* parse each module */
613 	module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
614 					    sizeof(*header));
615 	remaining = fw->size - sizeof(*header) - fw_offset;
616 	/* check for wrap */
617 	if (remaining > fw->size) {
618 		dev_err(sdev->dev, "error: fw size smaller than header size\n");
619 		return -EINVAL;
620 	}
621 
622 	for (count = 0; count < header->num_modules; count++) {
623 		/* check for wrap */
624 		if (remaining < sizeof(*module)) {
625 			dev_err(sdev->dev, "error: not enough data remaining\n");
626 			return -EINVAL;
627 		}
628 
629 		/* minus header size of module */
630 		remaining -= sizeof(*module);
631 
632 		/* module */
633 		ret = load_module(sdev, module);
634 		if (ret < 0) {
635 			dev_err(sdev->dev, "error: invalid module %d\n", count);
636 			return ret;
637 		}
638 
639 		if (remaining < module->size) {
640 			dev_err(sdev->dev, "error: not enough data remaining\n");
641 			return -EINVAL;
642 		}
643 
644 		/* minus body size of module */
645 		remaining -=  module->size;
646 		module = (struct snd_sof_mod_hdr *)((u8 *)module
647 			+ sizeof(*module) + module->size);
648 	}
649 
650 	return 0;
651 }
652 
653 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
654 {
655 	struct snd_sof_pdata *plat_data = sdev->pdata;
656 	const char *fw_filename;
657 	ssize_t ext_man_size;
658 	int ret;
659 
660 	/* Don't request firmware again if firmware is already requested */
661 	if (plat_data->fw)
662 		return 0;
663 
664 	fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
665 				plat_data->fw_filename_prefix,
666 				plat_data->fw_filename);
667 	if (!fw_filename)
668 		return -ENOMEM;
669 
670 	ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
671 
672 	if (ret < 0) {
673 		dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
674 			fw_filename, ret);
675 		goto err;
676 	} else {
677 		dev_dbg(sdev->dev, "request_firmware %s successful\n",
678 			fw_filename);
679 	}
680 
681 	/* check for extended manifest */
682 	ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
683 	if (ext_man_size > 0) {
684 		/* when no error occurred, drop extended manifest */
685 		plat_data->fw_offset = ext_man_size;
686 	} else if (!ext_man_size) {
687 		/* No extended manifest, so nothing to skip during FW load */
688 		dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n");
689 	} else {
690 		ret = ext_man_size;
691 		dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n",
692 			fw_filename, ret);
693 	}
694 
695 err:
696 	kfree(fw_filename);
697 
698 	return ret;
699 }
700 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
701 
702 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
703 {
704 	struct snd_sof_pdata *plat_data = sdev->pdata;
705 	int ret;
706 
707 	ret = snd_sof_load_firmware_raw(sdev);
708 	if (ret < 0)
709 		return ret;
710 
711 	/* make sure the FW header and file is valid */
712 	ret = check_header(sdev, plat_data->fw, plat_data->fw_offset);
713 	if (ret < 0) {
714 		dev_err(sdev->dev, "error: invalid FW header\n");
715 		goto error;
716 	}
717 
718 	/* prepare the DSP for FW loading */
719 	ret = snd_sof_dsp_reset(sdev);
720 	if (ret < 0) {
721 		dev_err(sdev->dev, "error: failed to reset DSP\n");
722 		goto error;
723 	}
724 
725 	/* parse and load firmware modules to DSP */
726 	ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset);
727 	if (ret < 0) {
728 		dev_err(sdev->dev, "error: invalid FW modules\n");
729 		goto error;
730 	}
731 
732 	return 0;
733 
734 error:
735 	release_firmware(plat_data->fw);
736 	plat_data->fw = NULL;
737 	return ret;
738 
739 }
740 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
741 
742 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
743 {
744 	dev_dbg(sdev->dev, "loading firmware\n");
745 
746 	if (sof_ops(sdev)->load_firmware)
747 		return sof_ops(sdev)->load_firmware(sdev);
748 	return 0;
749 }
750 EXPORT_SYMBOL(snd_sof_load_firmware);
751 
752 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
753 {
754 	int ret;
755 	int init_core_mask;
756 
757 	init_waitqueue_head(&sdev->boot_wait);
758 
759 	/* create read-only fw_version debugfs to store boot version info */
760 	if (sdev->first_boot) {
761 		ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
762 					       sizeof(sdev->fw_version),
763 					       "fw_version", 0444);
764 		/* errors are only due to memory allocation, not debugfs */
765 		if (ret < 0) {
766 			dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
767 			return ret;
768 		}
769 	}
770 
771 	/* perform pre fw run operations */
772 	ret = snd_sof_dsp_pre_fw_run(sdev);
773 	if (ret < 0) {
774 		dev_err(sdev->dev, "error: failed pre fw run op\n");
775 		return ret;
776 	}
777 
778 	dev_dbg(sdev->dev, "booting DSP firmware\n");
779 
780 	/* boot the firmware on the DSP */
781 	ret = snd_sof_dsp_run(sdev);
782 	if (ret < 0) {
783 		dev_err(sdev->dev, "error: failed to reset DSP\n");
784 		return ret;
785 	}
786 
787 	init_core_mask = ret;
788 
789 	/*
790 	 * now wait for the DSP to boot. There are 3 possible outcomes:
791 	 * 1. Boot wait times out indicating FW boot failure.
792 	 * 2. FW boots successfully and fw_ready op succeeds.
793 	 * 3. FW boots but fw_ready op fails.
794 	 */
795 	ret = wait_event_timeout(sdev->boot_wait,
796 				 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS,
797 				 msecs_to_jiffies(sdev->boot_timeout));
798 	if (ret == 0) {
799 		dev_err(sdev->dev, "error: firmware boot failure\n");
800 		snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
801 			SOF_DBG_TEXT | SOF_DBG_PCI);
802 		sdev->fw_state = SOF_FW_BOOT_FAILED;
803 		return -EIO;
804 	}
805 
806 	if (sdev->fw_state == SOF_FW_BOOT_COMPLETE)
807 		dev_dbg(sdev->dev, "firmware boot complete\n");
808 	else
809 		return -EIO; /* FW boots but fw_ready op failed */
810 
811 	/* perform post fw run operations */
812 	ret = snd_sof_dsp_post_fw_run(sdev);
813 	if (ret < 0) {
814 		dev_err(sdev->dev, "error: failed post fw run op\n");
815 		return ret;
816 	}
817 
818 	/* fw boot is complete. Update the active cores mask */
819 	sdev->enabled_cores_mask = init_core_mask;
820 
821 	return 0;
822 }
823 EXPORT_SYMBOL(snd_sof_run_firmware);
824 
825 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
826 {
827 	/* TODO: support module unloading at runtime */
828 }
829 EXPORT_SYMBOL(snd_sof_fw_unload);
830