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