]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
iwlwifi: add support for getting HW address from CSR
authorSara Sharon <sara.sharon@intel.com>
Mon, 7 Mar 2016 12:18:29 +0000 (14:18 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Wed, 9 Mar 2016 18:59:19 +0000 (20:59 +0200)
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>
drivers/net/wireless/intel/iwlwifi/iwl-9000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c

index 8e32a57dda0f9016310fc01b27ebd1be061b0304..318b1dc171f23510878a0d5df326020980ca3ff3 100644 (file)
@@ -140,7 +140,8 @@ static const struct iwl_tt_params iwl9000_tt_params = {
        .thermal_params = &iwl9000_tt_params,                           \
        .apmg_not_supported = true,                                     \
        .mq_rx_supported = true,                                        \
-       .vht_mu_mimo_supported = true
+       .vht_mu_mimo_supported = true,                                  \
+       .mac_addr_from_csr = true
 
 const struct iwl_cfg iwl9260_2ac_cfg = {
                .name = "Intel(R) Dual Band Wireless AC 9260",
index 4f2b57e8bbc7ede32c03f2383ac26cf811418b2f..3e4d346be3502ab1b84cb396ae9516dc2804c5f0 100644 (file)
@@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff {
  * @host_interrupt_operation_mode: device needs host interrupt operation
  *     mode set
  * @nvm_hw_section_num: the ID of the HW NVM section
+ * @mac_addr_from_csr: read HW address from CSR registers
  * @features: hw features, any combination of feature_whitelist
  * @pwr_tx_backoffs: translation table between power limits and backoffs
  * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
@@ -345,6 +346,7 @@ struct iwl_cfg {
        const bool host_interrupt_operation_mode;
        bool high_temp;
        u8   nvm_hw_section_num;
+       bool mac_addr_from_csr;
        bool lp_xtal_workaround;
        const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
        bool no_power_up_nic_in_init;
index a79c4f61a851d11c13937060740e539f2ed643f1..b978f6cae55cd95a2904eaf5cd98c20eac2b8f05 100644 (file)
@@ -598,4 +598,14 @@ enum msix_hw_int_causes {
 #define MSIX_AUTO_CLEAR_CAUSE                  0
 #define MSIX_NON_AUTO_CLEAR_CAUSE              BIT(7)
 
+/*****************************************************************************
+ *                     HW address related registers                          *
+ *****************************************************************************/
+
+#define CSR_ADDR_BASE                  (0x380)
+#define CSR_MAC_ADDR0_OTP              (CSR_ADDR_BASE)
+#define CSR_MAC_ADDR1_OTP              (CSR_ADDR_BASE + 4)
+#define CSR_MAC_ADDR0_STRAP            (CSR_ADDR_BASE + 8)
+#define CSR_MAC_ADDR1_STRAP            (CSR_ADDR_BASE + 0xC)
+
 #endif /* !__iwl_csr_h__ */
index 5e6b90da31798168bd5827091716fe69cc85a0c4..93a689583dff1678b5e1c4a56482a09de4ec31d9 100644 (file)
@@ -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;