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