Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 189fa2fa authored by Eran Harary's avatar Eran Harary Committed by Emmanuel Grumbach
Browse files

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: default avatarEran Harary <eran.harary@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent e4a9f8ce
Loading
Loading
Loading
Loading
+0 −32
Original line number Original line Diff line number Diff line
@@ -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)
 *
 *
+15 −0
Original line number Original line Diff line number Diff line
@@ -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;
+2 −0
Original line number Original line Diff line number Diff line
@@ -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);
+39 −0
Original line number Original line Diff line number Diff line
@@ -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__ */
+103 −88
Original line number Original line Diff line number Diff line
@@ -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;
	}
	}


	for (i = first_idx; i <= last_idx; i++) {
		if (!image->sec[i].data)
			break;
		if (i == first_idx + 1)
			/* set CPU to started */
			/* set CPU to started */
	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_STARTED << shift_param,
					  LMPM_CPU_HDRS_LOADING_COMPLETED
				1);
					  << shift_param);

	/* 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);


		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);
	return 0;

	/* 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  */
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_COMPLETED,
				      int cpu)
			   CSR_SECURE_BOOT_CPU_STATUS_VERF_COMPLETED,
{
			   CSR_SECURE_TIME_OUT);
	int shift_param;
	u32 first_idx, last_idx;
	int i, ret = 0;


	if (ret < 0) {
	if (cpu == 1) {
		IWL_ERR(trans, "Time out on secure boot process\n");
		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;
			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,55 +533,47 @@ 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 */
	} else {
	if (image->is_secure) {
		/* load to FW the binary Non secured sections of CPU1 */
		/* config CPU1 to start secure protocol */
		ret = iwl_pcie_load_cpu_sections(trans, image, 1);
		ret = iwl_pcie_secure_set(trans, 1);
		if (ret)
		if (ret)
			return ret;
			return ret;
	} else {
		/* Remove all resets to allow NIC to operate */
		iwl_write32(trans, CSR_RESET, 0);
	}
	}


	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,
								 image,
								 2);
		else
			ret = iwl_pcie_load_cpu_sections(trans, image, 2);
		if (ret)
		if (ret)
			return ret;
			return ret;
	}
	}
	}


	/* release CPU reset */
	/* release CPU reset */
	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
	if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
@@ -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;
}
}