aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/iwlwifi/pcie
diff options
context:
space:
mode:
authorEran Harary2013-10-02 13:53:40 +0300
committerJohannes Berg2013-10-11 15:05:02 +0200
commite2d6f4e71dc76c815434234cb58c410871888e53 (patch)
tree080bf001f3f95bb830cfdca70fffb01c643cb69c /drivers/net/wireless/iwlwifi/pcie
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/iwlwifi/pcie')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c124
1 files changed, 120 insertions, 4 deletions
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,
return ret;
}
+static int iwl_pcie_secure_set(struct iwl_trans *trans, int cpu)
+{
+ int shift_param;
+ u32 address;
+ int ret = 0;
+
+ if (cpu == 1) {
+ shift_param = 0;
+ address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
+ } else {
+ shift_param = 16;
+ address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
+ }
+
+ /* 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);
+
+ /* 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;
+ }
+
+ /* 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);
+
+ if (ret < 0) {
+ IWL_ERR(trans, "Time out on secure boot process\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image)
{
int i, ret = 0;
- for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
+ IWL_DEBUG_FW(trans,
+ "working with %s image\n",
+ image->is_secure ? "Secured" : "Non Secured");
+ IWL_DEBUG_FW(trans,
+ "working with %s CPU\n",
+ image->is_dual_cpus ? "Dual" : "Single");
+
+ /* 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);
+
+ /* release CPU1 reset if secure inspector image burned in OTP */
+ iwl_write32(trans, CSR_RESET, 0);
+ }
+
+ /* 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]);
if (ret)
return ret;
}
- /* Remove all resets to allow NIC to operate */
- iwl_write32(trans, CSR_RESET, 0);
+ /* 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);
+ 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;
+ }
+
+ if (image->is_secure) {
+ /* set CPU2 for secure protocol */
+ ret = iwl_pcie_secure_set(trans, 2);
+ if (ret)
+ return ret;
+ }
+ }
return 0;
}