Commit e2d6f4e7 authored by Eran Harary's avatar Eran Harary Committed by Johannes Berg

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: default avatarEran Harary <eran.harary@intel.com>
Reviewed-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 5023d966
...@@ -394,6 +394,38 @@ ...@@ -394,6 +394,38 @@
#define CSR_DRAM_INT_TBL_ENABLE (1 << 31) #define CSR_DRAM_INT_TBL_ENABLE (1 << 31)
#define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) #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) * HBUS (Host-side Bus)
* *
......
...@@ -483,6 +483,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, ...@@ -483,6 +483,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
const u8 *tlv_data; const u8 *tlv_data;
char buildstr[25]; char buildstr[25];
u32 build; u32 build;
int num_of_cpus;
if (len < sizeof(*ucode)) { if (len < sizeof(*ucode)) {
IWL_ERR(drv, "uCode has invalid length: %zd\n", len); 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,6 +693,42 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
goto invalid_tlv_len; goto invalid_tlv_len;
drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data); drv->fw.phy_config = le32_to_cpup((__le32 *)tlv_data);
break; break;
case IWL_UCODE_TLV_SECURE_SEC_RT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
tlv_len);
drv->fw.mvm_fw = true;
drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
break;
case IWL_UCODE_TLV_SECURE_SEC_INIT:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
tlv_len);
drv->fw.mvm_fw = true;
drv->fw.img[IWL_UCODE_INIT].is_secure = true;
break;
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
tlv_len);
drv->fw.mvm_fw = true;
drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
break;
case IWL_UCODE_TLV_NUM_OF_CPU:
if (tlv_len != sizeof(u32))
goto invalid_tlv_len;
num_of_cpus =
le32_to_cpup((__le32 *)tlv_data);
if (num_of_cpus == 2) {
drv->fw.img[IWL_UCODE_REGULAR].is_dual_cpus =
true;
drv->fw.img[IWL_UCODE_INIT].is_dual_cpus =
true;
drv->fw.img[IWL_UCODE_WOWLAN].is_dual_cpus =
true;
} else if ((num_of_cpus > 2) || (num_of_cpus < 1)) {
IWL_ERR(drv, "Driver support upto 2 CPUs\n");
return -EINVAL;
}
break;
default: default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break; break;
......
...@@ -121,6 +121,10 @@ enum iwl_ucode_tlv_type { ...@@ -121,6 +121,10 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_SEC_WOWLAN = 21, IWL_UCODE_TLV_SEC_WOWLAN = 21,
IWL_UCODE_TLV_DEF_CALIB = 22, IWL_UCODE_TLV_DEF_CALIB = 22,
IWL_UCODE_TLV_PHY_SKU = 23, IWL_UCODE_TLV_PHY_SKU = 23,
IWL_UCODE_TLV_SECURE_SEC_RT = 24,
IWL_UCODE_TLV_SECURE_SEC_INIT = 25,
IWL_UCODE_TLV_SECURE_SEC_WOWLAN = 26,
IWL_UCODE_TLV_NUM_OF_CPU = 27,
}; };
struct iwl_ucode_tlv { struct iwl_ucode_tlv {
......
...@@ -154,7 +154,8 @@ enum iwl_ucode_sec { ...@@ -154,7 +154,8 @@ enum iwl_ucode_sec {
* For 16.0 uCode and above, there is no differentiation between sections, * For 16.0 uCode and above, there is no differentiation between sections,
* just an offset to the HW address. * just an offset to the HW address.
*/ */
#define IWL_UCODE_SECTION_MAX 4 #define IWL_UCODE_SECTION_MAX 6
#define IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU (IWL_UCODE_SECTION_MAX/2)
struct iwl_ucode_capabilities { struct iwl_ucode_capabilities {
u32 max_probe_length; u32 max_probe_length;
...@@ -171,6 +172,8 @@ struct fw_desc { ...@@ -171,6 +172,8 @@ struct fw_desc {
struct fw_img { struct fw_img {
struct fw_desc sec[IWL_UCODE_SECTION_MAX]; struct fw_desc sec[IWL_UCODE_SECTION_MAX];
bool is_secure;
bool is_dual_cpus;
}; };
/* uCode version contains 4 values: Major/Minor/API/Serial */ /* uCode version contains 4 values: Major/Minor/API/Serial */
......
...@@ -446,22 +446,138 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, ...@@ -446,22 +446,138 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
return ret; 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, static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image) const struct fw_img *image)
{ {
int i, ret = 0; 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) if (!image->sec[i].data)
break; break;
ret = iwl_pcie_load_section(trans, i, &image->sec[i]); ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
if (ret) if (ret)
return 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);
if (ret)
return ret;
} else {
/* Remove all resets to allow NIC to operate */ /* Remove all resets to allow NIC to operate */
iwl_write32(trans, CSR_RESET, 0); 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment