]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
Merge branch 'linus' into locking/core, to pick up fixes
[people/arne_f/kernel.git] / drivers / net / wireless / intel / iwlwifi / iwl-nvm-parse.c
CommitLineData
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
b1e1adfa
JB
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
24 * USA
25 *
26 * The full GNU General Public License is included in this distribution
410dc5aa 27 * in the file called COPYING.
b1e1adfa
JB
28 *
29 * Contact Information:
d01c5366 30 * Intel Linux Wireless <linuxwifi@intel.com>
b1e1adfa
JB
31 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32 *
33 * BSD LICENSE
34 *
51368bf7 35 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
5f0d98f2 36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
29108495 37 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
b1e1adfa
JB
38 * All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 *
44 * * Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * * Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in
48 * the documentation and/or other materials provided with the
49 * distribution.
50 * * Neither the name Intel Corporation nor the names of its
51 * contributors may be used to endorse or promote products derived
52 * from this software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
55 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
56 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
58 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
59 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
64 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 *****************************************************************************/
66#include <linux/types.h>
67#include <linux/slab.h>
68#include <linux/export.h>
9f32e017 69#include <linux/etherdevice.h>
1e0b393a 70#include <linux/pci.h>
671bed3f 71#include <linux/acpi.h>
48e29340 72#include "iwl-drv.h"
b1e1adfa
JB
73#include "iwl-modparams.h"
74#include "iwl-nvm-parse.h"
afd5b170 75#include "iwl-prph.h"
17c867bf
SS
76#include "iwl-io.h"
77#include "iwl-csr.h"
b1e1adfa
JB
78
79/* NVM offsets (in words) definitions */
80enum wkp_nvm_offsets {
81 /* NVM HW-Section offset (in words) definitions */
82 HW_ADDR = 0x15,
83
77db0a3c 84 /* NVM SW-Section offset (in words) definitions */
b1e1adfa
JB
85 NVM_SW_SECTION = 0x1C0,
86 NVM_VERSION = 0,
87 RADIO_CFG = 1,
88 SKU = 2,
89 N_HW_ADDRS = 3,
90 NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
91
77db0a3c 92 /* NVM calibration section offset (in words) definitions */
b1e1adfa
JB
93 NVM_CALIB_SECTION = 0x2B8,
94 XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
95};
96
7042678d 97enum ext_nvm_offsets {
77db0a3c 98 /* NVM HW-Section offset (in words) definitions */
7042678d 99 MAC_ADDRESS_OVERRIDE_EXT_NVM = 1,
77db0a3c
EH
100
101 /* NVM SW-Section offset (in words) definitions */
7042678d
SS
102 NVM_VERSION_EXT_NVM = 0,
103 RADIO_CFG_FAMILY_EXT_NVM = 0,
5dd9c68a
EG
104 SKU_FAMILY_8000 = 2,
105 N_HW_ADDRS_FAMILY_8000 = 3,
ce500071 106
77db0a3c 107 /* NVM REGULATORY -Section offset (in words) definitions */
7042678d
SS
108 NVM_CHANNELS_EXTENDED = 0,
109 NVM_LAR_OFFSET_OLD = 0x4C7,
110 NVM_LAR_OFFSET = 0x507,
111 NVM_LAR_ENABLED = 0x7,
77db0a3c
EH
112};
113
b1e1adfa
JB
114/* SKU Capabilities (actual values from NVM definition) */
115enum nvm_sku_bits {
5f0d98f2
EG
116 NVM_SKU_CAP_BAND_24GHZ = BIT(0),
117 NVM_SKU_CAP_BAND_52GHZ = BIT(1),
118 NVM_SKU_CAP_11N_ENABLE = BIT(2),
119 NVM_SKU_CAP_11AC_ENABLE = BIT(3),
120 NVM_SKU_CAP_MIMO_DISABLE = BIT(5),
b1e1adfa
JB
121};
122
b1e1adfa
JB
123/*
124 * These are the channel numbers in the order that they are stored in the NVM
125 */
126static const u8 iwl_nvm_channels[] = {
127 /* 2.4 GHz */
128 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
129 /* 5 GHz */
130 36, 40, 44 , 48, 52, 56, 60, 64,
131 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
132 149, 153, 157, 161, 165
133};
134
7042678d 135static const u8 iwl_ext_nvm_channels[] = {
77db0a3c 136 /* 2.4 GHz */
9b1c9a66 137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
77db0a3c
EH
138 /* 5 GHz */
139 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
140 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
141 149, 153, 157, 161, 165, 169, 173, 177, 181
142};
143
749f1fe1 144#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
7042678d 145#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
749f1fe1 146#define NUM_2GHZ_CHANNELS 14
7042678d 147#define NUM_2GHZ_CHANNELS_EXT 14
749f1fe1
EH
148#define FIRST_2GHZ_HT_MINUS 5
149#define LAST_2GHZ_HT_PLUS 9
b281c93d
MG
150#define LAST_5GHZ_HT 165
151#define LAST_5GHZ_HT_FAMILY_8000 181
ce500071 152#define N_HW_ADDR_MASK 0xF
b1e1adfa 153
b1e1adfa
JB
154/* rate data (static) */
155static struct ieee80211_rate iwl_cfg80211_rates[] = {
156 { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
157 { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
158 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
159 { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
160 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
161 { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
162 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
163 { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
164 { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
165 { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
166 { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
167 { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
168 { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
169 { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
170 { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
171};
172#define RATES_24_OFFS 0
173#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
174#define RATES_52_OFFS 4
175#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
176
177/**
178 * enum iwl_nvm_channel_flags - channel flags in NVM
179 * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
180 * @NVM_CHANNEL_IBSS: usable as an IBSS channel
181 * @NVM_CHANNEL_ACTIVE: active scanning allowed
182 * @NVM_CHANNEL_RADAR: radar detection required
9ee6dace
DS
183 * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed
184 * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS
185 * on same channel on 2.4 or same UNII band on 5.2
b1e1adfa
JB
186 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
187 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
33158fef
EL
188 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
189 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
b1e1adfa
JB
190 */
191enum iwl_nvm_channel_flags {
192 NVM_CHANNEL_VALID = BIT(0),
193 NVM_CHANNEL_IBSS = BIT(1),
194 NVM_CHANNEL_ACTIVE = BIT(3),
195 NVM_CHANNEL_RADAR = BIT(4),
9ee6dace
DS
196 NVM_CHANNEL_INDOOR_ONLY = BIT(5),
197 NVM_CHANNEL_GO_CONCURRENT = BIT(6),
b1e1adfa
JB
198 NVM_CHANNEL_WIDE = BIT(8),
199 NVM_CHANNEL_40MHZ = BIT(9),
33158fef
EL
200 NVM_CHANNEL_80MHZ = BIT(10),
201 NVM_CHANNEL_160MHZ = BIT(11),
b1e1adfa
JB
202};
203
204#define CHECK_AND_PRINT_I(x) \
205 ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
206
770ceda6 207static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
b281c93d 208 u16 nvm_flags, const struct iwl_cfg *cfg)
770ceda6
AN
209{
210 u32 flags = IEEE80211_CHAN_NO_HT40;
b281c93d
MG
211 u32 last_5ghz_ht = LAST_5GHZ_HT;
212
7042678d 213 if (cfg->ext_nvm)
b281c93d 214 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
770ceda6
AN
215
216 if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
217 if (ch_num <= LAST_2GHZ_HT_PLUS)
218 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
219 if (ch_num >= FIRST_2GHZ_HT_MINUS)
220 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
b281c93d 221 } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) {
770ceda6
AN
222 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
223 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
224 else
225 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
226 }
227 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
228 flags |= IEEE80211_CHAN_NO_80MHZ;
229 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
230 flags |= IEEE80211_CHAN_NO_160MHZ;
231
232 if (!(nvm_flags & NVM_CHANNEL_IBSS))
233 flags |= IEEE80211_CHAN_NO_IR;
234
235 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
236 flags |= IEEE80211_CHAN_NO_IR;
237
238 if (nvm_flags & NVM_CHANNEL_RADAR)
239 flags |= IEEE80211_CHAN_RADAR;
240
241 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
242 flags |= IEEE80211_CHAN_INDOOR_ONLY;
243
244 /* Set the GO concurrent flag only in case that NO_IR is set.
245 * Otherwise it is meaningless
246 */
247 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
248 (flags & IEEE80211_CHAN_NO_IR))
06f207fc 249 flags |= IEEE80211_CHAN_IR_CONCURRENT;
770ceda6
AN
250
251 return flags;
252}
253
b1e1adfa
JB
254static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
255 struct iwl_nvm_data *data,
770ceda6
AN
256 const __le16 * const nvm_ch_flags,
257 bool lar_supported)
b1e1adfa
JB
258{
259 int ch_idx;
260 int n_channels = 0;
261 struct ieee80211_channel *channel;
262 u16 ch_flags;
263 bool is_5ghz;
749f1fe1 264 int num_of_ch, num_2ghz_channels;
77db0a3c
EH
265 const u8 *nvm_chan;
266
7042678d 267 if (!cfg->ext_nvm) {
77db0a3c
EH
268 num_of_ch = IWL_NUM_CHANNELS;
269 nvm_chan = &iwl_nvm_channels[0];
749f1fe1 270 num_2ghz_channels = NUM_2GHZ_CHANNELS;
77db0a3c 271 } else {
7042678d
SS
272 num_of_ch = IWL_NUM_CHANNELS_EXT;
273 nvm_chan = &iwl_ext_nvm_channels[0];
274 num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT;
77db0a3c 275 }
b1e1adfa 276
77db0a3c 277 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
b1e1adfa 278 ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
c5128654 279
749f1fe1 280 if (ch_idx >= num_2ghz_channels &&
c5128654 281 !data->sku_cap_band_52GHz_enable)
a76f3bfe 282 continue;
c5128654 283
4896d764
GG
284 if (ch_flags & NVM_CHANNEL_160MHZ)
285 data->vht160_supported = true;
286
770ceda6 287 if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
a76f3bfe
EP
288 /*
289 * Channels might become valid later if lar is
290 * supported, hence we still want to add them to
291 * the list of supported channels to cfg80211.
292 */
b1e1adfa
JB
293 IWL_DEBUG_EEPROM(dev,
294 "Ch. %d Flags %x [%sGHz] - No traffic\n",
77db0a3c 295 nvm_chan[ch_idx],
b1e1adfa 296 ch_flags,
749f1fe1 297 (ch_idx >= num_2ghz_channels) ?
b1e1adfa
JB
298 "5.2" : "2.4");
299 continue;
300 }
301
302 channel = &data->channels[n_channels];
303 n_channels++;
304
77db0a3c 305 channel->hw_value = nvm_chan[ch_idx];
749f1fe1 306 channel->band = (ch_idx < num_2ghz_channels) ?
57fbcce3 307 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
b1e1adfa
JB
308 channel->center_freq =
309 ieee80211_channel_to_frequency(
310 channel->hw_value, channel->band);
311
b1e1adfa
JB
312 /* Initialize regulatory-based run-time data */
313
88f2fd73
MG
314 /*
315 * Default value - highest tx power value. max_power
316 * is not used in mvm, and is used for backwards compatibility
317 */
22d059a5 318 channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
57fbcce3 319 is_5ghz = channel->band == NL80211_BAND_5GHZ;
770ceda6
AN
320
321 /* don't put limitations in case we're using LAR */
322 if (!lar_supported)
323 channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx],
324 ch_idx, is_5ghz,
b281c93d 325 ch_flags, cfg);
770ceda6
AN
326 else
327 channel->flags = 0;
328
b1e1adfa 329 IWL_DEBUG_EEPROM(dev,
4896d764 330 "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n",
b1e1adfa
JB
331 channel->hw_value,
332 is_5ghz ? "5.2" : "2.4",
4896d764 333 ch_flags,
b1e1adfa
JB
334 CHECK_AND_PRINT_I(VALID),
335 CHECK_AND_PRINT_I(IBSS),
336 CHECK_AND_PRINT_I(ACTIVE),
337 CHECK_AND_PRINT_I(RADAR),
9ee6dace
DS
338 CHECK_AND_PRINT_I(INDOOR_ONLY),
339 CHECK_AND_PRINT_I(GO_CONCURRENT),
4896d764
GG
340 CHECK_AND_PRINT_I(WIDE),
341 CHECK_AND_PRINT_I(40MHZ),
342 CHECK_AND_PRINT_I(80MHZ),
343 CHECK_AND_PRINT_I(160MHZ),
b1e1adfa
JB
344 channel->max_power,
345 ((ch_flags & NVM_CHANNEL_IBSS) &&
346 !(ch_flags & NVM_CHANNEL_RADAR))
347 ? "" : "not ");
348 }
349
350 return n_channels;
351}
352
33158fef
EL
353static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
354 struct iwl_nvm_data *data,
6ca89f1f
JB
355 struct ieee80211_sta_vht_cap *vht_cap,
356 u8 tx_chains, u8 rx_chains)
33158fef 357{
6ca89f1f
JB
358 int num_rx_ants = num_of_ant(rx_chains);
359 int num_tx_ants = num_of_ant(tx_chains);
c064ddf3
EH
360 unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?:
361 IEEE80211_VHT_MAX_AMPDU_1024K);
48e6de61 362
33158fef
EL
363 vht_cap->vht_supported = true;
364
365 vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
366 IEEE80211_VHT_CAP_RXSTBC_1 |
367 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
e36b766d 368 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
c064ddf3
EH
369 max_ampdu_exponent <<
370 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
33158fef 371
4896d764 372 if (data->vht160_supported)
fbbd4859
GG
373 vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
374 IEEE80211_VHT_CAP_SHORT_GI_160;
4896d764 375
e48c947f
SS
376 if (cfg->vht_mu_mimo_supported)
377 vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
378
a3576ff2
ES
379 if (cfg->ht_params->ldpc)
380 vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
381
5f0d98f2
EG
382 if (data->sku_cap_mimo_disabled) {
383 num_rx_ants = 1;
384 num_tx_ants = 1;
385 }
386
6ca89f1f 387 if (num_tx_ants > 1)
5f7a6f9b 388 vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
6ca89f1f
JB
389 else
390 vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
5f7a6f9b 391
6c4fbcbc 392 switch (iwlwifi_mod_params.amsdu_size) {
4bdd4dfe
EG
393 case IWL_AMSDU_DEF:
394 if (cfg->mq_rx_supported)
395 vht_cap->cap |=
396 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
397 else
398 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
399 break;
6c4fbcbc
EG
400 case IWL_AMSDU_4K:
401 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
402 break;
403 case IWL_AMSDU_8K:
33158fef 404 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
6c4fbcbc
EG
405 break;
406 case IWL_AMSDU_12K:
407 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
408 break;
409 default:
410 break;
411 }
33158fef
EL
412
413 vht_cap->vht_mcs.rx_mcs_map =
414 cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
415 IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
416 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
417 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
418 IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
419 IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
420 IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
421 IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
422
6ca89f1f
JB
423 if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) {
424 vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
33158fef
EL
425 /* this works because NOT_SUPPORTED == 3 */
426 vht_cap->vht_mcs.rx_mcs_map |=
427 cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
428 }
429
430 vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
431}
432
29108495
SS
433void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
434 struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
435 u8 tx_chains, u8 rx_chains, bool lar_supported)
b1e1adfa 436{
77db0a3c 437 int n_channels;
b1e1adfa
JB
438 int n_used = 0;
439 struct ieee80211_supported_band *sband;
440
29108495
SS
441 n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags,
442 lar_supported);
57fbcce3
JB
443 sband = &data->bands[NL80211_BAND_2GHZ];
444 sband->band = NL80211_BAND_2GHZ;
b1e1adfa
JB
445 sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
446 sband->n_bitrates = N_RATES_24;
447 n_used += iwl_init_sband_channels(data, sband, n_channels,
57fbcce3
JB
448 NL80211_BAND_2GHZ);
449 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_2GHZ,
9ce4fa72 450 tx_chains, rx_chains);
b1e1adfa 451
57fbcce3
JB
452 sband = &data->bands[NL80211_BAND_5GHZ];
453 sband->band = NL80211_BAND_5GHZ;
b1e1adfa
JB
454 sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
455 sband->n_bitrates = N_RATES_52;
456 n_used += iwl_init_sband_channels(data, sband, n_channels,
57fbcce3
JB
457 NL80211_BAND_5GHZ);
458 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_5GHZ,
9ce4fa72 459 tx_chains, rx_chains);
0d0985ad 460 if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac)
6ca89f1f
JB
461 iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
462 tx_chains, rx_chains);
b1e1adfa
JB
463
464 if (n_channels != n_used)
465 IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
466 n_used, n_channels);
467}
29108495 468IWL_EXPORT_SYMBOL(iwl_init_sbands);
b1e1adfa 469
5dd9c68a
EG
470static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
471 const __le16 *phy_sku)
77db0a3c 472{
7042678d 473 if (!cfg->ext_nvm)
77db0a3c 474 return le16_to_cpup(nvm_sw + SKU);
ce500071 475
5dd9c68a 476 return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000));
77db0a3c
EH
477}
478
5dd9c68a 479static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
77db0a3c 480{
7042678d 481 if (!cfg->ext_nvm)
77db0a3c
EH
482 return le16_to_cpup(nvm_sw + NVM_VERSION);
483 else
484 return le32_to_cpup((__le32 *)(nvm_sw +
7042678d 485 NVM_VERSION_EXT_NVM));
77db0a3c
EH
486}
487
5dd9c68a
EG
488static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
489 const __le16 *phy_sku)
77db0a3c 490{
7042678d 491 if (!cfg->ext_nvm)
77db0a3c 492 return le16_to_cpup(nvm_sw + RADIO_CFG);
ce500071 493
7042678d 494 return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM));
ce500071 495
77db0a3c
EH
496}
497
5dd9c68a 498static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
77db0a3c 499{
ce500071
EH
500 int n_hw_addr;
501
7042678d 502 if (!cfg->ext_nvm)
77db0a3c 503 return le16_to_cpup(nvm_sw + N_HW_ADDRS);
ce500071 504
5dd9c68a 505 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000));
ce500071
EH
506
507 return n_hw_addr & N_HW_ADDR_MASK;
77db0a3c
EH
508}
509
510static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
511 struct iwl_nvm_data *data,
512 u32 radio_cfg)
513{
7042678d 514 if (!cfg->ext_nvm) {
77db0a3c
EH
515 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
516 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
517 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
518 data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
77db0a3c
EH
519 return;
520 }
521
522 /* set the radio configuration for family 8000 */
7042678d
SS
523 data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg);
524 data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg);
525 data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg);
526 data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg);
527 data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
528 data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
77db0a3c
EH
529}
530
17c867bf
SS
531static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
532{
533 const u8 *hw_addr;
534
535 hw_addr = (const u8 *)&mac_addr0;
536 dest[0] = hw_addr[3];
537 dest[1] = hw_addr[2];
538 dest[2] = hw_addr[1];
539 dest[3] = hw_addr[0];
540
541 hw_addr = (const u8 *)&mac_addr1;
542 dest[4] = hw_addr[1];
543 dest[5] = hw_addr[0];
544}
545
29108495
SS
546void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
547 struct iwl_nvm_data *data)
17c867bf
SS
548{
549 __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
550 __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
551
a6c934b3
HD
552 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
553 /*
554 * If the OEM fused a valid address, use it instead of the one in the
555 * OTP
556 */
557 if (is_valid_ether_addr(data->hw_addr))
558 return;
559
560 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
561 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
17c867bf
SS
562
563 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
564}
29108495 565IWL_EXPORT_SYMBOL(iwl_set_hw_address_from_csr);
17c867bf 566
afd5b170 567static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
6a68a39f 568 const struct iwl_cfg *cfg,
9f32e017
EH
569 struct iwl_nvm_data *data,
570 const __le16 *mac_override,
afd5b170 571 const __le16 *nvm_hw)
9f32e017
EH
572{
573 const u8 *hw_addr;
574
575 if (mac_override) {
18f84673
LK
576 static const u8 reserved_mac[] = {
577 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00
578 };
579
9f32e017 580 hw_addr = (const u8 *)(mac_override +
7042678d 581 MAC_ADDRESS_OVERRIDE_EXT_NVM);
9f32e017 582
be88a1ad
LK
583 /*
584 * Store the MAC address from MAO section.
585 * No byte swapping is required in MAO section
586 */
587 memcpy(data->hw_addr, hw_addr, ETH_ALEN);
9f32e017 588
18f84673
LK
589 /*
590 * Force the use of the OTP MAC address in case of reserved MAC
591 * address in the NVM, or if address is given but invalid.
592 */
593 if (is_valid_ether_addr(data->hw_addr) &&
594 memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0)
9f32e017 595 return;
6a68a39f 596
afd5b170
SS
597 IWL_ERR(trans,
598 "mac address from nvm override section is not valid\n");
9f32e017
EH
599 }
600
6a68a39f 601 if (nvm_hw) {
afd5b170
SS
602 /* read the mac address from WFMP registers */
603 __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans,
604 WFMP_MAC_ADDR_0));
605 __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
606 WFMP_MAC_ADDR_1));
17c867bf
SS
607
608 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
1e0b393a 609
6a68a39f
EH
610 return;
611 }
9f32e017 612
afd5b170
SS
613 IWL_ERR(trans, "mac address is not found\n");
614}
615
17c867bf
SS
616static int iwl_set_hw_address(struct iwl_trans *trans,
617 const struct iwl_cfg *cfg,
618 struct iwl_nvm_data *data, const __le16 *nvm_hw,
619 const __le16 *mac_override)
afd5b170 620{
17c867bf
SS
621 if (cfg->mac_addr_from_csr) {
622 iwl_set_hw_address_from_csr(trans, data);
7042678d 623 } else if (!cfg->ext_nvm) {
afd5b170
SS
624 const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
625
626 /* The byte order is little endian 16 bit, meaning 214365 */
627 data->hw_addr[0] = hw_addr[1];
628 data->hw_addr[1] = hw_addr[0];
629 data->hw_addr[2] = hw_addr[3];
630 data->hw_addr[3] = hw_addr[2];
631 data->hw_addr[4] = hw_addr[5];
632 data->hw_addr[5] = hw_addr[4];
633 } else {
634 iwl_set_hw_address_family_8000(trans, cfg, data,
635 mac_override, nvm_hw);
636 }
17c867bf
SS
637
638 if (!is_valid_ether_addr(data->hw_addr)) {
639 IWL_ERR(trans, "no valid mac address was found\n");
640 return -EINVAL;
641 }
642
4409e72b
LC
643 IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr);
644
17c867bf 645 return 0;
9f32e017
EH
646}
647
b1e1adfa 648struct iwl_nvm_data *
afd5b170 649iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
b1e1adfa 650 const __le16 *nvm_hw, const __le16 *nvm_sw,
77db0a3c 651 const __le16 *nvm_calib, const __le16 *regulatory,
ce500071 652 const __le16 *mac_override, const __le16 *phy_sku,
afd5b170 653 u8 tx_chains, u8 rx_chains, bool lar_fw_supported)
b1e1adfa 654{
afd5b170 655 struct device *dev = trans->dev;
b1e1adfa 656 struct iwl_nvm_data *data;
afd5b170
SS
657 bool lar_enabled;
658 u32 sku, radio_cfg;
d0d15197 659 u16 lar_config;
afd5b170 660 const __le16 *ch_section;
77db0a3c 661
7042678d 662 if (!cfg->ext_nvm)
77db0a3c
EH
663 data = kzalloc(sizeof(*data) +
664 sizeof(struct ieee80211_channel) *
665 IWL_NUM_CHANNELS,
666 GFP_KERNEL);
667 else
668 data = kzalloc(sizeof(*data) +
669 sizeof(struct ieee80211_channel) *
7042678d 670 IWL_NUM_CHANNELS_EXT,
77db0a3c 671 GFP_KERNEL);
b1e1adfa
JB
672 if (!data)
673 return NULL;
674
77db0a3c 675 data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
b1e1adfa 676
5dd9c68a 677 radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw, phy_sku);
77db0a3c 678 iwl_set_radio_cfg(cfg, data, radio_cfg);
a0544272
MH
679 if (data->valid_tx_ant)
680 tx_chains &= data->valid_tx_ant;
681 if (data->valid_rx_ant)
682 rx_chains &= data->valid_rx_ant;
b1e1adfa 683
5dd9c68a 684 sku = iwl_get_sku(cfg, nvm_sw, phy_sku);
b1e1adfa
JB
685 data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
686 data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
687 data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
688 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
689 data->sku_cap_11n_enable = false;
2926f958
EP
690 data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
691 (sku & NVM_SKU_CAP_11AC_ENABLE);
5f0d98f2 692 data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE;
b1e1adfa 693
5dd9c68a 694 data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
b1e1adfa 695
7042678d 696 if (!cfg->ext_nvm) {
77db0a3c
EH
697 /* Checking for required sections */
698 if (!nvm_calib) {
afd5b170
SS
699 IWL_ERR(trans,
700 "Can't parse empty Calib NVM sections\n");
1270c416 701 kfree(data);
77db0a3c
EH
702 return NULL;
703 }
704 /* in family 8000 Xtal calibration values moved to OTP */
705 data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
706 data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
afd5b170 707 lar_enabled = true;
29108495 708 ch_section = &nvm_sw[NVM_CHANNELS];
77db0a3c 709 } else {
f5528631 710 u16 lar_offset = data->nvm_version < 0xE39 ?
7042678d
SS
711 NVM_LAR_OFFSET_OLD :
712 NVM_LAR_OFFSET;
f5528631
AN
713
714 lar_config = le16_to_cpup(regulatory + lar_offset);
d0d15197 715 data->lar_enabled = !!(lar_config &
7042678d 716 NVM_LAR_ENABLED);
afd5b170 717 lar_enabled = data->lar_enabled;
7042678d 718 ch_section = &regulatory[NVM_CHANNELS_EXTENDED];
77db0a3c 719 }
b1e1adfa 720
17c867bf
SS
721 /* If no valid mac address was found - bail out */
722 if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) {
723 kfree(data);
724 return NULL;
725 }
726
afd5b170
SS
727 iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
728 lar_fw_supported && lar_enabled);
33b2f684 729 data->calib_version = 255;
b1e1adfa
JB
730
731 return data;
732}
48e29340 733IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
af45a900
AN
734
735static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
b281c93d
MG
736 int ch_idx, u16 nvm_flags,
737 const struct iwl_cfg *cfg)
af45a900
AN
738{
739 u32 flags = NL80211_RRF_NO_HT40;
b281c93d
MG
740 u32 last_5ghz_ht = LAST_5GHZ_HT;
741
7042678d 742 if (cfg->ext_nvm)
b281c93d 743 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
af45a900
AN
744
745 if (ch_idx < NUM_2GHZ_CHANNELS &&
746 (nvm_flags & NVM_CHANNEL_40MHZ)) {
747 if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
748 flags &= ~NL80211_RRF_NO_HT40PLUS;
749 if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
750 flags &= ~NL80211_RRF_NO_HT40MINUS;
b281c93d 751 } else if (nvm_chan[ch_idx] <= last_5ghz_ht &&
af45a900
AN
752 (nvm_flags & NVM_CHANNEL_40MHZ)) {
753 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
754 flags &= ~NL80211_RRF_NO_HT40PLUS;
755 else
756 flags &= ~NL80211_RRF_NO_HT40MINUS;
757 }
758
759 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
760 flags |= NL80211_RRF_NO_80MHZ;
761 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
762 flags |= NL80211_RRF_NO_160MHZ;
763
af45a900
AN
764 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
765 flags |= NL80211_RRF_NO_IR;
766
767 if (nvm_flags & NVM_CHANNEL_RADAR)
768 flags |= NL80211_RRF_DFS;
769
770 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
771 flags |= NL80211_RRF_NO_OUTDOOR;
772
773 /* Set the GO concurrent flag only in case that NO_IR is set.
774 * Otherwise it is meaningless
775 */
776 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
777 (flags & NL80211_RRF_NO_IR))
778 flags |= NL80211_RRF_GO_CONCURRENT;
779
780 return flags;
781}
782
783struct ieee80211_regdomain *
162ee3c9
AN
784iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
785 int num_of_ch, __le32 *channels, u16 fw_mcc)
af45a900
AN
786{
787 int ch_idx;
92b0f7b2
EG
788 u16 ch_flags;
789 u32 reg_rule_flags, prev_reg_rule_flags = 0;
7042678d
SS
790 const u8 *nvm_chan = cfg->ext_nvm ?
791 iwl_ext_nvm_channels : iwl_nvm_channels;
af45a900
AN
792 struct ieee80211_regdomain *regd;
793 int size_of_regd;
794 struct ieee80211_reg_rule *rule;
57fbcce3 795 enum nl80211_band band;
af45a900
AN
796 int center_freq, prev_center_freq = 0;
797 int valid_rules = 0;
798 bool new_rule;
7042678d
SS
799 int max_num_ch = cfg->ext_nvm ?
800 IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;
af45a900
AN
801
802 if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
803 return ERR_PTR(-EINVAL);
804
4557eaba
AN
805 if (WARN_ON(num_of_ch > max_num_ch))
806 num_of_ch = max_num_ch;
807
af45a900
AN
808 IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
809 num_of_ch);
810
811 /* build a regdomain rule for every valid channel */
812 size_of_regd =
813 sizeof(struct ieee80211_regdomain) +
814 num_of_ch * sizeof(struct ieee80211_reg_rule);
815
816 regd = kzalloc(size_of_regd, GFP_KERNEL);
817 if (!regd)
818 return ERR_PTR(-ENOMEM);
819
820 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
821 ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
822 band = (ch_idx < NUM_2GHZ_CHANNELS) ?
57fbcce3 823 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
af45a900
AN
824 center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
825 band);
826 new_rule = false;
827
828 if (!(ch_flags & NVM_CHANNEL_VALID)) {
829 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
830 "Ch. %d Flags %x [%sGHz] - No traffic\n",
831 nvm_chan[ch_idx],
832 ch_flags,
833 (ch_idx >= NUM_2GHZ_CHANNELS) ?
834 "5.2" : "2.4");
835 continue;
836 }
837
92b0f7b2
EG
838 reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
839 ch_flags, cfg);
840
af45a900 841 /* we can't continue the same rule */
92b0f7b2 842 if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags ||
af45a900
AN
843 center_freq - prev_center_freq > 20) {
844 valid_rules++;
845 new_rule = true;
846 }
847
848 rule = &regd->reg_rules[valid_rules - 1];
849
850 if (new_rule)
851 rule->freq_range.start_freq_khz =
852 MHZ_TO_KHZ(center_freq - 10);
853
854 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
855
856 /* this doesn't matter - not used by FW */
857 rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
02a50495
EP
858 rule->power_rule.max_eirp =
859 DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);
af45a900 860
92b0f7b2 861 rule->flags = reg_rule_flags;
af45a900
AN
862
863 /* rely on auto-calculation to merge BW of contiguous chans */
864 rule->flags |= NL80211_RRF_AUTO_BW;
865 rule->freq_range.max_bandwidth_khz = 0;
866
af45a900 867 prev_center_freq = center_freq;
92b0f7b2 868 prev_reg_rule_flags = reg_rule_flags;
af45a900
AN
869
870 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
92b0f7b2 871 "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x) reg_flags 0x%x: %s\n",
af45a900 872 center_freq,
57fbcce3 873 band == NL80211_BAND_5GHZ ? "5.2" : "2.4",
af45a900 874 CHECK_AND_PRINT_I(VALID),
af45a900
AN
875 CHECK_AND_PRINT_I(ACTIVE),
876 CHECK_AND_PRINT_I(RADAR),
877 CHECK_AND_PRINT_I(WIDE),
878 CHECK_AND_PRINT_I(40MHZ),
879 CHECK_AND_PRINT_I(80MHZ),
880 CHECK_AND_PRINT_I(160MHZ),
881 CHECK_AND_PRINT_I(INDOOR_ONLY),
882 CHECK_AND_PRINT_I(GO_CONCURRENT),
92b0f7b2 883 ch_flags, reg_rule_flags,
bdf2fae8 884 ((ch_flags & NVM_CHANNEL_ACTIVE) &&
af45a900 885 !(ch_flags & NVM_CHANNEL_RADAR))
92b0f7b2 886 ? "Ad-Hoc" : "");
af45a900
AN
887 }
888
889 regd->n_reg_rules = valid_rules;
890
891 /* set alpha2 from FW. */
892 regd->alpha2[0] = fw_mcc >> 8;
893 regd->alpha2[1] = fw_mcc & 0xff;
894
895 return regd;
896}
897IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
671bed3f
AN
898
899#ifdef CONFIG_ACPI
900#define WRDD_METHOD "WRDD"
901#define WRDD_WIFI (0x07)
902#define WRDD_WIGIG (0x10)
903
904static u32 iwl_wrdd_get_mcc(struct device *dev, union acpi_object *wrdd)
905{
906 union acpi_object *mcc_pkg, *domain_type, *mcc_value;
907 u32 i;
908
909 if (wrdd->type != ACPI_TYPE_PACKAGE ||
910 wrdd->package.count < 2 ||
911 wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
912 wrdd->package.elements[0].integer.value != 0) {
913 IWL_DEBUG_EEPROM(dev, "Unsupported wrdd structure\n");
914 return 0;
915 }
916
917 for (i = 1 ; i < wrdd->package.count ; ++i) {
918 mcc_pkg = &wrdd->package.elements[i];
919
920 if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
921 mcc_pkg->package.count < 2 ||
922 mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
923 mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
924 mcc_pkg = NULL;
925 continue;
926 }
927
928 domain_type = &mcc_pkg->package.elements[0];
929 if (domain_type->integer.value == WRDD_WIFI)
930 break;
931
932 mcc_pkg = NULL;
933 }
934
935 if (mcc_pkg) {
936 mcc_value = &mcc_pkg->package.elements[1];
937 return mcc_value->integer.value;
938 }
939
940 return 0;
941}
942
943int iwl_get_bios_mcc(struct device *dev, char *mcc)
944{
945 acpi_handle root_handle;
946 acpi_handle handle;
947 struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
948 acpi_status status;
949 u32 mcc_val;
950
951 root_handle = ACPI_HANDLE(dev);
952 if (!root_handle) {
953 IWL_DEBUG_EEPROM(dev,
954 "Could not retrieve root port ACPI handle\n");
955 return -ENOENT;
956 }
957
958 /* Get the method's handle */
959 status = acpi_get_handle(root_handle, (acpi_string)WRDD_METHOD,
960 &handle);
961 if (ACPI_FAILURE(status)) {
962 IWL_DEBUG_EEPROM(dev, "WRD method not found\n");
963 return -ENOENT;
964 }
965
966 /* Call WRDD with no arguments */
967 status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
968 if (ACPI_FAILURE(status)) {
969 IWL_DEBUG_EEPROM(dev, "WRDC invocation failed (0x%x)\n",
970 status);
971 return -ENOENT;
972 }
973
974 mcc_val = iwl_wrdd_get_mcc(dev, wrdd.pointer);
975 kfree(wrdd.pointer);
976 if (!mcc_val)
977 return -ENOENT;
978
979 mcc[0] = (mcc_val >> 8) & 0xff;
980 mcc[1] = mcc_val & 0xff;
981 mcc[2] = '\0';
982 return 0;
983}
984IWL_EXPORT_SYMBOL(iwl_get_bios_mcc);
985#endif