aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEran Harary <eran.harary@intel.com>2013-10-02 06:53:40 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-11 09:05:02 -0400
commite2d6f4e71dc76c815434234cb58c410871888e53 (patch)
tree080bf001f3f95bb830cfdca70fffb01c643cb69c /drivers/net/wireless
parent5023d96616a1faf46656f8bb5545387d7cca9026 (diff)
iwlwifi: support Signed firmware image and Dual CPUs
Support Signed firmware based on code signing system (CSS) protocol and dual CPUs download, the code recognize if there are more than one CPU and if we need to operate the signed protocol according to the ucode binary image Signed-off-by: Eran Harary <eran.harary@intel.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h5
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c124
5 files changed, 197 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index a276af476e2d..54a4fdc631b7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -394,6 +394,38 @@
394#define CSR_DRAM_INT_TBL_ENABLE (1 << 31) 394#define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
395#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) 395#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27)
396 396
397/* SECURE boot registers */
398#define CSR_SECURE_BOOT_CONFIG_ADDR (0x100)
399enum secure_boot_config_reg {
400 CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001,
401 CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002,
402};
403
404#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100)
405#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100)
406enum secure_boot_status_reg {
407 CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003,
408 CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002,
409 CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004,
410 CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008,
411 CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010,
412};
413
414#define CSR_UCODE_LOAD_STATUS_ADDR (0x100)
415enum secure_load_status_reg {
416 CSR_CPU_STATUS_LOADING_STARTED = 0x00000001,
417 CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002,
418 CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8,
419 CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00,
420};
421
422#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
423#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
424
425#define CSR_SECURE_TIME_OUT (100)
426
427#define FH_TCSR_0_REG0 (0x1D00)
428
397/* 429/*
398 * HBUS (Host-side Bus) 430 * HBUS (Host-side Bus)
399 * 431 *
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 99e1da3123c9..ff570027e9dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -483,6 +483,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
483 const u8 *tlv_data; 483 const u8 *tlv_data;
484 char buildstr[25]; 484 char buildstr[25];
485 u32 build; 485 u32 build;
486 int num_of_cpus;
486 487
487 if (len < sizeof(*ucode)) { 488 if (len < sizeof(*ucode)) {
488 IWL_ERR(drv, "uCode has invalid length: %zd\n", len); 489 IWL_ERR(drv, "uCode has invalid length: %zd\n", len);
@@ -692,6 +693,42 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
692 goto invalid_tlv_len; 693 goto invalid_tlv_len;
693 drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); 694 drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
694 break; 695 break;
696 case IWL_UCODE_TLV_SECURE_SEC_RT:
697 iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
698 tlv_len);
699 drv->fw.mvm_fw = true;
700 drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
701 break;
702 case IWL_UCODE_TLV_SECURE_SEC_INIT:
703 iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
704 tlv_len);
705 drv->fw.mvm_fw = true;
706 drv->fw.img[IWL_UCODE_INIT].is_secure = true;
707 break;
708 case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
709 iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
710 tlv_len);
711 drv->fw.mvm_fw = true;
712 drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
713 break;
714 case IWL_UCODE_TLV_NUM_OF_CPU:
715 if (tlv_len != sizeof(u32))
716 goto invalid_tlv_len;
717 num_of_cpus =
718 le32_to_cpup((__le32 *)tlv_data);
719
720 if (num_of_cpus == 2) {
721 drv->fw.img[IWL_UCODE_REGULAR].is_dual_cpus =
722 true;
723 drv->fw.img[IWL_UCODE_INIT].is_dual_cpus =
724 true;
725 drv->fw.img[IWL_UCODE_WOWLAN].is_dual_cpus =
726 true;
727 } else if ((num_of_cpus > 2) || (num_of_cpus < 1)) {
728 IWL_ERR(drv, "Driver support upto 2 CPUs\n");
729 return -EINVAL;
730 }
731 break;
695 default: 732 default:
696 IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); 733 IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
697 break; 734 break;
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 8b6c6fd95ed0..6c6c35c5228c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -121,6 +121,10 @@ enum iwl_ucode_tlv_type {
121 IWL_UCODE_TLV_SEC_WOWLAN = 21, 121 IWL_UCODE_TLV_SEC_WOWLAN = 21,
122 IWL_UCODE_TLV_DEF_CALIB = 22, 122 IWL_UCODE_TLV_DEF_CALIB = 22,
123 IWL_UCODE_TLV_PHY_SKU = 23, 123 IWL_UCODE_TLV_PHY_SKU = 23,
124 IWL_UCODE_TLV_SECURE_SEC_RT = 24,
125 IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
126 IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
127 IWL_UCODE_TLV_NUM_OF_CPU = 27,
124}; 128};
125 129
126struct iwl_ucode_tlv { 130struct iwl_ucode_tlv {
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 6bdae0e9dd78..87b66a821ec8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -154,7 +154,8 @@ enum iwl_ucode_sec {
154 * For 16.0 uCode and above, there is no differentiation between sections, 154 * For 16.0 uCode and above, there is no differentiation between sections,
155 * just an offset to the HW address. 155 * just an offset to the HW address.
156 */ 156 */
157#define IWL_UCODE_SECTION_MAX 4 157#define IWL_UCODE_SECTION_MAX 6
158#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
158 159
159struct iwl_ucode_capabilities { 160struct iwl_ucode_capabilities {
160 u32 max_probe_length; 161 u32 max_probe_length;
@@ -171,6 +172,8 @@ struct fw_desc {
171 172
172struct fw_img { 173struct fw_img {
173 struct fw_desc sec[IWL_UCODE_SECTION_MAX]; 174 struct fw_desc sec[IWL_UCODE_SECTION_MAX];
175 bool is_secure;
176 bool is_dual_cpus;
174}; 177};
175 178
176/* uCode version contains 4 values: Major/Minor/API/Serial */ 179/* uCode version contains 4 values: Major/Minor/API/Serial */
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 6392f67dc1af..5d9337bec67a 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -446,22 +446,138 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
446 return ret; 446 return ret;
447} 447}
448 448
449static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu)
450{
451 int shift_param;
452 u32 address;
453 int ret = 0;
454
455 if (cpu == 1) {
456 shift_param = 0;
457 address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
458 } else {
459 shift_param = 16;
460 address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
461 }
462
463 /* set CPU to started */
464 iwl_trans_set_bits_mask(trans,
465 CSR_UCODE_LOAD_STATUS_ADDR,
466 CSR_CPU_STATUS_LOADING_STARTED << shift_param,
467 1);
468
469 /* set last complete descriptor number */
470 iwl_trans_set_bits_mask(trans,
471 CSR_UCODE_LOAD_STATUS_ADDR,
472 CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
473 << shift_param,
474 1);
475
476 /* set last loaded block */
477 iwl_trans_set_bits_mask(trans,
478 CSR_UCODE_LOAD_STATUS_ADDR,
479 CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
480 << shift_param,
481 1);
482
483 /* image loading complete */
484 iwl_trans_set_bits_mask(trans,
485 CSR_UCODE_LOAD_STATUS_ADDR,
486 CSR_CPU_STATUS_LOADING_COMPLETED
487 << shift_param,
488 1);
489
490 /* set FH_TCSR_0_REG */
491 iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1);
492
493 /* verify image verification started */
494 ret = iwl_poll_bit(trans, address,
495 CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
496 CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
497 CSR_SECURE_TIME_OUT);
498 if (ret < 0) {
499 IWL_ERR(trans, "secure boot process didn't start\n");
500 return ret;
501 }
502
503 /* wait for image verification to complete */
504 ret = iwl_poll_bit(trans, address,
505 CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
506 CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
507 CSR_SECURE_TIME_OUT);
508
509 if (ret < 0) {
510 IWL_ERR(trans, "Time out on secure boot process\n");
511 return ret;
512 }
513
514 return 0;
515}
516
449static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, 517static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
450 const struct fw_img *image) 518 const struct fw_img *image)
451{ 519{
452 int i, ret = 0; 520 int i, ret = 0;
453 521
454 for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { 522 IWL_DEBUG_FW(trans,
523 "working with %s image\n",
524 image->is_secure ? "Secured" : "Non Secured");
525 IWL_DEBUG_FW(trans,
526 "working with %s CPU\n",
527 image->is_dual_cpus ? "Dual" : "Single");
528
529 /* configure the ucode to be ready to get the secured image */
530 if (image->is_secure) {
531 /* set secure boot inspector addresses */
532 iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0);
533 iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0);
534
535 /* release CPU1 reset if secure inspector image burned in OTP */
536 iwl_write32(trans, CSR_RESET, 0);
537 }
538
539 /* load to FW the binary sections of CPU1 */
540 IWL_DEBUG_INFO(trans, "Loading CPU1\n");
541 for (i = 0;
542 i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
543 i++) {
455 if (!image->sec[i].data) 544 if (!image->sec[i].data)
456 break; 545 break;
457
458 ret = iwl_pcie_load_section(trans, i, &image->sec[i]); 546 ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
459 if (ret) 547 if (ret)
460 return ret; 548 return ret;
461 } 549 }
462 550
463 /* Remove all resets to allow NIC to operate */ 551 /* configure the ucode to start secure process on CPU1 */
464 iwl_write32(trans, CSR_RESET, 0); 552 if (image->is_secure) {
553 /* config CPU1 to start secure protocol */
554 ret = iwl_pcie_secure_set(trans, 1);
555 if (ret)
556 return ret;
557 } else {
558 /* Remove all resets to allow NIC to operate */
559 iwl_write32(trans, CSR_RESET, 0);
560 }
561
562 if (image->is_dual_cpus) {
563 /* load to FW the binary sections of CPU2 */
564 IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n");
565 for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
566 i < IWL_UCODE_SECTION_MAX; i++) {
567 if (!image->sec[i].data)
568 break;
569 ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
570 if (ret)
571 return ret;
572 }
573
574 if (image->is_secure) {
575 /* set CPU2 for secure protocol */
576 ret = iwl_pcie_secure_set(trans, 2);
577 if (ret)
578 return ret;
579 }
580 }
465 581
466 return 0; 582 return 0;
467} 583}