diff options
author | Eran Harary <eran.harary@intel.com> | 2014-01-23 09:26:32 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-02-03 15:23:32 -0500 |
commit | 189fa2faac49bce07c6c6d83eca21cbe5bf47411 (patch) | |
tree | 359d94bf34ed99a36e201bc5f35190ec5ee9e1f5 /drivers/net/wireless/iwlwifi/pcie/trans.c | |
parent | e4a9f8cea50406a57c8dc5429d9aca6429d82436 (diff) |
iwlwifi: pcie: fix secure section / dual cpu firmware loading
Also handle the bypass mode in which the second CPU doesn't
interfere.
Signed-off-by: Eran Harary <eran.harary@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/trans.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 191 |
1 files changed, 103 insertions, 88 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index ff7d70da64f9..7290f422be65 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -441,78 +441,87 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, | |||
441 | return ret; | 441 | return ret; |
442 | } | 442 | } |
443 | 443 | ||
444 | static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu) | 444 | static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans, |
445 | const struct fw_img *image, | ||
446 | int cpu) | ||
445 | { | 447 | { |
446 | int shift_param; | 448 | int shift_param; |
447 | u32 address; | 449 | u32 first_idx, last_idx; |
448 | int ret = 0; | 450 | int i, ret = 0; |
449 | 451 | ||
450 | if (cpu == 1) { | 452 | if (cpu == 1) { |
451 | shift_param = 0; | 453 | shift_param = 0; |
452 | address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR; | 454 | first_idx = 0; |
455 | last_idx = 2; | ||
453 | } else { | 456 | } else { |
454 | shift_param = 16; | 457 | shift_param = 16; |
455 | address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR; | 458 | first_idx = 3; |
459 | last_idx = 5; | ||
456 | } | 460 | } |
457 | 461 | ||
458 | /* set CPU to started */ | 462 | for (i = first_idx; i <= last_idx; i++) { |
459 | iwl_trans_set_bits_mask(trans, | 463 | if (!image->sec[i].data) |
460 | CSR_UCODE_LOAD_STATUS_ADDR, | 464 | break; |
461 | CSR_CPU_STATUS_LOADING_STARTED << shift_param, | 465 | if (i == first_idx + 1) |
462 | 1); | 466 | /* set CPU to started */ |
463 | 467 | iwl_set_bits_prph(trans, | |
464 | /* set last complete descriptor number */ | 468 | CSR_UCODE_LOAD_STATUS_ADDR, |
465 | iwl_trans_set_bits_mask(trans, | 469 | LMPM_CPU_HDRS_LOADING_COMPLETED |
466 | CSR_UCODE_LOAD_STATUS_ADDR, | 470 | << shift_param); |
467 | CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED | ||
468 | << shift_param, | ||
469 | 1); | ||
470 | |||
471 | /* set last loaded block */ | ||
472 | iwl_trans_set_bits_mask(trans, | ||
473 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
474 | CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK | ||
475 | << shift_param, | ||
476 | 1); | ||
477 | 471 | ||
478 | /* image loading complete */ | 472 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); |
479 | iwl_trans_set_bits_mask(trans, | 473 | if (ret) |
480 | CSR_UCODE_LOAD_STATUS_ADDR, | 474 | return ret; |
481 | CSR_CPU_STATUS_LOADING_COMPLETED | ||
482 | << shift_param, | ||
483 | 1); | ||
484 | |||
485 | /* set FH_TCSR_0_REG */ | ||
486 | iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1); | ||
487 | |||
488 | /* verify image verification started */ | ||
489 | ret = iwl_poll_bit(trans, address, | ||
490 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, | ||
491 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS, | ||
492 | CSR_SECURE_TIME_OUT); | ||
493 | if (ret < 0) { | ||
494 | IWL_ERR(trans, "secure boot process didn't start\n"); | ||
495 | return ret; | ||
496 | } | 475 | } |
476 | /* image loading complete */ | ||
477 | iwl_set_bits_prph(trans, | ||
478 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
479 | LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param); | ||
497 | 480 | ||
498 | /* wait for image verification to complete */ | 481 | return 0; |
499 | ret = iwl_poll_bit(trans, address, | 482 | } |
500 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, | ||
501 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED, | ||
502 | CSR_SECURE_TIME_OUT); | ||
503 | 483 | ||
504 | if (ret < 0) { | 484 | static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, |
505 | IWL_ERR(trans, "Time out on secure boot process\n"); | 485 | const struct fw_img *image, |
506 | return ret; | 486 | int cpu) |
487 | { | ||
488 | int shift_param; | ||
489 | u32 first_idx, last_idx; | ||
490 | int i, ret = 0; | ||
491 | |||
492 | if (cpu == 1) { | ||
493 | shift_param = 0; | ||
494 | first_idx = 0; | ||
495 | last_idx = 1; | ||
496 | } else { | ||
497 | shift_param = 16; | ||
498 | first_idx = 2; | ||
499 | last_idx = 3; | ||
507 | } | 500 | } |
508 | 501 | ||
502 | for (i = first_idx; i <= last_idx; i++) { | ||
503 | if (!image->sec[i].data) | ||
504 | break; | ||
505 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | ||
506 | if (ret) | ||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) | ||
511 | iwl_set_bits_prph(trans, | ||
512 | CSR_UCODE_LOAD_STATUS_ADDR, | ||
513 | (LMPM_CPU_UCODE_LOADING_COMPLETED | | ||
514 | LMPM_CPU_HDRS_LOADING_COMPLETED | | ||
515 | LMPM_CPU_UCODE_LOADING_STARTED) << | ||
516 | shift_param); | ||
517 | |||
509 | return 0; | 518 | return 0; |
510 | } | 519 | } |
511 | 520 | ||
512 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | 521 | static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, |
513 | const struct fw_img *image) | 522 | const struct fw_img *image) |
514 | { | 523 | { |
515 | int i, ret = 0; | 524 | int ret = 0; |
516 | 525 | ||
517 | IWL_DEBUG_FW(trans, | 526 | IWL_DEBUG_FW(trans, |
518 | "working with %s image\n", | 527 | "working with %s image\n", |
@@ -524,54 +533,46 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
524 | /* configure the ucode to be ready to get the secured image */ | 533 | /* configure the ucode to be ready to get the secured image */ |
525 | if (image->is_secure) { | 534 | if (image->is_secure) { |
526 | /* set secure boot inspector addresses */ | 535 | /* set secure boot inspector addresses */ |
527 | iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0); | 536 | iwl_write_prph(trans, |
528 | iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0); | 537 | LMPM_SECURE_INSPECTOR_CODE_ADDR, |
538 | LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE); | ||
529 | 539 | ||
530 | /* release CPU1 reset if secure inspector image burned in OTP */ | 540 | iwl_write_prph(trans, |
531 | iwl_write32(trans, CSR_RESET, 0); | 541 | LMPM_SECURE_INSPECTOR_DATA_ADDR, |
532 | } | 542 | LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE); |
533 | 543 | ||
534 | /* load to FW the binary sections of CPU1 */ | 544 | /* set CPU1 header address */ |
535 | IWL_DEBUG_INFO(trans, "Loading CPU1\n"); | 545 | iwl_write_prph(trans, |
536 | for (i = 0; | 546 | LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR, |
537 | i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; | 547 | LMPM_SECURE_CPU1_HDR_MEM_SPACE); |
538 | i++) { | 548 | |
539 | if (!image->sec[i].data) | 549 | /* load to FW the binary Secured sections of CPU1 */ |
540 | break; | 550 | ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1); |
541 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | ||
542 | if (ret) | 551 | if (ret) |
543 | return ret; | 552 | return ret; |
544 | } | ||
545 | 553 | ||
546 | /* configure the ucode to start secure process on CPU1 */ | 554 | } else { |
547 | if (image->is_secure) { | 555 | /* load to FW the binary Non secured sections of CPU1 */ |
548 | /* config CPU1 to start secure protocol */ | 556 | ret = iwl_pcie_load_cpu_sections(trans, image, 1); |
549 | ret = iwl_pcie_secure_set(trans, 1); | ||
550 | if (ret) | 557 | if (ret) |
551 | return ret; | 558 | return ret; |
552 | } else { | ||
553 | /* Remove all resets to allow NIC to operate */ | ||
554 | iwl_write32(trans, CSR_RESET, 0); | ||
555 | } | 559 | } |
556 | 560 | ||
557 | if (image->is_dual_cpus) { | 561 | if (image->is_dual_cpus) { |
558 | /* load to FW the binary sections of CPU2 */ | 562 | /* set CPU2 header address */ |
559 | IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n"); | 563 | iwl_write_prph(trans, |
560 | for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU; | 564 | LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR, |
561 | i < IWL_UCODE_SECTION_MAX; i++) { | 565 | LMPM_SECURE_CPU2_HDR_MEM_SPACE); |
562 | if (!image->sec[i].data) | ||
563 | break; | ||
564 | ret = iwl_pcie_load_section(trans, i, &image->sec[i]); | ||
565 | if (ret) | ||
566 | return ret; | ||
567 | } | ||
568 | 566 | ||
569 | if (image->is_secure) { | 567 | /* load to FW the binary sections of CPU2 */ |
570 | /* set CPU2 for secure protocol */ | 568 | if (image->is_secure) |
571 | ret = iwl_pcie_secure_set(trans, 2); | 569 | ret = iwl_pcie_load_cpu_secured_sections(trans, |
572 | if (ret) | 570 | image, |
573 | return ret; | 571 | 2); |
574 | } | 572 | else |
573 | ret = iwl_pcie_load_cpu_sections(trans, image, 2); | ||
574 | if (ret) | ||
575 | return ret; | ||
575 | } | 576 | } |
576 | 577 | ||
577 | /* release CPU reset */ | 578 | /* release CPU reset */ |
@@ -580,6 +581,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, | |||
580 | else | 581 | else |
581 | iwl_write32(trans, CSR_RESET, 0); | 582 | iwl_write32(trans, CSR_RESET, 0); |
582 | 583 | ||
584 | if (image->is_secure) { | ||
585 | /* wait for image verification to complete */ | ||
586 | ret = iwl_poll_prph_bit(trans, | ||
587 | LMPM_SECURE_BOOT_CPU1_STATUS_ADDR, | ||
588 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
589 | LMPM_SECURE_BOOT_STATUS_SUCCESS, | ||
590 | LMPM_SECURE_TIME_OUT); | ||
591 | |||
592 | if (ret < 0) { | ||
593 | IWL_ERR(trans, "Time out on secure boot process\n"); | ||
594 | return ret; | ||
595 | } | ||
596 | } | ||
597 | |||
583 | return 0; | 598 | return 0; |
584 | } | 599 | } |
585 | 600 | ||