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 | |
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>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-csr.h | 32 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-io.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-io.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-prph.h | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/trans.c | 191 |
5 files changed, 159 insertions, 120 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 9d325516c42d..f13dec9ad9c9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h | |||
@@ -395,38 +395,6 @@ | |||
395 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) | 395 | #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) |
396 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) | 396 | #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) |
397 | 397 | ||
398 | /* SECURE boot registers */ | ||
399 | #define CSR_SECURE_BOOT_CONFIG_ADDR (0x100) | ||
400 | enum secure_boot_config_reg { | ||
401 | CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, | ||
402 | CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | ||
403 | }; | ||
404 | |||
405 | #define CSR_SECURE_BOOT_CPU1_STATUS_ADDR (0x100) | ||
406 | #define CSR_SECURE_BOOT_CPU2_STATUS_ADDR (0x100) | ||
407 | enum secure_boot_status_reg { | ||
408 | CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000003, | ||
409 | CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, | ||
410 | CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, | ||
411 | CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, | ||
412 | CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, | ||
413 | }; | ||
414 | |||
415 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x100) | ||
416 | enum secure_load_status_reg { | ||
417 | CSR_CPU_STATUS_LOADING_STARTED = 0x00000001, | ||
418 | CSR_CPU_STATUS_LOADING_COMPLETED = 0x00000002, | ||
419 | CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, | ||
420 | CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, | ||
421 | }; | ||
422 | |||
423 | #define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100) | ||
424 | #define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100) | ||
425 | |||
426 | #define CSR_SECURE_TIME_OUT (100) | ||
427 | |||
428 | #define FH_TCSR_0_REG0 (0x1D00) | ||
429 | |||
430 | /* | 398 | /* |
431 | * HBUS (Host-side Bus) | 399 | * HBUS (Host-side Bus) |
432 | * | 400 | * |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index f98175a0d35b..07372f2b0250 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c | |||
@@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) | |||
130 | } | 130 | } |
131 | IWL_EXPORT_SYMBOL(iwl_write_prph); | 131 | IWL_EXPORT_SYMBOL(iwl_write_prph); |
132 | 132 | ||
133 | int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, | ||
134 | u32 bits, u32 mask, int timeout) | ||
135 | { | ||
136 | int t = 0; | ||
137 | |||
138 | do { | ||
139 | if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) | ||
140 | return t; | ||
141 | udelay(IWL_POLL_INTERVAL); | ||
142 | t += IWL_POLL_INTERVAL; | ||
143 | } while (t < timeout); | ||
144 | |||
145 | return -ETIMEDOUT; | ||
146 | } | ||
147 | |||
133 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) | 148 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) |
134 | { | 149 | { |
135 | unsigned long flags; | 150 | unsigned long flags; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index c339c1bed080..9e81b23d738b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h | |||
@@ -72,6 +72,8 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); | |||
72 | 72 | ||
73 | u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); | 73 | u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); |
74 | void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); | 74 | void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); |
75 | int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, | ||
76 | u32 bits, u32 mask, int timeout); | ||
75 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); | 77 | void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); |
76 | void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, | 78 | void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, |
77 | u32 bits, u32 mask); | 79 | u32 bits, u32 mask); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index fc3b6bee7734..9c90186d1744 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h | |||
@@ -288,4 +288,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) | |||
288 | #define OSC_CLK (0xa04068) | 288 | #define OSC_CLK (0xa04068) |
289 | #define OSC_CLK_FORCE_CONTROL (0x8) | 289 | #define OSC_CLK_FORCE_CONTROL (0x8) |
290 | 290 | ||
291 | /* SECURE boot registers */ | ||
292 | #define LMPM_SECURE_BOOT_CONFIG_ADDR (0x100) | ||
293 | enum secure_boot_config_reg { | ||
294 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001, | ||
295 | LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ = 0x00000002, | ||
296 | }; | ||
297 | |||
298 | #define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR (0x1E30) | ||
299 | #define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR (0x1E34) | ||
300 | enum secure_boot_status_reg { | ||
301 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS = 0x00000001, | ||
302 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED = 0x00000002, | ||
303 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS = 0x00000004, | ||
304 | LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL = 0x00000008, | ||
305 | LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL = 0x00000010, | ||
306 | LMPM_SECURE_BOOT_STATUS_SUCCESS = 0x00000003, | ||
307 | }; | ||
308 | |||
309 | #define CSR_UCODE_LOAD_STATUS_ADDR (0x1E70) | ||
310 | enum secure_load_status_reg { | ||
311 | LMPM_CPU_UCODE_LOADING_STARTED = 0x00000001, | ||
312 | LMPM_CPU_HDRS_LOADING_COMPLETED = 0x00000003, | ||
313 | LMPM_CPU_UCODE_LOADING_COMPLETED = 0x00000007, | ||
314 | LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED = 0x000000F8, | ||
315 | LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK = 0x0000FF00, | ||
316 | }; | ||
317 | |||
318 | #define LMPM_SECURE_INSPECTOR_CODE_ADDR (0x1E38) | ||
319 | #define LMPM_SECURE_INSPECTOR_DATA_ADDR (0x1E3C) | ||
320 | #define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR (0x1E78) | ||
321 | #define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR (0x1E7C) | ||
322 | |||
323 | #define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE (0x400000) | ||
324 | #define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE (0x402000) | ||
325 | #define LMPM_SECURE_CPU1_HDR_MEM_SPACE (0x420000) | ||
326 | #define LMPM_SECURE_CPU2_HDR_MEM_SPACE (0x420400) | ||
327 | |||
328 | #define LMPM_SECURE_TIME_OUT (100) | ||
329 | |||
291 | #endif /* __iwl_prph_h__ */ | 330 | #endif /* __iwl_prph_h__ */ |
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 | ||