iwlwifi: pcie: fix secure section / dual cpu firmware loading
authorEran Harary <eran.harary@intel.com>
Thu, 23 Jan 2014 14:26:32 +0000 (16:26 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 3 Feb 2014 20:23:32 +0000 (22:23 +0200)
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>
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/pcie/trans.c

index 9d325516c42d80111eb2336c2ffe1a4b1f2c3d99..f13dec9ad9c95306553389e89c610531bdcfef73 100644 (file)
 #define CSR_DRAM_INT_TBL_ENABLE                (1 << 31)
 #define CSR_DRAM_INIT_TBL_WRAP_CHECK   (1 << 27)
 
-/* SECURE boot registers */
-#define CSR_SECURE_BOOT_CONFIG_ADDR    (0x100)
-enum secure_boot_config_reg {
-       CSR_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP  = 0x00000001,
-       CSR_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ        = 0x00000002,
-};
-
-#define CSR_SECURE_BOOT_CPU1_STATUS_ADDR       (0x100)
-#define CSR_SECURE_BOOT_CPU2_STATUS_ADDR       (0x100)
-enum secure_boot_status_reg {
-       CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS          = 0x00000003,
-       CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED       = 0x00000002,
-       CSR_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS         = 0x00000004,
-       CSR_SECURE_BOOT_CPU_STATUS_VERF_FAIL            = 0x00000008,
-       CSR_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL       = 0x00000010,
-};
-
-#define CSR_UCODE_LOAD_STATUS_ADDR     (0x100)
-enum secure_load_status_reg {
-       CSR_CPU_STATUS_LOADING_STARTED                  = 0x00000001,
-       CSR_CPU_STATUS_LOADING_COMPLETED                = 0x00000002,
-       CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED            = 0x000000F8,
-       CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK         = 0x0000FF00,
-};
-
-#define CSR_SECURE_INSPECTOR_CODE_ADDR (0x100)
-#define CSR_SECURE_INSPECTOR_DATA_ADDR (0x100)
-
-#define CSR_SECURE_TIME_OUT    (100)
-
-#define FH_TCSR_0_REG0 (0x1D00)
-
 /*
  * HBUS (Host-side Bus)
  *
index f98175a0d35b7e508c0e71b7fa10c8c0fc7c22e1..07372f2b0250d27b4120f135e7e6900bec3cfc03 100644 (file)
@@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
 }
 IWL_EXPORT_SYMBOL(iwl_write_prph);
 
+int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
+                     u32 bits, u32 mask, int timeout)
+{
+       int t = 0;
+
+       do {
+               if ((iwl_read_prph(trans, addr) & mask) == (bits & mask))
+                       return t;
+               udelay(IWL_POLL_INTERVAL);
+               t += IWL_POLL_INTERVAL;
+       } while (t < timeout);
+
+       return -ETIMEDOUT;
+}
+
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
 {
        unsigned long flags;
index c339c1bed08056fe217c54c0825404d9618b2768..9e81b23d738bc3c9f198c9d9a0e2edf3c8ad21e3 100644 (file)
@@ -72,6 +72,8 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
 
 u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
 void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
+int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
+                     u32 bits, u32 mask, int timeout);
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
                            u32 bits, u32 mask);
index fc3b6bee77344491fab3e66ef9507a78bb3d0add..9c90186d1744dbbe2fd49a6f854d714c664d55b6 100644 (file)
@@ -288,4 +288,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
 #define OSC_CLK                                (0xa04068)
 #define OSC_CLK_FORCE_CONTROL          (0x8)
 
+/* SECURE boot registers */
+#define LMPM_SECURE_BOOT_CONFIG_ADDR   (0x100)
+enum secure_boot_config_reg {
+       LMPM_SECURE_BOOT_CONFIG_INSPECTOR_BURNED_IN_OTP = 0x00000001,
+       LMPM_SECURE_BOOT_CONFIG_INSPECTOR_NOT_REQ       = 0x00000002,
+};
+
+#define LMPM_SECURE_BOOT_CPU1_STATUS_ADDR      (0x1E30)
+#define LMPM_SECURE_BOOT_CPU2_STATUS_ADDR      (0x1E34)
+enum secure_boot_status_reg {
+       LMPM_SECURE_BOOT_CPU_STATUS_VERF_STATUS         = 0x00000001,
+       LMPM_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED      = 0x00000002,
+       LMPM_SECURE_BOOT_CPU_STATUS_VERF_SUCCESS        = 0x00000004,
+       LMPM_SECURE_BOOT_CPU_STATUS_VERF_FAIL           = 0x00000008,
+       LMPM_SECURE_BOOT_CPU_STATUS_SIGN_VERF_FAIL      = 0x00000010,
+       LMPM_SECURE_BOOT_STATUS_SUCCESS                 = 0x00000003,
+};
+
+#define CSR_UCODE_LOAD_STATUS_ADDR     (0x1E70)
+enum secure_load_status_reg {
+       LMPM_CPU_UCODE_LOADING_STARTED                  = 0x00000001,
+       LMPM_CPU_HDRS_LOADING_COMPLETED                 = 0x00000003,
+       LMPM_CPU_UCODE_LOADING_COMPLETED                = 0x00000007,
+       LMPM_CPU_STATUS_NUM_OF_LAST_COMPLETED           = 0x000000F8,
+       LMPM_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK        = 0x0000FF00,
+};
+
+#define LMPM_SECURE_INSPECTOR_CODE_ADDR        (0x1E38)
+#define LMPM_SECURE_INSPECTOR_DATA_ADDR        (0x1E3C)
+#define LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR   (0x1E78)
+#define LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR   (0x1E7C)
+
+#define LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE   (0x400000)
+#define LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE   (0x402000)
+#define LMPM_SECURE_CPU1_HDR_MEM_SPACE         (0x420000)
+#define LMPM_SECURE_CPU2_HDR_MEM_SPACE         (0x420400)
+
+#define LMPM_SECURE_TIME_OUT   (100)
+
 #endif                         /* __iwl_prph_h__ */
index ff7d70da64f98ef02d28bb723e21e23c2e16d7e6..7290f422be65b60f7f1b8f8ce5b236c3d5881900 100644 (file)
@@ -441,78 +441,87 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
        return ret;
 }
 
-static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu)
+static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans,
+                                             const struct fw_img *image,
+                                             int cpu)
 {
        int shift_param;
-       u32 address;
-       int ret = 0;
+       u32 first_idx, last_idx;
+       int i, ret = 0;
 
        if (cpu == 1) {
                shift_param = 0;
-               address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
+               first_idx = 0;
+               last_idx = 2;
        } else {
                shift_param = 16;
-               address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
+               first_idx = 3;
+               last_idx = 5;
        }
 
-       /* set CPU to started */
-       iwl_trans_set_bits_mask(trans,
-                               CSR_UCODE_LOAD_STATUS_ADDR,
-                               CSR_CPU_STATUS_LOADING_STARTED << shift_param,
-                               1);
-
-       /* set last complete descriptor number */
-       iwl_trans_set_bits_mask(trans,
-                               CSR_UCODE_LOAD_STATUS_ADDR,
-                               CSR_CPU_STATUS_NUM_OF_LAST_COMPLETED
-                               << shift_param,
-                               1);
-
-       /* set last loaded block */
-       iwl_trans_set_bits_mask(trans,
-                               CSR_UCODE_LOAD_STATUS_ADDR,
-                               CSR_CPU_STATUS_NUM_OF_LAST_LOADED_BLOCK
-                               << shift_param,
-                               1);
+       for (i = first_idx; i <= last_idx; i++) {
+               if (!image->sec[i].data)
+                       break;
+               if (i == first_idx + 1)
+                       /* set CPU to started */
+                       iwl_set_bits_prph(trans,
+                                         CSR_UCODE_LOAD_STATUS_ADDR,
+                                         LMPM_CPU_HDRS_LOADING_COMPLETED
+                                         << shift_param);
 
-       /* image loading complete */
-       iwl_trans_set_bits_mask(trans,
-                               CSR_UCODE_LOAD_STATUS_ADDR,
-                               CSR_CPU_STATUS_LOADING_COMPLETED
-                               << shift_param,
-                               1);
-
-       /* set FH_TCSR_0_REG  */
-       iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1);
-
-       /* verify image verification started  */
-       ret = iwl_poll_bit(trans, address,
-                          CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
-                          CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
-                          CSR_SECURE_TIME_OUT);
-       if (ret < 0) {
-               IWL_ERR(trans, "secure boot process didn't start\n");
-               return ret;
+               ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+               if (ret)
+                       return ret;
        }
+       /* image loading complete */
+       iwl_set_bits_prph(trans,
+                         CSR_UCODE_LOAD_STATUS_ADDR,
+                         LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param);
 
-       /* wait for image verification to complete  */
-       ret = iwl_poll_bit(trans, address,
-                          CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
-                          CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
-                          CSR_SECURE_TIME_OUT);
+       return 0;
+}
 
-       if (ret < 0) {
-               IWL_ERR(trans, "Time out on secure boot process\n");
-               return ret;
+static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
+                                     const struct fw_img *image,
+                                     int cpu)
+{
+       int shift_param;
+       u32 first_idx, last_idx;
+       int i, ret = 0;
+
+       if (cpu == 1) {
+               shift_param = 0;
+               first_idx = 0;
+               last_idx = 1;
+       } else {
+               shift_param = 16;
+               first_idx = 2;
+               last_idx = 3;
        }
 
+       for (i = first_idx; i <= last_idx; i++) {
+               if (!image->sec[i].data)
+                       break;
+               ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+               if (ret)
+                       return ret;
+       }
+
+       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               iwl_set_bits_prph(trans,
+                                 CSR_UCODE_LOAD_STATUS_ADDR,
+                                 (LMPM_CPU_UCODE_LOADING_COMPLETED |
+                                  LMPM_CPU_HDRS_LOADING_COMPLETED |
+                                  LMPM_CPU_UCODE_LOADING_STARTED) <<
+                                       shift_param);
+
        return 0;
 }
 
 static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                                const struct fw_img *image)
 {
-       int i, ret = 0;
+       int ret = 0;
 
        IWL_DEBUG_FW(trans,
                     "working with %s image\n",
@@ -524,54 +533,46 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        /* configure the ucode to be ready to get the secured image */
        if (image->is_secure) {
                /* set secure boot inspector addresses */
-               iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0);
-               iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0);
+               iwl_write_prph(trans,
+                              LMPM_SECURE_INSPECTOR_CODE_ADDR,
+                              LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE);
 
-               /* release CPU1 reset if secure inspector image burned in OTP */
-               iwl_write32(trans, CSR_RESET, 0);
-       }
+               iwl_write_prph(trans,
+                              LMPM_SECURE_INSPECTOR_DATA_ADDR,
+                              LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE);
 
-       /* load to FW the binary sections of CPU1 */
-       IWL_DEBUG_INFO(trans, "Loading CPU1\n");
-       for (i = 0;
-            i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
-            i++) {
-               if (!image->sec[i].data)
-                       break;
-               ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
+               /* set CPU1 header address */
+               iwl_write_prph(trans,
+                              LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR,
+                              LMPM_SECURE_CPU1_HDR_MEM_SPACE);
+
+               /* load to FW the binary Secured sections of CPU1 */
+               ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1);
                if (ret)
                        return ret;
-       }
 
-       /* configure the ucode to start secure process on CPU1 */
-       if (image->is_secure) {
-               /* config CPU1 to start secure protocol */
-               ret = iwl_pcie_secure_set(trans, 1);
+       } else {
+               /* load to FW the binary Non secured sections of CPU1 */
+               ret = iwl_pcie_load_cpu_sections(trans, image, 1);
                if (ret)
                        return ret;
-       } else {
-               /* Remove all resets to allow NIC to operate */
-               iwl_write32(trans, CSR_RESET, 0);
        }
 
        if (image->is_dual_cpus) {
-               /* load to FW the binary sections of CPU2 */
-               IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n");
-               for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
-                       i < IWL_UCODE_SECTION_MAX; i++) {
-                       if (!image->sec[i].data)
-                               break;
-                       ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
-                       if (ret)
-                               return ret;
-               }
+               /* set CPU2 header address */
+               iwl_write_prph(trans,
+                              LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR,
+                              LMPM_SECURE_CPU2_HDR_MEM_SPACE);
 
-               if (image->is_secure) {
-                       /* set CPU2 for secure protocol */
-                       ret = iwl_pcie_secure_set(trans, 2);
-                       if (ret)
-                               return ret;
-               }
+               /* load to FW the binary sections of CPU2 */
+               if (image->is_secure)
+                       ret = iwl_pcie_load_cpu_secured_sections(trans,
+                                                                image,
+                                                                2);
+               else
+                       ret = iwl_pcie_load_cpu_sections(trans, image, 2);
+               if (ret)
+                       return ret;
        }
 
        /* release CPU reset */
@@ -580,6 +581,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        else
                iwl_write32(trans, CSR_RESET, 0);
 
+       if (image->is_secure) {
+               /* wait for image verification to complete  */
+               ret = iwl_poll_prph_bit(trans,
+                                       LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
+                                       LMPM_SECURE_BOOT_STATUS_SUCCESS,
+                                       LMPM_SECURE_BOOT_STATUS_SUCCESS,
+                                       LMPM_SECURE_TIME_OUT);
+
+               if (ret < 0) {
+                       IWL_ERR(trans, "Time out on secure boot process\n");
+                       return ret;
+               }
+       }
+
        return 0;
 }