blob: b372105604a06e8d58beaa2a6a34bf795eee1e5d [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,
Arik Nemtsovf5528632015-02-04 15:38:56 +0200113 NVM_LAR_OFFSET_FAMILY_8000_OLD = 0x4C7,
114 NVM_LAR_OFFSET_FAMILY_8000 = 0x507,
Matti Gottliebd0d15192014-07-31 09:16:25 +0300115 NVM_LAR_ENABLED_FAMILY_8000 = 0x7,
Eran Harary77db0a32014-02-04 14:21:38 +0200116
117 /* NVM calibration section offset (in words) definitions */
118 NVM_CALIB_SECTION_FAMILY_8000 = 0x2B8,
119 XTAL_CALIB_FAMILY_8000 = 0x316 - NVM_CALIB_SECTION_FAMILY_8000
120};
121
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100122/* SKU Capabilities (actual values from NVM definition) */
123enum nvm_sku_bits {
124 NVM_SKU_CAP_BAND_24GHZ = BIT(0),
125 NVM_SKU_CAP_BAND_52GHZ = BIT(1),
126 NVM_SKU_CAP_11N_ENABLE = BIT(2),
Johannes Bergbfc824b2013-05-06 16:06:51 +0200127 NVM_SKU_CAP_11AC_ENABLE = BIT(3),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100128};
129
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100130/*
131 * These are the channel numbers in the order that they are stored in the NVM
132 */
133static const u8 iwl_nvm_channels[] = {
134 /* 2.4 GHz */
135 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
136 /* 5 GHz */
137 36, 40, 44 , 48, 52, 56, 60, 64,
138 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
139 149, 153, 157, 161, 165
140};
141
Eran Harary77db0a32014-02-04 14:21:38 +0200142static const u8 iwl_nvm_channels_family_8000[] = {
143 /* 2.4 GHz */
Eran Harary9b1c9a62014-05-07 08:22:41 +0300144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
Eran Harary77db0a32014-02-04 14:21:38 +0200145 /* 5 GHz */
146 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92,
147 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
148 149, 153, 157, 161, 165, 169, 173, 177, 181
149};
150
Eran Harary749f1fe2014-03-06 09:25:30 +0200151#define IWL_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels)
Eran Harary77db0a32014-02-04 14:21:38 +0200152#define IWL_NUM_CHANNELS_FAMILY_8000 ARRAY_SIZE(iwl_nvm_channels_family_8000)
Eran Harary749f1fe2014-03-06 09:25:30 +0200153#define NUM_2GHZ_CHANNELS 14
Eran Harary9b1c9a62014-05-07 08:22:41 +0300154#define NUM_2GHZ_CHANNELS_FAMILY_8000 14
Eran Harary749f1fe2014-03-06 09:25:30 +0200155#define FIRST_2GHZ_HT_MINUS 5
156#define LAST_2GHZ_HT_PLUS 9
Matti Gottliebb281c932014-06-26 11:10:57 +0300157#define LAST_5GHZ_HT 165
158#define LAST_5GHZ_HT_FAMILY_8000 181
Eran Hararyce500072014-12-01 17:53:53 +0200159#define N_HW_ADDR_MASK 0xF
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100160
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100161/* rate data (static) */
162static struct ieee80211_rate iwl_cfg80211_rates[] = {
163 { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, },
164 { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1,
165 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
166 { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2,
167 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
168 { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3,
169 .flags = IEEE80211_RATE_SHORT_PREAMBLE, },
170 { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, },
171 { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, },
172 { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, },
173 { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, },
174 { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, },
175 { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, },
176 { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, },
177 { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, },
178};
179#define RATES_24_OFFS 0
180#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates)
181#define RATES_52_OFFS 4
182#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS)
183
184/**
185 * enum iwl_nvm_channel_flags - channel flags in NVM
186 * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo
187 * @NVM_CHANNEL_IBSS: usable as an IBSS channel
188 * @NVM_CHANNEL_ACTIVE: active scanning allowed
189 * @NVM_CHANNEL_RADAR: radar detection required
David Spinadel9ee6dac2013-05-29 11:37:28 +0300190 * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed
191 * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS
192 * on same channel on 2.4 or same UNII band on 5.2
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100193 * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
194 * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200195 * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
196 * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100197 */
198enum iwl_nvm_channel_flags {
199 NVM_CHANNEL_VALID = BIT(0),
200 NVM_CHANNEL_IBSS = BIT(1),
201 NVM_CHANNEL_ACTIVE = BIT(3),
202 NVM_CHANNEL_RADAR = BIT(4),
David Spinadel9ee6dac2013-05-29 11:37:28 +0300203 NVM_CHANNEL_INDOOR_ONLY = BIT(5),
204 NVM_CHANNEL_GO_CONCURRENT = BIT(6),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100205 NVM_CHANNEL_WIDE = BIT(8),
206 NVM_CHANNEL_40MHZ = BIT(9),
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200207 NVM_CHANNEL_80MHZ = BIT(10),
208 NVM_CHANNEL_160MHZ = BIT(11),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100209};
210
211#define CHECK_AND_PRINT_I(x) \
212 ((ch_flags & NVM_CHANNEL_##x) ? # x " " : "")
213
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200214static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz,
Matti Gottliebb281c932014-06-26 11:10:57 +0300215 u16 nvm_flags, const struct iwl_cfg *cfg)
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200216{
217 u32 flags = IEEE80211_CHAN_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300218 u32 last_5ghz_ht = LAST_5GHZ_HT;
219
220 if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
221 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200222
223 if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) {
224 if (ch_num <= LAST_2GHZ_HT_PLUS)
225 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
226 if (ch_num >= FIRST_2GHZ_HT_MINUS)
227 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300228 } else if (ch_num <= last_5ghz_ht && (nvm_flags & NVM_CHANNEL_40MHZ)) {
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200229 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
230 flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
231 else
232 flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
233 }
234 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
235 flags |= IEEE80211_CHAN_NO_80MHZ;
236 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
237 flags |= IEEE80211_CHAN_NO_160MHZ;
238
239 if (!(nvm_flags & NVM_CHANNEL_IBSS))
240 flags |= IEEE80211_CHAN_NO_IR;
241
242 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
243 flags |= IEEE80211_CHAN_NO_IR;
244
245 if (nvm_flags & NVM_CHANNEL_RADAR)
246 flags |= IEEE80211_CHAN_RADAR;
247
248 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
249 flags |= IEEE80211_CHAN_INDOOR_ONLY;
250
251 /* Set the GO concurrent flag only in case that NO_IR is set.
252 * Otherwise it is meaningless
253 */
254 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
255 (flags & IEEE80211_CHAN_NO_IR))
256 flags |= IEEE80211_CHAN_GO_CONCURRENT;
257
258 return flags;
259}
260
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100261static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
262 struct iwl_nvm_data *data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200263 const __le16 * const nvm_ch_flags,
264 bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100265{
266 int ch_idx;
267 int n_channels = 0;
268 struct ieee80211_channel *channel;
269 u16 ch_flags;
270 bool is_5ghz;
Eran Harary749f1fe2014-03-06 09:25:30 +0200271 int num_of_ch, num_2ghz_channels;
Eran Harary77db0a32014-02-04 14:21:38 +0200272 const u8 *nvm_chan;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100273
Eran Harary77db0a32014-02-04 14:21:38 +0200274 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
275 num_of_ch = IWL_NUM_CHANNELS;
276 nvm_chan = &iwl_nvm_channels[0];
Eran Harary749f1fe2014-03-06 09:25:30 +0200277 num_2ghz_channels = NUM_2GHZ_CHANNELS;
Eran Harary77db0a32014-02-04 14:21:38 +0200278 } else {
279 num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
280 nvm_chan = &iwl_nvm_channels_family_8000[0];
Eran Harary749f1fe2014-03-06 09:25:30 +0200281 num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
Eran Harary77db0a32014-02-04 14:21:38 +0200282 }
283
284 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100285 ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200286
Eran Harary749f1fe2014-03-06 09:25:30 +0200287 if (ch_idx >= num_2ghz_channels &&
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200288 !data->sku_cap_band_52GHz_enable)
Eliad Pellera76f3bf2014-05-26 18:11:37 +0300289 continue;
Emmanuel Grumbachc5128652013-12-05 22:42:55 +0200290
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 Bergb1e1adf2013-01-24 14:14:22 +0100311 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
312 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 Bergb1e1adf2013-01-24 14:14:22 +0100323 is_5ghz = channel->band == IEEE80211_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,
David Spinadel9ee6dac2013-05-29 11:37:28 +0300334 "Ch. %d [%sGHz] %s%s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100335 channel->hw_value,
336 is_5ghz ? "5.2" : "2.4",
337 CHECK_AND_PRINT_I(VALID),
338 CHECK_AND_PRINT_I(IBSS),
339 CHECK_AND_PRINT_I(ACTIVE),
340 CHECK_AND_PRINT_I(RADAR),
341 CHECK_AND_PRINT_I(WIDE),
David Spinadel9ee6dac2013-05-29 11:37:28 +0300342 CHECK_AND_PRINT_I(INDOOR_ONLY),
343 CHECK_AND_PRINT_I(GO_CONCURRENT),
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100344 ch_flags,
345 channel->max_power,
346 ((ch_flags & NVM_CHANNEL_IBSS) &&
347 !(ch_flags & NVM_CHANNEL_RADAR))
348 ? "" : "not ");
349 }
350
351 return n_channels;
352}
353
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200354static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
355 struct iwl_nvm_data *data,
Johannes Berg6ca89f12014-02-12 21:56:26 +0100356 struct ieee80211_sta_vht_cap *vht_cap,
357 u8 tx_chains, u8 rx_chains)
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200358{
Johannes Berg6ca89f12014-02-12 21:56:26 +0100359 int num_rx_ants = num_of_ant(rx_chains);
360 int num_tx_ants = num_of_ant(tx_chains);
Eran Hararyc064ddf2014-09-30 06:42:06 +0200361 unsigned int max_ampdu_exponent = (cfg->max_vht_ampdu_exponent ?:
362 IEEE80211_VHT_MAX_AMPDU_1024K);
Eyal Shapira48e6de62013-11-03 10:04:08 +0200363
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200364 vht_cap->vht_supported = true;
365
366 vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
367 IEEE80211_VHT_CAP_RXSTBC_1 |
368 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
Eyal Shapirae36b7662014-01-06 20:16:48 +0200369 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
Eran Hararyc064ddf2014-09-30 06:42:06 +0200370 max_ampdu_exponent <<
371 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200372
Eyal Shapiraa3576ff2014-08-09 10:57:59 +0300373 if (cfg->ht_params->ldpc)
374 vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
375
Johannes Berg6ca89f12014-02-12 21:56:26 +0100376 if (num_tx_ants > 1)
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200377 vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
Johannes Berg6ca89f12014-02-12 21:56:26 +0100378 else
379 vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
Eyal Shapira5f7a6f92013-11-12 22:40:40 +0200380
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200381 if (iwlwifi_mod_params.amsdu_size_8K)
382 vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
383
384 vht_cap->vht_mcs.rx_mcs_map =
385 cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
386 IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
387 IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
388 IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
389 IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
390 IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
391 IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
392 IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
393
Johannes Berg6ca89f12014-02-12 21:56:26 +0100394 if (num_rx_ants == 1 || cfg->rx_with_siso_diversity) {
395 vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
Eytan Lifshitz33158fe2013-02-20 11:01:13 +0200396 /* this works because NOT_SUPPORTED == 3 */
397 vht_cap->vht_mcs.rx_mcs_map |=
398 cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
399 }
400
401 vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
402}
403
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100404static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
Eran Harary77db0a32014-02-04 14:21:38 +0200405 struct iwl_nvm_data *data,
Eliad Peller2926f952014-10-23 16:29:10 +0300406 const __le16 *ch_section,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200407 u8 tx_chains, u8 rx_chains, bool lar_supported)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100408{
Eran Harary77db0a32014-02-04 14:21:38 +0200409 int n_channels;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100410 int n_used = 0;
411 struct ieee80211_supported_band *sband;
412
Eran Harary77db0a32014-02-04 14:21:38 +0200413 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
414 n_channels = iwl_init_channel_map(
415 dev, cfg, data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200416 &ch_section[NVM_CHANNELS], lar_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200417 else
418 n_channels = iwl_init_channel_map(
419 dev, cfg, data,
Arik Nemtsov770ceda2014-03-23 16:18:40 +0200420 &ch_section[NVM_CHANNELS_FAMILY_8000],
421 lar_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200422
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100423 sband = &data->bands[IEEE80211_BAND_2GHZ];
424 sband->band = IEEE80211_BAND_2GHZ;
425 sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS];
426 sband->n_bitrates = N_RATES_24;
427 n_used += iwl_init_sband_channels(data, sband, n_channels,
428 IEEE80211_BAND_2GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300429 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_2GHZ,
430 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100431
432 sband = &data->bands[IEEE80211_BAND_5GHZ];
433 sband->band = IEEE80211_BAND_5GHZ;
434 sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS];
435 sband->n_bitrates = N_RATES_52;
436 n_used += iwl_init_sband_channels(data, sband, n_channels,
437 IEEE80211_BAND_5GHZ);
Emmanuel Grumbach9ce4fa72013-05-22 13:16:23 +0300438 iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
439 tx_chains, rx_chains);
Eliad Peller2926f952014-10-23 16:29:10 +0300440 if (data->sku_cap_11ac_enable)
Johannes Berg6ca89f12014-02-12 21:56:26 +0100441 iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
442 tx_chains, rx_chains);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100443
444 if (n_channels != n_used)
445 IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
446 n_used, n_channels);
447}
448
Eran Harary77db0a32014-02-04 14:21:38 +0200449static int iwl_get_sku(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200450 const __le16 *nvm_sw, const __le16 *phy_sku,
451 bool is_family_8000_a_step)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100452{
Eran Harary77db0a32014-02-04 14:21:38 +0200453 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
454 return le16_to_cpup(nvm_sw + SKU);
Eran Hararyce500072014-12-01 17:53:53 +0200455
456 if (!is_family_8000_a_step)
457 return le32_to_cpup((__le32 *)(phy_sku +
458 SKU_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200459 else
460 return le32_to_cpup((__le32 *)(nvm_sw + SKU_FAMILY_8000));
461}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100462
Eran Harary77db0a32014-02-04 14:21:38 +0200463static int iwl_get_nvm_version(const struct iwl_cfg *cfg,
464 const __le16 *nvm_sw)
465{
466 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
467 return le16_to_cpup(nvm_sw + NVM_VERSION);
468 else
469 return le32_to_cpup((__le32 *)(nvm_sw +
470 NVM_VERSION_FAMILY_8000));
471}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100472
Eran Harary77db0a32014-02-04 14:21:38 +0200473static int iwl_get_radio_cfg(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200474 const __le16 *nvm_sw, const __le16 *phy_sku,
475 bool is_family_8000_a_step)
Eran Harary77db0a32014-02-04 14:21:38 +0200476{
477 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
478 return le16_to_cpup(nvm_sw + RADIO_CFG);
Eran Hararyce500072014-12-01 17:53:53 +0200479
480 if (!is_family_8000_a_step)
481 return le32_to_cpup((__le32 *)(phy_sku +
482 RADIO_CFG_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200483 else
484 return le32_to_cpup((__le32 *)(nvm_sw + RADIO_CFG_FAMILY_8000));
Eran Hararyce500072014-12-01 17:53:53 +0200485
Eran Harary77db0a32014-02-04 14:21:38 +0200486}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100487
Eran Harary77db0a32014-02-04 14:21:38 +0200488static int iwl_get_n_hw_addrs(const struct iwl_cfg *cfg,
Eran Hararyce500072014-12-01 17:53:53 +0200489 const __le16 *nvm_sw, bool is_family_8000_a_step)
Eran Harary77db0a32014-02-04 14:21:38 +0200490{
Eran Hararyce500072014-12-01 17:53:53 +0200491 int n_hw_addr;
492
Eran Harary77db0a32014-02-04 14:21:38 +0200493 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
494 return le16_to_cpup(nvm_sw + N_HW_ADDRS);
Eran Hararyce500072014-12-01 17:53:53 +0200495
496 if (!is_family_8000_a_step)
497 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
498 N_HW_ADDRS_FAMILY_8000_B0));
Eran Harary77db0a32014-02-04 14:21:38 +0200499 else
Eran Hararyce500072014-12-01 17:53:53 +0200500 n_hw_addr = le32_to_cpup((__le32 *)(nvm_sw +
501 N_HW_ADDRS_FAMILY_8000));
502
503 return n_hw_addr & N_HW_ADDR_MASK;
Eran Harary77db0a32014-02-04 14:21:38 +0200504}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100505
Eran Harary77db0a32014-02-04 14:21:38 +0200506static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
507 struct iwl_nvm_data *data,
508 u32 radio_cfg)
509{
510 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
511 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK(radio_cfg);
512 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK(radio_cfg);
513 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK(radio_cfg);
514 data->radio_cfg_pnum = NVM_RF_CFG_PNUM_MSK(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200515 return;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100516 }
517
Eran Harary77db0a32014-02-04 14:21:38 +0200518 /* set the radio configuration for family 8000 */
519 data->radio_cfg_type = NVM_RF_CFG_TYPE_MSK_FAMILY_8000(radio_cfg);
520 data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
521 data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
522 data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
Moshe Harela0544272014-12-08 21:13:14 +0200523 data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg);
524 data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
Eran Harary77db0a32014-02-04 14:21:38 +0200525}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100526
Eran Harary77db0a32014-02-04 14:21:38 +0200527static void iwl_set_hw_address(const struct iwl_cfg *cfg,
528 struct iwl_nvm_data *data,
529 const __le16 *nvm_sec)
530{
Eran Harary9f32e012014-04-28 15:22:40 +0300531 const u8 *hw_addr = (const u8 *)(nvm_sec + HW_ADDR);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100532
533 /* The byte order is little endian 16 bit, meaning 214365 */
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100534 data->hw_addr[0] = hw_addr[1];
535 data->hw_addr[1] = hw_addr[0];
536 data->hw_addr[2] = hw_addr[3];
537 data->hw_addr[3] = hw_addr[2];
538 data->hw_addr[4] = hw_addr[5];
539 data->hw_addr[5] = hw_addr[4];
Eran Harary77db0a32014-02-04 14:21:38 +0200540}
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100541
Eran Harary6a68a392014-05-07 11:09:11 +0300542static void iwl_set_hw_address_family_8000(struct device *dev,
543 const struct iwl_cfg *cfg,
Eran Harary9f32e012014-04-28 15:22:40 +0300544 struct iwl_nvm_data *data,
545 const __le16 *mac_override,
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200546 const __le16 *nvm_hw,
547 u32 mac_addr0, u32 mac_addr1)
Eran Harary9f32e012014-04-28 15:22:40 +0300548{
549 const u8 *hw_addr;
550
551 if (mac_override) {
552 hw_addr = (const u8 *)(mac_override +
553 MAC_ADDRESS_OVERRIDE_FAMILY_8000);
554
555 /* The byte order is little endian 16 bit, meaning 214365 */
556 data->hw_addr[0] = hw_addr[1];
557 data->hw_addr[1] = hw_addr[0];
558 data->hw_addr[2] = hw_addr[3];
559 data->hw_addr[3] = hw_addr[2];
560 data->hw_addr[4] = hw_addr[5];
561 data->hw_addr[5] = hw_addr[4];
562
Eran Harary6a68a392014-05-07 11:09:11 +0300563 if (is_valid_ether_addr(data->hw_addr))
Eran Harary9f32e012014-04-28 15:22:40 +0300564 return;
Eran Harary6a68a392014-05-07 11:09:11 +0300565
566 IWL_ERR_DEV(dev,
567 "mac address from nvm override section is not valid\n");
Eran Harary9f32e012014-04-28 15:22:40 +0300568 }
569
Eran Harary6a68a392014-05-07 11:09:11 +0300570 if (nvm_hw) {
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200571 /* read the MAC address from HW resisters */
572 hw_addr = (const u8 *)&mac_addr0;
573 data->hw_addr[0] = hw_addr[3];
574 data->hw_addr[1] = hw_addr[2];
575 data->hw_addr[2] = hw_addr[1];
576 data->hw_addr[3] = hw_addr[0];
Eran Harary9f32e012014-04-28 15:22:40 +0300577
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200578 hw_addr = (const u8 *)&mac_addr1;
579 data->hw_addr[4] = hw_addr[1];
580 data->hw_addr[5] = hw_addr[0];
Eran Harary1e0b3932014-06-11 11:37:09 +0300581
Eran Hararyca55eb42014-06-29 11:53:06 +0300582 if (!is_valid_ether_addr(data->hw_addr))
583 IWL_ERR_DEV(dev,
584 "mac address from hw section is not valid\n");
Eran Harary1e0b3932014-06-11 11:37:09 +0300585
Eran Harary6a68a392014-05-07 11:09:11 +0300586 return;
587 }
588
589 IWL_ERR_DEV(dev, "mac address is not found\n");
Eran Harary9f32e012014-04-28 15:22:40 +0300590}
591
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100592struct iwl_nvm_data *
593iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
594 const __le16 *nvm_hw, const __le16 *nvm_sw,
Eran Harary77db0a32014-02-04 14:21:38 +0200595 const __le16 *nvm_calib, const __le16 *regulatory,
Eran Hararyce500072014-12-01 17:53:53 +0200596 const __le16 *mac_override, const __le16 *phy_sku,
597 u8 tx_chains, u8 rx_chains,
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200598 bool lar_fw_supported, bool is_family_8000_a_step,
599 u32 mac_addr0, u32 mac_addr1)
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100600{
601 struct iwl_nvm_data *data;
Eran Harary77db0a32014-02-04 14:21:38 +0200602 u32 sku;
603 u32 radio_cfg;
Matti Gottliebd0d15192014-07-31 09:16:25 +0300604 u16 lar_config;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100605
Eran Harary77db0a32014-02-04 14:21:38 +0200606 if (cfg->device_family != IWL_DEVICE_FAMILY_8000)
607 data = kzalloc(sizeof(*data) +
608 sizeof(struct ieee80211_channel) *
609 IWL_NUM_CHANNELS,
610 GFP_KERNEL);
611 else
612 data = kzalloc(sizeof(*data) +
613 sizeof(struct ieee80211_channel) *
614 IWL_NUM_CHANNELS_FAMILY_8000,
615 GFP_KERNEL);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100616 if (!data)
617 return NULL;
618
Eran Harary77db0a32014-02-04 14:21:38 +0200619 data->nvm_version = iwl_get_nvm_version(cfg, nvm_sw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100620
Eran Hararyce500072014-12-01 17:53:53 +0200621 radio_cfg =
622 iwl_get_radio_cfg(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
Eran Harary77db0a32014-02-04 14:21:38 +0200623 iwl_set_radio_cfg(cfg, data, radio_cfg);
Moshe Harela0544272014-12-08 21:13:14 +0200624 if (data->valid_tx_ant)
625 tx_chains &= data->valid_tx_ant;
626 if (data->valid_rx_ant)
627 rx_chains &= data->valid_rx_ant;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100628
Eran Hararyce500072014-12-01 17:53:53 +0200629 sku = iwl_get_sku(cfg, nvm_sw, phy_sku, is_family_8000_a_step);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100630 data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
631 data->sku_cap_band_52GHz_enable = sku & NVM_SKU_CAP_BAND_52GHZ;
632 data->sku_cap_11n_enable = sku & NVM_SKU_CAP_11N_ENABLE;
633 if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
634 data->sku_cap_11n_enable = false;
Eliad Peller2926f952014-10-23 16:29:10 +0300635 data->sku_cap_11ac_enable = data->sku_cap_11n_enable &&
636 (sku & NVM_SKU_CAP_11AC_ENABLE);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100637
Eran Hararyce500072014-12-01 17:53:53 +0200638 data->n_hw_addrs =
639 iwl_get_n_hw_addrs(cfg, nvm_sw, is_family_8000_a_step);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100640
Eran Harary77db0a32014-02-04 14:21:38 +0200641 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
642 /* Checking for required sections */
643 if (!nvm_calib) {
644 IWL_ERR_DEV(dev,
645 "Can't parse empty Calib NVM sections\n");
Eytan Lifshitz1270c412014-02-18 15:02:29 +0200646 kfree(data);
Eran Harary77db0a32014-02-04 14:21:38 +0200647 return NULL;
648 }
649 /* in family 8000 Xtal calibration values moved to OTP */
650 data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB);
651 data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1);
652 }
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100653
Eran Harary77db0a32014-02-04 14:21:38 +0200654 if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
655 iwl_set_hw_address(cfg, data, nvm_hw);
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100656
Eran Harary77db0a32014-02-04 14:21:38 +0200657 iwl_init_sbands(dev, cfg, data, nvm_sw,
Eliad Peller2926f952014-10-23 16:29:10 +0300658 tx_chains, rx_chains, lar_fw_supported);
Eran Harary77db0a32014-02-04 14:21:38 +0200659 } else {
Arik Nemtsovf5528632015-02-04 15:38:56 +0200660 u16 lar_offset = data->nvm_version < 0xE39 ?
661 NVM_LAR_OFFSET_FAMILY_8000_OLD :
662 NVM_LAR_OFFSET_FAMILY_8000;
663
664 lar_config = le16_to_cpup(regulatory + lar_offset);
Matti Gottliebd0d15192014-07-31 09:16:25 +0300665 data->lar_enabled = !!(lar_config &
666 NVM_LAR_ENABLED_FAMILY_8000);
667
Eran Harary77db0a32014-02-04 14:21:38 +0200668 /* MAC address in family 8000 */
Eran Harary6a68a392014-05-07 11:09:11 +0300669 iwl_set_hw_address_family_8000(dev, cfg, data, mac_override,
Eran Harary8ba2d7a2015-02-08 11:41:43 +0200670 nvm_hw, mac_addr0, mac_addr1);
Eran Harary77db0a32014-02-04 14:21:38 +0200671
672 iwl_init_sbands(dev, cfg, data, regulatory,
Eliad Peller2926f952014-10-23 16:29:10 +0300673 tx_chains, rx_chains,
674 lar_fw_supported && data->lar_enabled);
Eran Harary77db0a32014-02-04 14:21:38 +0200675 }
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100676
Emmanuel Grumbach33b2f682014-01-14 13:48:22 +0200677 data->calib_version = 255;
Johannes Bergb1e1adf2013-01-24 14:14:22 +0100678
679 return data;
680}
Johannes Berg48e29342013-03-01 00:13:33 +0100681IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200682
683static u32 iwl_nvm_get_regdom_bw_flags(const u8 *nvm_chan,
Matti Gottliebb281c932014-06-26 11:10:57 +0300684 int ch_idx, u16 nvm_flags,
685 const struct iwl_cfg *cfg)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200686{
687 u32 flags = NL80211_RRF_NO_HT40;
Matti Gottliebb281c932014-06-26 11:10:57 +0300688 u32 last_5ghz_ht = LAST_5GHZ_HT;
689
690 if (cfg->device_family == IWL_DEVICE_FAMILY_8000)
691 last_5ghz_ht = LAST_5GHZ_HT_FAMILY_8000;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200692
693 if (ch_idx < NUM_2GHZ_CHANNELS &&
694 (nvm_flags & NVM_CHANNEL_40MHZ)) {
695 if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
696 flags &= ~NL80211_RRF_NO_HT40PLUS;
697 if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
698 flags &= ~NL80211_RRF_NO_HT40MINUS;
Matti Gottliebb281c932014-06-26 11:10:57 +0300699 } else if (nvm_chan[ch_idx] <= last_5ghz_ht &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200700 (nvm_flags & NVM_CHANNEL_40MHZ)) {
701 if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
702 flags &= ~NL80211_RRF_NO_HT40PLUS;
703 else
704 flags &= ~NL80211_RRF_NO_HT40MINUS;
705 }
706
707 if (!(nvm_flags & NVM_CHANNEL_80MHZ))
708 flags |= NL80211_RRF_NO_80MHZ;
709 if (!(nvm_flags & NVM_CHANNEL_160MHZ))
710 flags |= NL80211_RRF_NO_160MHZ;
711
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200712 if (!(nvm_flags & NVM_CHANNEL_ACTIVE))
713 flags |= NL80211_RRF_NO_IR;
714
715 if (nvm_flags & NVM_CHANNEL_RADAR)
716 flags |= NL80211_RRF_DFS;
717
718 if (nvm_flags & NVM_CHANNEL_INDOOR_ONLY)
719 flags |= NL80211_RRF_NO_OUTDOOR;
720
721 /* Set the GO concurrent flag only in case that NO_IR is set.
722 * Otherwise it is meaningless
723 */
724 if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
725 (flags & NL80211_RRF_NO_IR))
726 flags |= NL80211_RRF_GO_CONCURRENT;
727
728 return flags;
729}
730
731struct ieee80211_regdomain *
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300732iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
733 int num_of_ch, __le32 *channels, u16 fw_mcc)
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200734{
735 int ch_idx;
736 u16 ch_flags, prev_ch_flags = 0;
Arik Nemtsov162ee3c2014-06-10 11:25:35 +0300737 const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
738 iwl_nvm_channels_family_8000 : iwl_nvm_channels;
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200739 struct ieee80211_regdomain *regd;
740 int size_of_regd;
741 struct ieee80211_reg_rule *rule;
742 enum ieee80211_band band;
743 int center_freq, prev_center_freq = 0;
744 int valid_rules = 0;
745 bool new_rule;
746
747 if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
748 return ERR_PTR(-EINVAL);
749
750 IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
751 num_of_ch);
752
753 /* build a regdomain rule for every valid channel */
754 size_of_regd =
755 sizeof(struct ieee80211_regdomain) +
756 num_of_ch * sizeof(struct ieee80211_reg_rule);
757
758 regd = kzalloc(size_of_regd, GFP_KERNEL);
759 if (!regd)
760 return ERR_PTR(-ENOMEM);
761
762 for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
763 ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
764 band = (ch_idx < NUM_2GHZ_CHANNELS) ?
765 IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
766 center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
767 band);
768 new_rule = false;
769
770 if (!(ch_flags & NVM_CHANNEL_VALID)) {
771 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
772 "Ch. %d Flags %x [%sGHz] - No traffic\n",
773 nvm_chan[ch_idx],
774 ch_flags,
775 (ch_idx >= NUM_2GHZ_CHANNELS) ?
776 "5.2" : "2.4");
777 continue;
778 }
779
780 /* we can't continue the same rule */
781 if (ch_idx == 0 || prev_ch_flags != ch_flags ||
782 center_freq - prev_center_freq > 20) {
783 valid_rules++;
784 new_rule = true;
785 }
786
787 rule = &regd->reg_rules[valid_rules - 1];
788
789 if (new_rule)
790 rule->freq_range.start_freq_khz =
791 MHZ_TO_KHZ(center_freq - 10);
792
793 rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);
794
795 /* this doesn't matter - not used by FW */
796 rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
Eliad Peller02a50492014-09-07 17:45:11 +0300797 rule->power_rule.max_eirp =
798 DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200799
800 rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
Matti Gottliebb281c932014-06-26 11:10:57 +0300801 ch_flags, cfg);
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200802
803 /* rely on auto-calculation to merge BW of contiguous chans */
804 rule->flags |= NL80211_RRF_AUTO_BW;
805 rule->freq_range.max_bandwidth_khz = 0;
806
807 prev_ch_flags = ch_flags;
808 prev_center_freq = center_freq;
809
810 IWL_DEBUG_DEV(dev, IWL_DL_LAR,
Arik Nemtsovbdf2fae2014-10-30 15:12:39 +0200811 "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 +0200812 center_freq,
813 band == IEEE80211_BAND_5GHZ ? "5.2" : "2.4",
814 CHECK_AND_PRINT_I(VALID),
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200815 CHECK_AND_PRINT_I(ACTIVE),
816 CHECK_AND_PRINT_I(RADAR),
817 CHECK_AND_PRINT_I(WIDE),
818 CHECK_AND_PRINT_I(40MHZ),
819 CHECK_AND_PRINT_I(80MHZ),
820 CHECK_AND_PRINT_I(160MHZ),
821 CHECK_AND_PRINT_I(INDOOR_ONLY),
822 CHECK_AND_PRINT_I(GO_CONCURRENT),
823 ch_flags,
Arik Nemtsovbdf2fae2014-10-30 15:12:39 +0200824 ((ch_flags & NVM_CHANNEL_ACTIVE) &&
Arik Nemtsovaf45a902014-03-05 12:19:10 +0200825 !(ch_flags & NVM_CHANNEL_RADAR))
826 ? "" : "not ");
827 }
828
829 regd->n_reg_rules = valid_rules;
830
831 /* set alpha2 from FW. */
832 regd->alpha2[0] = fw_mcc >> 8;
833 regd->alpha2[1] = fw_mcc & 0xff;
834
835 return regd;
836}
837IWL_EXPORT_SYMBOL(iwl_parse_nvm_mcc_info);