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 static int ext_man_get_fw_version(struct snd_sof_dev *sdev, 90 const struct sof_ext_man_elem_header *hdr) 91 { 92 const struct sof_ext_man_fw_version *v = 93 container_of(hdr, struct sof_ext_man_fw_version, hdr); 94 95 memcpy(&sdev->fw_ready.version, &v->version, sizeof(v->version)); 96 sdev->fw_ready.flags = v->flags; 97 98 /* log ABI versions and check FW compatibility */ 99 return snd_sof_ipc_valid(sdev); 100 } 101 102 static int ext_man_get_windows(struct snd_sof_dev *sdev, 103 const struct sof_ext_man_elem_header *hdr) 104 { 105 const struct sof_ext_man_window *w; 106 107 w = container_of(hdr, struct sof_ext_man_window, hdr); 108 109 return get_ext_windows(sdev, &w->ipc_window.ext_hdr); 110 } 111 112 static int ext_man_get_cc_info(struct snd_sof_dev *sdev, 113 const struct sof_ext_man_elem_header *hdr) 114 { 115 const struct sof_ext_man_cc_version *cc; 116 117 cc = container_of(hdr, struct sof_ext_man_cc_version, hdr); 118 119 return get_cc_info(sdev, &cc->cc_version.ext_hdr); 120 } 121 122 static int ext_man_get_dbg_abi_info(struct snd_sof_dev *sdev, 123 const struct sof_ext_man_elem_header *hdr) 124 { 125 const struct ext_man_dbg_abi *dbg_abi = 126 container_of(hdr, struct ext_man_dbg_abi, hdr); 127 128 if (sdev->first_boot) 129 dev_dbg(sdev->dev, 130 "Firmware: DBG_ABI %d:%d:%d\n", 131 SOF_ABI_VERSION_MAJOR(dbg_abi->dbg_abi.abi_dbg_version), 132 SOF_ABI_VERSION_MINOR(dbg_abi->dbg_abi.abi_dbg_version), 133 SOF_ABI_VERSION_PATCH(dbg_abi->dbg_abi.abi_dbg_version)); 134 135 return 0; 136 } 137 138 static int ext_man_get_config_data(struct snd_sof_dev *sdev, 139 const struct sof_ext_man_elem_header *hdr) 140 { 141 const struct sof_ext_man_config_data *config = 142 container_of(hdr, struct sof_ext_man_config_data, hdr); 143 const struct sof_config_elem *elem; 144 int elems_counter; 145 int elems_size; 146 int ret = 0; 147 int i; 148 149 /* calculate elements counter */ 150 elems_size = config->hdr.size - sizeof(struct sof_ext_man_elem_header); 151 elems_counter = elems_size / sizeof(struct sof_config_elem); 152 153 dev_dbg(sdev->dev, "%s can hold up to %d config elements\n", 154 __func__, elems_counter); 155 156 for (i = 0; i < elems_counter; ++i) { 157 elem = &config->elems[i]; 158 dev_dbg(sdev->dev, "%s get index %d token %d val %d\n", 159 __func__, i, elem->token, elem->value); 160 switch (elem->token) { 161 case SOF_EXT_MAN_CONFIG_EMPTY: 162 /* unused memory space is zero filled - mapped to EMPTY elements */ 163 break; 164 case SOF_EXT_MAN_CONFIG_IPC_MSG_SIZE: 165 /* TODO: use ipc msg size from config data */ 166 break; 167 case SOF_EXT_MAN_CONFIG_MEMORY_USAGE_SCAN: 168 if (sdev->first_boot && elem->value) 169 ret = snd_sof_dbg_memory_info_init(sdev); 170 break; 171 default: 172 dev_info(sdev->dev, "Unknown firmware configuration token %d value %d", 173 elem->token, elem->value); 174 break; 175 } 176 if (ret < 0) { 177 dev_err(sdev->dev, "error: processing sof_ext_man_config_data failed for token %d value 0x%x, %d\n", 178 elem->token, elem->value, ret); 179 return ret; 180 } 181 } 182 183 return 0; 184 } 185 186 static ssize_t snd_sof_ext_man_size(const struct firmware *fw) 187 { 188 const struct sof_ext_man_header *head; 189 190 head = (struct sof_ext_man_header *)fw->data; 191 192 /* 193 * assert fw size is big enough to contain extended manifest header, 194 * it prevents from reading unallocated memory from `head` in following 195 * step. 196 */ 197 if (fw->size < sizeof(*head)) 198 return -EINVAL; 199 200 /* 201 * When fw points to extended manifest, 202 * then first u32 must be equal SOF_EXT_MAN_MAGIC_NUMBER. 203 */ 204 if (head->magic == SOF_EXT_MAN_MAGIC_NUMBER) 205 return head->full_size; 206 207 /* otherwise given fw don't have an extended manifest */ 208 return 0; 209 } 210 211 /* parse extended FW manifest data structures */ 212 static int snd_sof_fw_ext_man_parse(struct snd_sof_dev *sdev, 213 const struct firmware *fw) 214 { 215 const struct sof_ext_man_elem_header *elem_hdr; 216 const struct sof_ext_man_header *head; 217 ssize_t ext_man_size; 218 ssize_t remaining; 219 uintptr_t iptr; 220 int ret = 0; 221 222 head = (struct sof_ext_man_header *)fw->data; 223 remaining = head->full_size - head->header_size; 224 ext_man_size = snd_sof_ext_man_size(fw); 225 226 /* Assert firmware starts with extended manifest */ 227 if (ext_man_size <= 0) 228 return ext_man_size; 229 230 /* incompatible version */ 231 if (SOF_EXT_MAN_VERSION_INCOMPATIBLE(SOF_EXT_MAN_VERSION, 232 head->header_version)) { 233 dev_err(sdev->dev, "error: extended manifest version 0x%X differ from used 0x%X\n", 234 head->header_version, SOF_EXT_MAN_VERSION); 235 return -EINVAL; 236 } 237 238 /* get first extended manifest element header */ 239 iptr = (uintptr_t)fw->data + head->header_size; 240 241 while (remaining > sizeof(*elem_hdr)) { 242 elem_hdr = (struct sof_ext_man_elem_header *)iptr; 243 244 dev_dbg(sdev->dev, "found sof_ext_man header type %d size 0x%X\n", 245 elem_hdr->type, elem_hdr->size); 246 247 if (elem_hdr->size < sizeof(*elem_hdr) || 248 elem_hdr->size > remaining) { 249 dev_err(sdev->dev, "error: invalid sof_ext_man header size, type %d size 0x%X\n", 250 elem_hdr->type, elem_hdr->size); 251 return -EINVAL; 252 } 253 254 /* process structure data */ 255 switch (elem_hdr->type) { 256 case SOF_EXT_MAN_ELEM_FW_VERSION: 257 ret = ext_man_get_fw_version(sdev, elem_hdr); 258 break; 259 case SOF_EXT_MAN_ELEM_WINDOW: 260 ret = ext_man_get_windows(sdev, elem_hdr); 261 break; 262 case SOF_EXT_MAN_ELEM_CC_VERSION: 263 ret = ext_man_get_cc_info(sdev, elem_hdr); 264 break; 265 case SOF_EXT_MAN_ELEM_DBG_ABI: 266 ret = ext_man_get_dbg_abi_info(sdev, elem_hdr); 267 break; 268 case SOF_EXT_MAN_ELEM_CONFIG_DATA: 269 ret = ext_man_get_config_data(sdev, elem_hdr); 270 break; 271 case SOF_EXT_MAN_ELEM_PLATFORM_CONFIG_DATA: 272 ret = snd_sof_dsp_parse_platform_ext_manifest(sdev, elem_hdr); 273 break; 274 default: 275 dev_info(sdev->dev, "unknown sof_ext_man header type %d size 0x%X\n", 276 elem_hdr->type, elem_hdr->size); 277 break; 278 } 279 280 if (ret < 0) { 281 dev_err(sdev->dev, "error: failed to parse sof_ext_man header type %d size 0x%X\n", 282 elem_hdr->type, elem_hdr->size); 283 return ret; 284 } 285 286 remaining -= elem_hdr->size; 287 iptr += elem_hdr->size; 288 } 289 290 if (remaining) { 291 dev_err(sdev->dev, "error: sof_ext_man header is inconsistent\n"); 292 return -EINVAL; 293 } 294 295 return ext_man_size; 296 } 297 298 /* generic module parser for mmaped DSPs */ 299 int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, 300 struct snd_sof_mod_hdr *module) 301 { 302 struct snd_sof_blk_hdr *block; 303 int count, ret; 304 u32 offset; 305 size_t remaining; 306 307 dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", 308 module->size, module->num_blocks, module->type); 309 310 block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module)); 311 312 /* module->size doesn't include header size */ 313 remaining = module->size; 314 for (count = 0; count < module->num_blocks; count++) { 315 /* check for wrap */ 316 if (remaining < sizeof(*block)) { 317 dev_err(sdev->dev, "error: not enough data remaining\n"); 318 return -EINVAL; 319 } 320 321 /* minus header size of block */ 322 remaining -= sizeof(*block); 323 324 if (block->size == 0) { 325 dev_warn(sdev->dev, 326 "warning: block %d size zero\n", count); 327 dev_warn(sdev->dev, " type 0x%x offset 0x%x\n", 328 block->type, block->offset); 329 continue; 330 } 331 332 switch (block->type) { 333 case SOF_FW_BLK_TYPE_RSRVD0: 334 case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14: 335 continue; /* not handled atm */ 336 case SOF_FW_BLK_TYPE_IRAM: 337 case SOF_FW_BLK_TYPE_DRAM: 338 case SOF_FW_BLK_TYPE_SRAM: 339 offset = block->offset; 340 break; 341 default: 342 dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", 343 block->type, count); 344 return -EINVAL; 345 } 346 347 dev_dbg(sdev->dev, 348 "block %d type 0x%x size 0x%x ==> offset 0x%x\n", 349 count, block->type, block->size, offset); 350 351 /* checking block->size to avoid unaligned access */ 352 if (block->size % sizeof(u32)) { 353 dev_err(sdev->dev, "error: invalid block size 0x%x\n", 354 block->size); 355 return -EINVAL; 356 } 357 ret = snd_sof_dsp_block_write(sdev, block->type, offset, 358 block + 1, block->size); 359 if (ret < 0) { 360 dev_err(sdev->dev, "error: write to block type 0x%x failed\n", 361 block->type); 362 return ret; 363 } 364 365 if (remaining < block->size) { 366 dev_err(sdev->dev, "error: not enough data remaining\n"); 367 return -EINVAL; 368 } 369 370 /* minus body size of block */ 371 remaining -= block->size; 372 /* next block */ 373 block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block) 374 + block->size); 375 } 376 377 return 0; 378 } 379 EXPORT_SYMBOL(snd_sof_parse_module_memcpy); 380 381 static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw, 382 size_t fw_offset) 383 { 384 struct snd_sof_fw_header *header; 385 size_t fw_size = fw->size - fw_offset; 386 387 if (fw->size <= fw_offset) { 388 dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 389 return -EINVAL; 390 } 391 392 /* Read the header information from the data pointer */ 393 header = (struct snd_sof_fw_header *)(fw->data + fw_offset); 394 395 /* verify FW sig */ 396 if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) { 397 dev_err(sdev->dev, "error: invalid firmware signature\n"); 398 return -EINVAL; 399 } 400 401 /* check size is valid */ 402 if (fw_size != header->file_size + sizeof(*header)) { 403 dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n", 404 fw_size, header->file_size + sizeof(*header)); 405 return -EINVAL; 406 } 407 408 dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n", 409 header->file_size, header->num_modules, 410 header->abi, sizeof(*header)); 411 412 return 0; 413 } 414 415 static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw, 416 size_t fw_offset) 417 { 418 struct snd_sof_fw_header *header; 419 struct snd_sof_mod_hdr *module; 420 int (*load_module)(struct snd_sof_dev *sof_dev, 421 struct snd_sof_mod_hdr *hdr); 422 int ret, count; 423 size_t remaining; 424 425 header = (struct snd_sof_fw_header *)(fw->data + fw_offset); 426 load_module = sof_ops(sdev)->load_module; 427 if (!load_module) 428 return -EINVAL; 429 430 /* parse each module */ 431 module = (struct snd_sof_mod_hdr *)(fw->data + fw_offset + 432 sizeof(*header)); 433 remaining = fw->size - sizeof(*header) - fw_offset; 434 /* check for wrap */ 435 if (remaining > fw->size) { 436 dev_err(sdev->dev, "error: fw size smaller than header size\n"); 437 return -EINVAL; 438 } 439 440 for (count = 0; count < header->num_modules; count++) { 441 /* check for wrap */ 442 if (remaining < sizeof(*module)) { 443 dev_err(sdev->dev, "error: not enough data remaining\n"); 444 return -EINVAL; 445 } 446 447 /* minus header size of module */ 448 remaining -= sizeof(*module); 449 450 /* module */ 451 ret = load_module(sdev, module); 452 if (ret < 0) { 453 dev_err(sdev->dev, "error: invalid module %d\n", count); 454 return ret; 455 } 456 457 if (remaining < module->size) { 458 dev_err(sdev->dev, "error: not enough data remaining\n"); 459 return -EINVAL; 460 } 461 462 /* minus body size of module */ 463 remaining -= module->size; 464 module = (struct snd_sof_mod_hdr *)((u8 *)module 465 + sizeof(*module) + module->size); 466 } 467 468 return 0; 469 } 470 471 int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) 472 { 473 struct snd_sof_pdata *plat_data = sdev->pdata; 474 const char *fw_filename; 475 ssize_t ext_man_size; 476 int ret; 477 478 /* Don't request firmware again if firmware is already requested */ 479 if (plat_data->fw) 480 return 0; 481 482 fw_filename = kasprintf(GFP_KERNEL, "%s/%s", 483 plat_data->fw_filename_prefix, 484 plat_data->fw_filename); 485 if (!fw_filename) 486 return -ENOMEM; 487 488 ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); 489 490 if (ret < 0) { 491 dev_err(sdev->dev, 492 "error: sof firmware file is missing, you might need to\n"); 493 dev_err(sdev->dev, 494 " download it from https://github.com/thesofproject/sof-bin/\n"); 495 goto err; 496 } else { 497 dev_dbg(sdev->dev, "request_firmware %s successful\n", 498 fw_filename); 499 } 500 501 /* check for extended manifest */ 502 ext_man_size = snd_sof_fw_ext_man_parse(sdev, plat_data->fw); 503 if (ext_man_size > 0) { 504 /* when no error occurred, drop extended manifest */ 505 plat_data->fw_offset = ext_man_size; 506 } else if (!ext_man_size) { 507 /* No extended manifest, so nothing to skip during FW load */ 508 dev_dbg(sdev->dev, "firmware doesn't contain extended manifest\n"); 509 } else { 510 ret = ext_man_size; 511 dev_err(sdev->dev, "error: firmware %s contains unsupported or invalid extended manifest: %d\n", 512 fw_filename, ret); 513 } 514 515 err: 516 kfree(fw_filename); 517 518 return ret; 519 } 520 EXPORT_SYMBOL(snd_sof_load_firmware_raw); 521 522 int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) 523 { 524 struct snd_sof_pdata *plat_data = sdev->pdata; 525 int ret; 526 527 ret = snd_sof_load_firmware_raw(sdev); 528 if (ret < 0) 529 return ret; 530 531 /* make sure the FW header and file is valid */ 532 ret = check_header(sdev, plat_data->fw, plat_data->fw_offset); 533 if (ret < 0) { 534 dev_err(sdev->dev, "error: invalid FW header\n"); 535 goto error; 536 } 537 538 /* prepare the DSP for FW loading */ 539 ret = snd_sof_dsp_reset(sdev); 540 if (ret < 0) { 541 dev_err(sdev->dev, "error: failed to reset DSP\n"); 542 goto error; 543 } 544 545 /* parse and load firmware modules to DSP */ 546 ret = load_modules(sdev, plat_data->fw, plat_data->fw_offset); 547 if (ret < 0) { 548 dev_err(sdev->dev, "error: invalid FW modules\n"); 549 goto error; 550 } 551 552 return 0; 553 554 error: 555 release_firmware(plat_data->fw); 556 plat_data->fw = NULL; 557 return ret; 558 559 } 560 EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); 561 562 int snd_sof_run_firmware(struct snd_sof_dev *sdev) 563 { 564 int ret; 565 566 init_waitqueue_head(&sdev->boot_wait); 567 568 /* (re-)enable dsp dump */ 569 sdev->dbg_dump_printed = false; 570 sdev->ipc_dump_printed = false; 571 572 /* create read-only fw_version debugfs to store boot version info */ 573 if (sdev->first_boot) { 574 ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version, 575 sizeof(sdev->fw_version), 576 "fw_version", 0444); 577 /* errors are only due to memory allocation, not debugfs */ 578 if (ret < 0) { 579 dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); 580 return ret; 581 } 582 } 583 584 /* perform pre fw run operations */ 585 ret = snd_sof_dsp_pre_fw_run(sdev); 586 if (ret < 0) { 587 dev_err(sdev->dev, "error: failed pre fw run op\n"); 588 return ret; 589 } 590 591 dev_dbg(sdev->dev, "booting DSP firmware\n"); 592 593 /* boot the firmware on the DSP */ 594 ret = snd_sof_dsp_run(sdev); 595 if (ret < 0) { 596 snd_sof_dsp_dbg_dump(sdev, "Failed to start DSP", 597 SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_PCI); 598 return ret; 599 } 600 601 /* 602 * now wait for the DSP to boot. There are 3 possible outcomes: 603 * 1. Boot wait times out indicating FW boot failure. 604 * 2. FW boots successfully and fw_ready op succeeds. 605 * 3. FW boots but fw_ready op fails. 606 */ 607 ret = wait_event_timeout(sdev->boot_wait, 608 sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS, 609 msecs_to_jiffies(sdev->boot_timeout)); 610 if (ret == 0) { 611 snd_sof_dsp_dbg_dump(sdev, "Firmware boot failure due to timeout", 612 SOF_DBG_DUMP_REGS | SOF_DBG_DUMP_MBOX | 613 SOF_DBG_DUMP_TEXT | SOF_DBG_DUMP_PCI); 614 return -EIO; 615 } 616 617 if (sdev->fw_state == SOF_FW_BOOT_READY_FAILED) 618 return -EIO; /* FW boots but fw_ready op failed */ 619 620 /* perform post fw run operations */ 621 ret = snd_sof_dsp_post_fw_run(sdev); 622 if (ret < 0) { 623 dev_err(sdev->dev, "error: failed post fw run op\n"); 624 return ret; 625 } 626 627 dev_dbg(sdev->dev, "firmware boot complete\n"); 628 sof_set_fw_state(sdev, SOF_FW_BOOT_COMPLETE); 629 630 return 0; 631 } 632 EXPORT_SYMBOL(snd_sof_run_firmware); 633 634 void snd_sof_fw_unload(struct snd_sof_dev *sdev) 635 { 636 /* TODO: support module unloading at runtime */ 637 release_firmware(sdev->pdata->fw); 638 sdev->pdata->fw = NULL; 639 } 640 EXPORT_SYMBOL(snd_sof_fw_unload); 641