blob: 1172e4572a82042fe27ffc231e87d4a67cf6fa85 [file] [log] [blame]
Johannes Bergb1e1adf2013-01-24 14:14:22 +01001/******************************************************************************
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 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +02008 * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
Emmanuel Grumbach5f0d98f2014-10-30 10:19:38 +02009 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Sara Sharon29108492017-01-08 16:45:46 +020010 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
Johannes Bergb1e1adf2013-01-24 14:14:22 +010011 *
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
Emmanuel Grumbach410dc5a2013-02-18 09:22:28 +020027 * in the file called COPYING.
Johannes Bergb1e1adf2013-01-24 14:14:22 +010028 *
29 * Contact Information:
Emmanuel Grumbachd01c5362015-11-17 15:39:56 +020030 * Intel Linux Wireless <linuxwifi@intel.com>
Johannes Bergb1e1adf2013-01-24 14:14:22 +010031 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
32 *
33 * BSD LICENSE
34 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020035 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
Emmanuel Grumbach5f0d98f2014-10-30 10:19:38 +020036 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
Sara Sharon29108492017-01-08 16:45:46 +020037 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
Johannes Bergb1e1adf2013-01-24 14:14:22 +010038 * 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>
Eran Harary9f32e012014-04-28 15:22:40 +030069#include <linux/etherdevice.h>
Eran Harary1e0b3932014-06-11 11:37:09 +030070#include <linux/pci.h>
Arik Nemtsov671bed32016-08-07 18:58:29 +030071#include <linux/acpi.h>
Johannes Berg48e29342013-03-01 00:13:33 +010072#include "iwl-drv.h"
Johannes Bergb1e1adf2013-01-24 14:14:22 +010073#include "iwl-modparams.h"
74#include "iwl-nvm-parse.h"
Sara Sharonafd5b172016-03-01 12:18:22 +020075#include "iwl-prph.h"
Sara Sharon17c867b2016-03-07 14:18:29 +020076#include "iwl-io.h"
77#include "iwl-csr.h"
Johannes Bergb1e1adf2013-01-24 14:14:22 +010078
79/* NVM offsets (in words) definitions */
80enum wkp_nvm_offsets {
81 /* NVM HW-Section offset (in words) definitions */
82 HW_ADDR = 0x15,
83
Eran Harary77db0a32014-02-04 14:21:38 +020084 /* NVM SW-Section offset (in words) definitions */
Johannes Bergb1e1adf2013-01-24 14:14:22 +010085 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
Eran Harary77db0a32014-02-04 14:21:38 +020092 /* NVM calibration section offset (in words) definitions */
Johannes Bergb1e1adf2013-01-24 14:14:22 +010093 NVM_CALIB_SECTION = 0x2B8,
94 XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
95};
96
Sara Sharon70426782017-03-22 12:20:40 +020097enum ext_nvm_offsets {
Eran Harary77db0a32014-02-04 14:21:38 +020098 /* NVM HW-Section offset (in words) definitions */
Sara Sharon70426782017-03-22 12:20:40 +020099 MAC_ADDRESS_OVERRIDE_EXT_NVM = 1,
Eran Harary77db0a32014-02-04 14:21:38 +0200100
101 /* NVM SW-Section offset (in words) definitions */
Sara Sharon70426782017-03-22 12:20:40 +0200102 NVM_VERSION_EXT_NVM = 0,
103 RADIO_CFG_FAMILY_EXT_NVM = 0,
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200104 SKU_FAMILY_8000 = 2,
105 N_HW_ADDRS_FAMILY_8000 = 3,
Eran Hararyce500072014-12-01 17:53:53 +0200106
Eran Harary77db0a32014-02-04 14:21:38 +0200107 /* NVM REGULATORY -Section offset (in words) definitions */
Sara Sharon70426782017-03-22 12:20:40 +0200108 NVM_CHANNELS_EXTENDED = 0,
109 NVM_LAR_OFFSET_OLD = 0x4C7,
110 NVM_LAR_OFFSET = 0x507,
111 NVM_LAR_ENABLED = 0x7,
Eran Harary77db0a32014-02-04 14:21:38 +0200112};
113
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100114/* SKU Capabilities (actual values from NVM definition) */
115enum nvm_sku_bits {
Emmanuel Grumbach5f0d98f2014-10-30 10:19:38 +0200116 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),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100121};
122
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100123/*
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
Sara Sharon70426782017-03-22 12:20:40 +0200135static const u8 iwl_ext_nvm_channels[] = {
Eran Harary77db0a32014-02-04 14:21:38 +0200136 /* 2.4 GHz */
Eran Harary9b1c9a62014-05-07 08:22:41 +0300137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
Eran Harary77db0a32014-02-04 14:21:38 +0200138 /* 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
Eran Harary749f1fe2014-03-06 09:25:30 +0200144#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
Sara Sharon70426782017-03-22 12:20:40 +0200145#define IWL_NUM_CHANNELS_EXT ARRAY_SIZE(iwl_ext_nvm_channels)
Eran Harary749f1fe2014-03-06 09:25:30 +0200146#define NUM_2GHZ_CHANNELS 14
Sara Sharon70426782017-03-22 12:20:40 +0200147#define NUM_2GHZ_CHANNELS_EXT 14
Eran Harary749f1fe2014-03-06 09:25:30 +0200148#define FIRST_2GHZ_HT_MINUS 5
149#define LAST_2GHZ_HT_PLUS 9
Matti Gottliebb281c932014-06-26 11:10:57 +0300150#define LAST_5GHZ_HT 165
151#define LAST_5GHZ_HT_FAMILY_8000 181
Eran Hararyce500072014-12-01 17:53:53 +0200152#define N_HW_ADDR_MASK 0xF
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100153
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100154/* 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
David Spinadel9ee6dac2013-05-29 11:37:28 +0300183 * @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
Luca Coelhob823cf32017-08-16 10:46:52 +0300186 * @NVM_CHANNEL_UNIFORM: uniform spreading required
187 * @NVM_CHANNEL_20MHZ: 20 MHz channel okay
188 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay
189 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay
190 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay
191 * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100192 */
193enum iwl_nvm_channel_flags {
Luca Coelhob823cf32017-08-16 10:46:52 +0300194 NVM_CHANNEL_VALID = BIT(0),
195 NVM_CHANNEL_IBSS = BIT(1),
196 NVM_CHANNEL_ACTIVE = BIT(3),
197 NVM_CHANNEL_RADAR = BIT(4),
198 NVM_CHANNEL_INDOOR_ONLY = BIT(5),
199 NVM_CHANNEL_GO_CONCURRENT = BIT(6),
200 NVM_CHANNEL_UNIFORM = BIT(7),
201 NVM_CHANNEL_20MHZ = BIT(8),
202 NVM_CHANNEL_40MHZ = BIT(9),
203 NVM_CHANNEL_80MHZ = BIT(10),
204 NVM_CHANNEL_160MHZ = BIT(11),
205 NVM_CHANNEL_DC_HIGH = BIT(12),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100206};
207
208#define CHECK_AND_PRINT_I(x) \
209 ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
210
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200211static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
Matti Gottliebb281c932014-06-26 11:10:57 +0300212 u16 nvm_flags, const struct iwl_cfg *cfg)
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200213{
214 u32 flags = IEEE80211_CHAN_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300215 u32 last_5ghz_ht = LAST_5GHZ_HT;
216
Sara Sharon70426782017-03-22 12:20:40 +0200217 if (cfg->ext_nvm)
Matti Gottliebb281c932014-06-26 11:10:57 +0300218 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200219
220 if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
221 if (ch_num <= LAST_2GHZ_HT_PLUS)
222 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
223 if (ch_num >= FIRST_2GHZ_HT_MINUS)
224 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300225 } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) {
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200226 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
227 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
228 else
229 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
230 }
231 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
232 flags |= IEEE80211_CHAN_NO_80MHZ;
233 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
234 flags |= IEEE80211_CHAN_NO_160MHZ;
235
236 if (!(nvm_flags & NVM_CHANNEL_IBSS))
237 flags |= IEEE80211_CHAN_NO_IR;
238
239 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
240 flags |= IEEE80211_CHAN_NO_IR;
241
242 if (nvm_flags & NVM_CHANNEL_RADAR)
243 flags |= IEEE80211_CHAN_RADAR;
244
245 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
246 flags |= IEEE80211_CHAN_INDOOR_ONLY;
247
248 /* Set the GO concurrent flag only in case that NO_IR is set.
249 * Otherwise it is meaningless
250 */
251 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
252 (flags & IEEE80211_CHAN_NO_IR))
Arik Nemtsov06f207f2015-05-06 16:28:31 +0300253 flags |= IEEE80211_CHAN_IR_CONCURRENT;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200254
255 return flags;
256}
257
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100258static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
259 struct iwl_nvm_data *data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200260 const __le16 * const nvm_ch_flags,
261 bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100262{
263 int ch_idx;
264 int n_channels = 0;
265 struct ieee80211_channel *channel;
266 u16 ch_flags;
267 bool is_5ghz;
Eran Harary749f1fe2014-03-06 09:25:30 +0200268 int num_of_ch, num_2ghz_channels;
Eran Harary77db0a32014-02-04 14:21:38 +0200269 const u8 *nvm_chan;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100270
Sara Sharon70426782017-03-22 12:20:40 +0200271 if (!cfg->ext_nvm) {
Eran Harary77db0a32014-02-04 14:21:38 +0200272 num_of_ch = IWL_NUM_CHANNELS;
273 nvm_chan = &iwl_nvm_channels[0];
Eran Harary749f1fe2014-03-06 09:25:30 +0200274 num_2ghz_channels = NUM_2GHZ_CHANNELS;
Eran Harary77db0a32014-02-04 14:21:38 +0200275 } else {
Sara Sharon70426782017-03-22 12:20:40 +0200276 num_of_ch = IWL_NUM_CHANNELS_EXT;
277 nvm_chan = &iwl_ext_nvm_channels[0];
278 num_2ghz_channels = NUM_2GHZ_CHANNELS_EXT;
Eran Harary77db0a32014-02-04 14:21:38 +0200279 }
280
281 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100282 ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200283
Eran Harary749f1fe2014-03-06 09:25:30 +0200284 if (ch_idx >= num_2ghz_channels &&
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200285 !data->sku_cap_band_52GHz_enable)
Eliad Pellera76f3bf2014-05-26 18:11:37 +0300286 continue;
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200287
Gregory Greenman4896d762016-04-03 14:06:12 +0300288 if (ch_flags & NVM_CHANNEL_160MHZ)
289 data->vht160_supported = true;
290
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200291 if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
Eliad Pellera76f3bf2014-05-26 18:11:37 +0300292 /*
293 * Channels might become valid later if lar is
294 * supported, hence we still want to add them to
295 * the list of supported channels to cfg80211.
296 */
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100297 IWL_DEBUG_EEPROM(dev,
298 "Ch. %d Flags %x [%sGHz] - No traffic\n",
Eran Harary77db0a32014-02-04 14:21:38 +0200299 nvm_chan[ch_idx],
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100300 ch_flags,
Eran Harary749f1fe2014-03-06 09:25:30 +0200301 (ch_idx >= num_2ghz_channels) ?
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100302 "5.2" : "2.4");
303 continue;
304 }
305
306 channel = &data->channels[n_channels];
307 n_channels++;
308
Eran Harary77db0a32014-02-04 14:21:38 +0200309 channel->hw_value = nvm_chan[ch_idx];
Eran Harary749f1fe2014-03-06 09:25:30 +0200310 channel->band = (ch_idx < num_2ghz_channels) ?
Johannes Berg57fbcce2016-04-12 15:56:15 +0200311 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100312 channel->center_freq =
313 ieee80211_channel_to_frequency(
314 channel->hw_value, channel->band);
315
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100316 /* Initialize regulatory-based run-time data */
317
Matti Gottlieb88f2fd72013-07-09 15:25:46 +0300318 /*
319 * Default value - highest tx power value. max_power
320 * is not used in mvm, and is used for backwards compatibility
321 */
Eliad Peller22d059a2014-08-26 11:23:11 +0300322 channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200323 is_5ghz = channel->band == NL80211_BAND_5GHZ;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200324
325 /* don't put limitations in case we're using LAR */
326 if (!lar_supported)
327 channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx],
328 ch_idx, is_5ghz,
Matti Gottliebb281c932014-06-26 11:10:57 +0300329 ch_flags, cfg);
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200330 else
331 channel->flags = 0;
332
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100333 IWL_DEBUG_EEPROM(dev,
Luca Coelhob823cf32017-08-16 10:46:52 +0300334 "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n",
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100335 channel->hw_value,
336 is_5ghz ? "5.2" : "2.4",
Gregory Greenman4896d762016-04-03 14:06:12 +0300337 ch_flags,
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100338 CHECK_AND_PRINT_I(VALID),
339 CHECK_AND_PRINT_I(IBSS),
340 CHECK_AND_PRINT_I(ACTIVE),
341 CHECK_AND_PRINT_I(RADAR),
David Spinadel9ee6dac2013-05-29 11:37:28 +0300342 CHECK_AND_PRINT_I(INDOOR_ONLY),
343 CHECK_AND_PRINT_I(GO_CONCURRENT),
Luca Coelhob823cf32017-08-16 10:46:52 +0300344 CHECK_AND_PRINT_I(UNIFORM),
345 CHECK_AND_PRINT_I(20MHZ),
Gregory Greenman4896d762016-04-03 14:06:12 +0300346 CHECK_AND_PRINT_I(40MHZ),
347 CHECK_AND_PRINT_I(80MHZ),
348 CHECK_AND_PRINT_I(160MHZ),
Luca Coelhob823cf32017-08-16 10:46:52 +0300349 CHECK_AND_PRINT_I(DC_HIGH),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100350 channel->max_power,
351 ((ch_flags & NVM_CHANNEL_IBSS) &&
352 !(ch_flags & NVM_CHANNEL_RADAR))
353 ? "" : "not ");
354 }
355
356 return n_channels;
357}
358
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200359static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
360 struct iwl_nvm_data *data,
Johannes Berg6ca89f12014-02-12 21:56:26 +0100361 struct ieee80211_sta_vht_cap *vht_cap,
362 u8 tx_chains, u8 rx_chains)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200363{
Johannes Berg6ca89f12014-02-12 21:56:26 +0100364 int num_rx_ants = num_of_ant(rx_chains);
365 int num_tx_ants = num_of_ant(tx_chains);
Eran Hararyc064ddf2014-09-30 06:42:06 +0200366 unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?:
367 IEEE80211_VHT_MAX_AMPDU_1024K);
Eyal Shapira48e6de62013-11-03 10:04:08 +0200368
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200369 vht_cap->vht_supported = true;
370
371 vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
372 IEEE80211_VHT_CAP_RXSTBC_1 |
373 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
Eyal Shapirae36b7662014-01-06 20:16:48 +0200374 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
Eran Hararyc064ddf2014-09-30 06:42:06 +0200375 max_ampdu_exponent <<
376 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200377
Gregory Greenman4896d762016-04-03 14:06:12 +0300378 if (data->vht160_supported)
Gregory Greenmanfbbd4852016-04-12 15:16:24 +0300379 vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
380 IEEE80211_VHT_CAP_SHORT_GI_160;
Gregory Greenman4896d762016-04-03 14:06:12 +0300381
Sara Sharone48c9472016-01-27 18:59:48 +0200382 if (cfg->vht_mu_mimo_supported)
383 vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
384
Eyal Shapiraa3576ff2014-08-09 10:57:59 +0300385 if (cfg->ht_params->ldpc)
386 vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
387
Emmanuel Grumbach5f0d98f2014-10-30 10:19:38 +0200388 if (data->sku_cap_mimo_disabled) {
389 num_rx_ants = 1;
390 num_tx_ants = 1;
391 }
392
Johannes Berg6ca89f12014-02-12 21:56:26 +0100393 if (num_tx_ants > 1)
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200394 vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
Johannes Berg6ca89f12014-02-12 21:56:26 +0100395 else
396 vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200397
Emmanuel Grumbach6c4fbcb2015-11-10 11:57:41 +0200398 switch (iwlwifi_mod_params.amsdu_size) {
Emmanuel Grumbach4bdd4df2016-04-07 16:44:42 +0300399 case IWL_AMSDU_DEF:
400 if (cfg->mq_rx_supported)
401 vht_cap->cap |=
402 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
403 else
404 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
405 break;
Emmanuel Grumbach6c4fbcb2015-11-10 11:57:41 +0200406 case IWL_AMSDU_4K:
407 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
408 break;
409 case IWL_AMSDU_8K:
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200410 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
Emmanuel Grumbach6c4fbcb2015-11-10 11:57:41 +0200411 break;
412 case IWL_AMSDU_12K:
413 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
414 break;
415 default:
416 break;
417 }
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200418
419 vht_cap->vht_mcs.rx_mcs_map =
420 cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
421 IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
422 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
423 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
424 IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
425 IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
426 IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
427 IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
428
Johannes Berg6ca89f12014-02-12 21:56:26 +0100429 if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) {
430 vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200431 /* this works because NOT_SUPPORTED == 3 */
432 vht_cap->vht_mcs.rx_mcs_map |=
433 cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
434 }
435
436 vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
437}
438
Sara Sharon29108492017-01-08 16:45:46 +0200439void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
440 struct iwl_nvm_data *data, const __le16 *nvm_ch_flags,
441 u8 tx_chains, u8 rx_chains, bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100442{
Eran Harary77db0a32014-02-04 14:21:38 +0200443 int n_channels;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100444 int n_used = 0;
445 struct ieee80211_supported_band *sband;
446
Sara Sharon29108492017-01-08 16:45:46 +0200447 n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags,
448 lar_supported);
Johannes Berg57fbcce2016-04-12 15:56:15 +0200449 sband = &data->bands[NL80211_BAND_2GHZ];
450 sband->band = NL80211_BAND_2GHZ;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100451 sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
452 sband->n_bitrates = N_RATES_24;
453 n_used += iwl_init_sband_channels(data, sband, n_channels,
Johannes Berg57fbcce2016-04-12 15:56:15 +0200454 NL80211_BAND_2GHZ);
455 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_2GHZ,
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300456 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100457
Johannes Berg57fbcce2016-04-12 15:56:15 +0200458 sband = &data->bands[NL80211_BAND_5GHZ];
459 sband->band = NL80211_BAND_5GHZ;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100460 sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
461 sband->n_bitrates = N_RATES_52;
462 n_used += iwl_init_sband_channels(data, sband, n_channels,
Johannes Berg57fbcce2016-04-12 15:56:15 +0200463 NL80211_BAND_5GHZ);
464 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, NL80211_BAND_5GHZ,
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300465 tx_chains, rx_chains);
Andrei Otcheretianski0d0985a2016-02-29 13:25:48 +0200466 if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac)
Johannes Berg6ca89f12014-02-12 21:56:26 +0100467 iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
468 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100469
470 if (n_channels != n_used)
471 IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
472 n_used, n_channels);
473}
Sara Sharon29108492017-01-08 16:45:46 +0200474IWL_EXPORT_SYMBOL(iwl_init_sbands);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100475
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200476static int iwl_get_sku(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
477 const __le16 *phy_sku)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100478{
Sara Sharon70426782017-03-22 12:20:40 +0200479 if (!cfg->ext_nvm)
Eran Harary77db0a32014-02-04 14:21:38 +0200480 return le16_to_cpup(nvm_sw + SKU);
Eran Hararyce500072014-12-01 17:53:53 +0200481
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200482 return le32_to_cpup((__le32 *)(phy_sku + SKU_FAMILY_8000));
Eran Harary77db0a32014-02-04 14:21:38 +0200483}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100484
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200485static int iwl_get_nvm_version(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
Eran Harary77db0a32014-02-04 14:21:38 +0200486{
Sara Sharon70426782017-03-22 12:20:40 +0200487 if (!cfg->ext_nvm)
Eran Harary77db0a32014-02-04 14:21:38 +0200488 return le16_to_cpup(nvm_sw + NVM_VERSION);
489 else
490 return le32_to_cpup((__le32 *)(nvm_sw +
Sara Sharon70426782017-03-22 12:20:40 +0200491 NVM_VERSION_EXT_NVM));
Eran Harary77db0a32014-02-04 14:21:38 +0200492}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100493
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200494static int iwl_get_radio_cfg(const struct iwl_cfg *cfg, const __le16 *nvm_sw,
495 const __le16 *phy_sku)
Eran Harary77db0a32014-02-04 14:21:38 +0200496{
Sara Sharon70426782017-03-22 12:20:40 +0200497 if (!cfg->ext_nvm)
Eran Harary77db0a32014-02-04 14:21:38 +0200498 return le16_to_cpup(nvm_sw + RADIO_CFG);
Eran Hararyce500072014-12-01 17:53:53 +0200499
Sara Sharon70426782017-03-22 12:20:40 +0200500 return le32_to_cpup((__le32 *)(phy_sku + RADIO_CFG_FAMILY_EXT_NVM));
Eran Hararyce500072014-12-01 17:53:53 +0200501
Eran Harary77db0a32014-02-04 14:21:38 +0200502}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100503
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200504static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg, const __le16 *nvm_sw)
Eran Harary77db0a32014-02-04 14:21:38 +0200505{
Eran Hararyce500072014-12-01 17:53:53 +0200506 int n_hw_addr;
507
Sara Sharon70426782017-03-22 12:20:40 +0200508 if (!cfg->ext_nvm)
Eran Harary77db0a32014-02-04 14:21:38 +0200509 return le16_to_cpup(nvm_sw + N_HW_ADDRS);
Eran Hararyce500072014-12-01 17:53:53 +0200510
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200511 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw + N_HW_ADDRS_FAMILY_8000));
Eran Hararyce500072014-12-01 17:53:53 +0200512
513 return n_hw_addr & N_HW_ADDR_MASK;
Eran Harary77db0a32014-02-04 14:21:38 +0200514}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100515
Eran Harary77db0a32014-02-04 14:21:38 +0200516static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
517 struct iwl_nvm_data *data,
518 u32 radio_cfg)
519{
Sara Sharon70426782017-03-22 12:20:40 +0200520 if (!cfg->ext_nvm) {
Eran Harary77db0a32014-02-04 14:21:38 +0200521 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
522 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
523 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
524 data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200525 return;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100526 }
527
Eran Harary77db0a32014-02-04 14:21:38 +0200528 /* set the radio configuration for family 8000 */
Sara Sharon70426782017-03-22 12:20:40 +0200529 data->radio_cfg_type = EXT_NVM_RF_CFG_TYPE_MSK(radio_cfg);
530 data->radio_cfg_step = EXT_NVM_RF_CFG_STEP_MSK(radio_cfg);
531 data->radio_cfg_dash = EXT_NVM_RF_CFG_DASH_MSK(radio_cfg);
532 data->radio_cfg_pnum = EXT_NVM_RF_CFG_FLAVOR_MSK(radio_cfg);
533 data->valid_tx_ant = EXT_NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
534 data->valid_rx_ant = EXT_NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200535}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100536
Sara Sharon17c867b2016-03-07 14:18:29 +0200537static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest)
538{
539 const u8 *hw_addr;
540
541 hw_addr = (const u8 *)&mac_addr0;
542 dest[0] = hw_addr[3];
543 dest[1] = hw_addr[2];
544 dest[2] = hw_addr[1];
545 dest[3] = hw_addr[0];
546
547 hw_addr = (const u8 *)&mac_addr1;
548 dest[4] = hw_addr[1];
549 dest[5] = hw_addr[0];
550}
551
Sara Sharon29108492017-01-08 16:45:46 +0200552void iwl_set_hw_address_from_csr(struct iwl_trans *trans,
553 struct iwl_nvm_data *data)
Sara Sharon17c867b2016-03-07 14:18:29 +0200554{
555 __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_STRAP));
556 __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_STRAP));
557
Haim Dreyfussa6c934b2016-08-02 15:28:23 +0300558 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
559 /*
560 * If the OEM fused a valid address, use it instead of the one in the
561 * OTP
562 */
563 if (is_valid_ether_addr(data->hw_addr))
564 return;
565
566 mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP));
567 mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP));
Sara Sharon17c867b2016-03-07 14:18:29 +0200568
569 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
570}
Sara Sharon29108492017-01-08 16:45:46 +0200571IWL_EXPORT_SYMBOL(iwl_set_hw_address_from_csr);
Sara Sharon17c867b2016-03-07 14:18:29 +0200572
Sara Sharonafd5b172016-03-01 12:18:22 +0200573static void iwl_set_hw_address_family_8000(struct iwl_trans *trans,
Eran Harary6a68a392014-05-07 11:09:11 +0300574 const struct iwl_cfg *cfg,
Eran Harary9f32e012014-04-28 15:22:40 +0300575 struct iwl_nvm_data *data,
576 const __le16 *mac_override,
Sara Sharonafd5b172016-03-01 12:18:22 +0200577 const __le16 *nvm_hw)
Eran Harary9f32e012014-04-28 15:22:40 +0300578{
579 const u8 *hw_addr;
580
581 if (mac_override) {
Liad Kaufman18f84672015-05-20 15:50:07 +0300582 static const u8 reserved_mac[] = {
583 0x02, 0xcc, 0xaa, 0xff, 0xee, 0x00
584 };
585
Eran Harary9f32e012014-04-28 15:22:40 +0300586 hw_addr = (const u8 *)(mac_override +
Sara Sharon70426782017-03-22 12:20:40 +0200587 MAC_ADDRESS_OVERRIDE_EXT_NVM);
Eran Harary9f32e012014-04-28 15:22:40 +0300588
Liad Kaufmanbe88a1a2015-07-01 17:28:34 +0300589 /*
590 * Store the MAC address from MAO section.
591 * No byte swapping is required in MAO section
592 */
593 memcpy(data->hw_addr, hw_addr, ETH_ALEN);
Eran Harary9f32e012014-04-28 15:22:40 +0300594
Liad Kaufman18f84672015-05-20 15:50:07 +0300595 /*
596 * Force the use of the OTP MAC address in case of reserved MAC
597 * address in the NVM, or if address is given but invalid.
598 */
599 if (is_valid_ether_addr(data->hw_addr) &&
600 memcmp(reserved_mac, hw_addr, ETH_ALEN) != 0)
Eran Harary9f32e012014-04-28 15:22:40 +0300601 return;
Eran Harary6a68a392014-05-07 11:09:11 +0300602
Sara Sharonafd5b172016-03-01 12:18:22 +0200603 IWL_ERR(trans,
604 "mac address from nvm override section is not valid\n");
Eran Harary9f32e012014-04-28 15:22:40 +0300605 }
606
Eran Harary6a68a392014-05-07 11:09:11 +0300607 if (nvm_hw) {
Sara Sharonafd5b172016-03-01 12:18:22 +0200608 /* read the mac address from WFMP registers */
609 __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans,
610 WFMP_MAC_ADDR_0));
611 __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans,
612 WFMP_MAC_ADDR_1));
Eran Harary9f32e012014-04-28 15:22:40 +0300613
Sara Sharon17c867b2016-03-07 14:18:29 +0200614 iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr);
Eran Harary1e0b3932014-06-11 11:37:09 +0300615
Eran Harary6a68a392014-05-07 11:09:11 +0300616 return;
617 }
618
Sara Sharonafd5b172016-03-01 12:18:22 +0200619 IWL_ERR(trans, "mac address is not found\n");
620}
621
Sara Sharon17c867b2016-03-07 14:18:29 +0200622static int iwl_set_hw_address(struct iwl_trans *trans,
623 const struct iwl_cfg *cfg,
624 struct iwl_nvm_data *data, const __le16 *nvm_hw,
625 const __le16 *mac_override)
Sara Sharonafd5b172016-03-01 12:18:22 +0200626{
Sara Sharon17c867b2016-03-07 14:18:29 +0200627 if (cfg->mac_addr_from_csr) {
628 iwl_set_hw_address_from_csr(trans, data);
Sara Sharon70426782017-03-22 12:20:40 +0200629 } else if (!cfg->ext_nvm) {
Sara Sharonafd5b172016-03-01 12:18:22 +0200630 const u8 *hw_addr = (const u8 *)(nvm_hw + HW_ADDR);
631
632 /* The byte order is little endian 16 bit, meaning 214365 */
633 data->hw_addr[0] = hw_addr[1];
634 data->hw_addr[1] = hw_addr[0];
635 data->hw_addr[2] = hw_addr[3];
636 data->hw_addr[3] = hw_addr[2];
637 data->hw_addr[4] = hw_addr[5];
638 data->hw_addr[5] = hw_addr[4];
639 } else {
640 iwl_set_hw_address_family_8000(trans, cfg, data,
641 mac_override, nvm_hw);
642 }
Sara Sharon17c867b2016-03-07 14:18:29 +0200643
644 if (!is_valid_ether_addr(data->hw_addr)) {
645 IWL_ERR(trans, "no valid mac address was found\n");
646 return -EINVAL;
647 }
648
Luca Coelho4409e722017-05-09 22:46:19 +0300649 IWL_INFO(trans, "base HW address: %pM\n", data->hw_addr);
650
Sara Sharon17c867b2016-03-07 14:18:29 +0200651 return 0;
Eran Harary9f32e012014-04-28 15:22:40 +0300652}
653
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100654struct iwl_nvm_data *
Sara Sharonafd5b172016-03-01 12:18:22 +0200655iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg,
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100656 const __le16 *nvm_hw, const __le16 *nvm_sw,
Eran Harary77db0a32014-02-04 14:21:38 +0200657 const __le16 *nvm_calib, const __le16 *regulatory,
Eran Hararyce500072014-12-01 17:53:53 +0200658 const __le16 *mac_override, const __le16 *phy_sku,
Sara Sharonafd5b172016-03-01 12:18:22 +0200659 u8 tx_chains, u8 rx_chains, bool lar_fw_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100660{
Sara Sharonafd5b172016-03-01 12:18:22 +0200661 struct device *dev = trans->dev;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100662 struct iwl_nvm_data *data;
Sara Sharonafd5b172016-03-01 12:18:22 +0200663 bool lar_enabled;
664 u32 sku, radio_cfg;
Matti Gottliebd0d15192014-07-31 09:16:25 +0300665 u16 lar_config;
Sara Sharonafd5b172016-03-01 12:18:22 +0200666 const __le16 *ch_section;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100667
Sara Sharon70426782017-03-22 12:20:40 +0200668 if (!cfg->ext_nvm)
Eran Harary77db0a32014-02-04 14:21:38 +0200669 data = kzalloc(sizeof(*data) +
670 sizeof(struct ieee80211_channel) *
671 IWL_NUM_CHANNELS,
672 GFP_KERNEL);
673 else
674 data = kzalloc(sizeof(*data) +
675 sizeof(struct ieee80211_channel) *
Sara Sharon70426782017-03-22 12:20:40 +0200676 IWL_NUM_CHANNELS_EXT,
Eran Harary77db0a32014-02-04 14:21:38 +0200677 GFP_KERNEL);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100678 if (!data)
679 return NULL;
680
Eran Harary77db0a32014-02-04 14:21:38 +0200681 data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100682
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200683 radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw, phy_sku);
Eran Harary77db0a32014-02-04 14:21:38 +0200684 iwl_set_radio_cfg(cfg, data, radio_cfg);
Moshe Harela0544272014-12-08 21:13:14 +0200685 if (data->valid_tx_ant)
686 tx_chains &= data->valid_tx_ant;
687 if (data->valid_rx_ant)
688 rx_chains &= data->valid_rx_ant;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100689
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200690 sku = iwl_get_sku(cfg, nvm_sw, phy_sku);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100691 data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
692 data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
693 data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
694 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
695 data->sku_cap_11n_enable = false;
Eliad Peller2926f952014-10-23 16:29:10 +0300696 data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
697 (sku & NVM_SKU_CAP_11AC_ENABLE);
Emmanuel Grumbach5f0d98f2014-10-30 10:19:38 +0200698 data->sku_cap_mimo_disabled = sku & NVM_SKU_CAP_MIMO_DISABLE;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100699
Emmanuel Grumbach5dd9c682015-03-05 13:06:13 +0200700 data->n_hw_addrs = iwl_get_n_hw_addrs(cfg, nvm_sw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100701
Sara Sharon70426782017-03-22 12:20:40 +0200702 if (!cfg->ext_nvm) {
Eran Harary77db0a32014-02-04 14:21:38 +0200703 /* Checking for required sections */
704 if (!nvm_calib) {
Sara Sharonafd5b172016-03-01 12:18:22 +0200705 IWL_ERR(trans,
706 "Can't parse empty Calib NVM sections\n");
Eytan Lifshitz1270c412014-02-18 15:02:29 +0200707 kfree(data);
Eran Harary77db0a32014-02-04 14:21:38 +0200708 return NULL;
709 }
710 /* in family 8000 Xtal calibration values moved to OTP */
711 data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
712 data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
Sara Sharonafd5b172016-03-01 12:18:22 +0200713 lar_enabled = true;
Sara Sharon29108492017-01-08 16:45:46 +0200714 ch_section = &nvm_sw[NVM_CHANNELS];
Eran Harary77db0a32014-02-04 14:21:38 +0200715 } else {
Arik Nemtsovf5528632015-02-04 15:38:56 +0200716 u16 lar_offset = data->nvm_version < 0xE39 ?
Sara Sharon70426782017-03-22 12:20:40 +0200717 NVM_LAR_OFFSET_OLD :
718 NVM_LAR_OFFSET;
Arik Nemtsovf5528632015-02-04 15:38:56 +0200719
720 lar_config = le16_to_cpup(regulatory + lar_offset);
Matti Gottliebd0d15192014-07-31 09:16:25 +0300721 data->lar_enabled = !!(lar_config &
Sara Sharon70426782017-03-22 12:20:40 +0200722 NVM_LAR_ENABLED);
Sara Sharonafd5b172016-03-01 12:18:22 +0200723 lar_enabled = data->lar_enabled;
Sara Sharon70426782017-03-22 12:20:40 +0200724 ch_section = &regulatory[NVM_CHANNELS_EXTENDED];
Eran Harary77db0a32014-02-04 14:21:38 +0200725 }
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100726
Sara Sharon17c867b2016-03-07 14:18:29 +0200727 /* If no valid mac address was found - bail out */
728 if (iwl_set_hw_address(trans, cfg, data, nvm_hw, mac_override)) {
729 kfree(data);
730 return NULL;
731 }
732
Sara Sharonafd5b172016-03-01 12:18:22 +0200733 iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains,
734 lar_fw_supported && lar_enabled);
Emmanuel Grumbach33b2f682014-01-14 13:48:22 +0200735 data->calib_version = 255;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100736
737 return data;
738}
Johannes Berg48e29342013-03-01 00:13:33 +0100739IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200740
741static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
Matti Gottliebb281c932014-06-26 11:10:57 +0300742 int ch_idx, u16 nvm_flags,
743 const struct iwl_cfg *cfg)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200744{
745 u32 flags = NL80211_RRF_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300746 u32 last_5ghz_ht = LAST_5GHZ_HT;
747
Sara Sharon70426782017-03-22 12:20:40 +0200748 if (cfg->ext_nvm)
Matti Gottliebb281c932014-06-26 11:10:57 +0300749 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200750
751 if (ch_idx < NUM_2GHZ_CHANNELS &&
752 (nvm_flags & NVM_CHANNEL_40MHZ)) {
753 if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
754 flags &= ~NL80211_RRF_NO_HT40PLUS;
755 if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
756 flags &= ~NL80211_RRF_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300757 } else if (nvm_chan[ch_idx] <= last_5ghz_ht &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200758 (nvm_flags & NVM_CHANNEL_40MHZ)) {
759 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
760 flags &= ~NL80211_RRF_NO_HT40PLUS;
761 else
762 flags &= ~NL80211_RRF_NO_HT40MINUS;
763 }
764
765 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
766 flags |= NL80211_RRF_NO_80MHZ;
767 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
768 flags |= NL80211_RRF_NO_160MHZ;
769
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200770 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
771 flags |= NL80211_RRF_NO_IR;
772
773 if (nvm_flags & NVM_CHANNEL_RADAR)
774 flags |= NL80211_RRF_DFS;
775
776 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
777 flags |= NL80211_RRF_NO_OUTDOOR;
778
779 /* Set the GO concurrent flag only in case that NO_IR is set.
780 * Otherwise it is meaningless
781 */
782 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
783 (flags & NL80211_RRF_NO_IR))
784 flags |= NL80211_RRF_GO_CONCURRENT;
785
786 return flags;
787}
788
789struct ieee80211_regdomain *
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300790iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
791 int num_of_ch, __le32 *channels, u16 fw_mcc)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200792{
793 int ch_idx;
794 u16 ch_flags, prev_ch_flags = 0;
Sara Sharon70426782017-03-22 12:20:40 +0200795 const u8 *nvm_chan = cfg->ext_nvm ?
796 iwl_ext_nvm_channels : iwl_nvm_channels;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200797 struct ieee80211_regdomain *regd;
798 int size_of_regd;
799 struct ieee80211_reg_rule *rule;
Johannes Berg57fbcce2016-04-12 15:56:15 +0200800 enum nl80211_band band;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200801 int center_freq, prev_center_freq = 0;
802 int valid_rules = 0;
803 bool new_rule;
Sara Sharon70426782017-03-22 12:20:40 +0200804 int max_num_ch = cfg->ext_nvm ?
805 IWL_NUM_CHANNELS_EXT : IWL_NUM_CHANNELS;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200806
807 if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
808 return ERR_PTR(-EINVAL);
809
Arik Nemtsov4557eab2015-03-01 18:24:57 +0200810 if (WARN_ON(num_of_ch > max_num_ch))
811 num_of_ch = max_num_ch;
812
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200813 IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
814 num_of_ch);
815
816 /* build a regdomain rule for every valid channel */
817 size_of_regd =
818 sizeof(struct ieee80211_regdomain) +
819 num_of_ch * sizeof(struct ieee80211_reg_rule);
820
821 regd = kzalloc(size_of_regd, GFP_KERNEL);
822 if (!regd)
823 return ERR_PTR(-ENOMEM);
824
825 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
826 ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
827 band = (ch_idx < NUM_2GHZ_CHANNELS) ?
Johannes Berg57fbcce2016-04-12 15:56:15 +0200828 NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200829 center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
830 band);
831 new_rule = false;
832
833 if (!(ch_flags & NVM_CHANNEL_VALID)) {
834 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
835 "Ch. %d Flags %x [%sGHz] - No traffic\n",
836 nvm_chan[ch_idx],
837 ch_flags,
838 (ch_idx >= NUM_2GHZ_CHANNELS) ?
839 "5.2" : "2.4");
840 continue;
841 }
842
843 /* we can't continue the same rule */
844 if (ch_idx == 0 || prev_ch_flags != ch_flags ||
845 center_freq - prev_center_freq > 20) {
846 valid_rules++;
847 new_rule = true;
848 }
849
850 rule = &regd->reg_rules[valid_rules - 1];
851
852 if (new_rule)
853 rule->freq_range.start_freq_khz =
854 MHZ_TO_KHZ(center_freq - 10);
855
856 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
857
858 /* this doesn't matter - not used by FW */
859 rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
Eliad Peller02a50492014-09-07 17:45:11 +0300860 rule->power_rule.max_eirp =
861 DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200862
863 rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
Matti Gottliebb281c932014-06-26 11:10:57 +0300864 ch_flags, cfg);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200865
866 /* rely on auto-calculation to merge BW of contiguous chans */
867 rule->flags |= NL80211_RRF_AUTO_BW;
868 rule->freq_range.max_bandwidth_khz = 0;
869
870 prev_ch_flags = ch_flags;
871 prev_center_freq = center_freq;
872
873 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
Luca Coelhob823cf32017-08-16 10:46:52 +0300874 "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s%s%s(0x%02x): %s\n",
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200875 center_freq,
Johannes Berg57fbcce2016-04-12 15:56:15 +0200876 band == NL80211_BAND_5GHZ ? "5.2" : "2.4",
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200877 CHECK_AND_PRINT_I(VALID),
Luca Coelhob823cf32017-08-16 10:46:52 +0300878 CHECK_AND_PRINT_I(IBSS),
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200879 CHECK_AND_PRINT_I(ACTIVE),
880 CHECK_AND_PRINT_I(RADAR),
Luca Coelhob823cf32017-08-16 10:46:52 +0300881 CHECK_AND_PRINT_I(INDOOR_ONLY),
882 CHECK_AND_PRINT_I(GO_CONCURRENT),
883 CHECK_AND_PRINT_I(UNIFORM),
884 CHECK_AND_PRINT_I(20MHZ),
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200885 CHECK_AND_PRINT_I(40MHZ),
886 CHECK_AND_PRINT_I(80MHZ),
887 CHECK_AND_PRINT_I(160MHZ),
Luca Coelhob823cf32017-08-16 10:46:52 +0300888 CHECK_AND_PRINT_I(DC_HIGH),
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200889 ch_flags,
Arik Nemtsovbdf2fae2014-10-30 15:12:39 +0200890 ((ch_flags & NVM_CHANNEL_ACTIVE) &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200891 !(ch_flags & NVM_CHANNEL_RADAR))
Luca Coelhob823cf32017-08-16 10:46:52 +0300892 ? "Ad-Hoc" : "");
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200893 }
894
895 regd->n_reg_rules = valid_rules;
896
897 /* set alpha2 from FW. */
898 regd->alpha2[0] = fw_mcc >> 8;
899 regd->alpha2[1] = fw_mcc & 0xff;
900
901 return regd;
902}
903IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);
Arik Nemtsov671bed32016-08-07 18:58:29 +0300904
905#ifdef CONFIG_ACPI
906#define WRDD_METHOD "WRDD"
907#define WRDD_WIFI (0x07)
908#define WRDD_WIGIG (0x10)
909
910static u32 iwl_wrdd_get_mcc(struct device *dev, union acpi_object *wrdd)
911{
912 union acpi_object *mcc_pkg, *domain_type, *mcc_value;
913 u32 i;
914
915 if (wrdd->type != ACPI_TYPE_PACKAGE ||
916 wrdd->package.count < 2 ||
917 wrdd->package.elements[0].type != ACPI_TYPE_INTEGER ||
918 wrdd->package.elements[0].integer.value != 0) {
919 IWL_DEBUG_EEPROM(dev, "Unsupported wrdd structure\n");
920 return 0;
921 }
922
923 for (i = 1 ; i < wrdd->package.count ; ++i) {
924 mcc_pkg = &wrdd->package.elements[i];
925
926 if (mcc_pkg->type != ACPI_TYPE_PACKAGE ||
927 mcc_pkg->package.count < 2 ||
928 mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
929 mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
930 mcc_pkg = NULL;
931 continue;
932 }
933
934 domain_type = &mcc_pkg->package.elements[0];
935 if (domain_type->integer.value == WRDD_WIFI)
936 break;
937
938 mcc_pkg = NULL;
939 }
940
941 if (mcc_pkg) {
942 mcc_value = &mcc_pkg->package.elements[1];
943 return mcc_value->integer.value;
944 }
945
946 return 0;
947}
948
949int iwl_get_bios_mcc(struct device *dev, char *mcc)
950{
951 acpi_handle root_handle;
952 acpi_handle handle;
953 struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
954 acpi_status status;
955 u32 mcc_val;
956
957 root_handle = ACPI_HANDLE(dev);
958 if (!root_handle) {
959 IWL_DEBUG_EEPROM(dev,
960 "Could not retrieve root port ACPI handle\n");
961 return -ENOENT;
962 }
963
964 /* Get the method's handle */
965 status = acpi_get_handle(root_handle, (acpi_string)WRDD_METHOD,
966 &handle);
967 if (ACPI_FAILURE(status)) {
968 IWL_DEBUG_EEPROM(dev, "WRD method not found\n");
969 return -ENOENT;
970 }
971
972 /* Call WRDD with no arguments */
973 status = acpi_evaluate_object(handle, NULL, NULL, &wrdd);
974 if (ACPI_FAILURE(status)) {
975 IWL_DEBUG_EEPROM(dev, "WRDC invocation failed (0x%x)\n",
976 status);
977 return -ENOENT;
978 }
979
980 mcc_val = iwl_wrdd_get_mcc(dev, wrdd.pointer);
981 kfree(wrdd.pointer);
982 if (!mcc_val)
983 return -ENOENT;
984
985 mcc[0] = (mcc_val >> 8) & 0xff;
986 mcc[1] = mcc_val & 0xff;
987 mcc[2] = '\0';
988 return 0;
989}
990IWL_EXPORT_SYMBOL(iwl_get_bios_mcc);
991#endif