1bfcc09ddSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2bfcc09ddSBjoern A. Zeeb /* 39af1bba4SBjoern A. Zeeb * Copyright (C) 2005-2014, 2018-2023 Intel Corporation 4bfcc09ddSBjoern A. Zeeb * Copyright (C) 2013-2015 Intel Mobile Communications GmbH 5bfcc09ddSBjoern A. Zeeb * Copyright (C) 2016-2017 Intel Deutschland GmbH 6bfcc09ddSBjoern A. Zeeb */ 7bfcc09ddSBjoern A. Zeeb #include <linux/types.h> 8bfcc09ddSBjoern A. Zeeb #include <linux/slab.h> 9bfcc09ddSBjoern A. Zeeb #include <linux/export.h> 10bfcc09ddSBjoern A. Zeeb #include <linux/etherdevice.h> 11bfcc09ddSBjoern A. Zeeb #include <linux/pci.h> 12bfcc09ddSBjoern A. Zeeb #include <linux/firmware.h> 13bfcc09ddSBjoern A. Zeeb 14bfcc09ddSBjoern A. Zeeb #include "iwl-drv.h" 15bfcc09ddSBjoern A. Zeeb #include "iwl-modparams.h" 16bfcc09ddSBjoern A. Zeeb #include "iwl-nvm-parse.h" 17bfcc09ddSBjoern A. Zeeb #include "iwl-prph.h" 18bfcc09ddSBjoern A. Zeeb #include "iwl-io.h" 19bfcc09ddSBjoern A. Zeeb #include "iwl-csr.h" 20bfcc09ddSBjoern A. Zeeb #include "fw/acpi.h" 21bfcc09ddSBjoern A. Zeeb #include "fw/api/nvm-reg.h" 22bfcc09ddSBjoern A. Zeeb #include "fw/api/commands.h" 23bfcc09ddSBjoern A. Zeeb #include "fw/api/cmdhdr.h" 24bfcc09ddSBjoern A. Zeeb #include "fw/img.h" 25d9836fb4SBjoern A. Zeeb #include "mei/iwl-mei.h" 26bfcc09ddSBjoern A. Zeeb 27bfcc09ddSBjoern A. Zeeb /* NVM offsets (in words) definitions */ 28bfcc09ddSBjoern A. Zeeb enum nvm_offsets { 29bfcc09ddSBjoern A. Zeeb /* NVM HW-Section offset (in words) definitions */ 30bfcc09ddSBjoern A. Zeeb SUBSYSTEM_ID = 0x0A, 31bfcc09ddSBjoern A. Zeeb HW_ADDR = 0x15, 32bfcc09ddSBjoern A. Zeeb 33bfcc09ddSBjoern A. Zeeb /* NVM SW-Section offset (in words) definitions */ 34bfcc09ddSBjoern A. Zeeb NVM_SW_SECTION = 0x1C0, 35bfcc09ddSBjoern A. Zeeb NVM_VERSION = 0, 36bfcc09ddSBjoern A. Zeeb RADIO_CFG = 1, 37bfcc09ddSBjoern A. Zeeb SKU = 2, 38bfcc09ddSBjoern A. Zeeb N_HW_ADDRS = 3, 39bfcc09ddSBjoern A. Zeeb NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, 40bfcc09ddSBjoern A. Zeeb 41bfcc09ddSBjoern A. Zeeb /* NVM REGULATORY -Section offset (in words) definitions */ 42bfcc09ddSBjoern A. Zeeb NVM_CHANNELS_SDP = 0, 43bfcc09ddSBjoern A. Zeeb }; 44bfcc09ddSBjoern A. Zeeb 45bfcc09ddSBjoern A. Zeeb enum ext_nvm_offsets { 46bfcc09ddSBjoern A. Zeeb /* NVM HW-Section offset (in words) definitions */ 47*a4128aadSBjoern A. Zeeb 48bfcc09ddSBjoern A. Zeeb MAC_ADDRESS_OVERRIDE_EXT_NVM = 1, 49bfcc09ddSBjoern A. Zeeb 50bfcc09ddSBjoern A. Zeeb /* NVM SW-Section offset (in words) definitions */ 51bfcc09ddSBjoern A. Zeeb NVM_VERSION_EXT_NVM = 0, 52bfcc09ddSBjoern A. Zeeb N_HW_ADDRS_FAMILY_8000 = 3, 53bfcc09ddSBjoern A. Zeeb 54bfcc09ddSBjoern A. Zeeb /* NVM PHY_SKU-Section offset (in words) definitions */ 55bfcc09ddSBjoern A. Zeeb RADIO_CFG_FAMILY_EXT_NVM = 0, 56bfcc09ddSBjoern A. Zeeb SKU_FAMILY_8000 = 2, 57bfcc09ddSBjoern A. Zeeb 58bfcc09ddSBjoern A. Zeeb /* NVM REGULATORY -Section offset (in words) definitions */ 59bfcc09ddSBjoern A. Zeeb NVM_CHANNELS_EXTENDED = 0, 60bfcc09ddSBjoern A. Zeeb NVM_LAR_OFFSET_OLD = 0x4C7, 61bfcc09ddSBjoern A. Zeeb NVM_LAR_OFFSET = 0x507, 62bfcc09ddSBjoern A. Zeeb NVM_LAR_ENABLED = 0x7, 63bfcc09ddSBjoern A. Zeeb }; 64bfcc09ddSBjoern A. Zeeb 65bfcc09ddSBjoern A. Zeeb /* SKU Capabilities (actual values from NVM definition) */ 66bfcc09ddSBjoern A. Zeeb enum nvm_sku_bits { 67bfcc09ddSBjoern A. Zeeb NVM_SKU_CAP_BAND_24GHZ = BIT(0), 68bfcc09ddSBjoern A. Zeeb NVM_SKU_CAP_BAND_52GHZ = BIT(1), 69bfcc09ddSBjoern A. Zeeb NVM_SKU_CAP_11N_ENABLE = BIT(2), 70bfcc09ddSBjoern A. Zeeb NVM_SKU_CAP_11AC_ENABLE = BIT(3), 71bfcc09ddSBjoern A. Zeeb NVM_SKU_CAP_MIMO_DISABLE = BIT(5), 72bfcc09ddSBjoern A. Zeeb }; 73bfcc09ddSBjoern A. Zeeb 74bfcc09ddSBjoern A. Zeeb /* 75bfcc09ddSBjoern A. Zeeb * These are the channel numbers in the order that they are stored in the NVM 76bfcc09ddSBjoern A. Zeeb */ 77bfcc09ddSBjoern A. Zeeb static const u16 iwl_nvm_channels[] = { 78bfcc09ddSBjoern A. Zeeb /* 2.4 GHz */ 79bfcc09ddSBjoern A. Zeeb 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 80bfcc09ddSBjoern A. Zeeb /* 5 GHz */ 81bfcc09ddSBjoern A. Zeeb 36, 40, 44, 48, 52, 56, 60, 64, 82bfcc09ddSBjoern A. Zeeb 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 83bfcc09ddSBjoern A. Zeeb 149, 153, 157, 161, 165 84bfcc09ddSBjoern A. Zeeb }; 85bfcc09ddSBjoern A. Zeeb 86bfcc09ddSBjoern A. Zeeb static const u16 iwl_ext_nvm_channels[] = { 87bfcc09ddSBjoern A. Zeeb /* 2.4 GHz */ 88bfcc09ddSBjoern A. Zeeb 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 89bfcc09ddSBjoern A. Zeeb /* 5 GHz */ 90bfcc09ddSBjoern A. Zeeb 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 91bfcc09ddSBjoern A. Zeeb 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 92bfcc09ddSBjoern A. Zeeb 149, 153, 157, 161, 165, 169, 173, 177, 181 93bfcc09ddSBjoern A. Zeeb }; 94bfcc09ddSBjoern A. Zeeb 95bfcc09ddSBjoern A. Zeeb static const u16 iwl_uhb_nvm_channels[] = { 96bfcc09ddSBjoern A. Zeeb /* 2.4 GHz */ 97bfcc09ddSBjoern A. Zeeb 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 98bfcc09ddSBjoern A. Zeeb /* 5 GHz */ 99bfcc09ddSBjoern A. Zeeb 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 100bfcc09ddSBjoern A. Zeeb 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 101bfcc09ddSBjoern A. Zeeb 149, 153, 157, 161, 165, 169, 173, 177, 181, 102bfcc09ddSBjoern A. Zeeb /* 6-7 GHz */ 103bfcc09ddSBjoern A. Zeeb 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 104bfcc09ddSBjoern A. Zeeb 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 105bfcc09ddSBjoern A. Zeeb 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, 106bfcc09ddSBjoern A. Zeeb 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 107bfcc09ddSBjoern A. Zeeb }; 108bfcc09ddSBjoern A. Zeeb 109bfcc09ddSBjoern A. Zeeb #define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) 110bfcc09ddSBjoern A. Zeeb #define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) 111bfcc09ddSBjoern A. Zeeb #define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels) 112bfcc09ddSBjoern A. Zeeb #define NUM_2GHZ_CHANNELS 14 113bfcc09ddSBjoern A. Zeeb #define NUM_5GHZ_CHANNELS 37 114bfcc09ddSBjoern A. Zeeb #define FIRST_2GHZ_HT_MINUS 5 115bfcc09ddSBjoern A. Zeeb #define LAST_2GHZ_HT_PLUS 9 116bfcc09ddSBjoern A. Zeeb #define N_HW_ADDR_MASK 0xF 117bfcc09ddSBjoern A. Zeeb 118bfcc09ddSBjoern A. Zeeb /* rate data (static) */ 119bfcc09ddSBjoern A. Zeeb static struct ieee80211_rate iwl_cfg80211_rates[] = { 120bfcc09ddSBjoern A. Zeeb { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, 121bfcc09ddSBjoern A. Zeeb { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1, 122bfcc09ddSBjoern A. Zeeb .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, 123bfcc09ddSBjoern A. Zeeb { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2, 124bfcc09ddSBjoern A. Zeeb .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, 125bfcc09ddSBjoern A. Zeeb { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3, 126bfcc09ddSBjoern A. Zeeb .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, 127bfcc09ddSBjoern A. Zeeb { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, }, 128bfcc09ddSBjoern A. Zeeb { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, }, 129bfcc09ddSBjoern A. Zeeb { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, }, 130bfcc09ddSBjoern A. Zeeb { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, }, 131bfcc09ddSBjoern A. Zeeb { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, }, 132bfcc09ddSBjoern A. Zeeb { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, }, 133bfcc09ddSBjoern A. Zeeb { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, }, 134bfcc09ddSBjoern A. Zeeb { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, }, 135bfcc09ddSBjoern A. Zeeb }; 136bfcc09ddSBjoern A. Zeeb #define RATES_24_OFFS 0 137bfcc09ddSBjoern A. Zeeb #define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates) 138bfcc09ddSBjoern A. Zeeb #define RATES_52_OFFS 4 139bfcc09ddSBjoern A. Zeeb #define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) 140bfcc09ddSBjoern A. Zeeb 141bfcc09ddSBjoern A. Zeeb /** 142bfcc09ddSBjoern A. Zeeb * enum iwl_nvm_channel_flags - channel flags in NVM 143bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo 144bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_IBSS: usable as an IBSS channel 145bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_ACTIVE: active scanning allowed 146bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_RADAR: radar detection required 147bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed 148bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS 149bfcc09ddSBjoern A. Zeeb * on same channel on 2.4 or same UNII band on 5.2 150bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_UNIFORM: uniform spreading required 151bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_20MHZ: 20 MHz channel okay 152bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_40MHZ: 40 MHz channel okay 153bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_80MHZ: 80 MHz channel okay 154bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_160MHZ: 160 MHz channel okay 155bfcc09ddSBjoern A. Zeeb * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) 156*a4128aadSBjoern A. Zeeb * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP 157*a4128aadSBjoern A. Zeeb * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP 158bfcc09ddSBjoern A. Zeeb */ 159bfcc09ddSBjoern A. Zeeb enum iwl_nvm_channel_flags { 160bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_VALID = BIT(0), 161bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_IBSS = BIT(1), 162bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_ACTIVE = BIT(3), 163bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_RADAR = BIT(4), 164bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_INDOOR_ONLY = BIT(5), 165bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_GO_CONCURRENT = BIT(6), 166bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_UNIFORM = BIT(7), 167bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_20MHZ = BIT(8), 168bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_40MHZ = BIT(9), 169bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_80MHZ = BIT(10), 170bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_160MHZ = BIT(11), 171bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_DC_HIGH = BIT(12), 172*a4128aadSBjoern A. Zeeb NVM_CHANNEL_VLP = BIT(13), 173*a4128aadSBjoern A. Zeeb NVM_CHANNEL_AFC = BIT(14), 174bfcc09ddSBjoern A. Zeeb }; 175bfcc09ddSBjoern A. Zeeb 176bfcc09ddSBjoern A. Zeeb /** 1779af1bba4SBjoern A. Zeeb * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory 178bfcc09ddSBjoern A. Zeeb * domain. 1799af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the 180bfcc09ddSBjoern A. Zeeb * 2.4Ghz band is allowed. 1819af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the 182bfcc09ddSBjoern A. Zeeb * 5Ghz band is allowed. 1839af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed 184bfcc09ddSBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 1859af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed 186bfcc09ddSBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 1879af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. 1889af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. 1899af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden 190bfcc09ddSBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 1919af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_DC_HIGH_ENABLED: DC HIGH allowed. 1929af1bba4SBjoern A. Zeeb * @REG_CAPA_V1_11AX_DISABLED: 11ax is forbidden for this regulatory domain. 193bfcc09ddSBjoern A. Zeeb */ 1949af1bba4SBjoern A. Zeeb enum iwl_reg_capa_flags_v1 { 1959af1bba4SBjoern A. Zeeb REG_CAPA_V1_BF_CCD_LOW_BAND = BIT(0), 1969af1bba4SBjoern A. Zeeb REG_CAPA_V1_BF_CCD_HIGH_BAND = BIT(1), 1979af1bba4SBjoern A. Zeeb REG_CAPA_V1_160MHZ_ALLOWED = BIT(2), 1989af1bba4SBjoern A. Zeeb REG_CAPA_V1_80MHZ_ALLOWED = BIT(3), 1999af1bba4SBjoern A. Zeeb REG_CAPA_V1_MCS_8_ALLOWED = BIT(4), 2009af1bba4SBjoern A. Zeeb REG_CAPA_V1_MCS_9_ALLOWED = BIT(5), 2019af1bba4SBjoern A. Zeeb REG_CAPA_V1_40MHZ_FORBIDDEN = BIT(7), 2029af1bba4SBjoern A. Zeeb REG_CAPA_V1_DC_HIGH_ENABLED = BIT(9), 2039af1bba4SBjoern A. Zeeb REG_CAPA_V1_11AX_DISABLED = BIT(10), 2049af1bba4SBjoern A. Zeeb }; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_1 */ 205bfcc09ddSBjoern A. Zeeb 206bfcc09ddSBjoern A. Zeeb /** 207bfcc09ddSBjoern A. Zeeb * enum iwl_reg_capa_flags_v2 - global flags applied for the whole regulatory 208bfcc09ddSBjoern A. Zeeb * domain (version 2). 209bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_STRADDLE_DISABLED: Straddle channels (144, 142, 138) are 210bfcc09ddSBjoern A. Zeeb * disabled. 211bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the 212bfcc09ddSBjoern A. Zeeb * 2.4Ghz band is allowed. 213bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the 214bfcc09ddSBjoern A. Zeeb * 5Ghz band is allowed. 215bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed 216bfcc09ddSBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 217bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed 218bfcc09ddSBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 219bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. 220bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. 221bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_WEATHER_DISABLED: Weather radar channels (120, 124, 128, 118, 222bfcc09ddSBjoern A. Zeeb * 126, 122) are disabled. 223bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_40MHZ_ALLOWED: 11n channel with a width of 40Mhz is allowed 224bfcc09ddSBjoern A. Zeeb * for this regulatory domain (uvalid only in 5Ghz). 225bfcc09ddSBjoern A. Zeeb * @REG_CAPA_V2_11AX_DISABLED: 11ax is forbidden for this regulatory domain. 226bfcc09ddSBjoern A. Zeeb */ 227bfcc09ddSBjoern A. Zeeb enum iwl_reg_capa_flags_v2 { 228bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_STRADDLE_DISABLED = BIT(0), 229bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_BF_CCD_LOW_BAND = BIT(1), 230bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_BF_CCD_HIGH_BAND = BIT(2), 231bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_160MHZ_ALLOWED = BIT(3), 232bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_80MHZ_ALLOWED = BIT(4), 233bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_MCS_8_ALLOWED = BIT(5), 234bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_MCS_9_ALLOWED = BIT(6), 235bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_WEATHER_DISABLED = BIT(7), 236bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_40MHZ_ALLOWED = BIT(8), 237bfcc09ddSBjoern A. Zeeb REG_CAPA_V2_11AX_DISABLED = BIT(10), 2389af1bba4SBjoern A. Zeeb }; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_2 */ 2399af1bba4SBjoern A. Zeeb 2409af1bba4SBjoern A. Zeeb /** 2419af1bba4SBjoern A. Zeeb * enum iwl_reg_capa_flags_v4 - global flags applied for the whole regulatory 2429af1bba4SBjoern A. Zeeb * domain. 2439af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed 2449af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 2459af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed 2469af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 5Ghz). 2479af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_MCS_12_ALLOWED: 11ac with MCS 12 is allowed. 2489af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_MCS_13_ALLOWED: 11ac with MCS 13 is allowed. 2499af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_11BE_DISABLED: 11be is forbidden for this regulatory domain. 2509af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_11AX_DISABLED: 11ax is forbidden for this regulatory domain. 2519af1bba4SBjoern A. Zeeb * @REG_CAPA_V4_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed 2529af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 5GHz). 2539af1bba4SBjoern A. Zeeb */ 2549af1bba4SBjoern A. Zeeb enum iwl_reg_capa_flags_v4 { 2559af1bba4SBjoern A. Zeeb REG_CAPA_V4_160MHZ_ALLOWED = BIT(3), 2569af1bba4SBjoern A. Zeeb REG_CAPA_V4_80MHZ_ALLOWED = BIT(4), 2579af1bba4SBjoern A. Zeeb REG_CAPA_V4_MCS_12_ALLOWED = BIT(5), 2589af1bba4SBjoern A. Zeeb REG_CAPA_V4_MCS_13_ALLOWED = BIT(6), 2599af1bba4SBjoern A. Zeeb REG_CAPA_V4_11BE_DISABLED = BIT(8), 2609af1bba4SBjoern A. Zeeb REG_CAPA_V4_11AX_DISABLED = BIT(13), 2619af1bba4SBjoern A. Zeeb REG_CAPA_V4_320MHZ_ALLOWED = BIT(16), 2629af1bba4SBjoern A. Zeeb }; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4 */ 263bfcc09ddSBjoern A. Zeeb 264bfcc09ddSBjoern A. Zeeb /* 265bfcc09ddSBjoern A. Zeeb * API v2 for reg_capa_flags is relevant from version 6 and onwards of the 266bfcc09ddSBjoern A. Zeeb * MCC update command response. 267bfcc09ddSBjoern A. Zeeb */ 268bfcc09ddSBjoern A. Zeeb #define REG_CAPA_V2_RESP_VER 6 269bfcc09ddSBjoern A. Zeeb 2709af1bba4SBjoern A. Zeeb /* API v4 for reg_capa_flags is relevant from version 8 and onwards of the 2719af1bba4SBjoern A. Zeeb * MCC update command response. 2729af1bba4SBjoern A. Zeeb */ 2739af1bba4SBjoern A. Zeeb #define REG_CAPA_V4_RESP_VER 8 2749af1bba4SBjoern A. Zeeb 275bfcc09ddSBjoern A. Zeeb /** 276bfcc09ddSBjoern A. Zeeb * struct iwl_reg_capa - struct for global regulatory capabilities, Used for 277bfcc09ddSBjoern A. Zeeb * handling the different APIs of reg_capa_flags. 278bfcc09ddSBjoern A. Zeeb * 279bfcc09ddSBjoern A. Zeeb * @allow_40mhz: 11n channel with a width of 40Mhz is allowed 2809af1bba4SBjoern A. Zeeb * for this regulatory domain. 281bfcc09ddSBjoern A. Zeeb * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed 2829af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 5 and 6 Ghz). 283bfcc09ddSBjoern A. Zeeb * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed 2849af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 5 and 6 Ghz). 2859af1bba4SBjoern A. Zeeb * @allow_320mhz: 11be channel with a width of 320Mhz is allowed 2869af1bba4SBjoern A. Zeeb * for this regulatory domain (valid only in 6 Ghz). 287bfcc09ddSBjoern A. Zeeb * @disable_11ax: 11ax is forbidden for this regulatory domain. 2889af1bba4SBjoern A. Zeeb * @disable_11be: 11be is forbidden for this regulatory domain. 289bfcc09ddSBjoern A. Zeeb */ 290bfcc09ddSBjoern A. Zeeb struct iwl_reg_capa { 2919af1bba4SBjoern A. Zeeb bool allow_40mhz; 2929af1bba4SBjoern A. Zeeb bool allow_80mhz; 2939af1bba4SBjoern A. Zeeb bool allow_160mhz; 2949af1bba4SBjoern A. Zeeb bool allow_320mhz; 2959af1bba4SBjoern A. Zeeb bool disable_11ax; 2969af1bba4SBjoern A. Zeeb bool disable_11be; 297bfcc09ddSBjoern A. Zeeb }; 298bfcc09ddSBjoern A. Zeeb 299bfcc09ddSBjoern A. Zeeb static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, 300bfcc09ddSBjoern A. Zeeb int chan, u32 flags) 301bfcc09ddSBjoern A. Zeeb { 302bfcc09ddSBjoern A. Zeeb #define CHECK_AND_PRINT_I(x) \ 303bfcc09ddSBjoern A. Zeeb ((flags & NVM_CHANNEL_##x) ? " " #x : "") 304bfcc09ddSBjoern A. Zeeb 305bfcc09ddSBjoern A. Zeeb if (!(flags & NVM_CHANNEL_VALID)) { 306bfcc09ddSBjoern A. Zeeb IWL_DEBUG_DEV(dev, level, "Ch. %d: 0x%x: No traffic\n", 307bfcc09ddSBjoern A. Zeeb chan, flags); 308bfcc09ddSBjoern A. Zeeb return; 309bfcc09ddSBjoern A. Zeeb } 310bfcc09ddSBjoern A. Zeeb 311bfcc09ddSBjoern A. Zeeb /* Note: already can print up to 101 characters, 110 is the limit! */ 312bfcc09ddSBjoern A. Zeeb IWL_DEBUG_DEV(dev, level, 313*a4128aadSBjoern A. Zeeb "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", 314bfcc09ddSBjoern A. Zeeb chan, flags, 315bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(VALID), 316bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(IBSS), 317bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(ACTIVE), 318bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(RADAR), 319bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(INDOOR_ONLY), 320bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(GO_CONCURRENT), 321bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(UNIFORM), 322bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(20MHZ), 323bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(40MHZ), 324bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(80MHZ), 325bfcc09ddSBjoern A. Zeeb CHECK_AND_PRINT_I(160MHZ), 326*a4128aadSBjoern A. Zeeb CHECK_AND_PRINT_I(DC_HIGH), 327*a4128aadSBjoern A. Zeeb CHECK_AND_PRINT_I(VLP), 328*a4128aadSBjoern A. Zeeb CHECK_AND_PRINT_I(AFC)); 329bfcc09ddSBjoern A. Zeeb #undef CHECK_AND_PRINT_I 330bfcc09ddSBjoern A. Zeeb } 331bfcc09ddSBjoern A. Zeeb 332bfcc09ddSBjoern A. Zeeb static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, 333bfcc09ddSBjoern A. Zeeb u32 nvm_flags, const struct iwl_cfg *cfg) 334bfcc09ddSBjoern A. Zeeb { 335bfcc09ddSBjoern A. Zeeb u32 flags = IEEE80211_CHAN_NO_HT40; 336bfcc09ddSBjoern A. Zeeb 337bfcc09ddSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ && (nvm_flags & NVM_CHANNEL_40MHZ)) { 338bfcc09ddSBjoern A. Zeeb if (ch_num <= LAST_2GHZ_HT_PLUS) 339bfcc09ddSBjoern A. Zeeb flags &= ~IEEE80211_CHAN_NO_HT40PLUS; 340bfcc09ddSBjoern A. Zeeb if (ch_num >= FIRST_2GHZ_HT_MINUS) 341bfcc09ddSBjoern A. Zeeb flags &= ~IEEE80211_CHAN_NO_HT40MINUS; 342bfcc09ddSBjoern A. Zeeb } else if (nvm_flags & NVM_CHANNEL_40MHZ) { 343bfcc09ddSBjoern A. Zeeb if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) 344bfcc09ddSBjoern A. Zeeb flags &= ~IEEE80211_CHAN_NO_HT40PLUS; 345bfcc09ddSBjoern A. Zeeb else 346bfcc09ddSBjoern A. Zeeb flags &= ~IEEE80211_CHAN_NO_HT40MINUS; 347bfcc09ddSBjoern A. Zeeb } 348bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_80MHZ)) 349bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_80MHZ; 350bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_160MHZ)) 351bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_160MHZ; 352bfcc09ddSBjoern A. Zeeb 353bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_IBSS)) 354bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_IR; 355bfcc09ddSBjoern A. Zeeb 356bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) 357bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_IR; 358bfcc09ddSBjoern A. Zeeb 359bfcc09ddSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_RADAR) 360bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_RADAR; 361bfcc09ddSBjoern A. Zeeb 362bfcc09ddSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) 363bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_INDOOR_ONLY; 364bfcc09ddSBjoern A. Zeeb 365bfcc09ddSBjoern A. Zeeb /* Set the GO concurrent flag only in case that NO_IR is set. 366bfcc09ddSBjoern A. Zeeb * Otherwise it is meaningless 367bfcc09ddSBjoern A. Zeeb */ 368bfcc09ddSBjoern A. Zeeb if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && 369bfcc09ddSBjoern A. Zeeb (flags & IEEE80211_CHAN_NO_IR)) 370bfcc09ddSBjoern A. Zeeb flags |= IEEE80211_CHAN_IR_CONCURRENT; 371bfcc09ddSBjoern A. Zeeb 372*a4128aadSBjoern A. Zeeb /* Set the AP type for the UHB case. */ 373*a4128aadSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_VLP) 374*a4128aadSBjoern A. Zeeb flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP; 375*a4128aadSBjoern A. Zeeb else 376*a4128aadSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT; 377*a4128aadSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_AFC)) 378*a4128aadSBjoern A. Zeeb flags |= IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT; 379*a4128aadSBjoern A. Zeeb 380bfcc09ddSBjoern A. Zeeb return flags; 381bfcc09ddSBjoern A. Zeeb } 382bfcc09ddSBjoern A. Zeeb 383bfcc09ddSBjoern A. Zeeb static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx) 384bfcc09ddSBjoern A. Zeeb { 385bfcc09ddSBjoern A. Zeeb if (ch_idx >= NUM_2GHZ_CHANNELS + NUM_5GHZ_CHANNELS) { 386bfcc09ddSBjoern A. Zeeb return NL80211_BAND_6GHZ; 387bfcc09ddSBjoern A. Zeeb } 388bfcc09ddSBjoern A. Zeeb 389bfcc09ddSBjoern A. Zeeb if (ch_idx >= NUM_2GHZ_CHANNELS) 390bfcc09ddSBjoern A. Zeeb return NL80211_BAND_5GHZ; 391bfcc09ddSBjoern A. Zeeb return NL80211_BAND_2GHZ; 392bfcc09ddSBjoern A. Zeeb } 393bfcc09ddSBjoern A. Zeeb 394*a4128aadSBjoern A. Zeeb static int iwl_init_channel_map(struct iwl_trans *trans, 395*a4128aadSBjoern A. Zeeb const struct iwl_fw *fw, 396bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 397bfcc09ddSBjoern A. Zeeb const void * const nvm_ch_flags, 398bfcc09ddSBjoern A. Zeeb u32 sbands_flags, bool v4) 399bfcc09ddSBjoern A. Zeeb { 400*a4128aadSBjoern A. Zeeb const struct iwl_cfg *cfg = trans->cfg; 401*a4128aadSBjoern A. Zeeb struct device *dev = trans->dev; 402bfcc09ddSBjoern A. Zeeb int ch_idx; 403bfcc09ddSBjoern A. Zeeb int n_channels = 0; 404bfcc09ddSBjoern A. Zeeb struct ieee80211_channel *channel; 405bfcc09ddSBjoern A. Zeeb u32 ch_flags; 406bfcc09ddSBjoern A. Zeeb int num_of_ch; 407bfcc09ddSBjoern A. Zeeb const u16 *nvm_chan; 408bfcc09ddSBjoern A. Zeeb 409bfcc09ddSBjoern A. Zeeb if (cfg->uhb_supported) { 410bfcc09ddSBjoern A. Zeeb num_of_ch = IWL_NVM_NUM_CHANNELS_UHB; 411bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_uhb_nvm_channels; 412bfcc09ddSBjoern A. Zeeb } else if (cfg->nvm_type == IWL_NVM_EXT) { 413bfcc09ddSBjoern A. Zeeb num_of_ch = IWL_NVM_NUM_CHANNELS_EXT; 414bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_ext_nvm_channels; 415bfcc09ddSBjoern A. Zeeb } else { 416bfcc09ddSBjoern A. Zeeb num_of_ch = IWL_NVM_NUM_CHANNELS; 417bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_nvm_channels; 418bfcc09ddSBjoern A. Zeeb } 419bfcc09ddSBjoern A. Zeeb 420bfcc09ddSBjoern A. Zeeb for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { 421bfcc09ddSBjoern A. Zeeb enum nl80211_band band = 422bfcc09ddSBjoern A. Zeeb iwl_nl80211_band_from_channel_idx(ch_idx); 423bfcc09ddSBjoern A. Zeeb 424bfcc09ddSBjoern A. Zeeb if (v4) 425bfcc09ddSBjoern A. Zeeb ch_flags = 426bfcc09ddSBjoern A. Zeeb __le32_to_cpup((const __le32 *)nvm_ch_flags + ch_idx); 427bfcc09ddSBjoern A. Zeeb else 428bfcc09ddSBjoern A. Zeeb ch_flags = 429bfcc09ddSBjoern A. Zeeb __le16_to_cpup((const __le16 *)nvm_ch_flags + ch_idx); 430bfcc09ddSBjoern A. Zeeb 431bfcc09ddSBjoern A. Zeeb if (band == NL80211_BAND_5GHZ && 432bfcc09ddSBjoern A. Zeeb !data->sku_cap_band_52ghz_enable) 433bfcc09ddSBjoern A. Zeeb continue; 434bfcc09ddSBjoern A. Zeeb 435bfcc09ddSBjoern A. Zeeb /* workaround to disable wide channels in 5GHz */ 436bfcc09ddSBjoern A. Zeeb if ((sbands_flags & IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ) && 437bfcc09ddSBjoern A. Zeeb band == NL80211_BAND_5GHZ) { 438bfcc09ddSBjoern A. Zeeb ch_flags &= ~(NVM_CHANNEL_40MHZ | 439bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_80MHZ | 440bfcc09ddSBjoern A. Zeeb NVM_CHANNEL_160MHZ); 441bfcc09ddSBjoern A. Zeeb } 442bfcc09ddSBjoern A. Zeeb 443bfcc09ddSBjoern A. Zeeb if (ch_flags & NVM_CHANNEL_160MHZ) 444bfcc09ddSBjoern A. Zeeb data->vht160_supported = true; 445bfcc09ddSBjoern A. Zeeb 446bfcc09ddSBjoern A. Zeeb if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR) && 447bfcc09ddSBjoern A. Zeeb !(ch_flags & NVM_CHANNEL_VALID)) { 448bfcc09ddSBjoern A. Zeeb /* 449bfcc09ddSBjoern A. Zeeb * Channels might become valid later if lar is 450bfcc09ddSBjoern A. Zeeb * supported, hence we still want to add them to 451bfcc09ddSBjoern A. Zeeb * the list of supported channels to cfg80211. 452bfcc09ddSBjoern A. Zeeb */ 453bfcc09ddSBjoern A. Zeeb iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, 454bfcc09ddSBjoern A. Zeeb nvm_chan[ch_idx], ch_flags); 455bfcc09ddSBjoern A. Zeeb continue; 456bfcc09ddSBjoern A. Zeeb } 457bfcc09ddSBjoern A. Zeeb 458bfcc09ddSBjoern A. Zeeb channel = &data->channels[n_channels]; 459bfcc09ddSBjoern A. Zeeb n_channels++; 460bfcc09ddSBjoern A. Zeeb 461bfcc09ddSBjoern A. Zeeb channel->hw_value = nvm_chan[ch_idx]; 462bfcc09ddSBjoern A. Zeeb channel->band = band; 463bfcc09ddSBjoern A. Zeeb channel->center_freq = 464bfcc09ddSBjoern A. Zeeb ieee80211_channel_to_frequency( 465bfcc09ddSBjoern A. Zeeb channel->hw_value, channel->band); 466bfcc09ddSBjoern A. Zeeb 467bfcc09ddSBjoern A. Zeeb /* Initialize regulatory-based run-time data */ 468bfcc09ddSBjoern A. Zeeb 469bfcc09ddSBjoern A. Zeeb /* 470bfcc09ddSBjoern A. Zeeb * Default value - highest tx power value. max_power 471bfcc09ddSBjoern A. Zeeb * is not used in mvm, and is used for backwards compatibility 472bfcc09ddSBjoern A. Zeeb */ 473bfcc09ddSBjoern A. Zeeb channel->max_power = IWL_DEFAULT_MAX_TX_POWER; 474bfcc09ddSBjoern A. Zeeb 475bfcc09ddSBjoern A. Zeeb /* don't put limitations in case we're using LAR */ 476bfcc09ddSBjoern A. Zeeb if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR)) 477bfcc09ddSBjoern A. Zeeb channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], 478bfcc09ddSBjoern A. Zeeb ch_idx, band, 479bfcc09ddSBjoern A. Zeeb ch_flags, cfg); 480bfcc09ddSBjoern A. Zeeb else 481bfcc09ddSBjoern A. Zeeb channel->flags = 0; 482bfcc09ddSBjoern A. Zeeb 483*a4128aadSBjoern A. Zeeb if (fw_has_capa(&fw->ucode_capa, 484*a4128aadSBjoern A. Zeeb IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS)) 485*a4128aadSBjoern A. Zeeb channel->flags |= IEEE80211_CHAN_CAN_MONITOR; 486*a4128aadSBjoern A. Zeeb 487bfcc09ddSBjoern A. Zeeb iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, 488bfcc09ddSBjoern A. Zeeb channel->hw_value, ch_flags); 489bfcc09ddSBjoern A. Zeeb IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n", 490bfcc09ddSBjoern A. Zeeb channel->hw_value, channel->max_power); 491bfcc09ddSBjoern A. Zeeb } 492bfcc09ddSBjoern A. Zeeb 493bfcc09ddSBjoern A. Zeeb return n_channels; 494bfcc09ddSBjoern A. Zeeb } 495bfcc09ddSBjoern A. Zeeb 496bfcc09ddSBjoern A. Zeeb static void iwl_init_vht_hw_capab(struct iwl_trans *trans, 497bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 498bfcc09ddSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap, 499bfcc09ddSBjoern A. Zeeb u8 tx_chains, u8 rx_chains) 500bfcc09ddSBjoern A. Zeeb { 501bfcc09ddSBjoern A. Zeeb const struct iwl_cfg *cfg = trans->cfg; 502bfcc09ddSBjoern A. Zeeb int num_rx_ants = num_of_ant(rx_chains); 503bfcc09ddSBjoern A. Zeeb int num_tx_ants = num_of_ant(tx_chains); 504bfcc09ddSBjoern A. Zeeb 505bfcc09ddSBjoern A. Zeeb vht_cap->vht_supported = true; 506bfcc09ddSBjoern A. Zeeb 507bfcc09ddSBjoern A. Zeeb vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 | 508bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_RXSTBC_1 | 509bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 510bfcc09ddSBjoern A. Zeeb 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | 511bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MAX_AMPDU_1024K << 512bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; 513bfcc09ddSBjoern A. Zeeb 5149af1bba4SBjoern A. Zeeb if (!trans->cfg->ht_params->stbc) 5159af1bba4SBjoern A. Zeeb vht_cap->cap &= ~IEEE80211_VHT_CAP_RXSTBC_MASK; 5169af1bba4SBjoern A. Zeeb 517bfcc09ddSBjoern A. Zeeb if (data->vht160_supported) 518bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | 519bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_160; 520bfcc09ddSBjoern A. Zeeb 521bfcc09ddSBjoern A. Zeeb if (cfg->vht_mu_mimo_supported) 522bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; 523bfcc09ddSBjoern A. Zeeb 524bfcc09ddSBjoern A. Zeeb if (cfg->ht_params->ldpc) 525bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; 526bfcc09ddSBjoern A. Zeeb 527bfcc09ddSBjoern A. Zeeb if (data->sku_cap_mimo_disabled) { 528bfcc09ddSBjoern A. Zeeb num_rx_ants = 1; 529bfcc09ddSBjoern A. Zeeb num_tx_ants = 1; 530bfcc09ddSBjoern A. Zeeb } 531bfcc09ddSBjoern A. Zeeb 5329af1bba4SBjoern A. Zeeb if (trans->cfg->ht_params->stbc && num_tx_ants > 1) 533bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 534bfcc09ddSBjoern A. Zeeb else 535bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; 536bfcc09ddSBjoern A. Zeeb 537bfcc09ddSBjoern A. Zeeb switch (iwlwifi_mod_params.amsdu_size) { 538bfcc09ddSBjoern A. Zeeb case IWL_AMSDU_DEF: 539bfcc09ddSBjoern A. Zeeb if (trans->trans_cfg->mq_rx_supported) 540bfcc09ddSBjoern A. Zeeb vht_cap->cap |= 541bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; 542bfcc09ddSBjoern A. Zeeb else 543bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; 544bfcc09ddSBjoern A. Zeeb break; 545bfcc09ddSBjoern A. Zeeb case IWL_AMSDU_2K: 546bfcc09ddSBjoern A. Zeeb if (trans->trans_cfg->mq_rx_supported) 547bfcc09ddSBjoern A. Zeeb vht_cap->cap |= 548bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; 549bfcc09ddSBjoern A. Zeeb else 550bfcc09ddSBjoern A. Zeeb WARN(1, "RB size of 2K is not supported by this device\n"); 551bfcc09ddSBjoern A. Zeeb break; 552bfcc09ddSBjoern A. Zeeb case IWL_AMSDU_4K: 553bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; 554bfcc09ddSBjoern A. Zeeb break; 555bfcc09ddSBjoern A. Zeeb case IWL_AMSDU_8K: 556bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; 557bfcc09ddSBjoern A. Zeeb break; 558bfcc09ddSBjoern A. Zeeb case IWL_AMSDU_12K: 559bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; 560bfcc09ddSBjoern A. Zeeb break; 561bfcc09ddSBjoern A. Zeeb default: 562bfcc09ddSBjoern A. Zeeb break; 563bfcc09ddSBjoern A. Zeeb } 564bfcc09ddSBjoern A. Zeeb 565bfcc09ddSBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map = 566bfcc09ddSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | 567bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | 568bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | 569bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | 570bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | 571bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | 572bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | 573bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); 574bfcc09ddSBjoern A. Zeeb 575bfcc09ddSBjoern A. Zeeb if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) { 576bfcc09ddSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 577bfcc09ddSBjoern A. Zeeb /* this works because NOT_SUPPORTED == 3 */ 578bfcc09ddSBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map |= 579bfcc09ddSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); 580bfcc09ddSBjoern A. Zeeb } 581bfcc09ddSBjoern A. Zeeb 582bfcc09ddSBjoern A. Zeeb vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; 583bfcc09ddSBjoern A. Zeeb 584bfcc09ddSBjoern A. Zeeb vht_cap->vht_mcs.tx_highest |= 585bfcc09ddSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 586bfcc09ddSBjoern A. Zeeb } 587bfcc09ddSBjoern A. Zeeb 588bfcc09ddSBjoern A. Zeeb static const u8 iwl_vendor_caps[] = { 589bfcc09ddSBjoern A. Zeeb 0xdd, /* vendor element */ 590bfcc09ddSBjoern A. Zeeb 0x06, /* length */ 591bfcc09ddSBjoern A. Zeeb 0x00, 0x17, 0x35, /* Intel OUI */ 592bfcc09ddSBjoern A. Zeeb 0x08, /* type (Intel Capabilities) */ 593bfcc09ddSBjoern A. Zeeb /* followed by 16 bits of capabilities */ 594bfcc09ddSBjoern A. Zeeb #define IWL_VENDOR_CAP_IMPROVED_BF_FDBK_HE BIT(0) 595bfcc09ddSBjoern A. Zeeb IWL_VENDOR_CAP_IMPROVED_BF_FDBK_HE, 596bfcc09ddSBjoern A. Zeeb 0x00 597bfcc09ddSBjoern A. Zeeb }; 598bfcc09ddSBjoern A. Zeeb 5999af1bba4SBjoern A. Zeeb static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { 600bfcc09ddSBjoern A. Zeeb { 601*a4128aadSBjoern A. Zeeb .types_mask = BIT(NL80211_IFTYPE_STATION) | 602*a4128aadSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT), 603bfcc09ddSBjoern A. Zeeb .he_cap = { 604bfcc09ddSBjoern A. Zeeb .has_he = true, 605bfcc09ddSBjoern A. Zeeb .he_cap_elem = { 606bfcc09ddSBjoern A. Zeeb .mac_cap_info[0] = 607fac1f593SBjoern A. Zeeb IEEE80211_HE_MAC_CAP0_HTC_HE, 608bfcc09ddSBjoern A. Zeeb .mac_cap_info[1] = 609bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | 610bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 611bfcc09ddSBjoern A. Zeeb .mac_cap_info[2] = 612bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, 613bfcc09ddSBjoern A. Zeeb .mac_cap_info[3] = 614bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_OMI_CONTROL | 615bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS, 616bfcc09ddSBjoern A. Zeeb .mac_cap_info[4] = 617bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | 618bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, 619bfcc09ddSBjoern A. Zeeb .mac_cap_info[5] = 620bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | 621bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | 622bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | 623bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS | 624bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, 625bfcc09ddSBjoern A. Zeeb .phy_cap_info[1] = 626bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | 627bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | 628bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, 629bfcc09ddSBjoern A. Zeeb .phy_cap_info[2] = 630bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | 631bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ, 632bfcc09ddSBjoern A. Zeeb .phy_cap_info[3] = 633d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK | 634bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | 635d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK | 636bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, 637bfcc09ddSBjoern A. Zeeb .phy_cap_info[4] = 638bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | 639bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | 640bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, 641bfcc09ddSBjoern A. Zeeb .phy_cap_info[6] = 642bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | 643bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | 644bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, 645bfcc09ddSBjoern A. Zeeb .phy_cap_info[7] = 646bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | 647bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, 648bfcc09ddSBjoern A. Zeeb .phy_cap_info[8] = 649bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | 650bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | 651bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | 652bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | 653bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, 654bfcc09ddSBjoern A. Zeeb .phy_cap_info[9] = 655bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | 656bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | 657d9836fb4SBjoern A. Zeeb (IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED << 658d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS), 659bfcc09ddSBjoern A. Zeeb .phy_cap_info[10] = 660bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF, 661bfcc09ddSBjoern A. Zeeb }, 662bfcc09ddSBjoern A. Zeeb /* 663bfcc09ddSBjoern A. Zeeb * Set default Tx/Rx HE MCS NSS Support field. 664bfcc09ddSBjoern A. Zeeb * Indicate support for up to 2 spatial streams and all 665bfcc09ddSBjoern A. Zeeb * MCS, without any special cases 666bfcc09ddSBjoern A. Zeeb */ 667bfcc09ddSBjoern A. Zeeb .he_mcs_nss_supp = { 668bfcc09ddSBjoern A. Zeeb .rx_mcs_80 = cpu_to_le16(0xfffa), 669bfcc09ddSBjoern A. Zeeb .tx_mcs_80 = cpu_to_le16(0xfffa), 670bfcc09ddSBjoern A. Zeeb .rx_mcs_160 = cpu_to_le16(0xfffa), 671bfcc09ddSBjoern A. Zeeb .tx_mcs_160 = cpu_to_le16(0xfffa), 672bfcc09ddSBjoern A. Zeeb .rx_mcs_80p80 = cpu_to_le16(0xffff), 673bfcc09ddSBjoern A. Zeeb .tx_mcs_80p80 = cpu_to_le16(0xffff), 674bfcc09ddSBjoern A. Zeeb }, 675bfcc09ddSBjoern A. Zeeb /* 676bfcc09ddSBjoern A. Zeeb * Set default PPE thresholds, with PPET16 set to 0, 677bfcc09ddSBjoern A. Zeeb * PPET8 set to 7 678bfcc09ddSBjoern A. Zeeb */ 679bfcc09ddSBjoern A. Zeeb .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, 680bfcc09ddSBjoern A. Zeeb }, 6819af1bba4SBjoern A. Zeeb .eht_cap = { 6829af1bba4SBjoern A. Zeeb .has_eht = true, 6839af1bba4SBjoern A. Zeeb .eht_cap_elem = { 6849af1bba4SBjoern A. Zeeb .mac_cap_info[0] = 6859af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 6869af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | 687*a4128aadSBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 | 688*a4128aadSBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC, 6899af1bba4SBjoern A. Zeeb .phy_cap_info[0] = 6909af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 6919af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | 6929af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 6939af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | 6949af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, 6959af1bba4SBjoern A. Zeeb .phy_cap_info[1] = 6969af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | 6979af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, 6989af1bba4SBjoern A. Zeeb .phy_cap_info[3] = 6999af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 7009af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 7019af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 7029af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 7039af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | 7049af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 7059af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, 7069af1bba4SBjoern A. Zeeb 7079af1bba4SBjoern A. Zeeb .phy_cap_info[4] = 7089af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 7099af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | 7109af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI, 7119af1bba4SBjoern A. Zeeb .phy_cap_info[5] = 712*a4128aadSBjoern A. Zeeb FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, 713*a4128aadSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US) | 7149af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | 7159af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | 716*a4128aadSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP, 7179af1bba4SBjoern A. Zeeb .phy_cap_info[6] = 7189af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 7199af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, 7209af1bba4SBjoern A. Zeeb .phy_cap_info[8] = 7219af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA | 7229af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA, 7239af1bba4SBjoern A. Zeeb }, 7249af1bba4SBjoern A. Zeeb 7259af1bba4SBjoern A. Zeeb /* For all MCS and bandwidth, set 2 NSS for both Tx and 7269af1bba4SBjoern A. Zeeb * Rx - note we don't set the only_20mhz, but due to this 7279af1bba4SBjoern A. Zeeb * being a union, it gets set correctly anyway. 7289af1bba4SBjoern A. Zeeb */ 7299af1bba4SBjoern A. Zeeb .eht_mcs_nss_supp = { 7309af1bba4SBjoern A. Zeeb .bw._80 = { 7319af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 7329af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 7339af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 7349af1bba4SBjoern A. Zeeb }, 7359af1bba4SBjoern A. Zeeb .bw._160 = { 7369af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 7379af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 7389af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 7399af1bba4SBjoern A. Zeeb }, 7409af1bba4SBjoern A. Zeeb .bw._320 = { 7419af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 7429af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 7439af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 7449af1bba4SBjoern A. Zeeb }, 7459af1bba4SBjoern A. Zeeb }, 7469af1bba4SBjoern A. Zeeb 7479af1bba4SBjoern A. Zeeb /* 7489af1bba4SBjoern A. Zeeb * PPE thresholds for NSS = 2, and RU index bitmap set 7499af1bba4SBjoern A. Zeeb * to 0xc. 750*a4128aadSBjoern A. Zeeb * Note: just for stating what we want, not present in 751*a4128aadSBjoern A. Zeeb * the transmitted data due to not including 752*a4128aadSBjoern A. Zeeb * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. 7539af1bba4SBjoern A. Zeeb */ 7549af1bba4SBjoern A. Zeeb .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } 7559af1bba4SBjoern A. Zeeb }, 756bfcc09ddSBjoern A. Zeeb }, 757bfcc09ddSBjoern A. Zeeb { 758*a4128aadSBjoern A. Zeeb .types_mask = BIT(NL80211_IFTYPE_AP) | 759*a4128aadSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO), 760bfcc09ddSBjoern A. Zeeb .he_cap = { 761bfcc09ddSBjoern A. Zeeb .has_he = true, 762bfcc09ddSBjoern A. Zeeb .he_cap_elem = { 763bfcc09ddSBjoern A. Zeeb .mac_cap_info[0] = 764bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP0_HTC_HE, 765bfcc09ddSBjoern A. Zeeb .mac_cap_info[1] = 766bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, 767bfcc09ddSBjoern A. Zeeb .mac_cap_info[3] = 768bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_OMI_CONTROL, 769bfcc09ddSBjoern A. Zeeb .phy_cap_info[1] = 770bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, 771bfcc09ddSBjoern A. Zeeb .phy_cap_info[2] = 772bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | 773bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, 774bfcc09ddSBjoern A. Zeeb .phy_cap_info[3] = 775d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_BPSK | 776bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | 777d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_BPSK | 778bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, 779bfcc09ddSBjoern A. Zeeb .phy_cap_info[6] = 780bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, 781bfcc09ddSBjoern A. Zeeb .phy_cap_info[7] = 782bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, 783bfcc09ddSBjoern A. Zeeb .phy_cap_info[8] = 784bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | 785bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, 786bfcc09ddSBjoern A. Zeeb .phy_cap_info[9] = 787d9836fb4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED 788d9836fb4SBjoern A. Zeeb << IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS, 789bfcc09ddSBjoern A. Zeeb }, 790bfcc09ddSBjoern A. Zeeb /* 791bfcc09ddSBjoern A. Zeeb * Set default Tx/Rx HE MCS NSS Support field. 792bfcc09ddSBjoern A. Zeeb * Indicate support for up to 2 spatial streams and all 793bfcc09ddSBjoern A. Zeeb * MCS, without any special cases 794bfcc09ddSBjoern A. Zeeb */ 795bfcc09ddSBjoern A. Zeeb .he_mcs_nss_supp = { 796bfcc09ddSBjoern A. Zeeb .rx_mcs_80 = cpu_to_le16(0xfffa), 797bfcc09ddSBjoern A. Zeeb .tx_mcs_80 = cpu_to_le16(0xfffa), 798bfcc09ddSBjoern A. Zeeb .rx_mcs_160 = cpu_to_le16(0xfffa), 799bfcc09ddSBjoern A. Zeeb .tx_mcs_160 = cpu_to_le16(0xfffa), 800bfcc09ddSBjoern A. Zeeb .rx_mcs_80p80 = cpu_to_le16(0xffff), 801bfcc09ddSBjoern A. Zeeb .tx_mcs_80p80 = cpu_to_le16(0xffff), 802bfcc09ddSBjoern A. Zeeb }, 803bfcc09ddSBjoern A. Zeeb /* 804bfcc09ddSBjoern A. Zeeb * Set default PPE thresholds, with PPET16 set to 0, 805bfcc09ddSBjoern A. Zeeb * PPET8 set to 7 806bfcc09ddSBjoern A. Zeeb */ 807bfcc09ddSBjoern A. Zeeb .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, 808bfcc09ddSBjoern A. Zeeb }, 8099af1bba4SBjoern A. Zeeb .eht_cap = { 8109af1bba4SBjoern A. Zeeb .has_eht = true, 8119af1bba4SBjoern A. Zeeb .eht_cap_elem = { 8129af1bba4SBjoern A. Zeeb .mac_cap_info[0] = 8139af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_OM_CONTROL | 8149af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | 8159af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, 8169af1bba4SBjoern A. Zeeb .phy_cap_info[0] = 8179af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | 8189af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI, 8199af1bba4SBjoern A. Zeeb .phy_cap_info[5] = 820*a4128aadSBjoern A. Zeeb FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, 821*a4128aadSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US), 8229af1bba4SBjoern A. Zeeb }, 8239af1bba4SBjoern A. Zeeb 8249af1bba4SBjoern A. Zeeb /* For all MCS and bandwidth, set 2 NSS for both Tx and 8259af1bba4SBjoern A. Zeeb * Rx - note we don't set the only_20mhz, but due to this 8269af1bba4SBjoern A. Zeeb * being a union, it gets set correctly anyway. 8279af1bba4SBjoern A. Zeeb */ 8289af1bba4SBjoern A. Zeeb .eht_mcs_nss_supp = { 8299af1bba4SBjoern A. Zeeb .bw._80 = { 8309af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 8319af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 8329af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 8339af1bba4SBjoern A. Zeeb }, 8349af1bba4SBjoern A. Zeeb .bw._160 = { 8359af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 8369af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 8379af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 8389af1bba4SBjoern A. Zeeb }, 8399af1bba4SBjoern A. Zeeb .bw._320 = { 8409af1bba4SBjoern A. Zeeb .rx_tx_mcs9_max_nss = 0x22, 8419af1bba4SBjoern A. Zeeb .rx_tx_mcs11_max_nss = 0x22, 8429af1bba4SBjoern A. Zeeb .rx_tx_mcs13_max_nss = 0x22, 8439af1bba4SBjoern A. Zeeb }, 8449af1bba4SBjoern A. Zeeb }, 8459af1bba4SBjoern A. Zeeb 8469af1bba4SBjoern A. Zeeb /* 8479af1bba4SBjoern A. Zeeb * PPE thresholds for NSS = 2, and RU index bitmap set 8489af1bba4SBjoern A. Zeeb * to 0xc. 849*a4128aadSBjoern A. Zeeb * Note: just for stating what we want, not present in 850*a4128aadSBjoern A. Zeeb * the transmitted data due to not including 851*a4128aadSBjoern A. Zeeb * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. 8529af1bba4SBjoern A. Zeeb */ 8539af1bba4SBjoern A. Zeeb .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } 8549af1bba4SBjoern A. Zeeb }, 855bfcc09ddSBjoern A. Zeeb }, 856bfcc09ddSBjoern A. Zeeb }; 857bfcc09ddSBjoern A. Zeeb 858bfcc09ddSBjoern A. Zeeb static void iwl_init_he_6ghz_capa(struct iwl_trans *trans, 859bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 860bfcc09ddSBjoern A. Zeeb struct ieee80211_supported_band *sband, 861bfcc09ddSBjoern A. Zeeb u8 tx_chains, u8 rx_chains) 862bfcc09ddSBjoern A. Zeeb { 863bfcc09ddSBjoern A. Zeeb struct ieee80211_sta_ht_cap ht_cap; 864bfcc09ddSBjoern A. Zeeb struct ieee80211_sta_vht_cap vht_cap = {}; 865bfcc09ddSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data; 866bfcc09ddSBjoern A. Zeeb u16 he_6ghz_capa = 0; 867bfcc09ddSBjoern A. Zeeb u32 exp; 868bfcc09ddSBjoern A. Zeeb int i; 869bfcc09ddSBjoern A. Zeeb 870bfcc09ddSBjoern A. Zeeb if (sband->band != NL80211_BAND_6GHZ) 871bfcc09ddSBjoern A. Zeeb return; 872bfcc09ddSBjoern A. Zeeb 873bfcc09ddSBjoern A. Zeeb /* grab HT/VHT capabilities and calculate HE 6 GHz capabilities */ 874bfcc09ddSBjoern A. Zeeb iwl_init_ht_hw_capab(trans, data, &ht_cap, NL80211_BAND_5GHZ, 875bfcc09ddSBjoern A. Zeeb tx_chains, rx_chains); 876bfcc09ddSBjoern A. Zeeb WARN_ON(!ht_cap.ht_supported); 877bfcc09ddSBjoern A. Zeeb iwl_init_vht_hw_capab(trans, data, &vht_cap, tx_chains, rx_chains); 878bfcc09ddSBjoern A. Zeeb WARN_ON(!vht_cap.vht_supported); 879bfcc09ddSBjoern A. Zeeb 880bfcc09ddSBjoern A. Zeeb he_6ghz_capa |= 881bfcc09ddSBjoern A. Zeeb u16_encode_bits(ht_cap.ampdu_density, 882bfcc09ddSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); 883bfcc09ddSBjoern A. Zeeb exp = u32_get_bits(vht_cap.cap, 884bfcc09ddSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); 885bfcc09ddSBjoern A. Zeeb he_6ghz_capa |= 886bfcc09ddSBjoern A. Zeeb u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); 887bfcc09ddSBjoern A. Zeeb exp = u32_get_bits(vht_cap.cap, IEEE80211_VHT_CAP_MAX_MPDU_MASK); 888bfcc09ddSBjoern A. Zeeb he_6ghz_capa |= 889bfcc09ddSBjoern A. Zeeb u16_encode_bits(exp, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); 890bfcc09ddSBjoern A. Zeeb /* we don't support extended_ht_cap_info anywhere, so no RD_RESPONDER */ 891bfcc09ddSBjoern A. Zeeb if (vht_cap.cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN) 892bfcc09ddSBjoern A. Zeeb he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS; 893bfcc09ddSBjoern A. Zeeb if (vht_cap.cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN) 894bfcc09ddSBjoern A. Zeeb he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; 895bfcc09ddSBjoern A. Zeeb 896bfcc09ddSBjoern A. Zeeb IWL_DEBUG_EEPROM(trans->dev, "he_6ghz_capa=0x%x\n", he_6ghz_capa); 897bfcc09ddSBjoern A. Zeeb 898bfcc09ddSBjoern A. Zeeb /* we know it's writable - we set it before ourselves */ 899d9836fb4SBjoern A. Zeeb iftype_data = (void *)(uintptr_t)sband->iftype_data; 900bfcc09ddSBjoern A. Zeeb for (i = 0; i < sband->n_iftype_data; i++) 901bfcc09ddSBjoern A. Zeeb iftype_data[i].he_6ghz_capa.capa = cpu_to_le16(he_6ghz_capa); 902bfcc09ddSBjoern A. Zeeb } 903bfcc09ddSBjoern A. Zeeb 904bfcc09ddSBjoern A. Zeeb static void 905bfcc09ddSBjoern A. Zeeb iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, 9069af1bba4SBjoern A. Zeeb struct iwl_nvm_data *data, 907bfcc09ddSBjoern A. Zeeb struct ieee80211_supported_band *sband, 908bfcc09ddSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data, 909bfcc09ddSBjoern A. Zeeb u8 tx_chains, u8 rx_chains, 910bfcc09ddSBjoern A. Zeeb const struct iwl_fw *fw) 911bfcc09ddSBjoern A. Zeeb { 912*a4128aadSBjoern A. Zeeb bool is_ap = iftype_data->types_mask & (BIT(NL80211_IFTYPE_AP) | 913*a4128aadSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO)); 9149af1bba4SBjoern A. Zeeb bool no_320; 9159af1bba4SBjoern A. Zeeb 916*a4128aadSBjoern A. Zeeb no_320 = (!trans->trans_cfg->integrated && 917*a4128aadSBjoern A. Zeeb trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB) || 918*a4128aadSBjoern A. Zeeb trans->reduced_cap_sku; 9199af1bba4SBjoern A. Zeeb 9209af1bba4SBjoern A. Zeeb if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) 9219af1bba4SBjoern A. Zeeb iftype_data->eht_cap.has_eht = false; 922bfcc09ddSBjoern A. Zeeb 923bfcc09ddSBjoern A. Zeeb /* Advertise an A-MPDU exponent extension based on 924bfcc09ddSBjoern A. Zeeb * operating band 925bfcc09ddSBjoern A. Zeeb */ 9269af1bba4SBjoern A. Zeeb if (sband->band == NL80211_BAND_6GHZ && iftype_data->eht_cap.has_eht) 9279af1bba4SBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= 9289af1bba4SBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2; 9299af1bba4SBjoern A. Zeeb else if (sband->band != NL80211_BAND_2GHZ) 930bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= 931bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1; 932bfcc09ddSBjoern A. Zeeb else 933bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.mac_cap_info[3] |= 934bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; 935bfcc09ddSBjoern A. Zeeb 9369af1bba4SBjoern A. Zeeb switch (sband->band) { 9379af1bba4SBjoern A. Zeeb case NL80211_BAND_2GHZ: 938bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= 9399af1bba4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; 9409af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] |= 9419af1bba4SBjoern A. Zeeb u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, 9429af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); 9439af1bba4SBjoern A. Zeeb break; 9449af1bba4SBjoern A. Zeeb case NL80211_BAND_6GHZ: 9459af1bba4SBjoern A. Zeeb if (!no_320) { 9469af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[0] |= 9479af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; 9489af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[1] |= 9499af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK; 9509af1bba4SBjoern A. Zeeb } 9519af1bba4SBjoern A. Zeeb fallthrough; 9529af1bba4SBjoern A. Zeeb case NL80211_BAND_5GHZ: 9539af1bba4SBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= 9549af1bba4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 955bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 9569af1bba4SBjoern A. Zeeb break; 9579af1bba4SBjoern A. Zeeb default: 9589af1bba4SBjoern A. Zeeb WARN_ON(1); 9599af1bba4SBjoern A. Zeeb break; 9609af1bba4SBjoern A. Zeeb } 961bfcc09ddSBjoern A. Zeeb 962bfcc09ddSBjoern A. Zeeb if ((tx_chains & rx_chains) == ANT_AB) { 963bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= 964bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ; 965bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[5] |= 966bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | 967bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2; 9689af1bba4SBjoern A. Zeeb if (!is_ap) { 969bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= 970bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_MAX_NC_2; 9719af1bba4SBjoern A. Zeeb 9729af1bba4SBjoern A. Zeeb if (iftype_data->eht_cap.has_eht) { 9739af1bba4SBjoern A. Zeeb /* 9749af1bba4SBjoern A. Zeeb * Set the number of sounding dimensions for each 9759af1bba4SBjoern A. Zeeb * bandwidth to 1 to indicate the maximal supported 9769af1bba4SBjoern A. Zeeb * value of TXVECTOR parameter NUM_STS of 2 9779af1bba4SBjoern A. Zeeb */ 9789af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] |= 0x49; 9799af1bba4SBjoern A. Zeeb 9809af1bba4SBjoern A. Zeeb /* 9819af1bba4SBjoern A. Zeeb * Set the MAX NC to 1 to indicate sounding feedback of 9829af1bba4SBjoern A. Zeeb * 2 supported by the beamfomee. 9839af1bba4SBjoern A. Zeeb */ 9849af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] |= 0x10; 9859af1bba4SBjoern A. Zeeb } 9869af1bba4SBjoern A. Zeeb } 9879af1bba4SBjoern A. Zeeb } else { 988*a4128aadSBjoern A. Zeeb struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp = 989*a4128aadSBjoern A. Zeeb &iftype_data->he_cap.he_mcs_nss_supp; 990*a4128aadSBjoern A. Zeeb 9919af1bba4SBjoern A. Zeeb if (iftype_data->eht_cap.has_eht) { 9929af1bba4SBjoern A. Zeeb struct ieee80211_eht_mcs_nss_supp *mcs_nss = 9939af1bba4SBjoern A. Zeeb &iftype_data->eht_cap.eht_mcs_nss_supp; 9949af1bba4SBjoern A. Zeeb 9959af1bba4SBjoern A. Zeeb memset(mcs_nss, 0x11, sizeof(*mcs_nss)); 9969af1bba4SBjoern A. Zeeb } 9979af1bba4SBjoern A. Zeeb 9989af1bba4SBjoern A. Zeeb if (!is_ap) { 999bfcc09ddSBjoern A. Zeeb /* If not 2x2, we need to indicate 1x1 in the 1000bfcc09ddSBjoern A. Zeeb * Midamble RX Max NSTS - but not for AP mode 1001bfcc09ddSBjoern A. Zeeb */ 1002bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &= 1003bfcc09ddSBjoern A. Zeeb ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; 1004bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= 1005bfcc09ddSBjoern A. Zeeb ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; 1006bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= 1007bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_MAX_NC_1; 1008bfcc09ddSBjoern A. Zeeb } 1009*a4128aadSBjoern A. Zeeb 1010*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->rx_mcs_80 |= 1011*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 1012*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->tx_mcs_80 |= 1013*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 1014*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->rx_mcs_160 |= 1015*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 1016*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->tx_mcs_160 |= 1017*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 1018*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->rx_mcs_80p80 |= 1019*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 1020*a4128aadSBjoern A. Zeeb he_mcs_nss_supp->tx_mcs_80p80 |= 1021*a4128aadSBjoern A. Zeeb cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); 10229af1bba4SBjoern A. Zeeb } 10239af1bba4SBjoern A. Zeeb 10249af1bba4SBjoern A. Zeeb if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210 && !is_ap) 10259af1bba4SBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= 10269af1bba4SBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; 1027bfcc09ddSBjoern A. Zeeb 1028bfcc09ddSBjoern A. Zeeb switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { 1029bfcc09ddSBjoern A. Zeeb case IWL_CFG_RF_TYPE_GF: 1030*a4128aadSBjoern A. Zeeb case IWL_CFG_RF_TYPE_FM: 1031*a4128aadSBjoern A. Zeeb case IWL_CFG_RF_TYPE_WH: 1032bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= 1033bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; 1034bfcc09ddSBjoern A. Zeeb if (!is_ap) 1035bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= 1036bfcc09ddSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; 1037bfcc09ddSBjoern A. Zeeb break; 1038bfcc09ddSBjoern A. Zeeb } 1039bfcc09ddSBjoern A. Zeeb 10409af1bba4SBjoern A. Zeeb if (CSR_HW_REV_TYPE(trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && 10419af1bba4SBjoern A. Zeeb iftype_data->eht_cap.has_eht) { 10429af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] &= 1043*a4128aadSBjoern A. Zeeb ~(IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | 10449af1bba4SBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2); 10459af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[3] &= 10469af1bba4SBjoern A. Zeeb ~(IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | 10479af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | 10489af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | 10499af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | 10509af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | 1051*a4128aadSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | 1052*a4128aadSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK); 10539af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] &= 10549af1bba4SBjoern A. Zeeb ~(IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | 10559af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP); 10569af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] &= 10579af1bba4SBjoern A. Zeeb ~IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK; 10589af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[6] &= 10599af1bba4SBjoern A. Zeeb ~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | 10609af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP); 10619af1bba4SBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] |= 10629af1bba4SBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF; 10639af1bba4SBjoern A. Zeeb } 10649af1bba4SBjoern A. Zeeb 1065bfcc09ddSBjoern A. Zeeb if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) 1066bfcc09ddSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |= 1067bfcc09ddSBjoern A. Zeeb IEEE80211_HE_MAC_CAP2_BCAST_TWT; 1068bfcc09ddSBjoern A. Zeeb 1069bfcc09ddSBjoern A. Zeeb if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000 && 1070bfcc09ddSBjoern A. Zeeb !is_ap) { 1071bfcc09ddSBjoern A. Zeeb iftype_data->vendor_elems.data = iwl_vendor_caps; 1072bfcc09ddSBjoern A. Zeeb iftype_data->vendor_elems.len = ARRAY_SIZE(iwl_vendor_caps); 1073bfcc09ddSBjoern A. Zeeb } 10749af1bba4SBjoern A. Zeeb 10759af1bba4SBjoern A. Zeeb if (!trans->cfg->ht_params->stbc) { 10769af1bba4SBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= 10779af1bba4SBjoern A. Zeeb ~IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; 10789af1bba4SBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[7] &= 10799af1bba4SBjoern A. Zeeb ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; 10809af1bba4SBjoern A. Zeeb } 1081*a4128aadSBjoern A. Zeeb 1082*a4128aadSBjoern A. Zeeb if (trans->step_urm) { 1083*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs11_max_nss = 0; 1084*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs13_max_nss = 0; 1085*a4128aadSBjoern A. Zeeb } 1086*a4128aadSBjoern A. Zeeb 1087*a4128aadSBjoern A. Zeeb if (trans->no_160) 1088*a4128aadSBjoern A. Zeeb iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &= 1089*a4128aadSBjoern A. Zeeb ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 1090*a4128aadSBjoern A. Zeeb 1091*a4128aadSBjoern A. Zeeb if (trans->reduced_cap_sku) { 1092*a4128aadSBjoern A. Zeeb memset(&iftype_data->eht_cap.eht_mcs_nss_supp.bw._320, 0, 1093*a4128aadSBjoern A. Zeeb sizeof(iftype_data->eht_cap.eht_mcs_nss_supp.bw._320)); 1094*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss = 0; 1095*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_mcs_nss_supp.bw._160.rx_tx_mcs13_max_nss = 0; 1096*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[8] &= 1097*a4128aadSBjoern A. Zeeb ~IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA; 1098*a4128aadSBjoern A. Zeeb iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] &= 1099*a4128aadSBjoern A. Zeeb ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK; 1100*a4128aadSBjoern A. Zeeb } 1101bfcc09ddSBjoern A. Zeeb } 1102bfcc09ddSBjoern A. Zeeb 1103bfcc09ddSBjoern A. Zeeb static void iwl_init_he_hw_capab(struct iwl_trans *trans, 1104bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 1105bfcc09ddSBjoern A. Zeeb struct ieee80211_supported_band *sband, 1106bfcc09ddSBjoern A. Zeeb u8 tx_chains, u8 rx_chains, 1107bfcc09ddSBjoern A. Zeeb const struct iwl_fw *fw) 1108bfcc09ddSBjoern A. Zeeb { 1109bfcc09ddSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data; 1110bfcc09ddSBjoern A. Zeeb int i; 1111bfcc09ddSBjoern A. Zeeb 11129af1bba4SBjoern A. Zeeb BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_eht_capa)); 11139af1bba4SBjoern A. Zeeb BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_eht_capa)); 11149af1bba4SBjoern A. Zeeb BUILD_BUG_ON(sizeof(data->iftd.uhb) != sizeof(iwl_he_eht_capa)); 1115bfcc09ddSBjoern A. Zeeb 1116bfcc09ddSBjoern A. Zeeb switch (sband->band) { 1117bfcc09ddSBjoern A. Zeeb case NL80211_BAND_2GHZ: 1118bfcc09ddSBjoern A. Zeeb iftype_data = data->iftd.low; 1119bfcc09ddSBjoern A. Zeeb break; 1120bfcc09ddSBjoern A. Zeeb case NL80211_BAND_5GHZ: 1121bfcc09ddSBjoern A. Zeeb iftype_data = data->iftd.high; 1122bfcc09ddSBjoern A. Zeeb break; 11239af1bba4SBjoern A. Zeeb case NL80211_BAND_6GHZ: 11249af1bba4SBjoern A. Zeeb iftype_data = data->iftd.uhb; 11259af1bba4SBjoern A. Zeeb break; 1126bfcc09ddSBjoern A. Zeeb default: 1127bfcc09ddSBjoern A. Zeeb WARN_ON(1); 1128bfcc09ddSBjoern A. Zeeb return; 1129bfcc09ddSBjoern A. Zeeb } 1130bfcc09ddSBjoern A. Zeeb 11319af1bba4SBjoern A. Zeeb memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa)); 1132bfcc09ddSBjoern A. Zeeb 1133*a4128aadSBjoern A. Zeeb _ieee80211_set_sband_iftype_data(sband, iftype_data, 1134*a4128aadSBjoern A. Zeeb ARRAY_SIZE(iwl_he_eht_capa)); 1135bfcc09ddSBjoern A. Zeeb 1136bfcc09ddSBjoern A. Zeeb for (i = 0; i < sband->n_iftype_data; i++) 11379af1bba4SBjoern A. Zeeb iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i], 1138bfcc09ddSBjoern A. Zeeb tx_chains, rx_chains, fw); 1139bfcc09ddSBjoern A. Zeeb 1140bfcc09ddSBjoern A. Zeeb iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); 1141bfcc09ddSBjoern A. Zeeb } 1142bfcc09ddSBjoern A. Zeeb 1143*a4128aadSBjoern A. Zeeb void iwl_reinit_cab(struct iwl_trans *trans, struct iwl_nvm_data *data, 1144*a4128aadSBjoern A. Zeeb u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw) 1145*a4128aadSBjoern A. Zeeb { 1146*a4128aadSBjoern A. Zeeb struct ieee80211_supported_band *sband; 1147*a4128aadSBjoern A. Zeeb 1148*a4128aadSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_2GHZ]; 1149*a4128aadSBjoern A. Zeeb iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ, 1150*a4128aadSBjoern A. Zeeb tx_chains, rx_chains); 1151*a4128aadSBjoern A. Zeeb 1152*a4128aadSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1153*a4128aadSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1154*a4128aadSBjoern A. Zeeb fw); 1155*a4128aadSBjoern A. Zeeb 1156*a4128aadSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_5GHZ]; 1157*a4128aadSBjoern A. Zeeb iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ, 1158*a4128aadSBjoern A. Zeeb tx_chains, rx_chains); 1159*a4128aadSBjoern A. Zeeb if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac) 1160*a4128aadSBjoern A. Zeeb iwl_init_vht_hw_capab(trans, data, &sband->vht_cap, 1161*a4128aadSBjoern A. Zeeb tx_chains, rx_chains); 1162*a4128aadSBjoern A. Zeeb 1163*a4128aadSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1164*a4128aadSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1165*a4128aadSBjoern A. Zeeb fw); 1166*a4128aadSBjoern A. Zeeb 1167*a4128aadSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_6GHZ]; 1168*a4128aadSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1169*a4128aadSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1170*a4128aadSBjoern A. Zeeb fw); 1171*a4128aadSBjoern A. Zeeb } 1172*a4128aadSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_reinit_cab); 1173*a4128aadSBjoern A. Zeeb 1174bfcc09ddSBjoern A. Zeeb static void iwl_init_sbands(struct iwl_trans *trans, 1175bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 1176bfcc09ddSBjoern A. Zeeb const void *nvm_ch_flags, u8 tx_chains, 1177bfcc09ddSBjoern A. Zeeb u8 rx_chains, u32 sbands_flags, bool v4, 1178bfcc09ddSBjoern A. Zeeb const struct iwl_fw *fw) 1179bfcc09ddSBjoern A. Zeeb { 1180bfcc09ddSBjoern A. Zeeb struct device *dev = trans->dev; 1181bfcc09ddSBjoern A. Zeeb int n_channels; 1182bfcc09ddSBjoern A. Zeeb int n_used = 0; 1183bfcc09ddSBjoern A. Zeeb struct ieee80211_supported_band *sband; 1184bfcc09ddSBjoern A. Zeeb 1185*a4128aadSBjoern A. Zeeb n_channels = iwl_init_channel_map(trans, fw, data, nvm_ch_flags, 1186bfcc09ddSBjoern A. Zeeb sbands_flags, v4); 1187bfcc09ddSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_2GHZ]; 1188bfcc09ddSBjoern A. Zeeb sband->band = NL80211_BAND_2GHZ; 1189bfcc09ddSBjoern A. Zeeb sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; 1190bfcc09ddSBjoern A. Zeeb sband->n_bitrates = N_RATES_24; 1191bfcc09ddSBjoern A. Zeeb n_used += iwl_init_sband_channels(data, sband, n_channels, 1192bfcc09ddSBjoern A. Zeeb NL80211_BAND_2GHZ); 1193bfcc09ddSBjoern A. Zeeb iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ, 1194bfcc09ddSBjoern A. Zeeb tx_chains, rx_chains); 1195bfcc09ddSBjoern A. Zeeb 1196bfcc09ddSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1197bfcc09ddSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1198bfcc09ddSBjoern A. Zeeb fw); 1199bfcc09ddSBjoern A. Zeeb 1200bfcc09ddSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_5GHZ]; 1201bfcc09ddSBjoern A. Zeeb sband->band = NL80211_BAND_5GHZ; 1202bfcc09ddSBjoern A. Zeeb sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; 1203bfcc09ddSBjoern A. Zeeb sband->n_bitrates = N_RATES_52; 1204bfcc09ddSBjoern A. Zeeb n_used += iwl_init_sband_channels(data, sband, n_channels, 1205bfcc09ddSBjoern A. Zeeb NL80211_BAND_5GHZ); 1206bfcc09ddSBjoern A. Zeeb iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ, 1207bfcc09ddSBjoern A. Zeeb tx_chains, rx_chains); 1208bfcc09ddSBjoern A. Zeeb if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac) 1209bfcc09ddSBjoern A. Zeeb iwl_init_vht_hw_capab(trans, data, &sband->vht_cap, 1210bfcc09ddSBjoern A. Zeeb tx_chains, rx_chains); 1211bfcc09ddSBjoern A. Zeeb 1212bfcc09ddSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1213bfcc09ddSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1214bfcc09ddSBjoern A. Zeeb fw); 1215bfcc09ddSBjoern A. Zeeb 1216bfcc09ddSBjoern A. Zeeb /* 6GHz band. */ 1217bfcc09ddSBjoern A. Zeeb sband = &data->bands[NL80211_BAND_6GHZ]; 1218bfcc09ddSBjoern A. Zeeb sband->band = NL80211_BAND_6GHZ; 1219bfcc09ddSBjoern A. Zeeb /* use the same rates as 5GHz band */ 1220bfcc09ddSBjoern A. Zeeb sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; 1221bfcc09ddSBjoern A. Zeeb sband->n_bitrates = N_RATES_52; 1222bfcc09ddSBjoern A. Zeeb n_used += iwl_init_sband_channels(data, sband, n_channels, 1223bfcc09ddSBjoern A. Zeeb NL80211_BAND_6GHZ); 1224bfcc09ddSBjoern A. Zeeb 1225bfcc09ddSBjoern A. Zeeb if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) 1226bfcc09ddSBjoern A. Zeeb iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, 1227bfcc09ddSBjoern A. Zeeb fw); 1228bfcc09ddSBjoern A. Zeeb else 1229bfcc09ddSBjoern A. Zeeb sband->n_channels = 0; 1230bfcc09ddSBjoern A. Zeeb if (n_channels != n_used) 1231bfcc09ddSBjoern A. Zeeb IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", 1232bfcc09ddSBjoern A. Zeeb n_used, n_channels); 1233bfcc09ddSBjoern A. Zeeb } 1234bfcc09ddSBjoern A. Zeeb 1235bfcc09ddSBjoern A. Zeeb static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, 1236bfcc09ddSBjoern A. Zeeb const __le16 *phy_sku) 1237bfcc09ddSBjoern A. Zeeb { 1238bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) 1239bfcc09ddSBjoern A. Zeeb return le16_to_cpup(nvm_sw + SKU); 1240bfcc09ddSBjoern A. Zeeb 1241bfcc09ddSBjoern A. Zeeb return le32_to_cpup((const __le32 *)(phy_sku + SKU_FAMILY_8000)); 1242bfcc09ddSBjoern A. Zeeb } 1243bfcc09ddSBjoern A. Zeeb 1244bfcc09ddSBjoern A. Zeeb static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw) 1245bfcc09ddSBjoern A. Zeeb { 1246bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) 1247bfcc09ddSBjoern A. Zeeb return le16_to_cpup(nvm_sw + NVM_VERSION); 1248bfcc09ddSBjoern A. Zeeb else 1249bfcc09ddSBjoern A. Zeeb return le32_to_cpup((const __le32 *)(nvm_sw + 1250bfcc09ddSBjoern A. Zeeb NVM_VERSION_EXT_NVM)); 1251bfcc09ddSBjoern A. Zeeb } 1252bfcc09ddSBjoern A. Zeeb 1253bfcc09ddSBjoern A. Zeeb static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw, 1254bfcc09ddSBjoern A. Zeeb const __le16 *phy_sku) 1255bfcc09ddSBjoern A. Zeeb { 1256bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) 1257bfcc09ddSBjoern A. Zeeb return le16_to_cpup(nvm_sw + RADIO_CFG); 1258bfcc09ddSBjoern A. Zeeb 1259bfcc09ddSBjoern A. Zeeb return le32_to_cpup((const __le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM)); 1260bfcc09ddSBjoern A. Zeeb 1261bfcc09ddSBjoern A. Zeeb } 1262bfcc09ddSBjoern A. Zeeb 1263bfcc09ddSBjoern A. Zeeb static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw) 1264bfcc09ddSBjoern A. Zeeb { 1265bfcc09ddSBjoern A. Zeeb int n_hw_addr; 1266bfcc09ddSBjoern A. Zeeb 1267bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) 1268bfcc09ddSBjoern A. Zeeb return le16_to_cpup(nvm_sw + N_HW_ADDRS); 1269bfcc09ddSBjoern A. Zeeb 1270bfcc09ddSBjoern A. Zeeb n_hw_addr = le32_to_cpup((const __le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); 1271bfcc09ddSBjoern A. Zeeb 1272bfcc09ddSBjoern A. Zeeb return n_hw_addr & N_HW_ADDR_MASK; 1273bfcc09ddSBjoern A. Zeeb } 1274bfcc09ddSBjoern A. Zeeb 1275bfcc09ddSBjoern A. Zeeb static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, 1276bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 1277bfcc09ddSBjoern A. Zeeb u32 radio_cfg) 1278bfcc09ddSBjoern A. Zeeb { 1279bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) { 1280bfcc09ddSBjoern A. Zeeb data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); 1281bfcc09ddSBjoern A. Zeeb data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); 1282bfcc09ddSBjoern A. Zeeb data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); 1283bfcc09ddSBjoern A. Zeeb data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); 1284bfcc09ddSBjoern A. Zeeb return; 1285bfcc09ddSBjoern A. Zeeb } 1286bfcc09ddSBjoern A. Zeeb 1287bfcc09ddSBjoern A. Zeeb /* set the radio configuration for family 8000 */ 1288bfcc09ddSBjoern A. Zeeb data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg); 1289bfcc09ddSBjoern A. Zeeb data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg); 1290bfcc09ddSBjoern A. Zeeb data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg); 1291bfcc09ddSBjoern A. Zeeb data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg); 1292bfcc09ddSBjoern A. Zeeb data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg); 1293bfcc09ddSBjoern A. Zeeb data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg); 1294bfcc09ddSBjoern A. Zeeb } 1295bfcc09ddSBjoern A. Zeeb 1296bfcc09ddSBjoern A. Zeeb static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) 1297bfcc09ddSBjoern A. Zeeb { 1298bfcc09ddSBjoern A. Zeeb const u8 *hw_addr; 1299bfcc09ddSBjoern A. Zeeb 1300bfcc09ddSBjoern A. Zeeb hw_addr = (const u8 *)&mac_addr0; 1301bfcc09ddSBjoern A. Zeeb dest[0] = hw_addr[3]; 1302bfcc09ddSBjoern A. Zeeb dest[1] = hw_addr[2]; 1303bfcc09ddSBjoern A. Zeeb dest[2] = hw_addr[1]; 1304bfcc09ddSBjoern A. Zeeb dest[3] = hw_addr[0]; 1305bfcc09ddSBjoern A. Zeeb 1306bfcc09ddSBjoern A. Zeeb hw_addr = (const u8 *)&mac_addr1; 1307bfcc09ddSBjoern A. Zeeb dest[4] = hw_addr[1]; 1308bfcc09ddSBjoern A. Zeeb dest[5] = hw_addr[0]; 1309bfcc09ddSBjoern A. Zeeb } 1310bfcc09ddSBjoern A. Zeeb 1311bfcc09ddSBjoern A. Zeeb static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, 1312bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data) 1313bfcc09ddSBjoern A. Zeeb { 1314bfcc09ddSBjoern A. Zeeb __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, 1315bfcc09ddSBjoern A. Zeeb CSR_MAC_ADDR0_STRAP(trans))); 1316bfcc09ddSBjoern A. Zeeb __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, 1317bfcc09ddSBjoern A. Zeeb CSR_MAC_ADDR1_STRAP(trans))); 1318bfcc09ddSBjoern A. Zeeb 1319bfcc09ddSBjoern A. Zeeb iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); 1320bfcc09ddSBjoern A. Zeeb /* 1321bfcc09ddSBjoern A. Zeeb * If the OEM fused a valid address, use it instead of the one in the 1322bfcc09ddSBjoern A. Zeeb * OTP 1323bfcc09ddSBjoern A. Zeeb */ 1324bfcc09ddSBjoern A. Zeeb if (is_valid_ether_addr(data->hw_addr)) 1325bfcc09ddSBjoern A. Zeeb return; 1326bfcc09ddSBjoern A. Zeeb 1327bfcc09ddSBjoern A. Zeeb mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP(trans))); 1328bfcc09ddSBjoern A. Zeeb mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP(trans))); 1329bfcc09ddSBjoern A. Zeeb 1330bfcc09ddSBjoern A. Zeeb iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); 1331bfcc09ddSBjoern A. Zeeb } 1332bfcc09ddSBjoern A. Zeeb 1333bfcc09ddSBjoern A. Zeeb static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, 1334bfcc09ddSBjoern A. Zeeb const struct iwl_cfg *cfg, 1335bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, 1336bfcc09ddSBjoern A. Zeeb const __le16 *mac_override, 1337bfcc09ddSBjoern A. Zeeb const __be16 *nvm_hw) 1338bfcc09ddSBjoern A. Zeeb { 1339bfcc09ddSBjoern A. Zeeb const u8 *hw_addr; 1340bfcc09ddSBjoern A. Zeeb 1341bfcc09ddSBjoern A. Zeeb if (mac_override) { 1342bfcc09ddSBjoern A. Zeeb static const u8 reserved_mac[] = { 1343bfcc09ddSBjoern A. Zeeb 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00 1344bfcc09ddSBjoern A. Zeeb }; 1345bfcc09ddSBjoern A. Zeeb 1346bfcc09ddSBjoern A. Zeeb hw_addr = (const u8 *)(mac_override + 1347bfcc09ddSBjoern A. Zeeb MAC_ADDRESS_OVERRIDE_EXT_NVM); 1348bfcc09ddSBjoern A. Zeeb 1349bfcc09ddSBjoern A. Zeeb /* 1350bfcc09ddSBjoern A. Zeeb * Store the MAC address from MAO section. 1351bfcc09ddSBjoern A. Zeeb * No byte swapping is required in MAO section 1352bfcc09ddSBjoern A. Zeeb */ 1353bfcc09ddSBjoern A. Zeeb memcpy(data->hw_addr, hw_addr, ETH_ALEN); 1354bfcc09ddSBjoern A. Zeeb 1355bfcc09ddSBjoern A. Zeeb /* 1356bfcc09ddSBjoern A. Zeeb * Force the use of the OTP MAC address in case of reserved MAC 1357bfcc09ddSBjoern A. Zeeb * address in the NVM, or if address is given but invalid. 1358bfcc09ddSBjoern A. Zeeb */ 1359bfcc09ddSBjoern A. Zeeb if (is_valid_ether_addr(data->hw_addr) && 1360bfcc09ddSBjoern A. Zeeb memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0) 1361bfcc09ddSBjoern A. Zeeb return; 1362bfcc09ddSBjoern A. Zeeb 1363bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, 1364bfcc09ddSBjoern A. Zeeb "mac address from nvm override section is not valid\n"); 1365bfcc09ddSBjoern A. Zeeb } 1366bfcc09ddSBjoern A. Zeeb 1367bfcc09ddSBjoern A. Zeeb if (nvm_hw) { 1368bfcc09ddSBjoern A. Zeeb /* read the mac address from WFMP registers */ 1369bfcc09ddSBjoern A. Zeeb __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans, 1370bfcc09ddSBjoern A. Zeeb WFMP_MAC_ADDR_0)); 1371bfcc09ddSBjoern A. Zeeb __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans, 1372bfcc09ddSBjoern A. Zeeb WFMP_MAC_ADDR_1)); 1373bfcc09ddSBjoern A. Zeeb 1374bfcc09ddSBjoern A. Zeeb iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); 1375bfcc09ddSBjoern A. Zeeb 1376bfcc09ddSBjoern A. Zeeb return; 1377bfcc09ddSBjoern A. Zeeb } 1378bfcc09ddSBjoern A. Zeeb 1379bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "mac address is not found\n"); 1380bfcc09ddSBjoern A. Zeeb } 1381bfcc09ddSBjoern A. Zeeb 1382bfcc09ddSBjoern A. Zeeb static int iwl_set_hw_address(struct iwl_trans *trans, 1383bfcc09ddSBjoern A. Zeeb const struct iwl_cfg *cfg, 1384bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data, const __be16 *nvm_hw, 1385bfcc09ddSBjoern A. Zeeb const __le16 *mac_override) 1386bfcc09ddSBjoern A. Zeeb { 1387bfcc09ddSBjoern A. Zeeb if (cfg->mac_addr_from_csr) { 1388bfcc09ddSBjoern A. Zeeb iwl_set_hw_address_from_csr(trans, data); 1389bfcc09ddSBjoern A. Zeeb } else if (cfg->nvm_type != IWL_NVM_EXT) { 1390bfcc09ddSBjoern A. Zeeb const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); 1391bfcc09ddSBjoern A. Zeeb 1392bfcc09ddSBjoern A. Zeeb /* The byte order is little endian 16 bit, meaning 214365 */ 1393bfcc09ddSBjoern A. Zeeb data->hw_addr[0] = hw_addr[1]; 1394bfcc09ddSBjoern A. Zeeb data->hw_addr[1] = hw_addr[0]; 1395bfcc09ddSBjoern A. Zeeb data->hw_addr[2] = hw_addr[3]; 1396bfcc09ddSBjoern A. Zeeb data->hw_addr[3] = hw_addr[2]; 1397bfcc09ddSBjoern A. Zeeb data->hw_addr[4] = hw_addr[5]; 1398bfcc09ddSBjoern A. Zeeb data->hw_addr[5] = hw_addr[4]; 1399bfcc09ddSBjoern A. Zeeb } else { 1400bfcc09ddSBjoern A. Zeeb iwl_set_hw_address_family_8000(trans, cfg, data, 1401bfcc09ddSBjoern A. Zeeb mac_override, nvm_hw); 1402bfcc09ddSBjoern A. Zeeb } 1403bfcc09ddSBjoern A. Zeeb 1404bfcc09ddSBjoern A. Zeeb if (!is_valid_ether_addr(data->hw_addr)) { 1405bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "no valid mac address was found\n"); 1406bfcc09ddSBjoern A. Zeeb return -EINVAL; 1407bfcc09ddSBjoern A. Zeeb } 1408bfcc09ddSBjoern A. Zeeb 1409d9836fb4SBjoern A. Zeeb if (!trans->csme_own) 1410bfcc09ddSBjoern A. Zeeb #if defined(__linux__) 1411d9836fb4SBjoern A. Zeeb IWL_INFO(trans, "base HW address: %pM, OTP minor version: 0x%x\n", 1412d9836fb4SBjoern A. Zeeb data->hw_addr, iwl_read_prph(trans, REG_OTP_MINOR)); 1413bfcc09ddSBjoern A. Zeeb #elif defined(__FreeBSD__) 1414d9836fb4SBjoern A. Zeeb IWL_INFO(trans, "base HW address: %6D, OTP minor version: 0x%x\n", 1415d9836fb4SBjoern A. Zeeb data->hw_addr, ":", iwl_read_prph(trans, REG_OTP_MINOR)); 1416bfcc09ddSBjoern A. Zeeb #endif 1417bfcc09ddSBjoern A. Zeeb 1418bfcc09ddSBjoern A. Zeeb return 0; 1419bfcc09ddSBjoern A. Zeeb } 1420bfcc09ddSBjoern A. Zeeb 1421bfcc09ddSBjoern A. Zeeb static bool 1422bfcc09ddSBjoern A. Zeeb iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg, 1423bfcc09ddSBjoern A. Zeeb const __be16 *nvm_hw) 1424bfcc09ddSBjoern A. Zeeb { 1425bfcc09ddSBjoern A. Zeeb /* 1426bfcc09ddSBjoern A. Zeeb * Workaround a bug in Indonesia SKUs where the regulatory in 1427bfcc09ddSBjoern A. Zeeb * some 7000-family OTPs erroneously allow wide channels in 1428bfcc09ddSBjoern A. Zeeb * 5GHz. To check for Indonesia, we take the SKU value from 1429bfcc09ddSBjoern A. Zeeb * bits 1-4 in the subsystem ID and check if it is either 5 or 1430bfcc09ddSBjoern A. Zeeb * 9. In those cases, we need to force-disable wide channels 1431bfcc09ddSBjoern A. Zeeb * in 5GHz otherwise the FW will throw a sysassert when we try 1432bfcc09ddSBjoern A. Zeeb * to use them. 1433bfcc09ddSBjoern A. Zeeb */ 1434bfcc09ddSBjoern A. Zeeb if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) { 1435bfcc09ddSBjoern A. Zeeb /* 1436bfcc09ddSBjoern A. Zeeb * Unlike the other sections in the NVM, the hw 1437bfcc09ddSBjoern A. Zeeb * section uses big-endian. 1438bfcc09ddSBjoern A. Zeeb */ 1439bfcc09ddSBjoern A. Zeeb u16 subsystem_id = be16_to_cpup(nvm_hw + SUBSYSTEM_ID); 1440bfcc09ddSBjoern A. Zeeb u8 sku = (subsystem_id & 0x1e) >> 1; 1441bfcc09ddSBjoern A. Zeeb 1442bfcc09ddSBjoern A. Zeeb if (sku == 5 || sku == 9) { 1443bfcc09ddSBjoern A. Zeeb IWL_DEBUG_EEPROM(trans->dev, 1444bfcc09ddSBjoern A. Zeeb "disabling wide channels in 5GHz (0x%0x %d)\n", 1445bfcc09ddSBjoern A. Zeeb subsystem_id, sku); 1446bfcc09ddSBjoern A. Zeeb return true; 1447bfcc09ddSBjoern A. Zeeb } 1448bfcc09ddSBjoern A. Zeeb } 1449bfcc09ddSBjoern A. Zeeb 1450bfcc09ddSBjoern A. Zeeb return false; 1451bfcc09ddSBjoern A. Zeeb } 1452bfcc09ddSBjoern A. Zeeb 1453bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data * 1454d9836fb4SBjoern A. Zeeb iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, 1455d9836fb4SBjoern A. Zeeb const struct iwl_mei_nvm *mei_nvm, 1456*a4128aadSBjoern A. Zeeb const struct iwl_fw *fw, u8 tx_ant, u8 rx_ant) 1457d9836fb4SBjoern A. Zeeb { 1458d9836fb4SBjoern A. Zeeb struct iwl_nvm_data *data; 1459d9836fb4SBjoern A. Zeeb u32 sbands_flags = 0; 1460d9836fb4SBjoern A. Zeeb u8 rx_chains = fw->valid_rx_ant; 1461d9836fb4SBjoern A. Zeeb u8 tx_chains = fw->valid_rx_ant; 1462d9836fb4SBjoern A. Zeeb 1463d9836fb4SBjoern A. Zeeb if (cfg->uhb_supported) 1464d9836fb4SBjoern A. Zeeb data = kzalloc(struct_size(data, channels, 1465d9836fb4SBjoern A. Zeeb IWL_NVM_NUM_CHANNELS_UHB), 1466d9836fb4SBjoern A. Zeeb GFP_KERNEL); 1467d9836fb4SBjoern A. Zeeb else 1468d9836fb4SBjoern A. Zeeb data = kzalloc(struct_size(data, channels, 1469d9836fb4SBjoern A. Zeeb IWL_NVM_NUM_CHANNELS_EXT), 1470d9836fb4SBjoern A. Zeeb GFP_KERNEL); 1471d9836fb4SBjoern A. Zeeb if (!data) 1472d9836fb4SBjoern A. Zeeb return NULL; 1473d9836fb4SBjoern A. Zeeb 1474d9836fb4SBjoern A. Zeeb BUILD_BUG_ON(ARRAY_SIZE(mei_nvm->channels) != 1475d9836fb4SBjoern A. Zeeb IWL_NVM_NUM_CHANNELS_UHB); 1476d9836fb4SBjoern A. Zeeb data->nvm_version = mei_nvm->nvm_version; 1477d9836fb4SBjoern A. Zeeb 1478d9836fb4SBjoern A. Zeeb iwl_set_radio_cfg(cfg, data, mei_nvm->radio_cfg); 1479d9836fb4SBjoern A. Zeeb if (data->valid_tx_ant) 1480d9836fb4SBjoern A. Zeeb tx_chains &= data->valid_tx_ant; 1481d9836fb4SBjoern A. Zeeb if (data->valid_rx_ant) 1482d9836fb4SBjoern A. Zeeb rx_chains &= data->valid_rx_ant; 1483*a4128aadSBjoern A. Zeeb if (tx_ant) 1484*a4128aadSBjoern A. Zeeb tx_chains &= tx_ant; 1485*a4128aadSBjoern A. Zeeb if (rx_ant) 1486*a4128aadSBjoern A. Zeeb rx_chains &= rx_ant; 1487d9836fb4SBjoern A. Zeeb 1488d9836fb4SBjoern A. Zeeb data->sku_cap_mimo_disabled = false; 1489d9836fb4SBjoern A. Zeeb data->sku_cap_band_24ghz_enable = true; 1490d9836fb4SBjoern A. Zeeb data->sku_cap_band_52ghz_enable = true; 1491d9836fb4SBjoern A. Zeeb data->sku_cap_11n_enable = 1492d9836fb4SBjoern A. Zeeb !(iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL); 1493d9836fb4SBjoern A. Zeeb data->sku_cap_11ac_enable = true; 1494d9836fb4SBjoern A. Zeeb data->sku_cap_11ax_enable = 1495d9836fb4SBjoern A. Zeeb mei_nvm->caps & MEI_NVM_CAPS_11AX_SUPPORT; 1496d9836fb4SBjoern A. Zeeb 1497d9836fb4SBjoern A. Zeeb data->lar_enabled = mei_nvm->caps & MEI_NVM_CAPS_LARI_SUPPORT; 1498d9836fb4SBjoern A. Zeeb 1499d9836fb4SBjoern A. Zeeb data->n_hw_addrs = mei_nvm->n_hw_addrs; 1500d9836fb4SBjoern A. Zeeb /* If no valid mac address was found - bail out */ 1501d9836fb4SBjoern A. Zeeb if (iwl_set_hw_address(trans, cfg, data, NULL, NULL)) { 1502d9836fb4SBjoern A. Zeeb kfree(data); 1503d9836fb4SBjoern A. Zeeb return NULL; 1504d9836fb4SBjoern A. Zeeb } 1505d9836fb4SBjoern A. Zeeb 1506d9836fb4SBjoern A. Zeeb if (data->lar_enabled && 1507d9836fb4SBjoern A. Zeeb fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) 1508d9836fb4SBjoern A. Zeeb sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; 1509d9836fb4SBjoern A. Zeeb 1510d9836fb4SBjoern A. Zeeb iwl_init_sbands(trans, data, mei_nvm->channels, tx_chains, rx_chains, 1511d9836fb4SBjoern A. Zeeb sbands_flags, true, fw); 1512d9836fb4SBjoern A. Zeeb 1513d9836fb4SBjoern A. Zeeb return data; 1514d9836fb4SBjoern A. Zeeb } 1515d9836fb4SBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_parse_mei_nvm_data); 1516d9836fb4SBjoern A. Zeeb 1517d9836fb4SBjoern A. Zeeb struct iwl_nvm_data * 1518bfcc09ddSBjoern A. Zeeb iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, 1519bfcc09ddSBjoern A. Zeeb const struct iwl_fw *fw, 1520bfcc09ddSBjoern A. Zeeb const __be16 *nvm_hw, const __le16 *nvm_sw, 1521bfcc09ddSBjoern A. Zeeb const __le16 *nvm_calib, const __le16 *regulatory, 1522bfcc09ddSBjoern A. Zeeb const __le16 *mac_override, const __le16 *phy_sku, 1523bfcc09ddSBjoern A. Zeeb u8 tx_chains, u8 rx_chains) 1524bfcc09ddSBjoern A. Zeeb { 1525bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *data; 1526bfcc09ddSBjoern A. Zeeb bool lar_enabled; 1527bfcc09ddSBjoern A. Zeeb u32 sku, radio_cfg; 1528bfcc09ddSBjoern A. Zeeb u32 sbands_flags = 0; 1529bfcc09ddSBjoern A. Zeeb u16 lar_config; 1530bfcc09ddSBjoern A. Zeeb const __le16 *ch_section; 1531bfcc09ddSBjoern A. Zeeb 1532bfcc09ddSBjoern A. Zeeb if (cfg->uhb_supported) 1533bfcc09ddSBjoern A. Zeeb data = kzalloc(struct_size(data, channels, 1534bfcc09ddSBjoern A. Zeeb IWL_NVM_NUM_CHANNELS_UHB), 1535bfcc09ddSBjoern A. Zeeb GFP_KERNEL); 1536bfcc09ddSBjoern A. Zeeb else if (cfg->nvm_type != IWL_NVM_EXT) 1537bfcc09ddSBjoern A. Zeeb data = kzalloc(struct_size(data, channels, 1538bfcc09ddSBjoern A. Zeeb IWL_NVM_NUM_CHANNELS), 1539bfcc09ddSBjoern A. Zeeb GFP_KERNEL); 1540bfcc09ddSBjoern A. Zeeb else 1541bfcc09ddSBjoern A. Zeeb data = kzalloc(struct_size(data, channels, 1542bfcc09ddSBjoern A. Zeeb IWL_NVM_NUM_CHANNELS_EXT), 1543bfcc09ddSBjoern A. Zeeb GFP_KERNEL); 1544bfcc09ddSBjoern A. Zeeb if (!data) 1545bfcc09ddSBjoern A. Zeeb return NULL; 1546bfcc09ddSBjoern A. Zeeb 1547bfcc09ddSBjoern A. Zeeb data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); 1548bfcc09ddSBjoern A. Zeeb 1549bfcc09ddSBjoern A. Zeeb radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw, phy_sku); 1550bfcc09ddSBjoern A. Zeeb iwl_set_radio_cfg(cfg, data, radio_cfg); 1551bfcc09ddSBjoern A. Zeeb if (data->valid_tx_ant) 1552bfcc09ddSBjoern A. Zeeb tx_chains &= data->valid_tx_ant; 1553bfcc09ddSBjoern A. Zeeb if (data->valid_rx_ant) 1554bfcc09ddSBjoern A. Zeeb rx_chains &= data->valid_rx_ant; 1555bfcc09ddSBjoern A. Zeeb 1556bfcc09ddSBjoern A. Zeeb sku = iwl_get_sku(cfg, nvm_sw, phy_sku); 1557bfcc09ddSBjoern A. Zeeb data->sku_cap_band_24ghz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; 1558bfcc09ddSBjoern A. Zeeb data->sku_cap_band_52ghz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; 1559bfcc09ddSBjoern A. Zeeb data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; 1560bfcc09ddSBjoern A. Zeeb if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) 1561bfcc09ddSBjoern A. Zeeb data->sku_cap_11n_enable = false; 1562bfcc09ddSBjoern A. Zeeb data->sku_cap_11ac_enable = data->sku_cap_11n_enable && 1563bfcc09ddSBjoern A. Zeeb (sku & NVM_SKU_CAP_11AC_ENABLE); 1564bfcc09ddSBjoern A. Zeeb data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE; 1565bfcc09ddSBjoern A. Zeeb 1566bfcc09ddSBjoern A. Zeeb data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); 1567bfcc09ddSBjoern A. Zeeb 1568bfcc09ddSBjoern A. Zeeb if (cfg->nvm_type != IWL_NVM_EXT) { 1569bfcc09ddSBjoern A. Zeeb /* Checking for required sections */ 1570bfcc09ddSBjoern A. Zeeb if (!nvm_calib) { 1571bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, 1572bfcc09ddSBjoern A. Zeeb "Can't parse empty Calib NVM sections\n"); 1573bfcc09ddSBjoern A. Zeeb kfree(data); 1574bfcc09ddSBjoern A. Zeeb return NULL; 1575bfcc09ddSBjoern A. Zeeb } 1576bfcc09ddSBjoern A. Zeeb 1577bfcc09ddSBjoern A. Zeeb ch_section = cfg->nvm_type == IWL_NVM_SDP ? 1578bfcc09ddSBjoern A. Zeeb ®ulatory[NVM_CHANNELS_SDP] : 1579bfcc09ddSBjoern A. Zeeb &nvm_sw[NVM_CHANNELS]; 1580bfcc09ddSBjoern A. Zeeb 1581bfcc09ddSBjoern A. Zeeb lar_enabled = true; 1582bfcc09ddSBjoern A. Zeeb } else { 1583bfcc09ddSBjoern A. Zeeb u16 lar_offset = data->nvm_version < 0xE39 ? 1584bfcc09ddSBjoern A. Zeeb NVM_LAR_OFFSET_OLD : 1585bfcc09ddSBjoern A. Zeeb NVM_LAR_OFFSET; 1586bfcc09ddSBjoern A. Zeeb 1587bfcc09ddSBjoern A. Zeeb lar_config = le16_to_cpup(regulatory + lar_offset); 1588bfcc09ddSBjoern A. Zeeb data->lar_enabled = !!(lar_config & 1589bfcc09ddSBjoern A. Zeeb NVM_LAR_ENABLED); 1590bfcc09ddSBjoern A. Zeeb lar_enabled = data->lar_enabled; 1591bfcc09ddSBjoern A. Zeeb ch_section = ®ulatory[NVM_CHANNELS_EXTENDED]; 1592bfcc09ddSBjoern A. Zeeb } 1593bfcc09ddSBjoern A. Zeeb 1594bfcc09ddSBjoern A. Zeeb /* If no valid mac address was found - bail out */ 1595bfcc09ddSBjoern A. Zeeb if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) { 1596bfcc09ddSBjoern A. Zeeb kfree(data); 1597bfcc09ddSBjoern A. Zeeb return NULL; 1598bfcc09ddSBjoern A. Zeeb } 1599bfcc09ddSBjoern A. Zeeb 1600bfcc09ddSBjoern A. Zeeb if (lar_enabled && 1601bfcc09ddSBjoern A. Zeeb fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) 1602bfcc09ddSBjoern A. Zeeb sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; 1603bfcc09ddSBjoern A. Zeeb 1604bfcc09ddSBjoern A. Zeeb if (iwl_nvm_no_wide_in_5ghz(trans, cfg, nvm_hw)) 1605bfcc09ddSBjoern A. Zeeb sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ; 1606bfcc09ddSBjoern A. Zeeb 1607bfcc09ddSBjoern A. Zeeb iwl_init_sbands(trans, data, ch_section, tx_chains, rx_chains, 1608bfcc09ddSBjoern A. Zeeb sbands_flags, false, fw); 1609bfcc09ddSBjoern A. Zeeb data->calib_version = 255; 1610bfcc09ddSBjoern A. Zeeb 1611bfcc09ddSBjoern A. Zeeb return data; 1612bfcc09ddSBjoern A. Zeeb } 1613bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); 1614bfcc09ddSBjoern A. Zeeb 1615bfcc09ddSBjoern A. Zeeb static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, 1616bfcc09ddSBjoern A. Zeeb int ch_idx, u16 nvm_flags, 1617bfcc09ddSBjoern A. Zeeb struct iwl_reg_capa reg_capa, 1618bfcc09ddSBjoern A. Zeeb const struct iwl_cfg *cfg) 1619bfcc09ddSBjoern A. Zeeb { 1620bfcc09ddSBjoern A. Zeeb u32 flags = NL80211_RRF_NO_HT40; 1621bfcc09ddSBjoern A. Zeeb 1622bfcc09ddSBjoern A. Zeeb if (ch_idx < NUM_2GHZ_CHANNELS && 1623bfcc09ddSBjoern A. Zeeb (nvm_flags & NVM_CHANNEL_40MHZ)) { 1624bfcc09ddSBjoern A. Zeeb if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) 1625bfcc09ddSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40PLUS; 1626bfcc09ddSBjoern A. Zeeb if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) 1627bfcc09ddSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40MINUS; 1628*a4128aadSBjoern A. Zeeb } else if (ch_idx < NUM_2GHZ_CHANNELS + NUM_5GHZ_CHANNELS && 1629*a4128aadSBjoern A. Zeeb nvm_flags & NVM_CHANNEL_40MHZ) { 1630bfcc09ddSBjoern A. Zeeb if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) 1631bfcc09ddSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40PLUS; 1632bfcc09ddSBjoern A. Zeeb else 1633bfcc09ddSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40MINUS; 1634*a4128aadSBjoern A. Zeeb } else if (nvm_flags & NVM_CHANNEL_40MHZ) { 1635*a4128aadSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40PLUS; 1636*a4128aadSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_HT40MINUS; 1637bfcc09ddSBjoern A. Zeeb } 1638bfcc09ddSBjoern A. Zeeb 1639bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_80MHZ)) 1640bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_80MHZ; 1641bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_160MHZ)) 1642bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_160MHZ; 1643bfcc09ddSBjoern A. Zeeb 1644bfcc09ddSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) 1645bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_IR; 1646bfcc09ddSBjoern A. Zeeb 1647bfcc09ddSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_RADAR) 1648bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_DFS; 1649bfcc09ddSBjoern A. Zeeb 1650bfcc09ddSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) 1651bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_OUTDOOR; 1652bfcc09ddSBjoern A. Zeeb 1653bfcc09ddSBjoern A. Zeeb /* Set the GO concurrent flag only in case that NO_IR is set. 1654bfcc09ddSBjoern A. Zeeb * Otherwise it is meaningless 1655bfcc09ddSBjoern A. Zeeb */ 1656*a4128aadSBjoern A. Zeeb if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT)) { 1657*a4128aadSBjoern A. Zeeb if (flags & NL80211_RRF_NO_IR) 1658bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_GO_CONCURRENT; 1659*a4128aadSBjoern A. Zeeb if (flags & NL80211_RRF_DFS) { 1660*a4128aadSBjoern A. Zeeb flags |= NL80211_RRF_DFS_CONCURRENT; 1661*a4128aadSBjoern A. Zeeb /* Our device doesn't set active bit for DFS channels 1662*a4128aadSBjoern A. Zeeb * however, once marked as DFS no-ir is not needed. 1663*a4128aadSBjoern A. Zeeb */ 1664*a4128aadSBjoern A. Zeeb flags &= ~NL80211_RRF_NO_IR; 1665*a4128aadSBjoern A. Zeeb } 1666*a4128aadSBjoern A. Zeeb } 1667*a4128aadSBjoern A. Zeeb 1668*a4128aadSBjoern A. Zeeb /* Set the AP type for the UHB case. */ 1669*a4128aadSBjoern A. Zeeb if (nvm_flags & NVM_CHANNEL_VLP) 1670*a4128aadSBjoern A. Zeeb flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP; 1671*a4128aadSBjoern A. Zeeb else 1672*a4128aadSBjoern A. Zeeb flags |= NL80211_RRF_NO_6GHZ_VLP_CLIENT; 1673*a4128aadSBjoern A. Zeeb 1674*a4128aadSBjoern A. Zeeb if (!(nvm_flags & NVM_CHANNEL_AFC)) 1675*a4128aadSBjoern A. Zeeb flags |= NL80211_RRF_NO_6GHZ_AFC_CLIENT; 1676bfcc09ddSBjoern A. Zeeb 1677bfcc09ddSBjoern A. Zeeb /* 1678bfcc09ddSBjoern A. Zeeb * reg_capa is per regulatory domain so apply it for every channel 1679bfcc09ddSBjoern A. Zeeb */ 1680bfcc09ddSBjoern A. Zeeb if (ch_idx >= NUM_2GHZ_CHANNELS) { 1681bfcc09ddSBjoern A. Zeeb if (!reg_capa.allow_40mhz) 1682bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_HT40; 1683bfcc09ddSBjoern A. Zeeb 1684bfcc09ddSBjoern A. Zeeb if (!reg_capa.allow_80mhz) 1685bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_80MHZ; 1686bfcc09ddSBjoern A. Zeeb 1687bfcc09ddSBjoern A. Zeeb if (!reg_capa.allow_160mhz) 1688bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_160MHZ; 16899af1bba4SBjoern A. Zeeb 16909af1bba4SBjoern A. Zeeb if (!reg_capa.allow_320mhz) 16919af1bba4SBjoern A. Zeeb flags |= NL80211_RRF_NO_320MHZ; 1692bfcc09ddSBjoern A. Zeeb } 16939af1bba4SBjoern A. Zeeb 1694bfcc09ddSBjoern A. Zeeb if (reg_capa.disable_11ax) 1695bfcc09ddSBjoern A. Zeeb flags |= NL80211_RRF_NO_HE; 1696bfcc09ddSBjoern A. Zeeb 16979af1bba4SBjoern A. Zeeb if (reg_capa.disable_11be) 16989af1bba4SBjoern A. Zeeb flags |= NL80211_RRF_NO_EHT; 16999af1bba4SBjoern A. Zeeb 1700bfcc09ddSBjoern A. Zeeb return flags; 1701bfcc09ddSBjoern A. Zeeb } 1702bfcc09ddSBjoern A. Zeeb 17039af1bba4SBjoern A. Zeeb static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) 1704bfcc09ddSBjoern A. Zeeb { 17059af1bba4SBjoern A. Zeeb struct iwl_reg_capa reg_capa = {}; 1706bfcc09ddSBjoern A. Zeeb 17079af1bba4SBjoern A. Zeeb if (resp_ver >= REG_CAPA_V4_RESP_VER) { 17089af1bba4SBjoern A. Zeeb reg_capa.allow_40mhz = true; 17099af1bba4SBjoern A. Zeeb reg_capa.allow_80mhz = flags & REG_CAPA_V4_80MHZ_ALLOWED; 17109af1bba4SBjoern A. Zeeb reg_capa.allow_160mhz = flags & REG_CAPA_V4_160MHZ_ALLOWED; 17119af1bba4SBjoern A. Zeeb reg_capa.allow_320mhz = flags & REG_CAPA_V4_320MHZ_ALLOWED; 17129af1bba4SBjoern A. Zeeb reg_capa.disable_11ax = flags & REG_CAPA_V4_11AX_DISABLED; 17139af1bba4SBjoern A. Zeeb reg_capa.disable_11be = flags & REG_CAPA_V4_11BE_DISABLED; 17149af1bba4SBjoern A. Zeeb } else if (resp_ver >= REG_CAPA_V2_RESP_VER) { 1715bfcc09ddSBjoern A. Zeeb reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED; 1716bfcc09ddSBjoern A. Zeeb reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED; 1717bfcc09ddSBjoern A. Zeeb reg_capa.allow_160mhz = flags & REG_CAPA_V2_160MHZ_ALLOWED; 1718bfcc09ddSBjoern A. Zeeb reg_capa.disable_11ax = flags & REG_CAPA_V2_11AX_DISABLED; 1719bfcc09ddSBjoern A. Zeeb } else { 17209af1bba4SBjoern A. Zeeb reg_capa.allow_40mhz = !(flags & REG_CAPA_V1_40MHZ_FORBIDDEN); 17219af1bba4SBjoern A. Zeeb reg_capa.allow_80mhz = flags & REG_CAPA_V1_80MHZ_ALLOWED; 17229af1bba4SBjoern A. Zeeb reg_capa.allow_160mhz = flags & REG_CAPA_V1_160MHZ_ALLOWED; 17239af1bba4SBjoern A. Zeeb reg_capa.disable_11ax = flags & REG_CAPA_V1_11AX_DISABLED; 1724bfcc09ddSBjoern A. Zeeb } 1725bfcc09ddSBjoern A. Zeeb return reg_capa; 1726bfcc09ddSBjoern A. Zeeb } 1727bfcc09ddSBjoern A. Zeeb 1728bfcc09ddSBjoern A. Zeeb struct ieee80211_regdomain * 1729bfcc09ddSBjoern A. Zeeb iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, 1730bfcc09ddSBjoern A. Zeeb int num_of_ch, __le32 *channels, u16 fw_mcc, 17319af1bba4SBjoern A. Zeeb u16 geo_info, u32 cap, u8 resp_ver) 1732bfcc09ddSBjoern A. Zeeb { 1733bfcc09ddSBjoern A. Zeeb int ch_idx; 1734bfcc09ddSBjoern A. Zeeb u16 ch_flags; 1735bfcc09ddSBjoern A. Zeeb u32 reg_rule_flags, prev_reg_rule_flags = 0; 1736bfcc09ddSBjoern A. Zeeb const u16 *nvm_chan; 1737bfcc09ddSBjoern A. Zeeb struct ieee80211_regdomain *regd, *copy_rd; 1738bfcc09ddSBjoern A. Zeeb struct ieee80211_reg_rule *rule; 1739bfcc09ddSBjoern A. Zeeb int center_freq, prev_center_freq = 0; 1740bfcc09ddSBjoern A. Zeeb int valid_rules = 0; 1741bfcc09ddSBjoern A. Zeeb bool new_rule; 1742bfcc09ddSBjoern A. Zeeb int max_num_ch; 1743bfcc09ddSBjoern A. Zeeb struct iwl_reg_capa reg_capa; 1744bfcc09ddSBjoern A. Zeeb 1745bfcc09ddSBjoern A. Zeeb if (cfg->uhb_supported) { 1746bfcc09ddSBjoern A. Zeeb max_num_ch = IWL_NVM_NUM_CHANNELS_UHB; 1747bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_uhb_nvm_channels; 1748bfcc09ddSBjoern A. Zeeb } else if (cfg->nvm_type == IWL_NVM_EXT) { 1749bfcc09ddSBjoern A. Zeeb max_num_ch = IWL_NVM_NUM_CHANNELS_EXT; 1750bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_ext_nvm_channels; 1751bfcc09ddSBjoern A. Zeeb } else { 1752bfcc09ddSBjoern A. Zeeb max_num_ch = IWL_NVM_NUM_CHANNELS; 1753bfcc09ddSBjoern A. Zeeb nvm_chan = iwl_nvm_channels; 1754bfcc09ddSBjoern A. Zeeb } 1755bfcc09ddSBjoern A. Zeeb 1756d9836fb4SBjoern A. Zeeb if (num_of_ch > max_num_ch) { 1757d9836fb4SBjoern A. Zeeb IWL_DEBUG_DEV(dev, IWL_DL_LAR, 1758d9836fb4SBjoern A. Zeeb "Num of channels (%d) is greater than expected. Truncating to %d\n", 1759d9836fb4SBjoern A. Zeeb num_of_ch, max_num_ch); 1760bfcc09ddSBjoern A. Zeeb num_of_ch = max_num_ch; 1761d9836fb4SBjoern A. Zeeb } 1762bfcc09ddSBjoern A. Zeeb 1763bfcc09ddSBjoern A. Zeeb if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) 1764bfcc09ddSBjoern A. Zeeb return ERR_PTR(-EINVAL); 1765bfcc09ddSBjoern A. Zeeb 1766bfcc09ddSBjoern A. Zeeb IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", 1767bfcc09ddSBjoern A. Zeeb num_of_ch); 1768bfcc09ddSBjoern A. Zeeb 1769bfcc09ddSBjoern A. Zeeb /* build a regdomain rule for every valid channel */ 1770bfcc09ddSBjoern A. Zeeb regd = kzalloc(struct_size(regd, reg_rules, num_of_ch), GFP_KERNEL); 1771bfcc09ddSBjoern A. Zeeb if (!regd) 1772bfcc09ddSBjoern A. Zeeb return ERR_PTR(-ENOMEM); 1773bfcc09ddSBjoern A. Zeeb 1774bfcc09ddSBjoern A. Zeeb /* set alpha2 from FW. */ 1775bfcc09ddSBjoern A. Zeeb regd->alpha2[0] = fw_mcc >> 8; 1776bfcc09ddSBjoern A. Zeeb regd->alpha2[1] = fw_mcc & 0xff; 1777bfcc09ddSBjoern A. Zeeb 1778bfcc09ddSBjoern A. Zeeb /* parse regulatory capability flags */ 1779bfcc09ddSBjoern A. Zeeb reg_capa = iwl_get_reg_capa(cap, resp_ver); 1780bfcc09ddSBjoern A. Zeeb 1781bfcc09ddSBjoern A. Zeeb for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { 1782*a4128aadSBjoern A. Zeeb enum nl80211_band band = 1783*a4128aadSBjoern A. Zeeb iwl_nl80211_band_from_channel_idx(ch_idx); 1784*a4128aadSBjoern A. Zeeb 1785bfcc09ddSBjoern A. Zeeb ch_flags = (u16)__le32_to_cpup(channels + ch_idx); 1786bfcc09ddSBjoern A. Zeeb center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], 1787bfcc09ddSBjoern A. Zeeb band); 1788bfcc09ddSBjoern A. Zeeb new_rule = false; 1789bfcc09ddSBjoern A. Zeeb 1790bfcc09ddSBjoern A. Zeeb if (!(ch_flags & NVM_CHANNEL_VALID)) { 1791bfcc09ddSBjoern A. Zeeb iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, 1792bfcc09ddSBjoern A. Zeeb nvm_chan[ch_idx], ch_flags); 1793bfcc09ddSBjoern A. Zeeb continue; 1794bfcc09ddSBjoern A. Zeeb } 1795bfcc09ddSBjoern A. Zeeb 1796bfcc09ddSBjoern A. Zeeb reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, 1797bfcc09ddSBjoern A. Zeeb ch_flags, reg_capa, 1798bfcc09ddSBjoern A. Zeeb cfg); 1799bfcc09ddSBjoern A. Zeeb 1800bfcc09ddSBjoern A. Zeeb /* we can't continue the same rule */ 1801bfcc09ddSBjoern A. Zeeb if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags || 1802bfcc09ddSBjoern A. Zeeb center_freq - prev_center_freq > 20) { 1803bfcc09ddSBjoern A. Zeeb valid_rules++; 1804bfcc09ddSBjoern A. Zeeb new_rule = true; 1805bfcc09ddSBjoern A. Zeeb } 1806bfcc09ddSBjoern A. Zeeb 1807bfcc09ddSBjoern A. Zeeb rule = ®d->reg_rules[valid_rules - 1]; 1808bfcc09ddSBjoern A. Zeeb 1809bfcc09ddSBjoern A. Zeeb if (new_rule) 1810bfcc09ddSBjoern A. Zeeb rule->freq_range.start_freq_khz = 1811bfcc09ddSBjoern A. Zeeb MHZ_TO_KHZ(center_freq - 10); 1812bfcc09ddSBjoern A. Zeeb 1813bfcc09ddSBjoern A. Zeeb rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); 1814bfcc09ddSBjoern A. Zeeb 1815bfcc09ddSBjoern A. Zeeb /* this doesn't matter - not used by FW */ 1816bfcc09ddSBjoern A. Zeeb rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); 1817bfcc09ddSBjoern A. Zeeb rule->power_rule.max_eirp = 1818bfcc09ddSBjoern A. Zeeb DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); 1819bfcc09ddSBjoern A. Zeeb 1820bfcc09ddSBjoern A. Zeeb rule->flags = reg_rule_flags; 1821bfcc09ddSBjoern A. Zeeb 1822bfcc09ddSBjoern A. Zeeb /* rely on auto-calculation to merge BW of contiguous chans */ 1823bfcc09ddSBjoern A. Zeeb rule->flags |= NL80211_RRF_AUTO_BW; 1824bfcc09ddSBjoern A. Zeeb rule->freq_range.max_bandwidth_khz = 0; 1825bfcc09ddSBjoern A. Zeeb 1826bfcc09ddSBjoern A. Zeeb prev_center_freq = center_freq; 1827bfcc09ddSBjoern A. Zeeb prev_reg_rule_flags = reg_rule_flags; 1828bfcc09ddSBjoern A. Zeeb 1829bfcc09ddSBjoern A. Zeeb iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, 1830bfcc09ddSBjoern A. Zeeb nvm_chan[ch_idx], ch_flags); 1831bfcc09ddSBjoern A. Zeeb 1832bfcc09ddSBjoern A. Zeeb if (!(geo_info & GEO_WMM_ETSI_5GHZ_INFO) || 1833bfcc09ddSBjoern A. Zeeb band == NL80211_BAND_2GHZ) 1834bfcc09ddSBjoern A. Zeeb continue; 1835bfcc09ddSBjoern A. Zeeb 1836bfcc09ddSBjoern A. Zeeb reg_query_regdb_wmm(regd->alpha2, center_freq, rule); 1837bfcc09ddSBjoern A. Zeeb } 1838bfcc09ddSBjoern A. Zeeb 1839bfcc09ddSBjoern A. Zeeb /* 1840bfcc09ddSBjoern A. Zeeb * Certain firmware versions might report no valid channels 1841bfcc09ddSBjoern A. Zeeb * if booted in RF-kill, i.e. not all calibrations etc. are 1842bfcc09ddSBjoern A. Zeeb * running. We'll get out of this situation later when the 1843bfcc09ddSBjoern A. Zeeb * rfkill is removed and we update the regdomain again, but 1844bfcc09ddSBjoern A. Zeeb * since cfg80211 doesn't accept an empty regdomain, add a 1845bfcc09ddSBjoern A. Zeeb * dummy (unusable) rule here in this case so we can init. 1846bfcc09ddSBjoern A. Zeeb */ 1847bfcc09ddSBjoern A. Zeeb if (!valid_rules) { 1848bfcc09ddSBjoern A. Zeeb valid_rules = 1; 1849bfcc09ddSBjoern A. Zeeb rule = ®d->reg_rules[valid_rules - 1]; 1850bfcc09ddSBjoern A. Zeeb rule->freq_range.start_freq_khz = MHZ_TO_KHZ(2412); 1851bfcc09ddSBjoern A. Zeeb rule->freq_range.end_freq_khz = MHZ_TO_KHZ(2413); 1852bfcc09ddSBjoern A. Zeeb rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(1); 1853bfcc09ddSBjoern A. Zeeb rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); 1854bfcc09ddSBjoern A. Zeeb rule->power_rule.max_eirp = 1855bfcc09ddSBjoern A. Zeeb DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); 1856bfcc09ddSBjoern A. Zeeb } 1857bfcc09ddSBjoern A. Zeeb 1858bfcc09ddSBjoern A. Zeeb regd->n_reg_rules = valid_rules; 1859bfcc09ddSBjoern A. Zeeb 1860bfcc09ddSBjoern A. Zeeb /* 1861bfcc09ddSBjoern A. Zeeb * Narrow down regdom for unused regulatory rules to prevent hole 1862bfcc09ddSBjoern A. Zeeb * between reg rules to wmm rules. 1863bfcc09ddSBjoern A. Zeeb */ 1864bfcc09ddSBjoern A. Zeeb copy_rd = kmemdup(regd, struct_size(regd, reg_rules, valid_rules), 1865bfcc09ddSBjoern A. Zeeb GFP_KERNEL); 1866bfcc09ddSBjoern A. Zeeb if (!copy_rd) 1867bfcc09ddSBjoern A. Zeeb copy_rd = ERR_PTR(-ENOMEM); 1868bfcc09ddSBjoern A. Zeeb 1869bfcc09ddSBjoern A. Zeeb kfree(regd); 1870bfcc09ddSBjoern A. Zeeb return copy_rd; 1871bfcc09ddSBjoern A. Zeeb } 1872bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); 1873bfcc09ddSBjoern A. Zeeb 1874bfcc09ddSBjoern A. Zeeb #define IWL_MAX_NVM_SECTION_SIZE 0x1b58 1875bfcc09ddSBjoern A. Zeeb #define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc 1876bfcc09ddSBjoern A. Zeeb #define MAX_NVM_FILE_LEN 16384 1877bfcc09ddSBjoern A. Zeeb 1878bfcc09ddSBjoern A. Zeeb void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, 1879bfcc09ddSBjoern A. Zeeb unsigned int len) 1880bfcc09ddSBjoern A. Zeeb { 1881bfcc09ddSBjoern A. Zeeb #define IWL_4165_DEVICE_ID 0x5501 1882bfcc09ddSBjoern A. Zeeb #define NVM_SKU_CAP_MIMO_DISABLE BIT(5) 1883bfcc09ddSBjoern A. Zeeb 1884bfcc09ddSBjoern A. Zeeb if (section == NVM_SECTION_TYPE_PHY_SKU && 1885bfcc09ddSBjoern A. Zeeb hw_id == IWL_4165_DEVICE_ID && data && len >= 5 && 1886bfcc09ddSBjoern A. Zeeb (data[4] & NVM_SKU_CAP_MIMO_DISABLE)) 1887bfcc09ddSBjoern A. Zeeb /* OTP 0x52 bug work around: it's a 1x1 device */ 1888bfcc09ddSBjoern A. Zeeb data[3] = ANT_B | (ANT_B << 4); 1889bfcc09ddSBjoern A. Zeeb } 1890bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_nvm_fixups); 1891bfcc09ddSBjoern A. Zeeb 1892bfcc09ddSBjoern A. Zeeb /* 1893bfcc09ddSBjoern A. Zeeb * Reads external NVM from a file into mvm->nvm_sections 1894bfcc09ddSBjoern A. Zeeb * 1895bfcc09ddSBjoern A. Zeeb * HOW TO CREATE THE NVM FILE FORMAT: 1896bfcc09ddSBjoern A. Zeeb * ------------------------------ 1897bfcc09ddSBjoern A. Zeeb * 1. create hex file, format: 1898bfcc09ddSBjoern A. Zeeb * 3800 -> header 1899bfcc09ddSBjoern A. Zeeb * 0000 -> header 1900bfcc09ddSBjoern A. Zeeb * 5a40 -> data 1901bfcc09ddSBjoern A. Zeeb * 1902bfcc09ddSBjoern A. Zeeb * rev - 6 bit (word1) 1903bfcc09ddSBjoern A. Zeeb * len - 10 bit (word1) 1904bfcc09ddSBjoern A. Zeeb * id - 4 bit (word2) 1905bfcc09ddSBjoern A. Zeeb * rsv - 12 bit (word2) 1906bfcc09ddSBjoern A. Zeeb * 1907bfcc09ddSBjoern A. Zeeb * 2. flip 8bits with 8 bits per line to get the right NVM file format 1908bfcc09ddSBjoern A. Zeeb * 1909bfcc09ddSBjoern A. Zeeb * 3. create binary file from the hex file 1910bfcc09ddSBjoern A. Zeeb * 1911bfcc09ddSBjoern A. Zeeb * 4. save as "iNVM_xxx.bin" under /lib/firmware 1912bfcc09ddSBjoern A. Zeeb */ 1913bfcc09ddSBjoern A. Zeeb int iwl_read_external_nvm(struct iwl_trans *trans, 1914bfcc09ddSBjoern A. Zeeb const char *nvm_file_name, 1915bfcc09ddSBjoern A. Zeeb struct iwl_nvm_section *nvm_sections) 1916bfcc09ddSBjoern A. Zeeb { 1917bfcc09ddSBjoern A. Zeeb int ret, section_size; 1918bfcc09ddSBjoern A. Zeeb u16 section_id; 1919bfcc09ddSBjoern A. Zeeb const struct firmware *fw_entry; 1920bfcc09ddSBjoern A. Zeeb const struct { 1921bfcc09ddSBjoern A. Zeeb __le16 word1; 1922bfcc09ddSBjoern A. Zeeb __le16 word2; 1923bfcc09ddSBjoern A. Zeeb u8 data[]; 1924bfcc09ddSBjoern A. Zeeb } *file_sec; 1925bfcc09ddSBjoern A. Zeeb const u8 *eof; 1926bfcc09ddSBjoern A. Zeeb u8 *temp; 1927bfcc09ddSBjoern A. Zeeb int max_section_size; 1928bfcc09ddSBjoern A. Zeeb const __le32 *dword_buff; 1929bfcc09ddSBjoern A. Zeeb 1930bfcc09ddSBjoern A. Zeeb #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) 1931bfcc09ddSBjoern A. Zeeb #define NVM_WORD2_ID(x) (x >> 12) 1932bfcc09ddSBjoern A. Zeeb #define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) 1933bfcc09ddSBjoern A. Zeeb #define EXT_NVM_WORD1_ID(x) ((x) >> 4) 1934bfcc09ddSBjoern A. Zeeb #define NVM_HEADER_0 (0x2A504C54) 1935bfcc09ddSBjoern A. Zeeb #define NVM_HEADER_1 (0x4E564D2A) 1936bfcc09ddSBjoern A. Zeeb #define NVM_HEADER_SIZE (4 * sizeof(u32)) 1937bfcc09ddSBjoern A. Zeeb 1938bfcc09ddSBjoern A. Zeeb IWL_DEBUG_EEPROM(trans->dev, "Read from external NVM\n"); 1939bfcc09ddSBjoern A. Zeeb 1940bfcc09ddSBjoern A. Zeeb /* Maximal size depends on NVM version */ 1941bfcc09ddSBjoern A. Zeeb if (trans->cfg->nvm_type != IWL_NVM_EXT) 1942bfcc09ddSBjoern A. Zeeb max_section_size = IWL_MAX_NVM_SECTION_SIZE; 1943bfcc09ddSBjoern A. Zeeb else 1944bfcc09ddSBjoern A. Zeeb max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; 1945bfcc09ddSBjoern A. Zeeb 1946bfcc09ddSBjoern A. Zeeb /* 1947bfcc09ddSBjoern A. Zeeb * Obtain NVM image via request_firmware. Since we already used 1948bfcc09ddSBjoern A. Zeeb * request_firmware_nowait() for the firmware binary load and only 1949bfcc09ddSBjoern A. Zeeb * get here after that we assume the NVM request can be satisfied 1950bfcc09ddSBjoern A. Zeeb * synchronously. 1951bfcc09ddSBjoern A. Zeeb */ 1952bfcc09ddSBjoern A. Zeeb ret = request_firmware(&fw_entry, nvm_file_name, trans->dev); 1953bfcc09ddSBjoern A. Zeeb if (ret) { 1954bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "ERROR: %s isn't available %d\n", 1955bfcc09ddSBjoern A. Zeeb nvm_file_name, ret); 1956bfcc09ddSBjoern A. Zeeb return ret; 1957bfcc09ddSBjoern A. Zeeb } 1958bfcc09ddSBjoern A. Zeeb 1959bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "Loaded NVM file %s (%zu bytes)\n", 1960bfcc09ddSBjoern A. Zeeb nvm_file_name, fw_entry->size); 1961bfcc09ddSBjoern A. Zeeb 1962bfcc09ddSBjoern A. Zeeb if (fw_entry->size > MAX_NVM_FILE_LEN) { 1963bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "NVM file too large\n"); 1964bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 1965bfcc09ddSBjoern A. Zeeb goto out; 1966bfcc09ddSBjoern A. Zeeb } 1967bfcc09ddSBjoern A. Zeeb 1968bfcc09ddSBjoern A. Zeeb eof = fw_entry->data + fw_entry->size; 1969bfcc09ddSBjoern A. Zeeb dword_buff = (const __le32 *)fw_entry->data; 1970bfcc09ddSBjoern A. Zeeb 1971bfcc09ddSBjoern A. Zeeb /* some NVM file will contain a header. 1972bfcc09ddSBjoern A. Zeeb * The header is identified by 2 dwords header as follow: 1973bfcc09ddSBjoern A. Zeeb * dword[0] = 0x2A504C54 1974bfcc09ddSBjoern A. Zeeb * dword[1] = 0x4E564D2A 1975bfcc09ddSBjoern A. Zeeb * 1976bfcc09ddSBjoern A. Zeeb * This header must be skipped when providing the NVM data to the FW. 1977bfcc09ddSBjoern A. Zeeb */ 1978bfcc09ddSBjoern A. Zeeb if (fw_entry->size > NVM_HEADER_SIZE && 1979bfcc09ddSBjoern A. Zeeb dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && 1980bfcc09ddSBjoern A. Zeeb dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { 1981bfcc09ddSBjoern A. Zeeb file_sec = (const void *)(fw_entry->data + NVM_HEADER_SIZE); 1982bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); 1983bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "NVM Manufacturing date %08X\n", 1984bfcc09ddSBjoern A. Zeeb le32_to_cpu(dword_buff[3])); 1985bfcc09ddSBjoern A. Zeeb 1986bfcc09ddSBjoern A. Zeeb /* nvm file validation, dword_buff[2] holds the file version */ 1987bfcc09ddSBjoern A. Zeeb if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_8000 && 1988d9836fb4SBjoern A. Zeeb trans->hw_rev_step == SILICON_C_STEP && 1989bfcc09ddSBjoern A. Zeeb le32_to_cpu(dword_buff[2]) < 0xE4A) { 1990bfcc09ddSBjoern A. Zeeb ret = -EFAULT; 1991bfcc09ddSBjoern A. Zeeb goto out; 1992bfcc09ddSBjoern A. Zeeb } 1993bfcc09ddSBjoern A. Zeeb } else { 1994bfcc09ddSBjoern A. Zeeb file_sec = (const void *)fw_entry->data; 1995bfcc09ddSBjoern A. Zeeb } 1996bfcc09ddSBjoern A. Zeeb 1997bfcc09ddSBjoern A. Zeeb while (true) { 1998bfcc09ddSBjoern A. Zeeb if (file_sec->data > eof) { 1999bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, 2000bfcc09ddSBjoern A. Zeeb "ERROR - NVM file too short for section header\n"); 2001bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2002bfcc09ddSBjoern A. Zeeb break; 2003bfcc09ddSBjoern A. Zeeb } 2004bfcc09ddSBjoern A. Zeeb 2005bfcc09ddSBjoern A. Zeeb /* check for EOF marker */ 2006bfcc09ddSBjoern A. Zeeb if (!file_sec->word1 && !file_sec->word2) { 2007bfcc09ddSBjoern A. Zeeb ret = 0; 2008bfcc09ddSBjoern A. Zeeb break; 2009bfcc09ddSBjoern A. Zeeb } 2010bfcc09ddSBjoern A. Zeeb 2011bfcc09ddSBjoern A. Zeeb if (trans->cfg->nvm_type != IWL_NVM_EXT) { 2012bfcc09ddSBjoern A. Zeeb section_size = 2013bfcc09ddSBjoern A. Zeeb 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); 2014bfcc09ddSBjoern A. Zeeb section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); 2015bfcc09ddSBjoern A. Zeeb } else { 2016bfcc09ddSBjoern A. Zeeb section_size = 2 * EXT_NVM_WORD2_LEN( 2017bfcc09ddSBjoern A. Zeeb le16_to_cpu(file_sec->word2)); 2018bfcc09ddSBjoern A. Zeeb section_id = EXT_NVM_WORD1_ID( 2019bfcc09ddSBjoern A. Zeeb le16_to_cpu(file_sec->word1)); 2020bfcc09ddSBjoern A. Zeeb } 2021bfcc09ddSBjoern A. Zeeb 2022bfcc09ddSBjoern A. Zeeb if (section_size > max_section_size) { 2023bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "ERROR - section too large (%d)\n", 2024bfcc09ddSBjoern A. Zeeb section_size); 2025bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2026bfcc09ddSBjoern A. Zeeb break; 2027bfcc09ddSBjoern A. Zeeb } 2028bfcc09ddSBjoern A. Zeeb 2029bfcc09ddSBjoern A. Zeeb if (!section_size) { 2030bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "ERROR - section empty\n"); 2031bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2032bfcc09ddSBjoern A. Zeeb break; 2033bfcc09ddSBjoern A. Zeeb } 2034bfcc09ddSBjoern A. Zeeb 2035bfcc09ddSBjoern A. Zeeb if (file_sec->data + section_size > eof) { 2036bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, 2037bfcc09ddSBjoern A. Zeeb "ERROR - NVM file too short for section (%d bytes)\n", 2038bfcc09ddSBjoern A. Zeeb section_size); 2039bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2040bfcc09ddSBjoern A. Zeeb break; 2041bfcc09ddSBjoern A. Zeeb } 2042bfcc09ddSBjoern A. Zeeb 2043bfcc09ddSBjoern A. Zeeb if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, 2044bfcc09ddSBjoern A. Zeeb "Invalid NVM section ID %d\n", section_id)) { 2045bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2046bfcc09ddSBjoern A. Zeeb break; 2047bfcc09ddSBjoern A. Zeeb } 2048bfcc09ddSBjoern A. Zeeb 2049bfcc09ddSBjoern A. Zeeb temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); 2050bfcc09ddSBjoern A. Zeeb if (!temp) { 2051bfcc09ddSBjoern A. Zeeb ret = -ENOMEM; 2052bfcc09ddSBjoern A. Zeeb break; 2053bfcc09ddSBjoern A. Zeeb } 2054bfcc09ddSBjoern A. Zeeb 2055bfcc09ddSBjoern A. Zeeb iwl_nvm_fixups(trans->hw_id, section_id, temp, section_size); 2056bfcc09ddSBjoern A. Zeeb 2057bfcc09ddSBjoern A. Zeeb kfree(nvm_sections[section_id].data); 2058bfcc09ddSBjoern A. Zeeb nvm_sections[section_id].data = temp; 2059bfcc09ddSBjoern A. Zeeb nvm_sections[section_id].length = section_size; 2060bfcc09ddSBjoern A. Zeeb 2061bfcc09ddSBjoern A. Zeeb /* advance to the next section */ 2062bfcc09ddSBjoern A. Zeeb file_sec = (const void *)(file_sec->data + section_size); 2063bfcc09ddSBjoern A. Zeeb } 2064bfcc09ddSBjoern A. Zeeb out: 2065bfcc09ddSBjoern A. Zeeb release_firmware(fw_entry); 2066bfcc09ddSBjoern A. Zeeb return ret; 2067bfcc09ddSBjoern A. Zeeb } 2068bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_read_external_nvm); 2069bfcc09ddSBjoern A. Zeeb 2070bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, 2071*a4128aadSBjoern A. Zeeb const struct iwl_fw *fw, 2072*a4128aadSBjoern A. Zeeb u8 set_tx_ant, u8 set_rx_ant) 2073bfcc09ddSBjoern A. Zeeb { 2074bfcc09ddSBjoern A. Zeeb struct iwl_nvm_get_info cmd = {}; 2075bfcc09ddSBjoern A. Zeeb struct iwl_nvm_data *nvm; 2076bfcc09ddSBjoern A. Zeeb struct iwl_host_cmd hcmd = { 2077bfcc09ddSBjoern A. Zeeb .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, 2078bfcc09ddSBjoern A. Zeeb .data = { &cmd, }, 2079bfcc09ddSBjoern A. Zeeb .len = { sizeof(cmd) }, 2080bfcc09ddSBjoern A. Zeeb .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) 2081bfcc09ddSBjoern A. Zeeb }; 2082bfcc09ddSBjoern A. Zeeb int ret; 2083bfcc09ddSBjoern A. Zeeb bool empty_otp; 2084bfcc09ddSBjoern A. Zeeb u32 mac_flags; 2085bfcc09ddSBjoern A. Zeeb u32 sbands_flags = 0; 2086*a4128aadSBjoern A. Zeeb u8 tx_ant; 2087*a4128aadSBjoern A. Zeeb u8 rx_ant; 2088*a4128aadSBjoern A. Zeeb 2089bfcc09ddSBjoern A. Zeeb /* 2090bfcc09ddSBjoern A. Zeeb * All the values in iwl_nvm_get_info_rsp v4 are the same as 2091bfcc09ddSBjoern A. Zeeb * in v3, except for the channel profile part of the 2092bfcc09ddSBjoern A. Zeeb * regulatory. So we can just access the new struct, with the 2093bfcc09ddSBjoern A. Zeeb * exception of the latter. 2094bfcc09ddSBjoern A. Zeeb */ 2095bfcc09ddSBjoern A. Zeeb struct iwl_nvm_get_info_rsp *rsp; 2096bfcc09ddSBjoern A. Zeeb struct iwl_nvm_get_info_rsp_v3 *rsp_v3; 2097bfcc09ddSBjoern A. Zeeb bool v4 = fw_has_api(&fw->ucode_capa, 2098bfcc09ddSBjoern A. Zeeb IWL_UCODE_TLV_API_REGULATORY_NVM_INFO); 2099bfcc09ddSBjoern A. Zeeb size_t rsp_size = v4 ? sizeof(*rsp) : sizeof(*rsp_v3); 2100bfcc09ddSBjoern A. Zeeb void *channel_profile; 2101bfcc09ddSBjoern A. Zeeb 2102bfcc09ddSBjoern A. Zeeb ret = iwl_trans_send_cmd(trans, &hcmd); 2103bfcc09ddSBjoern A. Zeeb if (ret) 2104bfcc09ddSBjoern A. Zeeb return ERR_PTR(ret); 2105bfcc09ddSBjoern A. Zeeb 2106bfcc09ddSBjoern A. Zeeb if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != rsp_size, 2107bfcc09ddSBjoern A. Zeeb "Invalid payload len in NVM response from FW %d", 2108bfcc09ddSBjoern A. Zeeb iwl_rx_packet_payload_len(hcmd.resp_pkt))) { 2109bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2110bfcc09ddSBjoern A. Zeeb goto out; 2111bfcc09ddSBjoern A. Zeeb } 2112bfcc09ddSBjoern A. Zeeb 2113bfcc09ddSBjoern A. Zeeb rsp = (void *)hcmd.resp_pkt->data; 2114bfcc09ddSBjoern A. Zeeb empty_otp = !!(le32_to_cpu(rsp->general.flags) & 2115bfcc09ddSBjoern A. Zeeb NVM_GENERAL_FLAGS_EMPTY_OTP); 2116bfcc09ddSBjoern A. Zeeb if (empty_otp) 2117bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "OTP is empty\n"); 2118bfcc09ddSBjoern A. Zeeb 2119bfcc09ddSBjoern A. Zeeb nvm = kzalloc(struct_size(nvm, channels, IWL_NUM_CHANNELS), GFP_KERNEL); 2120bfcc09ddSBjoern A. Zeeb if (!nvm) { 2121bfcc09ddSBjoern A. Zeeb ret = -ENOMEM; 2122bfcc09ddSBjoern A. Zeeb goto out; 2123bfcc09ddSBjoern A. Zeeb } 2124bfcc09ddSBjoern A. Zeeb 2125bfcc09ddSBjoern A. Zeeb iwl_set_hw_address_from_csr(trans, nvm); 2126bfcc09ddSBjoern A. Zeeb /* TODO: if platform NVM has MAC address - override it here */ 2127bfcc09ddSBjoern A. Zeeb 2128bfcc09ddSBjoern A. Zeeb if (!is_valid_ether_addr(nvm->hw_addr)) { 2129bfcc09ddSBjoern A. Zeeb IWL_ERR(trans, "no valid mac address was found\n"); 2130bfcc09ddSBjoern A. Zeeb ret = -EINVAL; 2131bfcc09ddSBjoern A. Zeeb goto err_free; 2132bfcc09ddSBjoern A. Zeeb } 2133bfcc09ddSBjoern A. Zeeb 2134bfcc09ddSBjoern A. Zeeb #if defined(__linux__) 2135bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr); 2136bfcc09ddSBjoern A. Zeeb #elif defined(__FreeBSD__) 2137bfcc09ddSBjoern A. Zeeb IWL_INFO(trans, "base HW address: %6D\n", nvm->hw_addr, ":"); 2138bfcc09ddSBjoern A. Zeeb #endif 2139bfcc09ddSBjoern A. Zeeb 2140bfcc09ddSBjoern A. Zeeb /* Initialize general data */ 2141bfcc09ddSBjoern A. Zeeb nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); 2142bfcc09ddSBjoern A. Zeeb nvm->n_hw_addrs = rsp->general.n_hw_addrs; 2143bfcc09ddSBjoern A. Zeeb if (nvm->n_hw_addrs == 0) 2144bfcc09ddSBjoern A. Zeeb IWL_WARN(trans, 2145bfcc09ddSBjoern A. Zeeb "Firmware declares no reserved mac addresses. OTP is empty: %d\n", 2146bfcc09ddSBjoern A. Zeeb empty_otp); 2147bfcc09ddSBjoern A. Zeeb 2148bfcc09ddSBjoern A. Zeeb /* Initialize MAC sku data */ 2149bfcc09ddSBjoern A. Zeeb mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); 2150bfcc09ddSBjoern A. Zeeb nvm->sku_cap_11ac_enable = 2151bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); 2152bfcc09ddSBjoern A. Zeeb nvm->sku_cap_11n_enable = 2153bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); 2154bfcc09ddSBjoern A. Zeeb nvm->sku_cap_11ax_enable = 2155bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); 2156bfcc09ddSBjoern A. Zeeb nvm->sku_cap_band_24ghz_enable = 2157bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); 2158bfcc09ddSBjoern A. Zeeb nvm->sku_cap_band_52ghz_enable = 2159bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); 2160bfcc09ddSBjoern A. Zeeb nvm->sku_cap_mimo_disabled = 2161bfcc09ddSBjoern A. Zeeb !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); 2162*a4128aadSBjoern A. Zeeb if (CSR_HW_RFID_TYPE(trans->hw_rf_id) >= IWL_CFG_RF_TYPE_FM) 21639af1bba4SBjoern A. Zeeb nvm->sku_cap_11be_enable = true; 2164bfcc09ddSBjoern A. Zeeb 2165bfcc09ddSBjoern A. Zeeb /* Initialize PHY sku data */ 2166bfcc09ddSBjoern A. Zeeb nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); 2167bfcc09ddSBjoern A. Zeeb nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); 2168bfcc09ddSBjoern A. Zeeb 2169bfcc09ddSBjoern A. Zeeb if (le32_to_cpu(rsp->regulatory.lar_enabled) && 2170bfcc09ddSBjoern A. Zeeb fw_has_capa(&fw->ucode_capa, 2171bfcc09ddSBjoern A. Zeeb IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) { 2172bfcc09ddSBjoern A. Zeeb nvm->lar_enabled = true; 2173bfcc09ddSBjoern A. Zeeb sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; 2174bfcc09ddSBjoern A. Zeeb } 2175bfcc09ddSBjoern A. Zeeb 2176bfcc09ddSBjoern A. Zeeb rsp_v3 = (void *)rsp; 2177bfcc09ddSBjoern A. Zeeb channel_profile = v4 ? (void *)rsp->regulatory.channel_profile : 2178bfcc09ddSBjoern A. Zeeb (void *)rsp_v3->regulatory.channel_profile; 2179bfcc09ddSBjoern A. Zeeb 2180*a4128aadSBjoern A. Zeeb tx_ant = nvm->valid_tx_ant & fw->valid_tx_ant; 2181*a4128aadSBjoern A. Zeeb rx_ant = nvm->valid_rx_ant & fw->valid_rx_ant; 2182*a4128aadSBjoern A. Zeeb 2183*a4128aadSBjoern A. Zeeb if (set_tx_ant) 2184*a4128aadSBjoern A. Zeeb tx_ant &= set_tx_ant; 2185*a4128aadSBjoern A. Zeeb if (set_rx_ant) 2186*a4128aadSBjoern A. Zeeb rx_ant &= set_rx_ant; 2187*a4128aadSBjoern A. Zeeb 2188*a4128aadSBjoern A. Zeeb iwl_init_sbands(trans, nvm, channel_profile, tx_ant, rx_ant, 2189bfcc09ddSBjoern A. Zeeb sbands_flags, v4, fw); 2190bfcc09ddSBjoern A. Zeeb 2191bfcc09ddSBjoern A. Zeeb iwl_free_resp(&hcmd); 2192bfcc09ddSBjoern A. Zeeb return nvm; 2193bfcc09ddSBjoern A. Zeeb 2194bfcc09ddSBjoern A. Zeeb err_free: 2195bfcc09ddSBjoern A. Zeeb kfree(nvm); 2196bfcc09ddSBjoern A. Zeeb out: 2197bfcc09ddSBjoern A. Zeeb iwl_free_resp(&hcmd); 2198bfcc09ddSBjoern A. Zeeb return ERR_PTR(ret); 2199bfcc09ddSBjoern A. Zeeb } 2200bfcc09ddSBjoern A. Zeeb IWL_EXPORT_SYMBOL(iwl_get_nvm); 2201