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