xref: /freebsd/sys/contrib/dev/iwlwifi/iwl-nvm-parse.c (revision a4128aad8503277614f2d214011ef60a19447b83)
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 			     &regulatory[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 = &regulatory[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 = &regd->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 = &regd->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