blob: d9423eda6ad9dafff0ac97320a47688fcff7c0d8 [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.
Johannes Berg8b4139d2014-07-24 14:05:26 +02009 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
Johannes Bergb1e1adf2013-01-24 14:14:22 +010010 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
23 * USA
24 *
25 * The full GNU General Public License is included in this distribution
Emmanuel Grumbach410dc5a2013-02-18 09:22:28 +020026 * in the file called COPYING.
Johannes Bergb1e1adf2013-01-24 14:14:22 +010027 *
28 * Contact Information:
29 * Intel Linux Wireless <ilw@linux.intel.com>
30 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
31 *
32 * BSD LICENSE
33 *
Emmanuel Grumbach51368bf2013-12-30 13:15:54 +020034 * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
Johannes Berg8b4139d2014-07-24 14:05:26 +020035 * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
Johannes Bergb1e1adf2013-01-24 14:14:22 +010036 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 *
42 * * Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * * Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in
46 * the documentation and/or other materials provided with the
47 * distribution.
48 * * Neither the name Intel Corporation nor the names of its
49 * contributors may be used to endorse or promote products derived
50 * from this software without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
53 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
54 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
55 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
56 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
57 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
58 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
62 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 *****************************************************************************/
64#include <linux/types.h>
65#include <linux/slab.h>
66#include <linux/export.h>
Eran Harary9f32e012014-04-28 15:22:40 +030067#include <linux/etherdevice.h>
Eran Harary1e0b3932014-06-11 11:37:09 +030068#include <linux/pci.h>
Johannes Berg48e29342013-03-01 00:13:33 +010069#include "iwl-drv.h"
Johannes Bergb1e1adf2013-01-24 14:14:22 +010070#include "iwl-modparams.h"
71#include "iwl-nvm-parse.h"
72
73/* NVM offsets (in words) definitions */
74enum wkp_nvm_offsets {
75 /* NVM HW-Section offset (in words) definitions */
76 HW_ADDR = 0x15,
77
Eran Harary77db0a32014-02-04 14:21:38 +020078 /* NVM SW-Section offset (in words) definitions */
Johannes Bergb1e1adf2013-01-24 14:14:22 +010079 NVM_SW_SECTION = 0x1C0,
80 NVM_VERSION = 0,
81 RADIO_CFG = 1,
82 SKU = 2,
83 N_HW_ADDRS = 3,
84 NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION,
85
Eran Harary77db0a32014-02-04 14:21:38 +020086 /* NVM calibration section offset (in words) definitions */
Johannes Bergb1e1adf2013-01-24 14:14:22 +010087 NVM_CALIB_SECTION = 0x2B8,
88 XTAL_CALIB = 0x316 - NVM_CALIB_SECTION
89};
90
Eran Harary77db0a32014-02-04 14:21:38 +020091enum family_8000_nvm_offsets {
92 /* NVM HW-Section offset (in words) definitions */
Eran Harary1e0b3932014-06-11 11:37:09 +030093 HW_ADDR0_WFPM_FAMILY_8000 = 0x12,
94 HW_ADDR1_WFPM_FAMILY_8000 = 0x16,
95 HW_ADDR0_PCIE_FAMILY_8000 = 0x8A,
96 HW_ADDR1_PCIE_FAMILY_8000 = 0x8E,
Eran Harary77db0a32014-02-04 14:21:38 +020097 MAC_ADDRESS_OVERRIDE_FAMILY_8000 = 1,
98
99 /* NVM SW-Section offset (in words) definitions */
100 NVM_SW_SECTION_FAMILY_8000 = 0x1C0,
101 NVM_VERSION_FAMILY_8000 = 0,
102 RADIO_CFG_FAMILY_8000 = 2,
103 SKU_FAMILY_8000 = 4,
104 N_HW_ADDRS_FAMILY_8000 = 5,
105
Eran Hararyce500072014-12-01 17:53:53 +0200106 /* NVM PHY-SKU-Section offset (in words) for B0 */
107 RADIO_CFG_FAMILY_8000_B0 = 0,
108 SKU_FAMILY_8000_B0 = 2,
109 N_HW_ADDRS_FAMILY_8000_B0 = 3,
110
Eran Harary77db0a32014-02-04 14:21:38 +0200111 /* NVM REGULATORY -Section offset (in words) definitions */
112 NVM_CHANNELS_FAMILY_8000 = 0,
Matti Gottliebd0d15192014-07-31 09:16:25 +0300113 NVM_LAR_OFFSET_FAMILY_8000 = 0x4C7,
114 NVM_LAR_ENABLED_FAMILY_8000 = 0x7,
Eran Harary77db0a32014-02-04 14:21:38 +0200115
116 /* NVM calibration section offset (in words) definitions */
117 NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
118 XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
119};
120
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100121/* SKU Capabilities (actual values from NVM definition) */
122enum nvm_sku_bits {
123 NVM_SKU_CAP_BAND_24GHZ = BIT(0),
124 NVM_SKU_CAP_BAND_52GHZ = BIT(1),
125 NVM_SKU_CAP_11N_ENABLE = BIT(2),
Johannes Bergbfc824b2013-05-06 16:06:51 +0200126 NVM_SKU_CAP_11AC_ENABLE = BIT(3),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100127};
128
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100129/*
130 * These are the channel numbers in the order that they are stored in the NVM
131 */
132static const u8 iwl_nvm_channels[] = {
133 /* 2.4 GHz */
134 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
135 /* 5 GHz */
136 36, 40, 44 , 48, 52, 56, 60, 64,
137 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
138 149, 153, 157, 161, 165
139};
140
Eran Harary77db0a32014-02-04 14:21:38 +0200141static const u8 iwl_nvm_channels_family_8000[] = {
142 /* 2.4 GHz */
Eran Harary9b1c9a62014-05-07 08:22:41 +0300143 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
Eran Harary77db0a32014-02-04 14:21:38 +0200144 /* 5 GHz */
145 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
146 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
147 149, 153, 157, 161, 165, 169, 173, 177, 181
148};
149
Eran Harary749f1fe2014-03-06 09:25:30 +0200150#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
Eran Harary77db0a32014-02-04 14:21:38 +0200151#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000)
Eran Harary749f1fe2014-03-06 09:25:30 +0200152#define NUM_2GHZ_CHANNELS 14
Eran Harary9b1c9a62014-05-07 08:22:41 +0300153#define NUM_2GHZ_CHANNELS_FAMILY_8000 14
Eran Harary749f1fe2014-03-06 09:25:30 +0200154#define FIRST_2GHZ_HT_MINUS 5
155#define LAST_2GHZ_HT_PLUS 9
Matti Gottliebb281c932014-06-26 11:10:57 +0300156#define LAST_5GHZ_HT 165
157#define LAST_5GHZ_HT_FAMILY_8000 181
Eran Hararyce500072014-12-01 17:53:53 +0200158#define N_HW_ADDR_MASK 0xF
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100159
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100160/* rate data (static) */
161static struct ieee80211_rate iwl_cfg80211_rates[] = {
162 { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
163 { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
164 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
165 { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
166 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
167 { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
168 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
169 { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
170 { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
171 { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
172 { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
173 { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
174 { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
175 { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
176 { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
177};
178#define RATES_24_OFFS 0
179#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
180#define RATES_52_OFFS 4
181#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
182
183/**
184 * enum iwl_nvm_channel_flags - channel flags in NVM
185 * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
186 * @NVM_CHANNEL_IBSS: usable as an IBSS channel
187 * @NVM_CHANNEL_ACTIVE: active scanning allowed
188 * @NVM_CHANNEL_RADAR: radar detection required
David Spinadel9ee6dac2013-05-29 11:37:28 +0300189 * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed
190 * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS
191 * on same channel on 2.4 or same UNII band on 5.2
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100192 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
193 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200194 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
195 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100196 */
197enum iwl_nvm_channel_flags {
198 NVM_CHANNEL_VALID = BIT(0),
199 NVM_CHANNEL_IBSS = BIT(1),
200 NVM_CHANNEL_ACTIVE = BIT(3),
201 NVM_CHANNEL_RADAR = BIT(4),
David Spinadel9ee6dac2013-05-29 11:37:28 +0300202 NVM_CHANNEL_INDOOR_ONLY = BIT(5),
203 NVM_CHANNEL_GO_CONCURRENT = BIT(6),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100204 NVM_CHANNEL_WIDE = BIT(8),
205 NVM_CHANNEL_40MHZ = BIT(9),
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200206 NVM_CHANNEL_80MHZ = BIT(10),
207 NVM_CHANNEL_160MHZ = BIT(11),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100208};
209
210#define CHECK_AND_PRINT_I(x) \
211 ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
212
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200213static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
Matti Gottliebb281c932014-06-26 11:10:57 +0300214 u16 nvm_flags, const struct iwl_cfg *cfg)
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200215{
216 u32 flags = IEEE80211_CHAN_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300217 u32 last_5ghz_ht = LAST_5GHZ_HT;
218
219 if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
220 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200221
222 if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
223 if (ch_num <= LAST_2GHZ_HT_PLUS)
224 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
225 if (ch_num >= FIRST_2GHZ_HT_MINUS)
226 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300227 } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) {
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200228 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
229 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
230 else
231 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
232 }
233 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
234 flags |= IEEE80211_CHAN_NO_80MHZ;
235 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
236 flags |= IEEE80211_CHAN_NO_160MHZ;
237
238 if (!(nvm_flags & NVM_CHANNEL_IBSS))
239 flags |= IEEE80211_CHAN_NO_IR;
240
241 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
242 flags |= IEEE80211_CHAN_NO_IR;
243
244 if (nvm_flags & NVM_CHANNEL_RADAR)
245 flags |= IEEE80211_CHAN_RADAR;
246
247 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
248 flags |= IEEE80211_CHAN_INDOOR_ONLY;
249
250 /* Set the GO concurrent flag only in case that NO_IR is set.
251 * Otherwise it is meaningless
252 */
253 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
254 (flags & IEEE80211_CHAN_NO_IR))
255 flags |= IEEE80211_CHAN_GO_CONCURRENT;
256
257 return flags;
258}
259
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100260static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
261 struct iwl_nvm_data *data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200262 const __le16 * const nvm_ch_flags,
263 bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100264{
265 int ch_idx;
266 int n_channels = 0;
267 struct ieee80211_channel *channel;
268 u16 ch_flags;
269 bool is_5ghz;
Eran Harary749f1fe2014-03-06 09:25:30 +0200270 int num_of_ch, num_2ghz_channels;
Eran Harary77db0a32014-02-04 14:21:38 +0200271 const u8 *nvm_chan;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100272
Eran Harary77db0a32014-02-04 14:21:38 +0200273 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
274 num_of_ch = IWL_NUM_CHANNELS;
275 nvm_chan = &iwl_nvm_channels[0];
Eran Harary749f1fe2014-03-06 09:25:30 +0200276 num_2ghz_channels = NUM_2GHZ_CHANNELS;
Eran Harary77db0a32014-02-04 14:21:38 +0200277 } else {
278 num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
279 nvm_chan = &iwl_nvm_channels_family_8000[0];
Eran Harary749f1fe2014-03-06 09:25:30 +0200280 num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
Eran Harary77db0a32014-02-04 14:21:38 +0200281 }
282
283 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100284 ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200285
Eran Harary749f1fe2014-03-06 09:25:30 +0200286 if (ch_idx >= num_2ghz_channels &&
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200287 !data->sku_cap_band_52GHz_enable)
Eliad Pellera76f3bf2014-05-26 18:11:37 +0300288 continue;
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200289
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200290 if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
Eliad Pellera76f3bf2014-05-26 18:11:37 +0300291 /*
292 * Channels might become valid later if lar is
293 * supported, hence we still want to add them to
294 * the list of supported channels to cfg80211.
295 */
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100296 IWL_DEBUG_EEPROM(dev,
297 "Ch. %d Flags %x [%sGHz] - No traffic\n",
Eran Harary77db0a32014-02-04 14:21:38 +0200298 nvm_chan[ch_idx],
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100299 ch_flags,
Eran Harary749f1fe2014-03-06 09:25:30 +0200300 (ch_idx >= num_2ghz_channels) ?
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100301 "5.2" : "2.4");
302 continue;
303 }
304
305 channel = &data->channels[n_channels];
306 n_channels++;
307
Eran Harary77db0a32014-02-04 14:21:38 +0200308 channel->hw_value = nvm_chan[ch_idx];
Eran Harary749f1fe2014-03-06 09:25:30 +0200309 channel->band = (ch_idx < num_2ghz_channels) ?
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100310 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
311 channel->center_freq =
312 ieee80211_channel_to_frequency(
313 channel->hw_value, channel->band);
314
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100315 /* Initialize regulatory-based run-time data */
316
Matti Gottlieb88f2fd72013-07-09 15:25:46 +0300317 /*
318 * Default value - highest tx power value. max_power
319 * is not used in mvm, and is used for backwards compatibility
320 */
Eliad Peller22d059a2014-08-26 11:23:11 +0300321 channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100322 is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200323
324 /* don't put limitations in case we're using LAR */
325 if (!lar_supported)
326 channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx],
327 ch_idx, is_5ghz,
Matti Gottliebb281c932014-06-26 11:10:57 +0300328 ch_flags, cfg);
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200329 else
330 channel->flags = 0;
331
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100332 IWL_DEBUG_EEPROM(dev,
David Spinadel9ee6dac2013-05-29 11:37:28 +0300333 "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100334 channel->hw_value,
335 is_5ghz ? "5.2" : "2.4",
336 CHECK_AND_PRINT_I(VALID),
337 CHECK_AND_PRINT_I(IBSS),
338 CHECK_AND_PRINT_I(ACTIVE),
339 CHECK_AND_PRINT_I(RADAR),
340 CHECK_AND_PRINT_I(WIDE),
David Spinadel9ee6dac2013-05-29 11:37:28 +0300341 CHECK_AND_PRINT_I(INDOOR_ONLY),
342 CHECK_AND_PRINT_I(GO_CONCURRENT),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100343 ch_flags,
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
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200353static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
354 struct iwl_nvm_data *data,
Johannes Berg6ca89f12014-02-12 21:56:26 +0100355 struct ieee80211_sta_vht_cap *vht_cap,
356 u8 tx_chains, u8 rx_chains)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200357{
Johannes Berg6ca89f12014-02-12 21:56:26 +0100358 int num_rx_ants = num_of_ant(rx_chains);
359 int num_tx_ants = num_of_ant(tx_chains);
Eran Hararyc064ddf2014-09-30 06:42:06 +0200360 unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?:
361 IEEE80211_VHT_MAX_AMPDU_1024K);
Eyal Shapira48e6de62013-11-03 10:04:08 +0200362
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200363 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 |
Eyal Shapirae36b7662014-01-06 20:16:48 +0200368 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
Eran Hararyc064ddf2014-09-30 06:42:06 +0200369 max_ampdu_exponent <<
370 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200371
Eyal Shapiraa3576ff2014-08-09 10:57:59 +0300372 if (cfg->ht_params->ldpc)
373 vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
374
Johannes Berg6ca89f12014-02-12 21:56:26 +0100375 if (num_tx_ants > 1)
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200376 vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
Johannes Berg6ca89f12014-02-12 21:56:26 +0100377 else
378 vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200379
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200380 if (iwlwifi_mod_params.amsdu_size_8K)
381 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
382
383 vht_cap->vht_mcs.rx_mcs_map =
384 cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
385 IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
386 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
387 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
388 IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
389 IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
390 IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
391 IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
392
Johannes Berg6ca89f12014-02-12 21:56:26 +0100393 if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) {
394 vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200395 /* this works because NOT_SUPPORTED == 3 */
396 vht_cap->vht_mcs.rx_mcs_map |=
397 cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
398 }
399
400 vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
401}
402
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100403static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
Eran Harary77db0a32014-02-04 14:21:38 +0200404 struct iwl_nvm_data *data,
Eliad Peller2926f952014-10-23 16:29:10 +0300405 const __le16 *ch_section,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200406 u8 tx_chains, u8 rx_chains, bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100407{
Eran Harary77db0a32014-02-04 14:21:38 +0200408 int n_channels;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100409 int n_used = 0;
410 struct ieee80211_supported_band *sband;
411
Eran Harary77db0a32014-02-04 14:21:38 +0200412 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
413 n_channels = iwl_init_channel_map(
414 dev, cfg, data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200415 &ch_section[NVM_CHANNELS], lar_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200416 else
417 n_channels = iwl_init_channel_map(
418 dev, cfg, data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200419 &ch_section[NVM_CHANNELS_FAMILY_8000],
420 lar_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200421
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100422 sband = &data->bands[IEEE80211_BAND_2GHZ];
423 sband->band = IEEE80211_BAND_2GHZ;
424 sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
425 sband->n_bitrates = N_RATES_24;
426 n_used += iwl_init_sband_channels(data, sband, n_channels,
427 IEEE80211_BAND_2GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300428 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
429 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100430
431 sband = &data->bands[IEEE80211_BAND_5GHZ];
432 sband->band = IEEE80211_BAND_5GHZ;
433 sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
434 sband->n_bitrates = N_RATES_52;
435 n_used += iwl_init_sband_channels(data, sband, n_channels,
436 IEEE80211_BAND_5GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300437 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
438 tx_chains, rx_chains);
Eliad Peller2926f952014-10-23 16:29:10 +0300439 if (data->sku_cap_11ac_enable)
Johannes Berg6ca89f12014-02-12 21:56:26 +0100440 iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
441 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100442
443 if (n_channels != n_used)
444 IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
445 n_used, n_channels);
446}
447
Eran Harary77db0a32014-02-04 14:21:38 +0200448static int iwl_get_sku(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200449 const __le16 *nvm_sw, const __le16 *phy_sku,
450 bool is_family_8000_a_step)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100451{
Eran Harary77db0a32014-02-04 14:21:38 +0200452 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
453 return le16_to_cpup(nvm_sw + SKU);
Eran Hararyce500072014-12-01 17:53:53 +0200454
455 if (!is_family_8000_a_step)
456 return le32_to_cpup((__le32 *)(phy_sku +
457 SKU_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200458 else
459 return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
460}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100461
Eran Harary77db0a32014-02-04 14:21:38 +0200462static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
463 const __le16 *nvm_sw)
464{
465 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
466 return le16_to_cpup(nvm_sw + NVM_VERSION);
467 else
468 return le32_to_cpup((__le32 *)(nvm_sw +
469 NVM_VERSION_FAMILY_8000));
470}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100471
Eran Harary77db0a32014-02-04 14:21:38 +0200472static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200473 const __le16 *nvm_sw, const __le16 *phy_sku,
474 bool is_family_8000_a_step)
Eran Harary77db0a32014-02-04 14:21:38 +0200475{
476 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
477 return le16_to_cpup(nvm_sw + RADIO_CFG);
Eran Hararyce500072014-12-01 17:53:53 +0200478
479 if (!is_family_8000_a_step)
480 return le32_to_cpup((__le32 *)(phy_sku +
481 RADIO_CFG_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200482 else
483 return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
Eran Hararyce500072014-12-01 17:53:53 +0200484
Eran Harary77db0a32014-02-04 14:21:38 +0200485}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100486
Eran Harary77db0a32014-02-04 14:21:38 +0200487static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200488 const __le16 *nvm_sw, bool is_family_8000_a_step)
Eran Harary77db0a32014-02-04 14:21:38 +0200489{
Eran Hararyce500072014-12-01 17:53:53 +0200490 int n_hw_addr;
491
Eran Harary77db0a32014-02-04 14:21:38 +0200492 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
493 return le16_to_cpup(nvm_sw + N_HW_ADDRS);
Eran Hararyce500072014-12-01 17:53:53 +0200494
495 if (!is_family_8000_a_step)
496 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
497 N_HW_ADDRS_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200498 else
Eran Hararyce500072014-12-01 17:53:53 +0200499 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
500 N_HW_ADDRS_FAMILY_8000));
501
502 return n_hw_addr & N_HW_ADDR_MASK;
Eran Harary77db0a32014-02-04 14:21:38 +0200503}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100504
Eran Harary77db0a32014-02-04 14:21:38 +0200505static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
506 struct iwl_nvm_data *data,
507 u32 radio_cfg)
508{
509 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
510 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
511 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
512 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
513 data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200514 return;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100515 }
516
Eran Harary77db0a32014-02-04 14:21:38 +0200517 /* set the radio configuration for family 8000 */
518 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
519 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
520 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
521 data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
Moshe Harela0544272014-12-08 21:13:14 +0200522 data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg);
523 data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200524}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100525
Eran Harary77db0a32014-02-04 14:21:38 +0200526static void iwl_set_hw_address(const struct iwl_cfg *cfg,
527 struct iwl_nvm_data *data,
528 const __le16 *nvm_sec)
529{
Eran Harary9f32e012014-04-28 15:22:40 +0300530 const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100531
532 /* The byte order is little endian 16 bit, meaning 214365 */
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100533 data->hw_addr[0] = hw_addr[1];
534 data->hw_addr[1] = hw_addr[0];
535 data->hw_addr[2] = hw_addr[3];
536 data->hw_addr[3] = hw_addr[2];
537 data->hw_addr[4] = hw_addr[5];
538 data->hw_addr[5] = hw_addr[4];
Eran Harary77db0a32014-02-04 14:21:38 +0200539}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100540
Eran Harary6a68a392014-05-07 11:09:11 +0300541static void iwl_set_hw_address_family_8000(struct device *dev,
542 const struct iwl_cfg *cfg,
Eran Harary9f32e012014-04-28 15:22:40 +0300543 struct iwl_nvm_data *data,
544 const __le16 *mac_override,
545 const __le16 *nvm_hw)
546{
547 const u8 *hw_addr;
548
549 if (mac_override) {
550 hw_addr = (const u8 *)(mac_override +
551 MAC_ADDRESS_OVERRIDE_FAMILY_8000);
552
553 /* The byte order is little endian 16 bit, meaning 214365 */
554 data->hw_addr[0] = hw_addr[1];
555 data->hw_addr[1] = hw_addr[0];
556 data->hw_addr[2] = hw_addr[3];
557 data->hw_addr[3] = hw_addr[2];
558 data->hw_addr[4] = hw_addr[5];
559 data->hw_addr[5] = hw_addr[4];
560
Eran Harary6a68a392014-05-07 11:09:11 +0300561 if (is_valid_ether_addr(data->hw_addr))
Eran Harary9f32e012014-04-28 15:22:40 +0300562 return;
Eran Harary6a68a392014-05-07 11:09:11 +0300563
564 IWL_ERR_DEV(dev,
565 "mac address from nvm override section is not valid\n");
Eran Harary9f32e012014-04-28 15:22:40 +0300566 }
567
Eran Harary6a68a392014-05-07 11:09:11 +0300568 if (nvm_hw) {
Eran Harary1e0b3932014-06-11 11:37:09 +0300569 /* read the MAC address from OTP */
570 if (!dev_is_pci(dev) || (data->nvm_version < 0xE08)) {
571 /* read the mac address from the WFPM location */
572 hw_addr = (const u8 *)(nvm_hw +
573 HW_ADDR0_WFPM_FAMILY_8000);
574 data->hw_addr[0] = hw_addr[3];
575 data->hw_addr[1] = hw_addr[2];
576 data->hw_addr[2] = hw_addr[1];
577 data->hw_addr[3] = hw_addr[0];
Eran Harary9f32e012014-04-28 15:22:40 +0300578
Eran Harary1e0b3932014-06-11 11:37:09 +0300579 hw_addr = (const u8 *)(nvm_hw +
580 HW_ADDR1_WFPM_FAMILY_8000);
581 data->hw_addr[4] = hw_addr[1];
582 data->hw_addr[5] = hw_addr[0];
583 } else if ((data->nvm_version >= 0xE08) &&
584 (data->nvm_version < 0xE0B)) {
585 /* read "reverse order" from the PCIe location */
586 hw_addr = (const u8 *)(nvm_hw +
587 HW_ADDR0_PCIE_FAMILY_8000);
588 data->hw_addr[5] = hw_addr[2];
589 data->hw_addr[4] = hw_addr[1];
590 data->hw_addr[3] = hw_addr[0];
591
592 hw_addr = (const u8 *)(nvm_hw +
593 HW_ADDR1_PCIE_FAMILY_8000);
594 data->hw_addr[2] = hw_addr[3];
595 data->hw_addr[1] = hw_addr[2];
596 data->hw_addr[0] = hw_addr[1];
597 } else {
598 /* read from the PCIe location */
599 hw_addr = (const u8 *)(nvm_hw +
600 HW_ADDR0_PCIE_FAMILY_8000);
601 data->hw_addr[5] = hw_addr[0];
602 data->hw_addr[4] = hw_addr[1];
603 data->hw_addr[3] = hw_addr[2];
604
605 hw_addr = (const u8 *)(nvm_hw +
606 HW_ADDR1_PCIE_FAMILY_8000);
607 data->hw_addr[2] = hw_addr[1];
608 data->hw_addr[1] = hw_addr[2];
609 data->hw_addr[0] = hw_addr[3];
610 }
Eran Hararyca55eb42014-06-29 11:53:06 +0300611 if (!is_valid_ether_addr(data->hw_addr))
612 IWL_ERR_DEV(dev,
613 "mac address from hw section is not valid\n");
Eran Harary1e0b3932014-06-11 11:37:09 +0300614
Eran Harary6a68a392014-05-07 11:09:11 +0300615 return;
616 }
617
618 IWL_ERR_DEV(dev, "mac address is not found\n");
Eran Harary9f32e012014-04-28 15:22:40 +0300619}
620
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100621struct iwl_nvm_data *
622iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
623 const __le16 *nvm_hw, const __le16 *nvm_sw,
Eran Harary77db0a32014-02-04 14:21:38 +0200624 const __le16 *nvm_calib, const __le16 *regulatory,
Eran Hararyce500072014-12-01 17:53:53 +0200625 const __le16 *mac_override, const __le16 *phy_sku,
626 u8 tx_chains, u8 rx_chains,
627 bool lar_fw_supported, bool is_family_8000_a_step)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100628{
629 struct iwl_nvm_data *data;
Eran Harary77db0a32014-02-04 14:21:38 +0200630 u32 sku;
631 u32 radio_cfg;
Matti Gottliebd0d15192014-07-31 09:16:25 +0300632 u16 lar_config;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100633
Eran Harary77db0a32014-02-04 14:21:38 +0200634 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
635 data = kzalloc(sizeof(*data) +
636 sizeof(struct ieee80211_channel) *
637 IWL_NUM_CHANNELS,
638 GFP_KERNEL);
639 else
640 data = kzalloc(sizeof(*data) +
641 sizeof(struct ieee80211_channel) *
642 IWL_NUM_CHANNELS_FAMILY_8000,
643 GFP_KERNEL);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100644 if (!data)
645 return NULL;
646
Eran Harary77db0a32014-02-04 14:21:38 +0200647 data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100648
Eran Hararyce500072014-12-01 17:53:53 +0200649 radio_cfg =
650 iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
Eran Harary77db0a32014-02-04 14:21:38 +0200651 iwl_set_radio_cfg(cfg, data, radio_cfg);
Moshe Harela0544272014-12-08 21:13:14 +0200652 if (data->valid_tx_ant)
653 tx_chains &= data->valid_tx_ant;
654 if (data->valid_rx_ant)
655 rx_chains &= data->valid_rx_ant;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100656
Eran Hararyce500072014-12-01 17:53:53 +0200657 sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100658 data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
659 data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
660 data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
661 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
662 data->sku_cap_11n_enable = false;
Eliad Peller2926f952014-10-23 16:29:10 +0300663 data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
664 (sku & NVM_SKU_CAP_11AC_ENABLE);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100665
Eran Hararyce500072014-12-01 17:53:53 +0200666 data->n_hw_addrs =
667 iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100668
Eran Harary77db0a32014-02-04 14:21:38 +0200669 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
670 /* Checking for required sections */
671 if (!nvm_calib) {
672 IWL_ERR_DEV(dev,
673 "Can't parse empty Calib NVM sections\n");
Eytan Lifshitz1270c412014-02-18 15:02:29 +0200674 kfree(data);
Eran Harary77db0a32014-02-04 14:21:38 +0200675 return NULL;
676 }
677 /* in family 8000 Xtal calibration values moved to OTP */
678 data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
679 data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
680 }
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100681
Eran Harary77db0a32014-02-04 14:21:38 +0200682 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
683 iwl_set_hw_address(cfg, data, nvm_hw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100684
Eran Harary77db0a32014-02-04 14:21:38 +0200685 iwl_init_sbands(dev, cfg, data, nvm_sw,
Eliad Peller2926f952014-10-23 16:29:10 +0300686 tx_chains, rx_chains, lar_fw_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200687 } else {
Matti Gottliebd0d15192014-07-31 09:16:25 +0300688 lar_config = le16_to_cpup(regulatory +
689 NVM_LAR_OFFSET_FAMILY_8000);
690 data->lar_enabled = !!(lar_config &
691 NVM_LAR_ENABLED_FAMILY_8000);
692
Eran Harary77db0a32014-02-04 14:21:38 +0200693 /* MAC address in family 8000 */
Eran Harary6a68a392014-05-07 11:09:11 +0300694 iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
695 nvm_hw);
Eran Harary77db0a32014-02-04 14:21:38 +0200696
697 iwl_init_sbands(dev, cfg, data, regulatory,
Eliad Peller2926f952014-10-23 16:29:10 +0300698 tx_chains, rx_chains,
699 lar_fw_supported && data->lar_enabled);
Eran Harary77db0a32014-02-04 14:21:38 +0200700 }
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100701
Emmanuel Grumbach33b2f682014-01-14 13:48:22 +0200702 data->calib_version = 255;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100703
704 return data;
705}
Johannes Berg48e29342013-03-01 00:13:33 +0100706IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200707
708static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
Matti Gottliebb281c932014-06-26 11:10:57 +0300709 int ch_idx, u16 nvm_flags,
710 const struct iwl_cfg *cfg)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200711{
712 u32 flags = NL80211_RRF_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300713 u32 last_5ghz_ht = LAST_5GHZ_HT;
714
715 if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
716 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200717
718 if (ch_idx < NUM_2GHZ_CHANNELS &&
719 (nvm_flags & NVM_CHANNEL_40MHZ)) {
720 if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
721 flags &= ~NL80211_RRF_NO_HT40PLUS;
722 if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
723 flags &= ~NL80211_RRF_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300724 } else if (nvm_chan[ch_idx] <= last_5ghz_ht &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200725 (nvm_flags & NVM_CHANNEL_40MHZ)) {
726 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
727 flags &= ~NL80211_RRF_NO_HT40PLUS;
728 else
729 flags &= ~NL80211_RRF_NO_HT40MINUS;
730 }
731
732 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
733 flags |= NL80211_RRF_NO_80MHZ;
734 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
735 flags |= NL80211_RRF_NO_160MHZ;
736
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200737 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
738 flags |= NL80211_RRF_NO_IR;
739
740 if (nvm_flags & NVM_CHANNEL_RADAR)
741 flags |= NL80211_RRF_DFS;
742
743 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
744 flags |= NL80211_RRF_NO_OUTDOOR;
745
746 /* Set the GO concurrent flag only in case that NO_IR is set.
747 * Otherwise it is meaningless
748 */
749 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
750 (flags & NL80211_RRF_NO_IR))
751 flags |= NL80211_RRF_GO_CONCURRENT;
752
753 return flags;
754}
755
756struct ieee80211_regdomain *
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300757iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
758 int num_of_ch, __le32 *channels, u16 fw_mcc)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200759{
760 int ch_idx;
761 u16 ch_flags, prev_ch_flags = 0;
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300762 const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
763 iwl_nvm_channels_family_8000 : iwl_nvm_channels;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200764 struct ieee80211_regdomain *regd;
765 int size_of_regd;
766 struct ieee80211_reg_rule *rule;
767 enum ieee80211_band band;
768 int center_freq, prev_center_freq = 0;
769 int valid_rules = 0;
770 bool new_rule;
771
772 if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
773 return ERR_PTR(-EINVAL);
774
775 IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
776 num_of_ch);
777
778 /* build a regdomain rule for every valid channel */
779 size_of_regd =
780 sizeof(struct ieee80211_regdomain) +
781 num_of_ch * sizeof(struct ieee80211_reg_rule);
782
783 regd = kzalloc(size_of_regd, GFP_KERNEL);
784 if (!regd)
785 return ERR_PTR(-ENOMEM);
786
787 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
788 ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
789 band = (ch_idx < NUM_2GHZ_CHANNELS) ?
790 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
791 center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
792 band);
793 new_rule = false;
794
795 if (!(ch_flags & NVM_CHANNEL_VALID)) {
796 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
797 "Ch. %d Flags %x [%sGHz] - No traffic\n",
798 nvm_chan[ch_idx],
799 ch_flags,
800 (ch_idx >= NUM_2GHZ_CHANNELS) ?
801 "5.2" : "2.4");
802 continue;
803 }
804
805 /* we can't continue the same rule */
806 if (ch_idx == 0 || prev_ch_flags != ch_flags ||
807 center_freq - prev_center_freq > 20) {
808 valid_rules++;
809 new_rule = true;
810 }
811
812 rule = &regd->reg_rules[valid_rules - 1];
813
814 if (new_rule)
815 rule->freq_range.start_freq_khz =
816 MHZ_TO_KHZ(center_freq - 10);
817
818 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
819
820 /* this doesn't matter - not used by FW */
821 rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
Eliad Peller02a50492014-09-07 17:45:11 +0300822 rule->power_rule.max_eirp =
823 DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200824
825 rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
Matti Gottliebb281c932014-06-26 11:10:57 +0300826 ch_flags, cfg);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200827
828 /* rely on auto-calculation to merge BW of contiguous chans */
829 rule->flags |= NL80211_RRF_AUTO_BW;
830 rule->freq_range.max_bandwidth_khz = 0;
831
832 prev_ch_flags = ch_flags;
833 prev_center_freq = center_freq;
834
835 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
Arik Nemtsovbdf2fae2014-10-30 15:12:39 +0200836 "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n",
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200837 center_freq,
838 band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
839 CHECK_AND_PRINT_I(VALID),
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200840 CHECK_AND_PRINT_I(ACTIVE),
841 CHECK_AND_PRINT_I(RADAR),
842 CHECK_AND_PRINT_I(WIDE),
843 CHECK_AND_PRINT_I(40MHZ),
844 CHECK_AND_PRINT_I(80MHZ),
845 CHECK_AND_PRINT_I(160MHZ),
846 CHECK_AND_PRINT_I(INDOOR_ONLY),
847 CHECK_AND_PRINT_I(GO_CONCURRENT),
848 ch_flags,
Arik Nemtsovbdf2fae2014-10-30 15:12:39 +0200849 ((ch_flags & NVM_CHANNEL_ACTIVE) &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200850 !(ch_flags & NVM_CHANNEL_RADAR))
851 ? "" : "not ");
852 }
853
854 regd->n_reg_rules = valid_rules;
855
856 /* set alpha2 from FW. */
857 regd->alpha2[0] = fw_mcc >> 8;
858 regd->alpha2[1] = fw_mcc & 0xff;
859
860 return regd;
861}
862IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);