iwlwifi: mvm: fix bug in set_hw_address function
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / iwl-nvm-parse.c
index 4049c0d..f0ae038 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/etherdevice.h>
 #include "iwl-drv.h"
 #include "iwl-modparams.h"
 #include "iwl-nvm-parse.h"
@@ -127,7 +128,7 @@ static const u8 iwl_nvm_channels[] = {
 
 static const u8 iwl_nvm_channels_family_8000[] = {
        /* 2.4 GHz */
-       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+       1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
        /* 5 GHz */
        36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
        96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
@@ -137,7 +138,7 @@ static const u8 iwl_nvm_channels_family_8000[] = {
 #define IWL_NUM_CHANNELS               ARRAY_SIZE(iwl_nvm_channels)
 #define IWL_NUM_CHANNELS_FAMILY_8000   ARRAY_SIZE(iwl_nvm_channels_family_8000)
 #define NUM_2GHZ_CHANNELS              14
-#define NUM_2GHZ_CHANNELS_FAMILY_8000  13
+#define NUM_2GHZ_CHANNELS_FAMILY_8000  14
 #define FIRST_2GHZ_HT_MINUS            5
 #define LAST_2GHZ_HT_PLUS              9
 #define LAST_5GHZ_HT                   161
@@ -173,7 +174,9 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
  * @NVM_CHANNEL_IBSS: usable as an IBSS channel
  * @NVM_CHANNEL_ACTIVE: active scanning allowed
  * @NVM_CHANNEL_RADAR: radar detection required
- * @NVM_CHANNEL_DFS: dynamic freq selection candidate
+ * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed
+ * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS
+ *     on same channel on 2.4 or same UNII band on 5.2
  * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
  * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
  * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
@@ -184,7 +187,8 @@ enum iwl_nvm_channel_flags {
        NVM_CHANNEL_IBSS = BIT(1),
        NVM_CHANNEL_ACTIVE = BIT(3),
        NVM_CHANNEL_RADAR = BIT(4),
-       NVM_CHANNEL_DFS = BIT(7),
+       NVM_CHANNEL_INDOOR_ONLY = BIT(5),
+       NVM_CHANNEL_GO_CONCURRENT = BIT(6),
        NVM_CHANNEL_WIDE = BIT(8),
        NVM_CHANNEL_40MHZ = BIT(9),
        NVM_CHANNEL_80MHZ = BIT(10),
@@ -272,6 +276,16 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                if (ch_flags & NVM_CHANNEL_RADAR)
                        channel->flags |= IEEE80211_CHAN_RADAR;
 
+               if (ch_flags & NVM_CHANNEL_INDOOR_ONLY)
+                       channel->flags |= IEEE80211_CHAN_INDOOR_ONLY;
+
+               /* Set the GO concurrent flag only in case that NO_IR is set.
+                * Otherwise it is meaningless
+                */
+               if ((ch_flags & NVM_CHANNEL_GO_CONCURRENT) &&
+                   (channel->flags & IEEE80211_CHAN_NO_IR))
+                       channel->flags |= IEEE80211_CHAN_GO_CONCURRENT;
+
                /* Initialize regulatory-based run-time data */
 
                /*
@@ -281,7 +295,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                channel->max_power = DEFAULT_MAX_TX_POWER;
                is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
                IWL_DEBUG_EEPROM(dev,
-                                "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
+                                "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
                                 channel->hw_value,
                                 is_5ghz ? "5.2" : "2.4",
                                 CHECK_AND_PRINT_I(VALID),
@@ -289,7 +303,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
                                 CHECK_AND_PRINT_I(ACTIVE),
                                 CHECK_AND_PRINT_I(RADAR),
                                 CHECK_AND_PRINT_I(WIDE),
-                                CHECK_AND_PRINT_I(DFS),
+                                CHECK_AND_PRINT_I(INDOOR_ONLY),
+                                CHECK_AND_PRINT_I(GO_CONCURRENT),
                                 ch_flags,
                                 channel->max_power,
                                 ((ch_flags & NVM_CHANNEL_IBSS) &&
@@ -450,13 +465,7 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
                               struct iwl_nvm_data *data,
                               const __le16 *nvm_sec)
 {
-       u8 hw_addr[ETH_ALEN];
-
-       if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
-               memcpy(hw_addr, nvm_sec + HW_ADDR, ETH_ALEN);
-       else
-               memcpy(hw_addr, nvm_sec + MAC_ADDRESS_OVERRIDE_FAMILY_8000,
-                      ETH_ALEN);
+       const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR);
 
        /* The byte order is little endian 16 bit, meaning 214365 */
        data->hw_addr[0] = hw_addr[1];
@@ -467,6 +476,50 @@ static void iwl_set_hw_address(const struct iwl_cfg *cfg,
        data->hw_addr[5] = hw_addr[4];
 }
 
+static void iwl_set_hw_address_family_8000(struct device *dev,
+                                          const struct iwl_cfg *cfg,
+                                          struct iwl_nvm_data *data,
+                                          const __le16 *mac_override,
+                                          const __le16 *nvm_hw)
+{
+       const u8 *hw_addr;
+
+       if (mac_override) {
+               hw_addr = (const u8 *)(mac_override +
+                                MAC_ADDRESS_OVERRIDE_FAMILY_8000);
+
+               /* The byte order is little endian 16 bit, meaning 214365 */
+               data->hw_addr[0] = hw_addr[1];
+               data->hw_addr[1] = hw_addr[0];
+               data->hw_addr[2] = hw_addr[3];
+               data->hw_addr[3] = hw_addr[2];
+               data->hw_addr[4] = hw_addr[5];
+               data->hw_addr[5] = hw_addr[4];
+
+               if (is_valid_ether_addr(data->hw_addr))
+                       return;
+
+               IWL_ERR_DEV(dev,
+                           "mac address from nvm override section is not valid\n");
+       }
+
+       if (nvm_hw) {
+               /* take the MAC address from the OTP */
+               hw_addr = (const u8 *)(nvm_hw + HW_ADDR0_FAMILY_8000);
+               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 *)(nvm_hw + HW_ADDR1_FAMILY_8000);
+               data->hw_addr[4] = hw_addr[1];
+               data->hw_addr[5] = hw_addr[0];
+               return;
+       }
+
+       IWL_ERR_DEV(dev, "mac address is not found\n");
+}
+
 struct iwl_nvm_data *
 iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_hw, const __le16 *nvm_sw,
@@ -526,7 +579,8 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                                rx_chains);
        } else {
                /* MAC address in family 8000 */
-               iwl_set_hw_address(cfg, data, mac_override);
+               iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
+                                              nvm_hw);
 
                iwl_init_sbands(dev, cfg, data, regulatory,
                                sku & NVM_SKU_CAP_11AC_ENABLE, tx_chains,