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>
This commit is contained in:
parent
e4a9f8cea5
commit
189fa2faac
|
@ -395,38 +395,6 @@
|
||||||
#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)
|
||||||
*
|
*
|
||||||
|
|
|
@ -130,6 +130,21 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
|
||||||
}
|
}
|
||||||
IWL_EXPORT_SYMBOL(iwl_write_prph);
|
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)
|
void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
|
@ -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);
|
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
|
||||||
void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
|
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_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
|
||||||
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
|
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
|
||||||
u32 bits, u32 mask);
|
u32 bits, u32 mask);
|
||||||
|
|
|
@ -288,4 +288,43 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
|
||||||
#define OSC_CLK (0xa04068)
|
#define OSC_CLK (0xa04068)
|
||||||
#define OSC_CLK_FORCE_CONTROL (0x8)
|
#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__ */
|
#endif /* __iwl_prph_h__ */
|
||||||
|
|
|
@ -441,78 +441,87 @@ 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)
|
static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans,
|
||||||
|
const struct fw_img *image,
|
||||||
|
int cpu)
|
||||||
{
|
{
|
||||||
int shift_param;
|
int shift_param;
|
||||||
u32 address;
|
u32 first_idx, last_idx;
|
||||||
int ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
if (cpu == 1) {
|
if (cpu == 1) {
|
||||||
shift_param = 0;
|
shift_param = 0;
|
||||||
address = CSR_SECURE_BOOT_CPU1_STATUS_ADDR;
|
first_idx = 0;
|
||||||
|
last_idx = 2;
|
||||||
} else {
|
} else {
|
||||||
shift_param = 16;
|
shift_param = 16;
|
||||||
address = CSR_SECURE_BOOT_CPU2_STATUS_ADDR;
|
first_idx = 3;
|
||||||
|
last_idx = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set CPU to started */
|
for (i = first_idx; i <= last_idx; i++) {
|
||||||
iwl_trans_set_bits_mask(trans,
|
if (!image->sec[i].data)
|
||||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
break;
|
||||||
CSR_CPU_STATUS_LOADING_STARTED << shift_param,
|
if (i == first_idx + 1)
|
||||||
1);
|
/* set CPU to started */
|
||||||
|
iwl_set_bits_prph(trans,
|
||||||
/* set last complete descriptor number */
|
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||||
iwl_trans_set_bits_mask(trans,
|
LMPM_CPU_HDRS_LOADING_COMPLETED
|
||||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
<< shift_param);
|
||||||
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);
|
|
||||||
|
|
||||||
|
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
/* image loading complete */
|
/* image loading complete */
|
||||||
iwl_trans_set_bits_mask(trans,
|
iwl_set_bits_prph(trans,
|
||||||
CSR_UCODE_LOAD_STATUS_ADDR,
|
CSR_UCODE_LOAD_STATUS_ADDR,
|
||||||
CSR_CPU_STATUS_LOADING_COMPLETED
|
LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param);
|
||||||
<< shift_param,
|
|
||||||
1);
|
|
||||||
|
|
||||||
/* set FH_TCSR_0_REG */
|
return 0;
|
||||||
iwl_trans_set_bits_mask(trans, FH_TCSR_0_REG0, 0x00400000, 1);
|
}
|
||||||
|
|
||||||
/* verify image verification started */
|
static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
|
||||||
ret = iwl_poll_bit(trans, address,
|
const struct fw_img *image,
|
||||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
|
int cpu)
|
||||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_STATUS,
|
{
|
||||||
CSR_SECURE_TIME_OUT);
|
int shift_param;
|
||||||
if (ret < 0) {
|
u32 first_idx, last_idx;
|
||||||
IWL_ERR(trans, "secure boot process didn't start\n");
|
int i, ret = 0;
|
||||||
return ret;
|
|
||||||
|
if (cpu == 1) {
|
||||||
|
shift_param = 0;
|
||||||
|
first_idx = 0;
|
||||||
|
last_idx = 1;
|
||||||
|
} else {
|
||||||
|
shift_param = 16;
|
||||||
|
first_idx = 2;
|
||||||
|
last_idx = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wait for image verification to complete */
|
for (i = first_idx; i <= last_idx; i++) {
|
||||||
ret = iwl_poll_bit(trans, address,
|
if (!image->sec[i].data)
|
||||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
|
break;
|
||||||
CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
|
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
|
||||||
CSR_SECURE_TIME_OUT);
|
if (ret)
|
||||||
|
return ret;
|
||||||
if (ret < 0) {
|
|
||||||
IWL_ERR(trans, "Time out on secure boot process\n");
|
|
||||||
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;
|
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 ret = 0;
|
||||||
|
|
||||||
IWL_DEBUG_FW(trans,
|
IWL_DEBUG_FW(trans,
|
||||||
"working with %s image\n",
|
"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 */
|
/* configure the ucode to be ready to get the secured image */
|
||||||
if (image->is_secure) {
|
if (image->is_secure) {
|
||||||
/* set secure boot inspector addresses */
|
/* set secure boot inspector addresses */
|
||||||
iwl_write32(trans, CSR_SECURE_INSPECTOR_CODE_ADDR, 0);
|
iwl_write_prph(trans,
|
||||||
iwl_write32(trans, CSR_SECURE_INSPECTOR_DATA_ADDR, 0);
|
LMPM_SECURE_INSPECTOR_CODE_ADDR,
|
||||||
|
LMPM_SECURE_INSPECTOR_CODE_MEM_SPACE);
|
||||||
|
|
||||||
/* release CPU1 reset if secure inspector image burned in OTP */
|
iwl_write_prph(trans,
|
||||||
iwl_write32(trans, CSR_RESET, 0);
|
LMPM_SECURE_INSPECTOR_DATA_ADDR,
|
||||||
}
|
LMPM_SECURE_INSPECTOR_DATA_MEM_SPACE);
|
||||||
|
|
||||||
/* load to FW the binary sections of CPU1 */
|
/* set CPU1 header address */
|
||||||
IWL_DEBUG_INFO(trans, "Loading CPU1\n");
|
iwl_write_prph(trans,
|
||||||
for (i = 0;
|
LMPM_SECURE_UCODE_LOAD_CPU1_HDR_ADDR,
|
||||||
i < IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
|
LMPM_SECURE_CPU1_HDR_MEM_SPACE);
|
||||||
i++) {
|
|
||||||
if (!image->sec[i].data)
|
/* load to FW the binary Secured sections of CPU1 */
|
||||||
break;
|
ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1);
|
||||||
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 {
|
} else {
|
||||||
/* Remove all resets to allow NIC to operate */
|
/* load to FW the binary Non secured sections of CPU1 */
|
||||||
iwl_write32(trans, CSR_RESET, 0);
|
ret = iwl_pcie_load_cpu_sections(trans, image, 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image->is_dual_cpus) {
|
if (image->is_dual_cpus) {
|
||||||
/* load to FW the binary sections of CPU2 */
|
/* set CPU2 header address */
|
||||||
IWL_DEBUG_INFO(trans, "working w/ DUAL CPUs - Loading CPU2\n");
|
iwl_write_prph(trans,
|
||||||
for (i = IWL_UCODE_FIRST_SECTION_OF_SECOND_CPU;
|
LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR,
|
||||||
i < IWL_UCODE_SECTION_MAX; i++) {
|
LMPM_SECURE_CPU2_HDR_MEM_SPACE);
|
||||||
if (!image->sec[i].data)
|
|
||||||
break;
|
|
||||||
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image->is_secure) {
|
/* load to FW the binary sections of CPU2 */
|
||||||
/* set CPU2 for secure protocol */
|
if (image->is_secure)
|
||||||
ret = iwl_pcie_secure_set(trans, 2);
|
ret = iwl_pcie_load_cpu_secured_sections(trans,
|
||||||
if (ret)
|
image,
|
||||||
return ret;
|
2);
|
||||||
}
|
else
|
||||||
|
ret = iwl_pcie_load_cpu_sections(trans, image, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release CPU reset */
|
/* release CPU reset */
|
||||||
|
@ -580,6 +581,20 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
||||||
else
|
else
|
||||||
iwl_write32(trans, CSR_RESET, 0);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue