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