Commit | Line | Data |
---|---|---|
b1e1adfa JB |
1 | /****************************************************************************** |
2 | * | |
3 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
4 | * redistributing this file, you may do so under either license. | |
5 | * | |
6 | * GPL LICENSE SUMMARY | |
7 | * | |
51368bf7 | 8 | * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. |
5f0d98f2 | 9 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
29108495 | 10 | * Copyright(c) 2016 - 2017 Intel Deutschland GmbH |
7691fa69 | 11 | * Copyright(c) 2018 - 2019 Intel Corporation |
b1e1adfa JB |
12 | * |
13 | * This program is free software; you can redistribute it and/or modify | |
14 | * it under the terms of version 2 of the GNU General Public License as | |
15 | * published by the Free Software Foundation. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * General Public License for more details. | |
21 | * | |
b1e1adfa | 22 | * The full GNU General Public License is included in this distribution |
410dc5aa | 23 | * in the file called COPYING. |
b1e1adfa JB |
24 | * |
25 | * Contact Information: | |
d01c5366 | 26 | * Intel Linux Wireless <linuxwifi@intel.com> |
b1e1adfa JB |
27 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
28 | * | |
29 | * BSD LICENSE | |
30 | * | |
51368bf7 | 31 | * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. |
5f0d98f2 | 32 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
29108495 | 33 | * Copyright(c) 2016 - 2017 Intel Deutschland GmbH |
7691fa69 | 34 | * Copyright(c) 2018 - 2019 Intel Corporation |
b1e1adfa JB |
35 | * All rights reserved. |
36 | * | |
37 | * Redistribution and use in source and binary forms, with or without | |
38 | * modification, are permitted provided that the following conditions | |
39 | * are met: | |
40 | * | |
41 | * * Redistributions of source code must retain the above copyright | |
42 | * notice, this list of conditions and the following disclaimer. | |
43 | * * Redistributions in binary form must reproduce the above copyright | |
44 | * notice, this list of conditions and the following disclaimer in | |
45 | * the documentation and/or other materials provided with the | |
46 | * distribution. | |
47 | * * Neither the name Intel Corporation nor the names of its | |
48 | * contributors may be used to endorse or promote products derived | |
49 | * from this software without specific prior written permission. | |
50 | * | |
51 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
52 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
53 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
54 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
55 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
56 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
57 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
58 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
59 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
60 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
61 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
62 | *****************************************************************************/ | |
63 | #include <linux/types.h> | |
64 | #include <linux/slab.h> | |
65 | #include <linux/export.h> | |
9f32e017 | 66 | #include <linux/etherdevice.h> |
1e0b393a | 67 | #include <linux/pci.h> |
9c4f7d51 | 68 | #include <linux/firmware.h> |
813df5ce | 69 | |
48e29340 | 70 | #include "iwl-drv.h" |
b1e1adfa JB |
71 | #include "iwl-modparams.h" |
72 | #include "iwl-nvm-parse.h" | |
afd5b170 | 73 | #include "iwl-prph.h" |
17c867bf SS |
74 | #include "iwl-io.h" |
75 | #include "iwl-csr.h" | |
813df5ce | 76 | #include "fw/acpi.h" |
9c4f7d51 | 77 | #include "fw/api/nvm-reg.h" |
4c625c56 ST |
78 | #include "fw/api/commands.h" |
79 | #include "fw/api/cmdhdr.h" | |
80 | #include "fw/img.h" | |
b1e1adfa JB |
81 | |
82 | /* NVM offsets (in words) definitions */ | |
44fd09da | 83 | enum nvm_offsets { |
b1e1adfa | 84 | /* NVM HW-Section offset (in words) definitions */ |
01a9c948 | 85 | SUBSYSTEM_ID = 0x0A, |
b1e1adfa JB |
86 | HW_ADDR = 0x15, |
87 | ||
77db0a3c | 88 | /* NVM SW-Section offset (in words) definitions */ |
b1e1adfa JB |
89 | NVM_SW_SECTION = 0x1C0, |
90 | NVM_VERSION = 0, | |
91 | RADIO_CFG = 1, | |
92 | SKU = 2, | |
93 | N_HW_ADDRS = 3, | |
94 | NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, | |
95 | ||
77db0a3c | 96 | /* NVM calibration section offset (in words) definitions */ |
b1e1adfa | 97 | NVM_CALIB_SECTION = 0x2B8, |
44fd09da CRI |
98 | XTAL_CALIB = 0x316 - NVM_CALIB_SECTION, |
99 | ||
100 | /* NVM REGULATORY -Section offset (in words) definitions */ | |
101 | NVM_CHANNELS_SDP = 0, | |
b1e1adfa JB |
102 | }; |
103 | ||
7042678d | 104 | enum ext_nvm_offsets { |
77db0a3c | 105 | /* NVM HW-Section offset (in words) definitions */ |
7042678d | 106 | MAC_ADDRESS_OVERRIDE_EXT_NVM = 1, |
77db0a3c EH |
107 | |
108 | /* NVM SW-Section offset (in words) definitions */ | |
7042678d SS |
109 | NVM_VERSION_EXT_NVM = 0, |
110 | RADIO_CFG_FAMILY_EXT_NVM = 0, | |
5dd9c68a EG |
111 | SKU_FAMILY_8000 = 2, |
112 | N_HW_ADDRS_FAMILY_8000 = 3, | |
ce500071 | 113 | |
77db0a3c | 114 | /* NVM REGULATORY -Section offset (in words) definitions */ |
7042678d SS |
115 | NVM_CHANNELS_EXTENDED = 0, |
116 | NVM_LAR_OFFSET_OLD = 0x4C7, | |
117 | NVM_LAR_OFFSET = 0x507, | |
118 | NVM_LAR_ENABLED = 0x7, | |
77db0a3c EH |
119 | }; |
120 | ||
b1e1adfa JB |
121 | /* SKU Capabilities (actual values from NVM definition) */ |
122 | enum nvm_sku_bits { | |
5f0d98f2 EG |
123 | NVM_SKU_CAP_BAND_24GHZ = BIT(0), |
124 | NVM_SKU_CAP_BAND_52GHZ = BIT(1), | |
125 | NVM_SKU_CAP_11N_ENABLE = BIT(2), | |
126 | NVM_SKU_CAP_11AC_ENABLE = BIT(3), | |
127 | NVM_SKU_CAP_MIMO_DISABLE = BIT(5), | |
b1e1adfa JB |
128 | }; |
129 | ||
b1e1adfa JB |
130 | /* |
131 | * These are the channel numbers in the order that they are stored in the NVM | |
132 | */ | |
b15ef67c | 133 | static const u16 iwl_nvm_channels[] = { |
b1e1adfa JB |
134 | /* 2.4 GHz */ |
135 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
136 | /* 5 GHz */ | |
137 | 36, 40, 44 , 48, 52, 56, 60, 64, | |
138 | 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, | |
139 | 149, 153, 157, 161, 165 | |
140 | }; | |
141 | ||
b15ef67c | 142 | static const u16 iwl_ext_nvm_channels[] = { |
77db0a3c | 143 | /* 2.4 GHz */ |
9b1c9a66 | 144 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
77db0a3c EH |
145 | /* 5 GHz */ |
146 | 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, | |
147 | 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, | |
148 | 149, 153, 157, 161, 165, 169, 173, 177, 181 | |
149 | }; | |
150 | ||
b15ef67c ST |
151 | static const u16 iwl_uhb_nvm_channels[] = { |
152 | /* 2.4 GHz */ | |
153 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
154 | /* 5 GHz */ | |
155 | 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, | |
156 | 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, | |
157 | 149, 153, 157, 161, 165, 169, 173, 177, 181, | |
158 | /* 6-7 GHz */ | |
222ccf5e TM |
159 | 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, |
160 | 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, | |
161 | 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, | |
162 | 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 | |
b15ef67c ST |
163 | }; |
164 | ||
9c4f7d51 ST |
165 | #define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) |
166 | #define IWL_NVM_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels) | |
b15ef67c | 167 | #define IWL_NVM_NUM_CHANNELS_UHB ARRAY_SIZE(iwl_uhb_nvm_channels) |
749f1fe1 | 168 | #define NUM_2GHZ_CHANNELS 14 |
749f1fe1 EH |
169 | #define FIRST_2GHZ_HT_MINUS 5 |
170 | #define LAST_2GHZ_HT_PLUS 9 | |
ce500071 | 171 | #define N_HW_ADDR_MASK 0xF |
b1e1adfa | 172 | |
b1e1adfa JB |
173 | /* rate data (static) */ |
174 | static struct ieee80211_rate iwl_cfg80211_rates[] = { | |
175 | { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, | |
176 | { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1, | |
177 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | |
178 | { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2, | |
179 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | |
180 | { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3, | |
181 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, | |
182 | { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, }, | |
183 | { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, }, | |
184 | { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, }, | |
185 | { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, }, | |
186 | { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, }, | |
187 | { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, }, | |
188 | { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, }, | |
189 | { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, }, | |
190 | }; | |
191 | #define RATES_24_OFFS 0 | |
192 | #define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates) | |
193 | #define RATES_52_OFFS 4 | |
194 | #define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) | |
195 | ||
196 | /** | |
197 | * enum iwl_nvm_channel_flags - channel flags in NVM | |
198 | * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo | |
199 | * @NVM_CHANNEL_IBSS: usable as an IBSS channel | |
200 | * @NVM_CHANNEL_ACTIVE: active scanning allowed | |
201 | * @NVM_CHANNEL_RADAR: radar detection required | |
9ee6dace DS |
202 | * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed |
203 | * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS | |
204 | * on same channel on 2.4 or same UNII band on 5.2 | |
b823cf3b LC |
205 | * @NVM_CHANNEL_UNIFORM: uniform spreading required |
206 | * @NVM_CHANNEL_20MHZ: 20 MHz channel okay | |
207 | * @NVM_CHANNEL_40MHZ: 40 MHz channel okay | |
208 | * @NVM_CHANNEL_80MHZ: 80 MHz channel okay | |
209 | * @NVM_CHANNEL_160MHZ: 160 MHz channel okay | |
210 | * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) | |
b1e1adfa JB |
211 | */ |
212 | enum iwl_nvm_channel_flags { | |
b823cf3b LC |
213 | NVM_CHANNEL_VALID = BIT(0), |
214 | NVM_CHANNEL_IBSS = BIT(1), | |
215 | NVM_CHANNEL_ACTIVE = BIT(3), | |
216 | NVM_CHANNEL_RADAR = BIT(4), | |
217 | NVM_CHANNEL_INDOOR_ONLY = BIT(5), | |
218 | NVM_CHANNEL_GO_CONCURRENT = BIT(6), | |
219 | NVM_CHANNEL_UNIFORM = BIT(7), | |
220 | NVM_CHANNEL_20MHZ = BIT(8), | |
221 | NVM_CHANNEL_40MHZ = BIT(9), | |
222 | NVM_CHANNEL_80MHZ = BIT(10), | |
223 | NVM_CHANNEL_160MHZ = BIT(11), | |
224 | NVM_CHANNEL_DC_HIGH = BIT(12), | |
b1e1adfa JB |
225 | }; |
226 | ||
2763bba6 HD |
227 | /** |
228 | * enum iwl_reg_capa_flags - global flags applied for the whole regulatory | |
229 | * domain. | |
230 | * @REG_CAPA_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the | |
231 | * 2.4Ghz band is allowed. | |
232 | * @REG_CAPA_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the | |
233 | * 5Ghz band is allowed. | |
234 | * @REG_CAPA_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed | |
235 | * for this regulatory domain (valid only in 5Ghz). | |
236 | * @REG_CAPA_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed | |
237 | * for this regulatory domain (valid only in 5Ghz). | |
238 | * @REG_CAPA_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. | |
239 | * @REG_CAPA_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. | |
240 | * @REG_CAPA_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden | |
241 | * for this regulatory domain (valid only in 5Ghz). | |
242 | * @REG_CAPA_DC_HIGH_ENABLED: DC HIGH allowed. | |
a224883c | 243 | * @REG_CAPA_11AX_DISABLED: 11ax is forbidden for this regulatory domain. |
2763bba6 HD |
244 | */ |
245 | enum iwl_reg_capa_flags { | |
246 | REG_CAPA_BF_CCD_LOW_BAND = BIT(0), | |
247 | REG_CAPA_BF_CCD_HIGH_BAND = BIT(1), | |
248 | REG_CAPA_160MHZ_ALLOWED = BIT(2), | |
249 | REG_CAPA_80MHZ_ALLOWED = BIT(3), | |
250 | REG_CAPA_MCS_8_ALLOWED = BIT(4), | |
251 | REG_CAPA_MCS_9_ALLOWED = BIT(5), | |
252 | REG_CAPA_40MHZ_FORBIDDEN = BIT(7), | |
253 | REG_CAPA_DC_HIGH_ENABLED = BIT(9), | |
a224883c | 254 | REG_CAPA_11AX_DISABLED = BIT(10), |
2763bba6 HD |
255 | }; |
256 | ||
e27c506a GA |
257 | /** |
258 | * enum iwl_reg_capa_flags_v2 - global flags applied for the whole regulatory | |
259 | * domain (version 2). | |
260 | * @REG_CAPA_V2_STRADDLE_DISABLED: Straddle channels (144, 142, 138) are | |
261 | * disabled. | |
262 | * @REG_CAPA_V2_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the | |
263 | * 2.4Ghz band is allowed. | |
264 | * @REG_CAPA_V2_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the | |
265 | * 5Ghz band is allowed. | |
266 | * @REG_CAPA_V2_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed | |
267 | * for this regulatory domain (valid only in 5Ghz). | |
268 | * @REG_CAPA_V2_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed | |
269 | * for this regulatory domain (valid only in 5Ghz). | |
270 | * @REG_CAPA_V2_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. | |
271 | * @REG_CAPA_V2_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. | |
272 | * @REG_CAPA_V2_WEATHER_DISABLED: Weather radar channels (120, 124, 128, 118, | |
273 | * 126, 122) are disabled. | |
274 | * @REG_CAPA_V2_40MHZ_ALLOWED: 11n channel with a width of 40Mhz is allowed | |
275 | * for this regulatory domain (uvalid only in 5Ghz). | |
276 | * @REG_CAPA_V2_11AX_DISABLED: 11ax is forbidden for this regulatory domain. | |
277 | */ | |
278 | enum iwl_reg_capa_flags_v2 { | |
279 | REG_CAPA_V2_STRADDLE_DISABLED = BIT(0), | |
280 | REG_CAPA_V2_BF_CCD_LOW_BAND = BIT(1), | |
281 | REG_CAPA_V2_BF_CCD_HIGH_BAND = BIT(2), | |
282 | REG_CAPA_V2_160MHZ_ALLOWED = BIT(3), | |
283 | REG_CAPA_V2_80MHZ_ALLOWED = BIT(4), | |
284 | REG_CAPA_V2_MCS_8_ALLOWED = BIT(5), | |
285 | REG_CAPA_V2_MCS_9_ALLOWED = BIT(6), | |
286 | REG_CAPA_V2_WEATHER_DISABLED = BIT(7), | |
287 | REG_CAPA_V2_40MHZ_ALLOWED = BIT(8), | |
288 | REG_CAPA_V2_11AX_DISABLED = BIT(13), | |
289 | }; | |
290 | ||
291 | /* | |
292 | * API v2 for reg_capa_flags is relevant from version 6 and onwards of the | |
293 | * MCC update command response. | |
294 | */ | |
295 | #define REG_CAPA_V2_RESP_VER 6 | |
296 | ||
297 | /** | |
298 | * struct iwl_reg_capa - struct for global regulatory capabilities, Used for | |
299 | * handling the different APIs of reg_capa_flags. | |
300 | * | |
301 | * @allow_40mhz: 11n channel with a width of 40Mhz is allowed | |
302 | * for this regulatory domain (valid only in 5Ghz). | |
303 | * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed | |
304 | * for this regulatory domain (valid only in 5Ghz). | |
305 | * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed | |
306 | * for this regulatory domain (valid only in 5Ghz). | |
307 | * @disable_11ax: 11ax is forbidden for this regulatory domain. | |
308 | */ | |
309 | struct iwl_reg_capa { | |
310 | u16 allow_40mhz; | |
311 | u16 allow_80mhz; | |
312 | u16 allow_160mhz; | |
313 | u16 disable_11ax; | |
314 | }; | |
315 | ||
d8c73e45 | 316 | static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, |
2785ce00 | 317 | int chan, u32 flags) |
d8c73e45 | 318 | { |
b1e1adfa | 319 | #define CHECK_AND_PRINT_I(x) \ |
d8c73e45 JB |
320 | ((flags & NVM_CHANNEL_##x) ? " " #x : "") |
321 | ||
322 | if (!(flags & NVM_CHANNEL_VALID)) { | |
323 | IWL_DEBUG_DEV(dev, level, "Ch. %d: 0x%x: No traffic\n", | |
324 | chan, flags); | |
325 | return; | |
326 | } | |
327 | ||
328 | /* Note: already can print up to 101 characters, 110 is the limit! */ | |
329 | IWL_DEBUG_DEV(dev, level, | |
330 | "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s\n", | |
331 | chan, flags, | |
332 | CHECK_AND_PRINT_I(VALID), | |
333 | CHECK_AND_PRINT_I(IBSS), | |
334 | CHECK_AND_PRINT_I(ACTIVE), | |
335 | CHECK_AND_PRINT_I(RADAR), | |
336 | CHECK_AND_PRINT_I(INDOOR_ONLY), | |
337 | CHECK_AND_PRINT_I(GO_CONCURRENT), | |
338 | CHECK_AND_PRINT_I(UNIFORM), | |
339 | CHECK_AND_PRINT_I(20MHZ), | |
340 | CHECK_AND_PRINT_I(40MHZ), | |
341 | CHECK_AND_PRINT_I(80MHZ), | |
342 | CHECK_AND_PRINT_I(160MHZ), | |
343 | CHECK_AND_PRINT_I(DC_HIGH)); | |
344 | #undef CHECK_AND_PRINT_I | |
345 | } | |
b1e1adfa | 346 | |
e878325a | 347 | static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, |
2785ce00 | 348 | u32 nvm_flags, const struct iwl_cfg *cfg) |
770ceda6 AN |
349 | { |
350 | u32 flags = IEEE80211_CHAN_NO_HT40; | |
351 | ||
e878325a | 352 | if (band == NL80211_BAND_2GHZ && (nvm_flags & NVM_CHANNEL_40MHZ)) { |
770ceda6 AN |
353 | if (ch_num <= LAST_2GHZ_HT_PLUS) |
354 | flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | |
355 | if (ch_num >= FIRST_2GHZ_HT_MINUS) | |
356 | flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | |
b15ef67c | 357 | } else if (nvm_flags & NVM_CHANNEL_40MHZ) { |
770ceda6 AN |
358 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) |
359 | flags &= ~IEEE80211_CHAN_NO_HT40PLUS; | |
360 | else | |
361 | flags &= ~IEEE80211_CHAN_NO_HT40MINUS; | |
362 | } | |
363 | if (!(nvm_flags & NVM_CHANNEL_80MHZ)) | |
364 | flags |= IEEE80211_CHAN_NO_80MHZ; | |
365 | if (!(nvm_flags & NVM_CHANNEL_160MHZ)) | |
366 | flags |= IEEE80211_CHAN_NO_160MHZ; | |
367 | ||
368 | if (!(nvm_flags & NVM_CHANNEL_IBSS)) | |
369 | flags |= IEEE80211_CHAN_NO_IR; | |
370 | ||
371 | if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) | |
372 | flags |= IEEE80211_CHAN_NO_IR; | |
373 | ||
374 | if (nvm_flags & NVM_CHANNEL_RADAR) | |
375 | flags |= IEEE80211_CHAN_RADAR; | |
376 | ||
377 | if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) | |
378 | flags |= IEEE80211_CHAN_INDOOR_ONLY; | |
379 | ||
380 | /* Set the GO concurrent flag only in case that NO_IR is set. | |
381 | * Otherwise it is meaningless | |
382 | */ | |
383 | if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && | |
384 | (flags & IEEE80211_CHAN_NO_IR)) | |
06f207fc | 385 | flags |= IEEE80211_CHAN_IR_CONCURRENT; |
770ceda6 AN |
386 | |
387 | return flags; | |
388 | } | |
389 | ||
e878325a TM |
390 | static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx) |
391 | { | |
392 | if (ch_idx >= NUM_2GHZ_CHANNELS) | |
393 | return NL80211_BAND_5GHZ; | |
394 | return NL80211_BAND_2GHZ; | |
395 | } | |
396 | ||
b1e1adfa JB |
397 | static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, |
398 | struct iwl_nvm_data *data, | |
2785ce00 ST |
399 | const void * const nvm_ch_flags, |
400 | u32 sbands_flags, bool v4) | |
b1e1adfa JB |
401 | { |
402 | int ch_idx; | |
403 | int n_channels = 0; | |
404 | struct ieee80211_channel *channel; | |
2785ce00 | 405 | u32 ch_flags; |
e878325a | 406 | int num_of_ch; |
b15ef67c | 407 | const u16 *nvm_chan; |
77db0a3c | 408 | |
b15ef67c ST |
409 | if (cfg->uhb_supported) { |
410 | num_of_ch = IWL_NVM_NUM_CHANNELS_UHB; | |
411 | nvm_chan = iwl_uhb_nvm_channels; | |
412 | } else if (cfg->nvm_type == IWL_NVM_EXT) { | |
9c4f7d51 | 413 | num_of_ch = IWL_NVM_NUM_CHANNELS_EXT; |
b15ef67c ST |
414 | nvm_chan = iwl_ext_nvm_channels; |
415 | } else { | |
416 | num_of_ch = IWL_NVM_NUM_CHANNELS; | |
417 | nvm_chan = iwl_nvm_channels; | |
77db0a3c | 418 | } |
b1e1adfa | 419 | |
77db0a3c | 420 | for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { |
e878325a TM |
421 | enum nl80211_band band = |
422 | iwl_nl80211_band_from_channel_idx(ch_idx); | |
01a9c948 | 423 | |
2785ce00 ST |
424 | if (v4) |
425 | ch_flags = | |
426 | __le32_to_cpup((__le32 *)nvm_ch_flags + ch_idx); | |
427 | else | |
428 | ch_flags = | |
429 | __le16_to_cpup((__le16 *)nvm_ch_flags + ch_idx); | |
c5128654 | 430 | |
e878325a TM |
431 | if (band == NL80211_BAND_5GHZ && |
432 | !data->sku_cap_band_52ghz_enable) | |
a76f3bfe | 433 | continue; |
c5128654 | 434 | |
01a9c948 | 435 | /* workaround to disable wide channels in 5GHz */ |
4b82455c | 436 | if ((sbands_flags & IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ) && |
e878325a | 437 | band == NL80211_BAND_5GHZ) { |
01a9c948 LC |
438 | ch_flags &= ~(NVM_CHANNEL_40MHZ | |
439 | NVM_CHANNEL_80MHZ | | |
440 | NVM_CHANNEL_160MHZ); | |
441 | } | |
442 | ||
4896d764 GG |
443 | if (ch_flags & NVM_CHANNEL_160MHZ) |
444 | data->vht160_supported = true; | |
445 | ||
4b82455c LC |
446 | if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR) && |
447 | !(ch_flags & NVM_CHANNEL_VALID)) { | |
a76f3bfe EP |
448 | /* |
449 | * Channels might become valid later if lar is | |
450 | * supported, hence we still want to add them to | |
451 | * the list of supported channels to cfg80211. | |
452 | */ | |
d8c73e45 JB |
453 | iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, |
454 | nvm_chan[ch_idx], ch_flags); | |
b1e1adfa JB |
455 | continue; |
456 | } | |
457 | ||
458 | channel = &data->channels[n_channels]; | |
459 | n_channels++; | |
460 | ||
77db0a3c | 461 | channel->hw_value = nvm_chan[ch_idx]; |
e878325a | 462 | channel->band = band; |
b1e1adfa JB |
463 | channel->center_freq = |
464 | ieee80211_channel_to_frequency( | |
465 | channel->hw_value, channel->band); | |
466 | ||
b1e1adfa JB |
467 | /* Initialize regulatory-based run-time data */ |
468 | ||
88f2fd73 MG |
469 | /* |
470 | * Default value - highest tx power value. max_power | |
471 | * is not used in mvm, and is used for backwards compatibility | |
472 | */ | |
22d059a5 | 473 | channel->max_power = IWL_DEFAULT_MAX_TX_POWER; |
770ceda6 AN |
474 | |
475 | /* don't put limitations in case we're using LAR */ | |
4b82455c | 476 | if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR)) |
770ceda6 | 477 | channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], |
e878325a | 478 | ch_idx, band, |
b281c93d | 479 | ch_flags, cfg); |
770ceda6 AN |
480 | else |
481 | channel->flags = 0; | |
482 | ||
d8c73e45 JB |
483 | iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, |
484 | channel->hw_value, ch_flags); | |
485 | IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n", | |
486 | channel->hw_value, channel->max_power); | |
b1e1adfa JB |
487 | } |
488 | ||
489 | return n_channels; | |
490 | } | |
491 | ||
d8913b80 | 492 | static void iwl_init_vht_hw_capab(struct iwl_trans *trans, |
33158fef | 493 | struct iwl_nvm_data *data, |
6ca89f1f JB |
494 | struct ieee80211_sta_vht_cap *vht_cap, |
495 | u8 tx_chains, u8 rx_chains) | |
33158fef | 496 | { |
d8913b80 | 497 | const struct iwl_cfg *cfg = trans->cfg; |
6ca89f1f JB |
498 | int num_rx_ants = num_of_ant(rx_chains); |
499 | int num_tx_ants = num_of_ant(tx_chains); | |
c064ddf3 EH |
500 | unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?: |
501 | IEEE80211_VHT_MAX_AMPDU_1024K); | |
48e6de61 | 502 | |
33158fef EL |
503 | vht_cap->vht_supported = true; |
504 | ||
505 | vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 | | |
506 | IEEE80211_VHT_CAP_RXSTBC_1 | | |
507 | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | | |
e36b766d | 508 | 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | |
c064ddf3 EH |
509 | max_ampdu_exponent << |
510 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; | |
33158fef | 511 | |
4896d764 | 512 | if (data->vht160_supported) |
fbbd4859 GG |
513 | vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | |
514 | IEEE80211_VHT_CAP_SHORT_GI_160; | |
4896d764 | 515 | |
e48c947f SS |
516 | if (cfg->vht_mu_mimo_supported) |
517 | vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; | |
518 | ||
a3576ff2 ES |
519 | if (cfg->ht_params->ldpc) |
520 | vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC; | |
521 | ||
5f0d98f2 EG |
522 | if (data->sku_cap_mimo_disabled) { |
523 | num_rx_ants = 1; | |
524 | num_tx_ants = 1; | |
525 | } | |
526 | ||
6ca89f1f | 527 | if (num_tx_ants > 1) |
5f7a6f9b | 528 | vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; |
6ca89f1f JB |
529 | else |
530 | vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; | |
5f7a6f9b | 531 | |
6c4fbcbc | 532 | switch (iwlwifi_mod_params.amsdu_size) { |
4bdd4dfe | 533 | case IWL_AMSDU_DEF: |
7d34a7d7 | 534 | if (trans->trans_cfg->mq_rx_supported) |
4bdd4dfe EG |
535 | vht_cap->cap |= |
536 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; | |
537 | else | |
538 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; | |
539 | break; | |
1a4968d1 | 540 | case IWL_AMSDU_2K: |
7d34a7d7 | 541 | if (trans->trans_cfg->mq_rx_supported) |
1a4968d1 GBA |
542 | vht_cap->cap |= |
543 | IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; | |
544 | else | |
545 | WARN(1, "RB size of 2K is not supported by this device\n"); | |
546 | break; | |
6c4fbcbc EG |
547 | case IWL_AMSDU_4K: |
548 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; | |
549 | break; | |
550 | case IWL_AMSDU_8K: | |
33158fef | 551 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; |
6c4fbcbc EG |
552 | break; |
553 | case IWL_AMSDU_12K: | |
554 | vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; | |
555 | break; | |
556 | default: | |
557 | break; | |
558 | } | |
33158fef EL |
559 | |
560 | vht_cap->vht_mcs.rx_mcs_map = | |
561 | cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | | |
562 | IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | | |
563 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | | |
564 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | | |
565 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | | |
566 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | | |
567 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | | |
568 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); | |
569 | ||
6ca89f1f JB |
570 | if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) { |
571 | vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; | |
33158fef EL |
572 | /* this works because NOT_SUPPORTED == 3 */ |
573 | vht_cap->vht_mcs.rx_mcs_map |= | |
574 | cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2); | |
575 | } | |
576 | ||
577 | vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; | |
7691fa69 JB |
578 | |
579 | vht_cap->vht_mcs.tx_highest |= | |
580 | cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); | |
33158fef EL |
581 | } |
582 | ||
57a3a454 ST |
583 | static struct ieee80211_sband_iftype_data iwl_he_capa[] = { |
584 | { | |
585 | .types_mask = BIT(NL80211_IFTYPE_STATION), | |
586 | .he_cap = { | |
587 | .has_he = true, | |
588 | .he_cap_elem = { | |
589 | .mac_cap_info[0] = | |
590 | IEEE80211_HE_MAC_CAP0_HTC_HE | | |
591 | IEEE80211_HE_MAC_CAP0_TWT_REQ, | |
592 | .mac_cap_info[1] = | |
593 | IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | | |
594 | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, | |
595 | .mac_cap_info[2] = | |
38af8d5a | 596 | IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, |
57a3a454 ST |
597 | .mac_cap_info[3] = |
598 | IEEE80211_HE_MAC_CAP3_OMI_CONTROL | | |
599 | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, | |
600 | .mac_cap_info[4] = | |
601 | IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | | |
602 | IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, | |
603 | .mac_cap_info[5] = | |
604 | IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | | |
605 | IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 | | |
77ff2c6b LK |
606 | IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | |
607 | IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS | | |
608 | IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX, | |
57a3a454 ST |
609 | .phy_cap_info[0] = |
610 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | | |
611 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | | |
612 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, | |
613 | .phy_cap_info[1] = | |
614 | IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | | |
615 | IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | | |
77ff2c6b | 616 | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, |
57a3a454 | 617 | .phy_cap_info[2] = |
77ff2c6b | 618 | IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, |
57a3a454 | 619 | .phy_cap_info[3] = |
77ff2c6b | 620 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | |
57a3a454 | 621 | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | |
77ff2c6b | 622 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | |
57a3a454 ST |
623 | IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, |
624 | .phy_cap_info[4] = | |
625 | IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | | |
626 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | | |
627 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, | |
628 | .phy_cap_info[5] = | |
629 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | | |
77ff2c6b | 630 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, |
57a3a454 | 631 | .phy_cap_info[6] = |
57a3a454 ST |
632 | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, |
633 | .phy_cap_info[7] = | |
634 | IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | | |
635 | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | | |
636 | IEEE80211_HE_PHY_CAP7_MAX_NC_1, | |
637 | .phy_cap_info[8] = | |
638 | IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | | |
639 | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | | |
640 | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | | |
641 | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | | |
77ff2c6b | 642 | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, |
57a3a454 ST |
643 | .phy_cap_info[9] = |
644 | IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | | |
645 | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | | |
77ff2c6b LK |
646 | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | |
647 | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, | |
57a3a454 ST |
648 | }, |
649 | /* | |
650 | * Set default Tx/Rx HE MCS NSS Support field. | |
651 | * Indicate support for up to 2 spatial streams and all | |
652 | * MCS, without any special cases | |
653 | */ | |
654 | .he_mcs_nss_supp = { | |
655 | .rx_mcs_80 = cpu_to_le16(0xfffa), | |
656 | .tx_mcs_80 = cpu_to_le16(0xfffa), | |
657 | .rx_mcs_160 = cpu_to_le16(0xfffa), | |
658 | .tx_mcs_160 = cpu_to_le16(0xfffa), | |
659 | .rx_mcs_80p80 = cpu_to_le16(0xffff), | |
660 | .tx_mcs_80p80 = cpu_to_le16(0xffff), | |
661 | }, | |
662 | /* | |
663 | * Set default PPE thresholds, with PPET16 set to 0, | |
664 | * PPET8 set to 7 | |
665 | */ | |
666 | .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, | |
514c3069 | 667 | }, |
57a3a454 ST |
668 | }, |
669 | { | |
670 | .types_mask = BIT(NL80211_IFTYPE_AP), | |
671 | .he_cap = { | |
672 | .has_he = true, | |
673 | .he_cap_elem = { | |
674 | .mac_cap_info[0] = | |
7360f99e | 675 | IEEE80211_HE_MAC_CAP0_HTC_HE, |
57a3a454 ST |
676 | .mac_cap_info[1] = |
677 | IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | | |
678 | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, | |
679 | .mac_cap_info[2] = | |
38af8d5a | 680 | IEEE80211_HE_MAC_CAP2_BSR, |
57a3a454 ST |
681 | .mac_cap_info[3] = |
682 | IEEE80211_HE_MAC_CAP3_OMI_CONTROL | | |
683 | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, | |
684 | .mac_cap_info[4] = | |
685 | IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, | |
77ff2c6b LK |
686 | .mac_cap_info[5] = |
687 | IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, | |
57a3a454 ST |
688 | .phy_cap_info[0] = |
689 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | | |
690 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | | |
691 | IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G, | |
692 | .phy_cap_info[1] = | |
77ff2c6b | 693 | IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD, |
57a3a454 | 694 | .phy_cap_info[2] = |
77ff2c6b | 695 | IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US, |
57a3a454 | 696 | .phy_cap_info[3] = |
77ff2c6b | 697 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_NO_DCM | |
57a3a454 | 698 | IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_1 | |
77ff2c6b | 699 | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_NO_DCM | |
57a3a454 ST |
700 | IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1, |
701 | .phy_cap_info[4] = | |
702 | IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | | |
703 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_8 | | |
704 | IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_8, | |
705 | .phy_cap_info[5] = | |
706 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_2 | | |
77ff2c6b | 707 | IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_2, |
57a3a454 | 708 | .phy_cap_info[6] = |
57a3a454 ST |
709 | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, |
710 | .phy_cap_info[7] = | |
711 | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | | |
712 | IEEE80211_HE_PHY_CAP7_MAX_NC_1, | |
713 | .phy_cap_info[8] = | |
714 | IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | | |
715 | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | | |
716 | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | | |
717 | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | | |
77ff2c6b | 718 | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_2x996, |
57a3a454 ST |
719 | .phy_cap_info[9] = |
720 | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | | |
77ff2c6b LK |
721 | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | |
722 | IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_RESERVED, | |
57a3a454 ST |
723 | }, |
724 | /* | |
725 | * Set default Tx/Rx HE MCS NSS Support field. | |
726 | * Indicate support for up to 2 spatial streams and all | |
727 | * MCS, without any special cases | |
728 | */ | |
729 | .he_mcs_nss_supp = { | |
730 | .rx_mcs_80 = cpu_to_le16(0xfffa), | |
731 | .tx_mcs_80 = cpu_to_le16(0xfffa), | |
732 | .rx_mcs_160 = cpu_to_le16(0xfffa), | |
733 | .tx_mcs_160 = cpu_to_le16(0xfffa), | |
734 | .rx_mcs_80p80 = cpu_to_le16(0xffff), | |
735 | .tx_mcs_80p80 = cpu_to_le16(0xffff), | |
736 | }, | |
737 | /* | |
738 | * Set default PPE thresholds, with PPET16 set to 0, | |
739 | * PPET8 set to 7 | |
740 | */ | |
741 | .ppe_thres = {0x61, 0x1c, 0xc7, 0x71}, | |
514c3069 | 742 | }, |
514c3069 LC |
743 | }, |
744 | }; | |
745 | ||
df658908 JB |
746 | static void iwl_init_he_hw_capab(struct iwl_trans *trans, |
747 | struct iwl_nvm_data *data, | |
748 | struct ieee80211_supported_band *sband, | |
514c3069 LC |
749 | u8 tx_chains, u8 rx_chains) |
750 | { | |
186e6c87 | 751 | sband->iftype_data = iwl_he_capa; |
57a3a454 | 752 | sband->n_iftype_data = ARRAY_SIZE(iwl_he_capa); |
514c3069 LC |
753 | |
754 | /* If not 2x2, we need to indicate 1x1 in the Midamble RX Max NSTS */ | |
755 | if ((tx_chains & rx_chains) != ANT_AB) { | |
57a3a454 ST |
756 | int i; |
757 | ||
758 | for (i = 0; i < sband->n_iftype_data; i++) { | |
759 | iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[1] &= | |
760 | ~IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS; | |
761 | iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[2] &= | |
762 | ~IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS; | |
763 | iwl_he_capa[i].he_cap.he_cap_elem.phy_cap_info[7] &= | |
764 | ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; | |
765 | } | |
514c3069 LC |
766 | } |
767 | } | |
768 | ||
d8913b80 | 769 | static void iwl_init_sbands(struct iwl_trans *trans, |
4c625c56 | 770 | struct iwl_nvm_data *data, |
2785ce00 ST |
771 | const void *nvm_ch_flags, u8 tx_chains, |
772 | u8 rx_chains, u32 sbands_flags, bool v4) | |
b1e1adfa | 773 | { |
d8913b80 ST |
774 | struct device *dev = trans->dev; |
775 | const struct iwl_cfg *cfg = trans->cfg; | |
77db0a3c | 776 | int n_channels; |
b1e1adfa JB |
777 | int n_used = 0; |
778 | struct ieee80211_supported_band *sband; | |
779 | ||
29108495 | 780 | n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags, |
2785ce00 | 781 | sbands_flags, v4); |
57fbcce3 JB |
782 | sband = &data->bands[NL80211_BAND_2GHZ]; |
783 | sband->band = NL80211_BAND_2GHZ; | |
b1e1adfa JB |
784 | sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; |
785 | sband->n_bitrates = N_RATES_24; | |
786 | n_used += iwl_init_sband_channels(data, sband, n_channels, | |
57fbcce3 | 787 | NL80211_BAND_2GHZ); |
7d34a7d7 | 788 | iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ, |
9ce4fa72 | 789 | tx_chains, rx_chains); |
b1e1adfa | 790 | |
230ba6c5 | 791 | if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) |
df658908 | 792 | iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); |
514c3069 | 793 | |
57fbcce3 JB |
794 | sband = &data->bands[NL80211_BAND_5GHZ]; |
795 | sband->band = NL80211_BAND_5GHZ; | |
b1e1adfa JB |
796 | sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; |
797 | sband->n_bitrates = N_RATES_52; | |
798 | n_used += iwl_init_sband_channels(data, sband, n_channels, | |
57fbcce3 | 799 | NL80211_BAND_5GHZ); |
7d34a7d7 | 800 | iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ, |
9ce4fa72 | 801 | tx_chains, rx_chains); |
0d0985ad | 802 | if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac) |
d8913b80 | 803 | iwl_init_vht_hw_capab(trans, data, &sband->vht_cap, |
6ca89f1f | 804 | tx_chains, rx_chains); |
b1e1adfa | 805 | |
230ba6c5 | 806 | if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) |
df658908 | 807 | iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains); |
514c3069 | 808 | |
b1e1adfa JB |
809 | if (n_channels != n_used) |
810 | IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", | |
811 | n_used, n_channels); | |
812 | } | |
813 | ||
5dd9c68a EG |
814 | static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw, |
815 | const __le16 *phy_sku) | |
77db0a3c | 816 | { |
44fd09da | 817 | if (cfg->nvm_type != IWL_NVM_EXT) |
77db0a3c | 818 | return le16_to_cpup(nvm_sw + SKU); |
ce500071 | 819 | |
5dd9c68a | 820 | return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000)); |
77db0a3c EH |
821 | } |
822 | ||
5dd9c68a | 823 | static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw) |
77db0a3c | 824 | { |
44fd09da | 825 | if (cfg->nvm_type != IWL_NVM_EXT) |
77db0a3c EH |
826 | return le16_to_cpup(nvm_sw + NVM_VERSION); |
827 | else | |
828 | return le32_to_cpup((__le32 *)(nvm_sw + | |
7042678d | 829 | NVM_VERSION_EXT_NVM)); |
77db0a3c EH |
830 | } |
831 | ||
5dd9c68a EG |
832 | static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw, |
833 | const __le16 *phy_sku) | |
77db0a3c | 834 | { |
44fd09da | 835 | if (cfg->nvm_type != IWL_NVM_EXT) |
77db0a3c | 836 | return le16_to_cpup(nvm_sw + RADIO_CFG); |
ce500071 | 837 | |
7042678d | 838 | return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM)); |
ce500071 | 839 | |
77db0a3c EH |
840 | } |
841 | ||
5dd9c68a | 842 | static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw) |
77db0a3c | 843 | { |
ce500071 EH |
844 | int n_hw_addr; |
845 | ||
44fd09da | 846 | if (cfg->nvm_type != IWL_NVM_EXT) |
77db0a3c | 847 | return le16_to_cpup(nvm_sw + N_HW_ADDRS); |
ce500071 | 848 | |
5dd9c68a | 849 | n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000)); |
ce500071 EH |
850 | |
851 | return n_hw_addr & N_HW_ADDR_MASK; | |
77db0a3c EH |
852 | } |
853 | ||
854 | static void iwl_set_radio_cfg(const struct iwl_cfg *cfg, | |
855 | struct iwl_nvm_data *data, | |
856 | u32 radio_cfg) | |
857 | { | |
44fd09da | 858 | if (cfg->nvm_type != IWL_NVM_EXT) { |
77db0a3c EH |
859 | data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg); |
860 | data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg); | |
861 | data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg); | |
862 | data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg); | |
77db0a3c EH |
863 | return; |
864 | } | |
865 | ||
866 | /* set the radio configuration for family 8000 */ | |
7042678d SS |
867 | data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg); |
868 | data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg); | |
869 | data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg); | |
870 | data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg); | |
871 | data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg); | |
872 | data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg); | |
77db0a3c EH |
873 | } |
874 | ||
17c867bf SS |
875 | static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) |
876 | { | |
877 | const u8 *hw_addr; | |
878 | ||
879 | hw_addr = (const u8 *)&mac_addr0; | |
880 | dest[0] = hw_addr[3]; | |
881 | dest[1] = hw_addr[2]; | |
882 | dest[2] = hw_addr[1]; | |
883 | dest[3] = hw_addr[0]; | |
884 | ||
885 | hw_addr = (const u8 *)&mac_addr1; | |
886 | dest[4] = hw_addr[1]; | |
887 | dest[5] = hw_addr[0]; | |
888 | } | |
889 | ||
4c625c56 ST |
890 | static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, |
891 | struct iwl_nvm_data *data) | |
17c867bf | 892 | { |
6dece0e9 LC |
893 | __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP)); |
894 | __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP)); | |
17c867bf | 895 | |
a6c934b3 HD |
896 | iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); |
897 | /* | |
898 | * If the OEM fused a valid address, use it instead of the one in the | |
899 | * OTP | |
900 | */ | |
901 | if (is_valid_ether_addr(data->hw_addr)) | |
902 | return; | |
903 | ||
6dece0e9 LC |
904 | mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP)); |
905 | mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP)); | |
17c867bf SS |
906 | |
907 | iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); | |
908 | } | |
909 | ||
afd5b170 | 910 | static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, |
6a68a39f | 911 | const struct iwl_cfg *cfg, |
9f32e017 EH |
912 | struct iwl_nvm_data *data, |
913 | const __le16 *mac_override, | |
8fe34b06 | 914 | const __be16 *nvm_hw) |
9f32e017 EH |
915 | { |
916 | const u8 *hw_addr; | |
917 | ||
918 | if (mac_override) { | |
18f84673 LK |
919 | static const u8 reserved_mac[] = { |
920 | 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00 | |
921 | }; | |
922 | ||
9f32e017 | 923 | hw_addr = (const u8 *)(mac_override + |
7042678d | 924 | MAC_ADDRESS_OVERRIDE_EXT_NVM); |
9f32e017 | 925 | |
be88a1ad LK |
926 | /* |
927 | * Store the MAC address from MAO section. | |
928 | * No byte swapping is required in MAO section | |
929 | */ | |
930 | memcpy(data->hw_addr, hw_addr, ETH_ALEN); | |
9f32e017 | 931 | |
18f84673 LK |
932 | /* |
933 | * Force the use of the OTP MAC address in case of reserved MAC | |
934 | * address in the NVM, or if address is given but invalid. | |
935 | */ | |
936 | if (is_valid_ether_addr(data->hw_addr) && | |
937 | memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0) | |
9f32e017 | 938 | return; |
6a68a39f | 939 | |
afd5b170 SS |
940 | IWL_ERR(trans, |
941 | "mac address from nvm override section is not valid\n"); | |
9f32e017 EH |
942 | } |
943 | ||
6a68a39f | 944 | if (nvm_hw) { |
afd5b170 SS |
945 | /* read the mac address from WFMP registers */ |
946 | __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans, | |
947 | WFMP_MAC_ADDR_0)); | |
948 | __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans, | |
949 | WFMP_MAC_ADDR_1)); | |
17c867bf SS |
950 | |
951 | iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); | |
1e0b393a | 952 | |
6a68a39f EH |
953 | return; |
954 | } | |
9f32e017 | 955 | |
afd5b170 SS |
956 | IWL_ERR(trans, "mac address is not found\n"); |
957 | } | |
958 | ||
17c867bf SS |
959 | static int iwl_set_hw_address(struct iwl_trans *trans, |
960 | const struct iwl_cfg *cfg, | |
8fe34b06 | 961 | struct iwl_nvm_data *data, const __be16 *nvm_hw, |
17c867bf | 962 | const __le16 *mac_override) |
afd5b170 | 963 | { |
17c867bf SS |
964 | if (cfg->mac_addr_from_csr) { |
965 | iwl_set_hw_address_from_csr(trans, data); | |
44fd09da | 966 | } else if (cfg->nvm_type != IWL_NVM_EXT) { |
afd5b170 SS |
967 | const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR); |
968 | ||
969 | /* The byte order is little endian 16 bit, meaning 214365 */ | |
970 | data->hw_addr[0] = hw_addr[1]; | |
971 | data->hw_addr[1] = hw_addr[0]; | |
972 | data->hw_addr[2] = hw_addr[3]; | |
973 | data->hw_addr[3] = hw_addr[2]; | |
974 | data->hw_addr[4] = hw_addr[5]; | |
975 | data->hw_addr[5] = hw_addr[4]; | |
976 | } else { | |
977 | iwl_set_hw_address_family_8000(trans, cfg, data, | |
978 | mac_override, nvm_hw); | |
979 | } | |
17c867bf SS |
980 | |
981 | if (!is_valid_ether_addr(data->hw_addr)) { | |
982 | IWL_ERR(trans, "no valid mac address was found\n"); | |
983 | return -EINVAL; | |
984 | } | |
985 | ||
4409e72b LC |
986 | IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr); |
987 | ||
17c867bf | 988 | return 0; |
9f32e017 EH |
989 | } |
990 | ||
01a9c948 | 991 | static bool |
7d34a7d7 | 992 | iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg, |
8fe34b06 | 993 | const __be16 *nvm_hw) |
01a9c948 LC |
994 | { |
995 | /* | |
996 | * Workaround a bug in Indonesia SKUs where the regulatory in | |
997 | * some 7000-family OTPs erroneously allow wide channels in | |
998 | * 5GHz. To check for Indonesia, we take the SKU value from | |
999 | * bits 1-4 in the subsystem ID and check if it is either 5 or | |
1000 | * 9. In those cases, we need to force-disable wide channels | |
1001 | * in 5GHz otherwise the FW will throw a sysassert when we try | |
1002 | * to use them. | |
1003 | */ | |
7d34a7d7 | 1004 | if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) { |
01a9c948 LC |
1005 | /* |
1006 | * Unlike the other sections in the NVM, the hw | |
1007 | * section uses big-endian. | |
1008 | */ | |
8fe34b06 | 1009 | u16 subsystem_id = be16_to_cpup(nvm_hw + SUBSYSTEM_ID); |
01a9c948 LC |
1010 | u8 sku = (subsystem_id & 0x1e) >> 1; |
1011 | ||
1012 | if (sku == 5 || sku == 9) { | |
7d34a7d7 | 1013 | IWL_DEBUG_EEPROM(trans->dev, |
01a9c948 LC |
1014 | "disabling wide channels in 5GHz (0x%0x %d)\n", |
1015 | subsystem_id, sku); | |
1016 | return true; | |
1017 | } | |
1018 | } | |
1019 | ||
1020 | return false; | |
1021 | } | |
1022 | ||
b1e1adfa | 1023 | struct iwl_nvm_data * |
afd5b170 | 1024 | iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, |
f06021a1 | 1025 | const struct iwl_fw *fw, |
8fe34b06 | 1026 | const __be16 *nvm_hw, const __le16 *nvm_sw, |
77db0a3c | 1027 | const __le16 *nvm_calib, const __le16 *regulatory, |
ce500071 | 1028 | const __le16 *mac_override, const __le16 *phy_sku, |
f06021a1 | 1029 | u8 tx_chains, u8 rx_chains) |
b1e1adfa JB |
1030 | { |
1031 | struct iwl_nvm_data *data; | |
afd5b170 SS |
1032 | bool lar_enabled; |
1033 | u32 sku, radio_cfg; | |
4b82455c | 1034 | u32 sbands_flags = 0; |
d0d15197 | 1035 | u16 lar_config; |
afd5b170 | 1036 | const __le16 *ch_section; |
77db0a3c | 1037 | |
c8cfa08e TM |
1038 | if (cfg->uhb_supported) |
1039 | data = kzalloc(struct_size(data, channels, | |
1040 | IWL_NVM_NUM_CHANNELS_UHB), | |
1041 | GFP_KERNEL); | |
1042 | else if (cfg->nvm_type != IWL_NVM_EXT) | |
6b367c9f GS |
1043 | data = kzalloc(struct_size(data, channels, |
1044 | IWL_NVM_NUM_CHANNELS), | |
1045 | GFP_KERNEL); | |
77db0a3c | 1046 | else |
6b367c9f GS |
1047 | data = kzalloc(struct_size(data, channels, |
1048 | IWL_NVM_NUM_CHANNELS_EXT), | |
1049 | GFP_KERNEL); | |
b1e1adfa JB |
1050 | if (!data) |
1051 | return NULL; | |
1052 | ||
77db0a3c | 1053 | data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw); |
b1e1adfa | 1054 | |
5dd9c68a | 1055 | radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw, phy_sku); |
77db0a3c | 1056 | iwl_set_radio_cfg(cfg, data, radio_cfg); |
a0544272 MH |
1057 | if (data->valid_tx_ant) |
1058 | tx_chains &= data->valid_tx_ant; | |
1059 | if (data->valid_rx_ant) | |
1060 | rx_chains &= data->valid_rx_ant; | |
b1e1adfa | 1061 | |
5dd9c68a | 1062 | sku = iwl_get_sku(cfg, nvm_sw, phy_sku); |
28e9c00f LC |
1063 | data->sku_cap_band_24ghz_enable = sku & NVM_SKU_CAP_BAND_24GHZ; |
1064 | data->sku_cap_band_52ghz_enable = sku & NVM_SKU_CAP_BAND_52GHZ; | |
b1e1adfa JB |
1065 | data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE; |
1066 | if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) | |
1067 | data->sku_cap_11n_enable = false; | |
2926f958 EP |
1068 | data->sku_cap_11ac_enable = data->sku_cap_11n_enable && |
1069 | (sku & NVM_SKU_CAP_11AC_ENABLE); | |
5f0d98f2 | 1070 | data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE; |
b1e1adfa | 1071 | |
5dd9c68a | 1072 | data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw); |
b1e1adfa | 1073 | |
44fd09da | 1074 | if (cfg->nvm_type != IWL_NVM_EXT) { |
77db0a3c EH |
1075 | /* Checking for required sections */ |
1076 | if (!nvm_calib) { | |
afd5b170 SS |
1077 | IWL_ERR(trans, |
1078 | "Can't parse empty Calib NVM sections\n"); | |
1270c416 | 1079 | kfree(data); |
77db0a3c EH |
1080 | return NULL; |
1081 | } | |
44fd09da CRI |
1082 | |
1083 | ch_section = cfg->nvm_type == IWL_NVM_SDP ? | |
1084 | ®ulatory[NVM_CHANNELS_SDP] : | |
1085 | &nvm_sw[NVM_CHANNELS]; | |
1086 | ||
77db0a3c EH |
1087 | /* in family 8000 Xtal calibration values moved to OTP */ |
1088 | data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); | |
1089 | data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); | |
afd5b170 | 1090 | lar_enabled = true; |
77db0a3c | 1091 | } else { |
f5528631 | 1092 | u16 lar_offset = data->nvm_version < 0xE39 ? |
7042678d SS |
1093 | NVM_LAR_OFFSET_OLD : |
1094 | NVM_LAR_OFFSET; | |
f5528631 AN |
1095 | |
1096 | lar_config = le16_to_cpup(regulatory + lar_offset); | |
d0d15197 | 1097 | data->lar_enabled = !!(lar_config & |
7042678d | 1098 | NVM_LAR_ENABLED); |
afd5b170 | 1099 | lar_enabled = data->lar_enabled; |
7042678d | 1100 | ch_section = ®ulatory[NVM_CHANNELS_EXTENDED]; |
77db0a3c | 1101 | } |
b1e1adfa | 1102 | |
17c867bf SS |
1103 | /* If no valid mac address was found - bail out */ |
1104 | if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) { | |
1105 | kfree(data); | |
1106 | return NULL; | |
1107 | } | |
1108 | ||
f06021a1 LC |
1109 | if (lar_enabled && |
1110 | fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) | |
4b82455c LC |
1111 | sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; |
1112 | ||
7d34a7d7 | 1113 | if (iwl_nvm_no_wide_in_5ghz(trans, cfg, nvm_hw)) |
4b82455c LC |
1114 | sbands_flags |= IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ; |
1115 | ||
d8913b80 | 1116 | iwl_init_sbands(trans, data, ch_section, tx_chains, rx_chains, |
2785ce00 | 1117 | sbands_flags, false); |
33b2f684 | 1118 | data->calib_version = 255; |
b1e1adfa JB |
1119 | |
1120 | return data; | |
1121 | } | |
48e29340 | 1122 | IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); |
af45a900 | 1123 | |
b15ef67c | 1124 | static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, |
b281c93d | 1125 | int ch_idx, u16 nvm_flags, |
e27c506a | 1126 | struct iwl_reg_capa reg_capa, |
b281c93d | 1127 | const struct iwl_cfg *cfg) |
af45a900 AN |
1128 | { |
1129 | u32 flags = NL80211_RRF_NO_HT40; | |
1130 | ||
1131 | if (ch_idx < NUM_2GHZ_CHANNELS && | |
1132 | (nvm_flags & NVM_CHANNEL_40MHZ)) { | |
1133 | if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS) | |
1134 | flags &= ~NL80211_RRF_NO_HT40PLUS; | |
1135 | if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) | |
1136 | flags &= ~NL80211_RRF_NO_HT40MINUS; | |
b15ef67c | 1137 | } else if (nvm_flags & NVM_CHANNEL_40MHZ) { |
af45a900 AN |
1138 | if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) |
1139 | flags &= ~NL80211_RRF_NO_HT40PLUS; | |
1140 | else | |
1141 | flags &= ~NL80211_RRF_NO_HT40MINUS; | |
1142 | } | |
1143 | ||
1144 | if (!(nvm_flags & NVM_CHANNEL_80MHZ)) | |
1145 | flags |= NL80211_RRF_NO_80MHZ; | |
1146 | if (!(nvm_flags & NVM_CHANNEL_160MHZ)) | |
1147 | flags |= NL80211_RRF_NO_160MHZ; | |
1148 | ||
af45a900 AN |
1149 | if (!(nvm_flags & NVM_CHANNEL_ACTIVE)) |
1150 | flags |= NL80211_RRF_NO_IR; | |
1151 | ||
1152 | if (nvm_flags & NVM_CHANNEL_RADAR) | |
1153 | flags |= NL80211_RRF_DFS; | |
1154 | ||
1155 | if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY) | |
1156 | flags |= NL80211_RRF_NO_OUTDOOR; | |
1157 | ||
1158 | /* Set the GO concurrent flag only in case that NO_IR is set. | |
1159 | * Otherwise it is meaningless | |
1160 | */ | |
1161 | if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && | |
1162 | (flags & NL80211_RRF_NO_IR)) | |
1163 | flags |= NL80211_RRF_GO_CONCURRENT; | |
1164 | ||
2763bba6 | 1165 | /* |
e27c506a | 1166 | * reg_capa is per regulatory domain so apply it for every channel |
2763bba6 HD |
1167 | */ |
1168 | if (ch_idx >= NUM_2GHZ_CHANNELS) { | |
e27c506a | 1169 | if (!reg_capa.allow_40mhz) |
2763bba6 HD |
1170 | flags |= NL80211_RRF_NO_HT40; |
1171 | ||
e27c506a | 1172 | if (!reg_capa.allow_80mhz) |
2763bba6 HD |
1173 | flags |= NL80211_RRF_NO_80MHZ; |
1174 | ||
e27c506a | 1175 | if (!reg_capa.allow_160mhz) |
2763bba6 HD |
1176 | flags |= NL80211_RRF_NO_160MHZ; |
1177 | } | |
e27c506a | 1178 | if (reg_capa.disable_11ax) |
a224883c HD |
1179 | flags |= NL80211_RRF_NO_HE; |
1180 | ||
af45a900 AN |
1181 | return flags; |
1182 | } | |
1183 | ||
e27c506a GA |
1184 | static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) |
1185 | { | |
1186 | struct iwl_reg_capa reg_capa; | |
1187 | ||
1188 | if (resp_ver >= REG_CAPA_V2_RESP_VER) { | |
1189 | reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED; | |
1190 | reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED; | |
1191 | reg_capa.allow_160mhz = flags & REG_CAPA_V2_160MHZ_ALLOWED; | |
1192 | reg_capa.disable_11ax = flags & REG_CAPA_V2_11AX_DISABLED; | |
1193 | } else { | |
1194 | reg_capa.allow_40mhz = !(flags & REG_CAPA_40MHZ_FORBIDDEN); | |
1195 | reg_capa.allow_80mhz = flags & REG_CAPA_80MHZ_ALLOWED; | |
1196 | reg_capa.allow_160mhz = flags & REG_CAPA_160MHZ_ALLOWED; | |
1197 | reg_capa.disable_11ax = flags & REG_CAPA_11AX_DISABLED; | |
1198 | } | |
1199 | return reg_capa; | |
1200 | } | |
1201 | ||
af45a900 | 1202 | struct ieee80211_regdomain * |
162ee3c9 | 1203 | iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, |
77e30e10 | 1204 | int num_of_ch, __le32 *channels, u16 fw_mcc, |
e27c506a | 1205 | u16 geo_info, u16 cap, u8 resp_ver) |
af45a900 AN |
1206 | { |
1207 | int ch_idx; | |
92b0f7b2 EG |
1208 | u16 ch_flags; |
1209 | u32 reg_rule_flags, prev_reg_rule_flags = 0; | |
b15ef67c | 1210 | const u16 *nvm_chan; |
77e30e10 | 1211 | struct ieee80211_regdomain *regd, *copy_rd; |
af45a900 | 1212 | struct ieee80211_reg_rule *rule; |
57fbcce3 | 1213 | enum nl80211_band band; |
af45a900 | 1214 | int center_freq, prev_center_freq = 0; |
38cb87ee | 1215 | int valid_rules = 0; |
af45a900 | 1216 | bool new_rule; |
b15ef67c | 1217 | int max_num_ch; |
e27c506a | 1218 | struct iwl_reg_capa reg_capa; |
b15ef67c ST |
1219 | |
1220 | if (cfg->uhb_supported) { | |
1221 | max_num_ch = IWL_NVM_NUM_CHANNELS_UHB; | |
1222 | nvm_chan = iwl_uhb_nvm_channels; | |
1223 | } else if (cfg->nvm_type == IWL_NVM_EXT) { | |
1224 | max_num_ch = IWL_NVM_NUM_CHANNELS_EXT; | |
1225 | nvm_chan = iwl_ext_nvm_channels; | |
1226 | } else { | |
1227 | max_num_ch = IWL_NVM_NUM_CHANNELS; | |
1228 | nvm_chan = iwl_nvm_channels; | |
1229 | } | |
af45a900 | 1230 | |
4557eaba AN |
1231 | if (WARN_ON(num_of_ch > max_num_ch)) |
1232 | num_of_ch = max_num_ch; | |
1233 | ||
4c816b21 ST |
1234 | if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES)) |
1235 | return ERR_PTR(-EINVAL); | |
1236 | ||
af45a900 AN |
1237 | IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n", |
1238 | num_of_ch); | |
1239 | ||
1240 | /* build a regdomain rule for every valid channel */ | |
78d722b1 | 1241 | regd = kzalloc(struct_size(regd, reg_rules, num_of_ch), GFP_KERNEL); |
af45a900 AN |
1242 | if (!regd) |
1243 | return ERR_PTR(-ENOMEM); | |
1244 | ||
77e30e10 HD |
1245 | /* set alpha2 from FW. */ |
1246 | regd->alpha2[0] = fw_mcc >> 8; | |
1247 | regd->alpha2[1] = fw_mcc & 0xff; | |
1248 | ||
e27c506a GA |
1249 | /* parse regulatory capability flags */ |
1250 | reg_capa = iwl_get_reg_capa(cap, resp_ver); | |
1251 | ||
af45a900 AN |
1252 | for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { |
1253 | ch_flags = (u16)__le32_to_cpup(channels + ch_idx); | |
c2cf318d | 1254 | band = iwl_nl80211_band_from_channel_idx(ch_idx); |
af45a900 AN |
1255 | center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], |
1256 | band); | |
1257 | new_rule = false; | |
1258 | ||
1259 | if (!(ch_flags & NVM_CHANNEL_VALID)) { | |
d8c73e45 JB |
1260 | iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, |
1261 | nvm_chan[ch_idx], ch_flags); | |
af45a900 AN |
1262 | continue; |
1263 | } | |
1264 | ||
92b0f7b2 | 1265 | reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, |
e27c506a | 1266 | ch_flags, reg_capa, |
2763bba6 | 1267 | cfg); |
92b0f7b2 | 1268 | |
af45a900 | 1269 | /* we can't continue the same rule */ |
92b0f7b2 | 1270 | if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags || |
af45a900 AN |
1271 | center_freq - prev_center_freq > 20) { |
1272 | valid_rules++; | |
1273 | new_rule = true; | |
1274 | } | |
1275 | ||
1276 | rule = ®d->reg_rules[valid_rules - 1]; | |
1277 | ||
1278 | if (new_rule) | |
1279 | rule->freq_range.start_freq_khz = | |
1280 | MHZ_TO_KHZ(center_freq - 10); | |
1281 | ||
1282 | rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10); | |
1283 | ||
1284 | /* this doesn't matter - not used by FW */ | |
1285 | rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); | |
02a50495 EP |
1286 | rule->power_rule.max_eirp = |
1287 | DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER); | |
af45a900 | 1288 | |
92b0f7b2 | 1289 | rule->flags = reg_rule_flags; |
af45a900 AN |
1290 | |
1291 | /* rely on auto-calculation to merge BW of contiguous chans */ | |
1292 | rule->flags |= NL80211_RRF_AUTO_BW; | |
1293 | rule->freq_range.max_bandwidth_khz = 0; | |
1294 | ||
af45a900 | 1295 | prev_center_freq = center_freq; |
92b0f7b2 | 1296 | prev_reg_rule_flags = reg_rule_flags; |
af45a900 | 1297 | |
d8c73e45 JB |
1298 | iwl_nvm_print_channel_flags(dev, IWL_DL_LAR, |
1299 | nvm_chan[ch_idx], ch_flags); | |
77e30e10 HD |
1300 | |
1301 | if (!(geo_info & GEO_WMM_ETSI_5GHZ_INFO) || | |
1302 | band == NL80211_BAND_2GHZ) | |
1303 | continue; | |
1304 | ||
38cb87ee | 1305 | reg_query_regdb_wmm(regd->alpha2, center_freq, rule); |
af45a900 AN |
1306 | } |
1307 | ||
1308 | regd->n_reg_rules = valid_rules; | |
1309 | ||
77e30e10 HD |
1310 | /* |
1311 | * Narrow down regdom for unused regulatory rules to prevent hole | |
1312 | * between reg rules to wmm rules. | |
1313 | */ | |
78d722b1 Y |
1314 | copy_rd = kmemdup(regd, struct_size(regd, reg_rules, valid_rules), |
1315 | GFP_KERNEL); | |
a2a120a9 | 1316 | if (!copy_rd) |
77e30e10 | 1317 | copy_rd = ERR_PTR(-ENOMEM); |
77e30e10 | 1318 | |
77e30e10 HD |
1319 | kfree(regd); |
1320 | return copy_rd; | |
af45a900 AN |
1321 | } |
1322 | IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info); | |
9c4f7d51 ST |
1323 | |
1324 | #define IWL_MAX_NVM_SECTION_SIZE 0x1b58 | |
1325 | #define IWL_MAX_EXT_NVM_SECTION_SIZE 0x1ffc | |
1326 | #define MAX_NVM_FILE_LEN 16384 | |
1327 | ||
1328 | void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, | |
1329 | unsigned int len) | |
1330 | { | |
1331 | #define IWL_4165_DEVICE_ID 0x5501 | |
1332 | #define NVM_SKU_CAP_MIMO_DISABLE BIT(5) | |
1333 | ||
1334 | if (section == NVM_SECTION_TYPE_PHY_SKU && | |
1335 | hw_id == IWL_4165_DEVICE_ID && data && len >= 5 && | |
1336 | (data[4] & NVM_SKU_CAP_MIMO_DISABLE)) | |
1337 | /* OTP 0x52 bug work around: it's a 1x1 device */ | |
1338 | data[3] = ANT_B | (ANT_B << 4); | |
1339 | } | |
1340 | IWL_EXPORT_SYMBOL(iwl_nvm_fixups); | |
1341 | ||
1342 | /* | |
1343 | * Reads external NVM from a file into mvm->nvm_sections | |
1344 | * | |
1345 | * HOW TO CREATE THE NVM FILE FORMAT: | |
1346 | * ------------------------------ | |
1347 | * 1. create hex file, format: | |
1348 | * 3800 -> header | |
1349 | * 0000 -> header | |
1350 | * 5a40 -> data | |
1351 | * | |
1352 | * rev - 6 bit (word1) | |
1353 | * len - 10 bit (word1) | |
1354 | * id - 4 bit (word2) | |
1355 | * rsv - 12 bit (word2) | |
1356 | * | |
1357 | * 2. flip 8bits with 8 bits per line to get the right NVM file format | |
1358 | * | |
1359 | * 3. create binary file from the hex file | |
1360 | * | |
1361 | * 4. save as "iNVM_xxx.bin" under /lib/firmware | |
1362 | */ | |
1363 | int iwl_read_external_nvm(struct iwl_trans *trans, | |
1364 | const char *nvm_file_name, | |
1365 | struct iwl_nvm_section *nvm_sections) | |
1366 | { | |
1367 | int ret, section_size; | |
1368 | u16 section_id; | |
1369 | const struct firmware *fw_entry; | |
1370 | const struct { | |
1371 | __le16 word1; | |
1372 | __le16 word2; | |
1373 | u8 data[]; | |
1374 | } *file_sec; | |
1375 | const u8 *eof; | |
1376 | u8 *temp; | |
1377 | int max_section_size; | |
1378 | const __le32 *dword_buff; | |
1379 | ||
1380 | #define NVM_WORD1_LEN(x) (8 * (x & 0x03FF)) | |
1381 | #define NVM_WORD2_ID(x) (x >> 12) | |
1382 | #define EXT_NVM_WORD2_LEN(x) (2 * (((x) & 0xFF) << 8 | (x) >> 8)) | |
1383 | #define EXT_NVM_WORD1_ID(x) ((x) >> 4) | |
1384 | #define NVM_HEADER_0 (0x2A504C54) | |
1385 | #define NVM_HEADER_1 (0x4E564D2A) | |
1386 | #define NVM_HEADER_SIZE (4 * sizeof(u32)) | |
1387 | ||
1388 | IWL_DEBUG_EEPROM(trans->dev, "Read from external NVM\n"); | |
1389 | ||
1390 | /* Maximal size depends on NVM version */ | |
1391 | if (trans->cfg->nvm_type != IWL_NVM_EXT) | |
1392 | max_section_size = IWL_MAX_NVM_SECTION_SIZE; | |
1393 | else | |
1394 | max_section_size = IWL_MAX_EXT_NVM_SECTION_SIZE; | |
1395 | ||
1396 | /* | |
1397 | * Obtain NVM image via request_firmware. Since we already used | |
1398 | * request_firmware_nowait() for the firmware binary load and only | |
1399 | * get here after that we assume the NVM request can be satisfied | |
1400 | * synchronously. | |
1401 | */ | |
1402 | ret = request_firmware(&fw_entry, nvm_file_name, trans->dev); | |
1403 | if (ret) { | |
1404 | IWL_ERR(trans, "ERROR: %s isn't available %d\n", | |
1405 | nvm_file_name, ret); | |
1406 | return ret; | |
1407 | } | |
1408 | ||
1409 | IWL_INFO(trans, "Loaded NVM file %s (%zu bytes)\n", | |
1410 | nvm_file_name, fw_entry->size); | |
1411 | ||
1412 | if (fw_entry->size > MAX_NVM_FILE_LEN) { | |
1413 | IWL_ERR(trans, "NVM file too large\n"); | |
1414 | ret = -EINVAL; | |
1415 | goto out; | |
1416 | } | |
1417 | ||
1418 | eof = fw_entry->data + fw_entry->size; | |
1419 | dword_buff = (__le32 *)fw_entry->data; | |
1420 | ||
1421 | /* some NVM file will contain a header. | |
1422 | * The header is identified by 2 dwords header as follow: | |
1423 | * dword[0] = 0x2A504C54 | |
1424 | * dword[1] = 0x4E564D2A | |
1425 | * | |
1426 | * This header must be skipped when providing the NVM data to the FW. | |
1427 | */ | |
1428 | if (fw_entry->size > NVM_HEADER_SIZE && | |
1429 | dword_buff[0] == cpu_to_le32(NVM_HEADER_0) && | |
1430 | dword_buff[1] == cpu_to_le32(NVM_HEADER_1)) { | |
1431 | file_sec = (void *)(fw_entry->data + NVM_HEADER_SIZE); | |
1432 | IWL_INFO(trans, "NVM Version %08X\n", le32_to_cpu(dword_buff[2])); | |
1433 | IWL_INFO(trans, "NVM Manufacturing date %08X\n", | |
1434 | le32_to_cpu(dword_buff[3])); | |
1435 | ||
1436 | /* nvm file validation, dword_buff[2] holds the file version */ | |
286ca8eb | 1437 | if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_8000 && |
9c4f7d51 ST |
1438 | CSR_HW_REV_STEP(trans->hw_rev) == SILICON_C_STEP && |
1439 | le32_to_cpu(dword_buff[2]) < 0xE4A) { | |
1440 | ret = -EFAULT; | |
1441 | goto out; | |
1442 | } | |
1443 | } else { | |
1444 | file_sec = (void *)fw_entry->data; | |
1445 | } | |
1446 | ||
1447 | while (true) { | |
1448 | if (file_sec->data > eof) { | |
1449 | IWL_ERR(trans, | |
1450 | "ERROR - NVM file too short for section header\n"); | |
1451 | ret = -EINVAL; | |
1452 | break; | |
1453 | } | |
1454 | ||
1455 | /* check for EOF marker */ | |
1456 | if (!file_sec->word1 && !file_sec->word2) { | |
1457 | ret = 0; | |
1458 | break; | |
1459 | } | |
1460 | ||
1461 | if (trans->cfg->nvm_type != IWL_NVM_EXT) { | |
1462 | section_size = | |
1463 | 2 * NVM_WORD1_LEN(le16_to_cpu(file_sec->word1)); | |
1464 | section_id = NVM_WORD2_ID(le16_to_cpu(file_sec->word2)); | |
1465 | } else { | |
1466 | section_size = 2 * EXT_NVM_WORD2_LEN( | |
1467 | le16_to_cpu(file_sec->word2)); | |
1468 | section_id = EXT_NVM_WORD1_ID( | |
1469 | le16_to_cpu(file_sec->word1)); | |
1470 | } | |
1471 | ||
1472 | if (section_size > max_section_size) { | |
1473 | IWL_ERR(trans, "ERROR - section too large (%d)\n", | |
1474 | section_size); | |
1475 | ret = -EINVAL; | |
1476 | break; | |
1477 | } | |
1478 | ||
1479 | if (!section_size) { | |
1480 | IWL_ERR(trans, "ERROR - section empty\n"); | |
1481 | ret = -EINVAL; | |
1482 | break; | |
1483 | } | |
1484 | ||
1485 | if (file_sec->data + section_size > eof) { | |
1486 | IWL_ERR(trans, | |
1487 | "ERROR - NVM file too short for section (%d bytes)\n", | |
1488 | section_size); | |
1489 | ret = -EINVAL; | |
1490 | break; | |
1491 | } | |
1492 | ||
1493 | if (WARN(section_id >= NVM_MAX_NUM_SECTIONS, | |
1494 | "Invalid NVM section ID %d\n", section_id)) { | |
1495 | ret = -EINVAL; | |
1496 | break; | |
1497 | } | |
1498 | ||
1499 | temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); | |
1500 | if (!temp) { | |
1501 | ret = -ENOMEM; | |
1502 | break; | |
1503 | } | |
1504 | ||
1505 | iwl_nvm_fixups(trans->hw_id, section_id, temp, section_size); | |
1506 | ||
1507 | kfree(nvm_sections[section_id].data); | |
1508 | nvm_sections[section_id].data = temp; | |
1509 | nvm_sections[section_id].length = section_size; | |
1510 | ||
1511 | /* advance to the next section */ | |
1512 | file_sec = (void *)(file_sec->data + section_size); | |
1513 | } | |
1514 | out: | |
1515 | release_firmware(fw_entry); | |
1516 | return ret; | |
1517 | } | |
1518 | IWL_EXPORT_SYMBOL(iwl_read_external_nvm); | |
4c625c56 ST |
1519 | |
1520 | struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, | |
1521 | const struct iwl_fw *fw) | |
1522 | { | |
1523 | struct iwl_nvm_get_info cmd = {}; | |
4c625c56 ST |
1524 | struct iwl_nvm_data *nvm; |
1525 | struct iwl_host_cmd hcmd = { | |
1526 | .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, | |
1527 | .data = { &cmd, }, | |
1528 | .len = { sizeof(cmd) }, | |
1529 | .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) | |
1530 | }; | |
1531 | int ret; | |
e7eeee08 | 1532 | bool empty_otp; |
4c625c56 ST |
1533 | u32 mac_flags; |
1534 | u32 sbands_flags = 0; | |
2785ce00 ST |
1535 | /* |
1536 | * All the values in iwl_nvm_get_info_rsp v4 are the same as | |
1537 | * in v3, except for the channel profile part of the | |
1538 | * regulatory. So we can just access the new struct, with the | |
1539 | * exception of the latter. | |
1540 | */ | |
1541 | struct iwl_nvm_get_info_rsp *rsp; | |
1542 | struct iwl_nvm_get_info_rsp_v3 *rsp_v3; | |
1543 | bool v4 = fw_has_api(&fw->ucode_capa, | |
1544 | IWL_UCODE_TLV_API_REGULATORY_NVM_INFO); | |
1545 | size_t rsp_size = v4 ? sizeof(*rsp) : sizeof(*rsp_v3); | |
1546 | void *channel_profile; | |
4c625c56 ST |
1547 | |
1548 | ret = iwl_trans_send_cmd(trans, &hcmd); | |
1549 | if (ret) | |
1550 | return ERR_PTR(ret); | |
1551 | ||
2785ce00 | 1552 | if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != rsp_size, |
4c625c56 ST |
1553 | "Invalid payload len in NVM response from FW %d", |
1554 | iwl_rx_packet_payload_len(hcmd.resp_pkt))) { | |
1555 | ret = -EINVAL; | |
1556 | goto out; | |
1557 | } | |
1558 | ||
1559 | rsp = (void *)hcmd.resp_pkt->data; | |
e7eeee08 NG |
1560 | empty_otp = !!(le32_to_cpu(rsp->general.flags) & |
1561 | NVM_GENERAL_FLAGS_EMPTY_OTP); | |
1562 | if (empty_otp) | |
4c625c56 ST |
1563 | IWL_INFO(trans, "OTP is empty\n"); |
1564 | ||
6b367c9f | 1565 | nvm = kzalloc(struct_size(nvm, channels, IWL_NUM_CHANNELS), GFP_KERNEL); |
4c625c56 ST |
1566 | if (!nvm) { |
1567 | ret = -ENOMEM; | |
1568 | goto out; | |
1569 | } | |
1570 | ||
1571 | iwl_set_hw_address_from_csr(trans, nvm); | |
1572 | /* TODO: if platform NVM has MAC address - override it here */ | |
1573 | ||
1574 | if (!is_valid_ether_addr(nvm->hw_addr)) { | |
1575 | IWL_ERR(trans, "no valid mac address was found\n"); | |
1576 | ret = -EINVAL; | |
1577 | goto err_free; | |
1578 | } | |
1579 | ||
1580 | IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr); | |
1581 | ||
1582 | /* Initialize general data */ | |
1583 | nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); | |
e7eeee08 NG |
1584 | nvm->n_hw_addrs = rsp->general.n_hw_addrs; |
1585 | if (nvm->n_hw_addrs == 0) | |
1586 | IWL_WARN(trans, | |
1587 | "Firmware declares no reserved mac addresses. OTP is empty: %d\n", | |
1588 | empty_otp); | |
4c625c56 ST |
1589 | |
1590 | /* Initialize MAC sku data */ | |
1591 | mac_flags = le32_to_cpu(rsp->mac_sku.mac_sku_flags); | |
1592 | nvm->sku_cap_11ac_enable = | |
1593 | !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AC_ENABLED); | |
1594 | nvm->sku_cap_11n_enable = | |
1595 | !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11N_ENABLED); | |
514c3069 LC |
1596 | nvm->sku_cap_11ax_enable = |
1597 | !!(mac_flags & NVM_MAC_SKU_FLAGS_802_11AX_ENABLED); | |
4c625c56 ST |
1598 | nvm->sku_cap_band_24ghz_enable = |
1599 | !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_2_4_ENABLED); | |
1600 | nvm->sku_cap_band_52ghz_enable = | |
1601 | !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); | |
1602 | nvm->sku_cap_mimo_disabled = | |
1603 | !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); | |
1604 | ||
1605 | /* Initialize PHY sku data */ | |
1606 | nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); | |
1607 | nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); | |
1608 | ||
f06021a1 LC |
1609 | if (le32_to_cpu(rsp->regulatory.lar_enabled) && |
1610 | fw_has_capa(&fw->ucode_capa, | |
1611 | IWL_UCODE_TLV_CAPA_LAR_SUPPORT)) { | |
4c625c56 ST |
1612 | nvm->lar_enabled = true; |
1613 | sbands_flags |= IWL_NVM_SBANDS_FLAGS_LAR; | |
1614 | } | |
1615 | ||
2785ce00 ST |
1616 | rsp_v3 = (void *)rsp; |
1617 | channel_profile = v4 ? (void *)rsp->regulatory.channel_profile : | |
1618 | (void *)rsp_v3->regulatory.channel_profile; | |
1619 | ||
d8913b80 | 1620 | iwl_init_sbands(trans, nvm, |
14cf9bc6 | 1621 | channel_profile, |
4c625c56 ST |
1622 | nvm->valid_tx_ant & fw->valid_tx_ant, |
1623 | nvm->valid_rx_ant & fw->valid_rx_ant, | |
2785ce00 | 1624 | sbands_flags, v4); |
4c625c56 ST |
1625 | |
1626 | iwl_free_resp(&hcmd); | |
1627 | return nvm; | |
1628 | ||
1629 | err_free: | |
1630 | kfree(nvm); | |
1631 | out: | |
1632 | iwl_free_resp(&hcmd); | |
1633 | return ERR_PTR(ret); | |
1634 | } | |
1635 | IWL_EXPORT_SYMBOL(iwl_get_nvm); |