summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie
diff options
context:
space:
mode:
authorEran Harary <eran.harary@intel.com>2014-01-29 07:10:17 +0100
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-02-03 21:23:41 +0100
commit034846cfd23e00a70b48363d70dccc3f8d537053 (patch)
tree4f91d200b9ffd46b71e447ae187dae39ac987d14 /drivers/net/wireless/iwlwifi/pcie
parentiwlwifi: mvm: remove unneeded calculations (diff)
downloadlinux-034846cfd23e00a70b48363d70dccc3f8d537053.tar.xz
linux-034846cfd23e00a70b48363d70dccc3f8d537053.zip
iwlwifi: mvm: support multiple firmware sections
Newer devices have two embedded CPUs, and the firwmare for both of them is include in the .ucode file requested upon enumeration. An empty section with address=0xFFFFCCCC separates between the sections intended for cpu1 and the sections intended for cpu2. Update the driver to parse the .ucode file with this format and act accordingly. Signed-off-by: Eran Harary <eran.harary@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 61ae1af34f17..84d471299e5a 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -89,6 +89,7 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
/* PCI registers */
#define PCI_CFG_RETRY_TIMEOUT 0x041
+#define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC
static void iwl_pcie_apm_config(struct iwl_trans *trans)
{
@@ -443,26 +444,33 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans,
const struct fw_img *image,
- int cpu)
+ int cpu,
+ int *first_ucode_section)
{
int shift_param;
- u32 first_idx, last_idx;
int i, ret = 0;
+ u32 last_read_idx = 0;
if (cpu == 1) {
shift_param = 0;
- first_idx = 0;
- last_idx = 2;
+ *first_ucode_section = 0;
} else {
shift_param = 16;
- first_idx = 3;
- last_idx = 5;
+ (*first_ucode_section)++;
}
- for (i = first_idx; i <= last_idx; i++) {
- if (!image->sec[i].data)
+ for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+ last_read_idx = i;
+
+ if (!image->sec[i].data ||
+ image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) {
+ IWL_DEBUG_FW(trans,
+ "Break since Data not valid or Empty section, sec = %d\n",
+ i);
break;
- if (i == first_idx + 1)
+ }
+
+ if (i == (*first_ucode_section) + 1)
/* set CPU to started */
iwl_set_bits_prph(trans,
CSR_UCODE_LOAD_STATUS_ADDR,
@@ -478,30 +486,39 @@ static int iwl_pcie_load_cpu_secured_sections(struct iwl_trans *trans,
CSR_UCODE_LOAD_STATUS_ADDR,
LMPM_CPU_UCODE_LOADING_COMPLETED << shift_param);
+ *first_ucode_section = last_read_idx;
+
return 0;
}
static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
const struct fw_img *image,
- int cpu)
+ int cpu,
+ int *first_ucode_section)
{
int shift_param;
- u32 first_idx, last_idx;
int i, ret = 0;
+ u32 last_read_idx = 0;
if (cpu == 1) {
shift_param = 0;
- first_idx = 0;
- last_idx = 1;
+ *first_ucode_section = 0;
} else {
shift_param = 16;
- first_idx = 2;
- last_idx = 3;
+ (*first_ucode_section)++;
}
- for (i = first_idx; i <= last_idx; i++) {
- if (!image->sec[i].data)
+ for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) {
+ last_read_idx = i;
+
+ if (!image->sec[i].data ||
+ image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) {
+ IWL_DEBUG_FW(trans,
+ "Break since Data not valid or Empty section, sec = %d\n",
+ i);
break;
+ }
+
ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
if (ret)
return ret;
@@ -515,6 +532,8 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans,
LMPM_CPU_UCODE_LOADING_STARTED) <<
shift_param);
+ *first_ucode_section = last_read_idx;
+
return 0;
}
@@ -522,6 +541,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
const struct fw_img *image)
{
int ret = 0;
+ int first_ucode_section;
IWL_DEBUG_FW(trans,
"working with %s image\n",
@@ -547,13 +567,15 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
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);
+ ret = iwl_pcie_load_cpu_secured_sections(trans, image, 1,
+ &first_ucode_section);
if (ret)
return ret;
} else {
/* load to FW the binary Non secured sections of CPU1 */
- ret = iwl_pcie_load_cpu_sections(trans, image, 1);
+ ret = iwl_pcie_load_cpu_sections(trans, image, 1,
+ &first_ucode_section);
if (ret)
return ret;
}
@@ -566,11 +588,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
/* load to FW the binary sections of CPU2 */
if (image->is_secure)
- ret = iwl_pcie_load_cpu_secured_sections(trans,
- image,
- 2);
+ ret = iwl_pcie_load_cpu_secured_sections(
+ trans, image, 2,
+ &first_ucode_section);
else
- ret = iwl_pcie_load_cpu_sections(trans, image, 2);
+ ret = iwl_pcie_load_cpu_sections(trans, image, 2,
+ &first_ucode_section);
if (ret)
return ret;
}