#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"
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,
#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
* @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 (?)
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),
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 */
/*
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),
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) &&
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];
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,
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,