ASoC: SOF: loader: fix snd_sof_fw_parse_ext_data
[sfrench/cifs-2.6.git] / sound / soc / sof / loader.c
1 // SPDX-License-Identifier: (GPL-2.0 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 "ops.h"
16
17 static int get_ext_windows(struct snd_sof_dev *sdev,
18                            struct sof_ipc_ext_data_hdr *ext_hdr)
19 {
20         struct sof_ipc_window *w =
21                 container_of(ext_hdr, struct sof_ipc_window, ext_hdr);
22
23         if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS)
24                 return -EINVAL;
25
26         /* keep a local copy of the data */
27         sdev->info_window = kmemdup(w, struct_size(w, window, w->num_windows),
28                                     GFP_KERNEL);
29         if (!sdev->info_window)
30                 return -ENOMEM;
31
32         return 0;
33 }
34
35 /* parse the extended FW boot data structures from FW boot message */
36 int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset)
37 {
38         struct sof_ipc_ext_data_hdr *ext_hdr;
39         void *ext_data;
40         int ret = 0;
41
42         ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL);
43         if (!ext_data)
44                 return -ENOMEM;
45
46         /* get first header */
47         snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
48                                sizeof(*ext_hdr));
49         ext_hdr = ext_data;
50
51         while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) {
52                 /* read in ext structure */
53                 snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr),
54                                    (void *)((u8 *)ext_data + sizeof(*ext_hdr)),
55                                    ext_hdr->hdr.size - sizeof(*ext_hdr));
56
57                 dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n",
58                         ext_hdr->type, ext_hdr->hdr.size);
59
60                 /* process structure data */
61                 switch (ext_hdr->type) {
62                 case SOF_IPC_EXT_DMA_BUFFER:
63                         ret = 0;
64                         break;
65                 case SOF_IPC_EXT_WINDOW:
66                         ret = get_ext_windows(sdev, ext_hdr);
67                         break;
68                 default:
69                         dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n",
70                                  ext_hdr->type, ext_hdr->hdr.size);
71                         ret = 0;
72                         break;
73                 }
74
75                 if (ret < 0) {
76                         dev_err(sdev->dev, "error: failed to parse ext data type %d\n",
77                                 ext_hdr->type);
78                         break;
79                 }
80
81                 /* move to next header */
82                 offset += ext_hdr->hdr.size;
83                 snd_sof_dsp_block_read(sdev, bar, offset, ext_data,
84                                        sizeof(*ext_hdr));
85                 ext_hdr = ext_data;
86         }
87
88         kfree(ext_data);
89         return ret;
90 }
91 EXPORT_SYMBOL(snd_sof_fw_parse_ext_data);
92
93 /*
94  * IPC Firmware ready.
95  */
96 static void sof_get_windows(struct snd_sof_dev *sdev)
97 {
98         struct sof_ipc_window_elem *elem;
99         u32 outbox_offset = 0;
100         u32 stream_offset = 0;
101         u32 inbox_offset = 0;
102         u32 outbox_size = 0;
103         u32 stream_size = 0;
104         u32 inbox_size = 0;
105         int window_offset;
106         int bar;
107         int i;
108
109         if (!sdev->info_window) {
110                 dev_err(sdev->dev, "error: have no window info\n");
111                 return;
112         }
113
114         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
115         if (bar < 0) {
116                 dev_err(sdev->dev, "error: have no bar mapping\n");
117                 return;
118         }
119
120         for (i = 0; i < sdev->info_window->num_windows; i++) {
121                 elem = &sdev->info_window->window[i];
122
123                 window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id);
124                 if (window_offset < 0) {
125                         dev_warn(sdev->dev, "warn: no offset for window %d\n",
126                                  elem->id);
127                         continue;
128                 }
129
130                 switch (elem->type) {
131                 case SOF_IPC_REGION_UPBOX:
132                         inbox_offset = window_offset + elem->offset;
133                         inbox_size = elem->size;
134                         snd_sof_debugfs_io_item(sdev,
135                                                 sdev->bar[bar] +
136                                                 inbox_offset,
137                                                 elem->size, "inbox",
138                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
139                         break;
140                 case SOF_IPC_REGION_DOWNBOX:
141                         outbox_offset = window_offset + elem->offset;
142                         outbox_size = elem->size;
143                         snd_sof_debugfs_io_item(sdev,
144                                                 sdev->bar[bar] +
145                                                 outbox_offset,
146                                                 elem->size, "outbox",
147                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
148                         break;
149                 case SOF_IPC_REGION_TRACE:
150                         snd_sof_debugfs_io_item(sdev,
151                                                 sdev->bar[bar] +
152                                                 window_offset +
153                                                 elem->offset,
154                                                 elem->size, "etrace",
155                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
156                         break;
157                 case SOF_IPC_REGION_DEBUG:
158                         snd_sof_debugfs_io_item(sdev,
159                                                 sdev->bar[bar] +
160                                                 window_offset +
161                                                 elem->offset,
162                                                 elem->size, "debug",
163                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
164                         break;
165                 case SOF_IPC_REGION_STREAM:
166                         stream_offset = window_offset + elem->offset;
167                         stream_size = elem->size;
168                         snd_sof_debugfs_io_item(sdev,
169                                                 sdev->bar[bar] +
170                                                 stream_offset,
171                                                 elem->size, "stream",
172                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
173                         break;
174                 case SOF_IPC_REGION_REGS:
175                         snd_sof_debugfs_io_item(sdev,
176                                                 sdev->bar[bar] +
177                                                 window_offset +
178                                                 elem->offset,
179                                                 elem->size, "regs",
180                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
181                         break;
182                 case SOF_IPC_REGION_EXCEPTION:
183                         sdev->dsp_oops_offset = window_offset + elem->offset;
184                         snd_sof_debugfs_io_item(sdev,
185                                                 sdev->bar[bar] +
186                                                 window_offset +
187                                                 elem->offset,
188                                                 elem->size, "exception",
189                                                 SOF_DEBUGFS_ACCESS_D0_ONLY);
190                         break;
191                 default:
192                         dev_err(sdev->dev, "error: get illegal window info\n");
193                         return;
194                 }
195         }
196
197         if (outbox_size == 0 || inbox_size == 0) {
198                 dev_err(sdev->dev, "error: get illegal mailbox window\n");
199                 return;
200         }
201
202         snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size,
203                                  outbox_offset, outbox_size);
204         sdev->stream_box.offset = stream_offset;
205         sdev->stream_box.size = stream_size;
206
207         dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n",
208                 inbox_offset, inbox_size);
209         dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n",
210                 outbox_offset, outbox_size);
211         dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n",
212                 stream_offset, stream_size);
213 }
214
215 /* check for ABI compatibility and create memory windows on first boot */
216 int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
217 {
218         struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready;
219         int offset;
220         int bar;
221         int ret;
222
223         /* mailbox must be on 4k boundary */
224         offset = snd_sof_dsp_get_mailbox_offset(sdev);
225         if (offset < 0) {
226                 dev_err(sdev->dev, "error: have no mailbox offset\n");
227                 return offset;
228         }
229
230         bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM);
231         if (bar < 0) {
232                 dev_err(sdev->dev, "error: have no bar mapping\n");
233                 return -EINVAL;
234         }
235
236         dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n",
237                 msg_id, offset);
238
239         /* no need to re-check version/ABI for subsequent boots */
240         if (!sdev->first_boot)
241                 return 0;
242
243         /* copy data from the DSP FW ready offset */
244         sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready));
245
246         /* make sure ABI version is compatible */
247         ret = snd_sof_ipc_valid(sdev);
248         if (ret < 0)
249                 return ret;
250
251         /* now check for extended data */
252         snd_sof_fw_parse_ext_data(sdev, bar, offset +
253                                   sizeof(struct sof_ipc_fw_ready));
254
255         sof_get_windows(sdev);
256
257         return 0;
258 }
259 EXPORT_SYMBOL(sof_fw_ready);
260
261 /* generic module parser for mmaped DSPs */
262 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev,
263                                 struct snd_sof_mod_hdr *module)
264 {
265         struct snd_sof_blk_hdr *block;
266         int count, bar;
267         u32 offset;
268         size_t remaining;
269
270         dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n",
271                 module->size, module->num_blocks, module->type);
272
273         block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module));
274
275         /* module->size doesn't include header size */
276         remaining = module->size;
277         for (count = 0; count < module->num_blocks; count++) {
278                 /* check for wrap */
279                 if (remaining < sizeof(*block)) {
280                         dev_err(sdev->dev, "error: not enough data remaining\n");
281                         return -EINVAL;
282                 }
283
284                 /* minus header size of block */
285                 remaining -= sizeof(*block);
286
287                 if (block->size == 0) {
288                         dev_warn(sdev->dev,
289                                  "warning: block %d size zero\n", count);
290                         dev_warn(sdev->dev, " type 0x%x offset 0x%x\n",
291                                  block->type, block->offset);
292                         continue;
293                 }
294
295                 switch (block->type) {
296                 case SOF_FW_BLK_TYPE_RSRVD0:
297                 case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14:
298                         continue;       /* not handled atm */
299                 case SOF_FW_BLK_TYPE_IRAM:
300                 case SOF_FW_BLK_TYPE_DRAM:
301                 case SOF_FW_BLK_TYPE_SRAM:
302                         offset = block->offset;
303                         bar = snd_sof_dsp_get_bar_index(sdev, block->type);
304                         if (bar < 0) {
305                                 dev_err(sdev->dev,
306                                         "error: no BAR mapping for block type 0x%x\n",
307                                         block->type);
308                                 return bar;
309                         }
310                         break;
311                 default:
312                         dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n",
313                                 block->type, count);
314                         return -EINVAL;
315                 }
316
317                 dev_dbg(sdev->dev,
318                         "block %d type 0x%x size 0x%x ==>  offset 0x%x\n",
319                         count, block->type, block->size, offset);
320
321                 /* checking block->size to avoid unaligned access */
322                 if (block->size % sizeof(u32)) {
323                         dev_err(sdev->dev, "error: invalid block size 0x%x\n",
324                                 block->size);
325                         return -EINVAL;
326                 }
327                 snd_sof_dsp_block_write(sdev, bar, offset,
328                                         block + 1, block->size);
329
330                 if (remaining < block->size) {
331                         dev_err(sdev->dev, "error: not enough data remaining\n");
332                         return -EINVAL;
333                 }
334
335                 /* minus body size of block */
336                 remaining -= block->size;
337                 /* next block */
338                 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block)
339                         + block->size);
340         }
341
342         return 0;
343 }
344 EXPORT_SYMBOL(snd_sof_parse_module_memcpy);
345
346 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw)
347 {
348         struct snd_sof_fw_header *header;
349
350         /* Read the header information from the data pointer */
351         header = (struct snd_sof_fw_header *)fw->data;
352
353         /* verify FW sig */
354         if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) {
355                 dev_err(sdev->dev, "error: invalid firmware signature\n");
356                 return -EINVAL;
357         }
358
359         /* check size is valid */
360         if (fw->size != header->file_size + sizeof(*header)) {
361                 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n",
362                         fw->size, header->file_size + sizeof(*header));
363                 return -EINVAL;
364         }
365
366         dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n",
367                 header->file_size, header->num_modules,
368                 header->abi, sizeof(*header));
369
370         return 0;
371 }
372
373 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw)
374 {
375         struct snd_sof_fw_header *header;
376         struct snd_sof_mod_hdr *module;
377         int (*load_module)(struct snd_sof_dev *sof_dev,
378                            struct snd_sof_mod_hdr *hdr);
379         int ret, count;
380         size_t remaining;
381
382         header = (struct snd_sof_fw_header *)fw->data;
383         load_module = sof_ops(sdev)->load_module;
384         if (!load_module)
385                 return -EINVAL;
386
387         /* parse each module */
388         module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header));
389         remaining = fw->size - sizeof(*header);
390         /* check for wrap */
391         if (remaining > fw->size) {
392                 dev_err(sdev->dev, "error: fw size smaller than header size\n");
393                 return -EINVAL;
394         }
395
396         for (count = 0; count < header->num_modules; count++) {
397                 /* check for wrap */
398                 if (remaining < sizeof(*module)) {
399                         dev_err(sdev->dev, "error: not enough data remaining\n");
400                         return -EINVAL;
401                 }
402
403                 /* minus header size of module */
404                 remaining -= sizeof(*module);
405
406                 /* module */
407                 ret = load_module(sdev, module);
408                 if (ret < 0) {
409                         dev_err(sdev->dev, "error: invalid module %d\n", count);
410                         return ret;
411                 }
412
413                 if (remaining < module->size) {
414                         dev_err(sdev->dev, "error: not enough data remaining\n");
415                         return -EINVAL;
416                 }
417
418                 /* minus body size of module */
419                 remaining -=  module->size;
420                 module = (struct snd_sof_mod_hdr *)((u8 *)module
421                         + sizeof(*module) + module->size);
422         }
423
424         return 0;
425 }
426
427 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev)
428 {
429         struct snd_sof_pdata *plat_data = sdev->pdata;
430         const char *fw_filename;
431         int ret;
432
433         /* set code loading condition to true */
434         sdev->code_loading = 1;
435
436         /* Don't request firmware again if firmware is already requested */
437         if (plat_data->fw)
438                 return 0;
439
440         fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
441                                 plat_data->fw_filename_prefix,
442                                 plat_data->fw_filename);
443         if (!fw_filename)
444                 return -ENOMEM;
445
446         ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev);
447
448         if (ret < 0) {
449                 dev_err(sdev->dev, "error: request firmware %s failed err: %d\n",
450                         fw_filename, ret);
451         }
452
453         kfree(fw_filename);
454
455         return ret;
456 }
457 EXPORT_SYMBOL(snd_sof_load_firmware_raw);
458
459 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev)
460 {
461         struct snd_sof_pdata *plat_data = sdev->pdata;
462         int ret;
463
464         ret = snd_sof_load_firmware_raw(sdev);
465         if (ret < 0)
466                 return ret;
467
468         /* make sure the FW header and file is valid */
469         ret = check_header(sdev, plat_data->fw);
470         if (ret < 0) {
471                 dev_err(sdev->dev, "error: invalid FW header\n");
472                 goto error;
473         }
474
475         /* prepare the DSP for FW loading */
476         ret = snd_sof_dsp_reset(sdev);
477         if (ret < 0) {
478                 dev_err(sdev->dev, "error: failed to reset DSP\n");
479                 goto error;
480         }
481
482         /* parse and load firmware modules to DSP */
483         ret = load_modules(sdev, plat_data->fw);
484         if (ret < 0) {
485                 dev_err(sdev->dev, "error: invalid FW modules\n");
486                 goto error;
487         }
488
489         return 0;
490
491 error:
492         release_firmware(plat_data->fw);
493         plat_data->fw = NULL;
494         return ret;
495
496 }
497 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy);
498
499 int snd_sof_load_firmware(struct snd_sof_dev *sdev)
500 {
501         dev_dbg(sdev->dev, "loading firmware\n");
502
503         if (sof_ops(sdev)->load_firmware)
504                 return sof_ops(sdev)->load_firmware(sdev);
505         return 0;
506 }
507 EXPORT_SYMBOL(snd_sof_load_firmware);
508
509 int snd_sof_run_firmware(struct snd_sof_dev *sdev)
510 {
511         int ret;
512         int init_core_mask;
513
514         init_waitqueue_head(&sdev->boot_wait);
515         sdev->boot_complete = false;
516
517         /* create read-only fw_version debugfs to store boot version info */
518         if (sdev->first_boot) {
519                 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version,
520                                                sizeof(sdev->fw_version),
521                                                "fw_version", 0444);
522                 /* errors are only due to memory allocation, not debugfs */
523                 if (ret < 0) {
524                         dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n");
525                         return ret;
526                 }
527         }
528
529         /* perform pre fw run operations */
530         ret = snd_sof_dsp_pre_fw_run(sdev);
531         if (ret < 0) {
532                 dev_err(sdev->dev, "error: failed pre fw run op\n");
533                 return ret;
534         }
535
536         dev_dbg(sdev->dev, "booting DSP firmware\n");
537
538         /* boot the firmware on the DSP */
539         ret = snd_sof_dsp_run(sdev);
540         if (ret < 0) {
541                 dev_err(sdev->dev, "error: failed to reset DSP\n");
542                 return ret;
543         }
544
545         init_core_mask = ret;
546
547         /* now wait for the DSP to boot */
548         ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete,
549                                  msecs_to_jiffies(sdev->boot_timeout));
550         if (ret == 0) {
551                 dev_err(sdev->dev, "error: firmware boot failure\n");
552                 snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX |
553                         SOF_DBG_TEXT | SOF_DBG_PCI);
554                 /* after this point FW_READY msg should be ignored */
555                 sdev->boot_complete = true;
556                 return -EIO;
557         }
558
559         dev_info(sdev->dev, "firmware boot complete\n");
560
561         /* perform post fw run operations */
562         ret = snd_sof_dsp_post_fw_run(sdev);
563         if (ret < 0) {
564                 dev_err(sdev->dev, "error: failed post fw run op\n");
565                 return ret;
566         }
567
568         /* fw boot is complete. Update the active cores mask */
569         sdev->enabled_cores_mask = init_core_mask;
570
571         return 0;
572 }
573 EXPORT_SYMBOL(snd_sof_run_firmware);
574
575 void snd_sof_fw_unload(struct snd_sof_dev *sdev)
576 {
577         /* TODO: support module unloading at runtime */
578 }
579 EXPORT_SYMBOL(snd_sof_fw_unload);