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 sof_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); 885