1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/firmware.h>
14#include <sound/sof.h>
15#include <sound/sof/ext_manifest.h>
16#include "ops.h"
17
18static 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
37 sdev->info_window = kmemdup(w, w_size, GFP_KERNEL);
38 if (!sdev->info_window)
39 return -ENOMEM;
40
41 return 0;
42}
43
44static 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
65
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
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
89int 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
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
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
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
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}
144EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
145
146static 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
156 return snd_sof_ipc_valid(sdev);
157}
158
159static 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
169static 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
179static 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
187
188
189
190 if (fw->size < sizeof(*head))
191 return -EINVAL;
192
193
194
195
196
197 if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER)
198 return head->full_size;
199
200
201 return 0;
202}
203
204
205static 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
220 if (ext_man_size <= 0)
221 return ext_man_size;
222
223
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
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
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
284
285static 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
405int 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
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
429 if (!sdev->first_boot)
430 return 0;
431
432
433 sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
434
435
436 ret = snd_sof_ipc_valid(sdev);
437 if (ret < 0)
438 return ret;
439
440
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}
448EXPORT_SYMBOL(sof_fw_ready);
449
450
451int 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
465 remaining = module->size;
466 for (count = 0; count < module->num_blocks; count++) {
467
468 if (remaining < sizeof(*block)) {
469 dev_err(sdev->dev, "error: not enough data remaining\n");
470 return -EINVAL;
471 }
472
473
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;
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
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
525 remaining -= block->size;
526
527 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
528 + block->size);
529 }
530
531 return 0;
532}
533EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
534
535static 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
547 header = (struct snd_sof_fw_header *)(fw->data + fw_offset);
548
549
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
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
569static 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
585 module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset +
586 sizeof(*header));
587 remaining = fw->size - sizeof(*header) - fw_offset;
588
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
596 if (remaining < sizeof(*module)) {
597 dev_err(sdev->dev, "error: not enough data remaining\n");
598 return -EINVAL;
599 }
600
601
602 remaining -= sizeof(*module);
603
604
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
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
625int 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
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
654 ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw);
655 if (ext_man_size > 0) {
656
657 plat_data->fw_offset = ext_man_size;
658 } else if (!ext_man_size) {
659
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
667err:
668 kfree(fw_filename);
669
670 return ret;
671}
672EXPORT_SYMBOL(snd_sof_load_firmware_raw);
673
674int 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
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
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
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
706error:
707 release_firmware(plat_data->fw);
708 plat_data->fw = NULL;
709 return ret;
710
711}
712EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
713
714int 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}
722EXPORT_SYMBOL(snd_sof_load_firmware);
723
724int 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
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
737 if (ret < 0) {
738 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
739 return ret;
740 }
741 }
742
743
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
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
763
764
765
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;
782
783
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
791 sdev->enabled_cores_mask = init_core_mask;
792
793 return 0;
794}
795EXPORT_SYMBOL(snd_sof_run_firmware);
796
797void snd_sof_fw_unload(struct snd_sof_dev *sdev)
798{
799
800}
801EXPORT_SYMBOL(snd_sof_fw_unload);
802