summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
diff options
context:
space:
mode:
authorSara Sharon2016-03-07 13:18:29 +0100
committerEmmanuel Grumbach2016-03-09 19:59:19 +0100
commit17c867bfe89bd2e089752ac938468900387acbe2 (patch)
treee6a9f7d80eae175145dbe2311bb0ff0e8c4ca5b0 /drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
parentiwlwifi: pcie: fine tune number of rxbs (diff)
downloadkernel-qcow2-linux-17c867bfe89bd2e089752ac938468900387acbe2.tar.gz
kernel-qcow2-linux-17c867bfe89bd2e089752ac938468900387acbe2.tar.xz
kernel-qcow2-linux-17c867bfe89bd2e089752ac938468900387acbe2.zip
iwlwifi: add support for getting HW address from CSR
From 9000 family on, we need to get HW address from host CSR registers. OEM can override it by fusing the override registers - read those first, and if those are 0 - read the OTP registers instead. In addition - bail out if no valid mac address is present. Make it shared for all NICs. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c75
1 files changed, 54 insertions, 21 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 5e6b90da3179..93a689583dff 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -71,6 +71,8 @@
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
#include "iwl-prph.h"
+#include "iwl-io.h"
+#include "iwl-csr.h"
/* NVM offsets (in words) definitions */
enum wkp_nvm_offsets {
@@ -524,6 +526,36 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
}
+static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
+{
+ const u8 *hw_addr;
+
+ hw_addr = (const u8 *)&mac_addr0;
+ dest[0] = hw_addr[3];
+ dest[1] = hw_addr[2];
+ dest[2] = hw_addr[1];
+ dest[3] = hw_addr[0];
+
+ hw_addr = (const u8 *)&mac_addr1;
+ dest[4] = hw_addr[1];
+ dest[5] = hw_addr[0];
+}
+
+static void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
+ struct iwl_nvm_data *data)
+{
+ __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
+ __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
+
+ /* If OEM did not fuse address - get it from OTP */
+ if (!mac_addr0 && !mac_addr1) {
+ mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
+ mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
+ }
+
+ iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
+}
+
static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
const struct iwl_cfg *cfg,
struct iwl_nvm_data *data,
@@ -564,21 +596,8 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
WFMP_MAC_ADDR_0));
__le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
WFMP_MAC_ADDR_1));
- /* read the MAC address from HW resisters */
- hw_addr = (const u8 *)&mac_addr0;
- data->hw_addr[0] = hw_addr[3];
- data->hw_addr[1] = hw_addr[2];
- data->hw_addr[2] = hw_addr[1];
- data->hw_addr[3] = hw_addr[0];
-
- hw_addr = (const u8 *)&mac_addr1;
- data->hw_addr[4] = hw_addr[1];
- data->hw_addr[5] = hw_addr[0];
-
- if (!is_valid_ether_addr(data->hw_addr))
- IWL_ERR(trans,
- "mac address (%pM) from hw section is not valid\n",
- data->hw_addr);
+
+ iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
return;
}
@@ -586,12 +605,14 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
IWL_ERR(trans, "mac address is not found\n");
}
-static void iwl_set_hw_address(struct iwl_trans *trans,
- const struct iwl_cfg *cfg,
- struct iwl_nvm_data *data, const __le16 *nvm_hw,
- const __le16 *mac_override)
+static int iwl_set_hw_address(struct iwl_trans *trans,
+ const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data, const __le16 *nvm_hw,
+ const __le16 *mac_override)
{
- if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
+ if (cfg->mac_addr_from_csr) {
+ iwl_set_hw_address_from_csr(trans, data);
+ } else if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
/* The byte order is little endian 16 bit, meaning 214365 */
@@ -605,6 +626,13 @@ static void iwl_set_hw_address(struct iwl_trans *trans,
iwl_set_hw_address_family_8000(trans, cfg, data,
mac_override, nvm_hw);
}
+
+ if (!is_valid_ether_addr(data->hw_addr)) {
+ IWL_ERR(trans, "no valid mac address was found\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
struct iwl_nvm_data *
@@ -680,7 +708,12 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
ch_section = regulatory;
}
- iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override);
+ /* If no valid mac address was found - bail out */
+ if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) {
+ kfree(data);
+ return NULL;
+ }
+
iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
lar_fw_supported && lar_enabled);
data->calib_version = 255;