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