1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * NXP Wireless LAN device driver: Channel, Frequence and Power
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright 2011-2020 NXP
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This software file (the "File") is distributed by NXP
7*4882a593Smuzhiyun * under the terms of the GNU General Public License Version 2, June 1991
8*4882a593Smuzhiyun * (the "License"). You may use, redistribute and/or modify this File in
9*4882a593Smuzhiyun * accordance with the terms and conditions of the License, a copy of which
10*4882a593Smuzhiyun * is available by writing to the Free Software Foundation, Inc.,
11*4882a593Smuzhiyun * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12*4882a593Smuzhiyun * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15*4882a593Smuzhiyun * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16*4882a593Smuzhiyun * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17*4882a593Smuzhiyun * this warranty disclaimer.
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "decl.h"
21*4882a593Smuzhiyun #include "ioctl.h"
22*4882a593Smuzhiyun #include "util.h"
23*4882a593Smuzhiyun #include "fw.h"
24*4882a593Smuzhiyun #include "main.h"
25*4882a593Smuzhiyun #include "cfg80211.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* 100mW */
28*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_DEFAULT 20
29*4882a593Smuzhiyun /* 100mW */
30*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_US_DEFAULT 20
31*4882a593Smuzhiyun /* 50mW */
32*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_JP_DEFAULT 16
33*4882a593Smuzhiyun /* 100mW */
34*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_FR_100MW 20
35*4882a593Smuzhiyun /* 10mW */
36*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_FR_10MW 10
37*4882a593Smuzhiyun /* 100mW */
38*4882a593Smuzhiyun #define MWIFIEX_TX_PWR_EMEA_DEFAULT 20
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
43*4882a593Smuzhiyun 0xb0, 0x48, 0x60, 0x6c, 0 };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
46*4882a593Smuzhiyun 0x0c, 0x12, 0x18, 0x24,
47*4882a593Smuzhiyun 0x30, 0x48, 0x60, 0x6c, 0 };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
50*4882a593Smuzhiyun 0xb0, 0x48, 0x60, 0x6c, 0 };
51*4882a593Smuzhiyun static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
52*4882a593Smuzhiyun 0xb0, 0x48, 0x60, 0x6c, 0 };
53*4882a593Smuzhiyun static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
54*4882a593Smuzhiyun 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
55*4882a593Smuzhiyun 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
56*4882a593Smuzhiyun 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
57*4882a593Smuzhiyun 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
58*4882a593Smuzhiyun 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
63*4882a593Smuzhiyun 0x30, 0x48, 0x60, 0x6c, 0 };
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
66*4882a593Smuzhiyun 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
67*4882a593Smuzhiyun 0x60, 0x6c, 0 };
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30,
70*4882a593Smuzhiyun 0x31, 0x32, 0x40, 0x41, 0x50 };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* For every mcs_rate line, the first 8 bytes are for stream 1x1,
75*4882a593Smuzhiyun * and all 16 bytes are for stream 2x2.
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun static const u16 mcs_rate[4][16] = {
78*4882a593Smuzhiyun /* LGI 40M */
79*4882a593Smuzhiyun { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
80*4882a593Smuzhiyun 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* SGI 40M */
83*4882a593Smuzhiyun { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
84*4882a593Smuzhiyun 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun /* LGI 20M */
87*4882a593Smuzhiyun { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
88*4882a593Smuzhiyun 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /* SGI 20M */
91*4882a593Smuzhiyun { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
92*4882a593Smuzhiyun 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* AC rates */
96*4882a593Smuzhiyun static const u16 ac_mcs_rate_nss1[8][10] = {
97*4882a593Smuzhiyun /* LG 160M */
98*4882a593Smuzhiyun { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
99*4882a593Smuzhiyun 0x492, 0x57C, 0x618 },
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* SG 160M */
102*4882a593Smuzhiyun { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
103*4882a593Smuzhiyun 0x514, 0x618, 0x6C6 },
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* LG 80M */
106*4882a593Smuzhiyun { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
107*4882a593Smuzhiyun 0x249, 0x2BE, 0x30C },
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* SG 80M */
110*4882a593Smuzhiyun { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
111*4882a593Smuzhiyun 0x28A, 0x30C, 0x363 },
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* LG 40M */
114*4882a593Smuzhiyun { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
115*4882a593Smuzhiyun 0x10E, 0x144, 0x168 },
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* SG 40M */
118*4882a593Smuzhiyun { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
119*4882a593Smuzhiyun 0x12C, 0x168, 0x190 },
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* LG 20M */
122*4882a593Smuzhiyun { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* SG 20M */
125*4882a593Smuzhiyun { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* NSS2 note: the value in the table is 2 multiplier of the actual rate */
129*4882a593Smuzhiyun static const u16 ac_mcs_rate_nss2[8][10] = {
130*4882a593Smuzhiyun /* LG 160M */
131*4882a593Smuzhiyun { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
132*4882a593Smuzhiyun 0x924, 0xAF8, 0xC30 },
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* SG 160M */
135*4882a593Smuzhiyun { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
136*4882a593Smuzhiyun 0xA28, 0xC30, 0xD8B },
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* LG 80M */
139*4882a593Smuzhiyun { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
140*4882a593Smuzhiyun 0x492, 0x57C, 0x618 },
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* SG 80M */
143*4882a593Smuzhiyun { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
144*4882a593Smuzhiyun 0x514, 0x618, 0x6C6 },
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* LG 40M */
147*4882a593Smuzhiyun { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
148*4882a593Smuzhiyun 0x21C, 0x288, 0x2D0 },
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* SG 40M */
151*4882a593Smuzhiyun { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
152*4882a593Smuzhiyun 0x258, 0x2D0, 0x320 },
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* LG 20M */
155*4882a593Smuzhiyun { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
156*4882a593Smuzhiyun 0x138, 0x00 },
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* SG 20M */
159*4882a593Smuzhiyun { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
160*4882a593Smuzhiyun 0x15B, 0x00 },
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun struct region_code_mapping {
164*4882a593Smuzhiyun u8 code;
165*4882a593Smuzhiyun u8 region[IEEE80211_COUNTRY_STRING_LEN];
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun static struct region_code_mapping region_code_mapping_t[] = {
169*4882a593Smuzhiyun { 0x10, "US " }, /* US FCC */
170*4882a593Smuzhiyun { 0x20, "CA " }, /* IC Canada */
171*4882a593Smuzhiyun { 0x30, "FR " }, /* France */
172*4882a593Smuzhiyun { 0x31, "ES " }, /* Spain */
173*4882a593Smuzhiyun { 0x32, "FR " }, /* France */
174*4882a593Smuzhiyun { 0x40, "JP " }, /* Japan */
175*4882a593Smuzhiyun { 0x41, "JP " }, /* Japan */
176*4882a593Smuzhiyun { 0x50, "CN " }, /* China */
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /* This function converts integer code to region string */
mwifiex_11d_code_2_region(u8 code)180*4882a593Smuzhiyun u8 *mwifiex_11d_code_2_region(u8 code)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun u8 i;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* Look for code in mapping table */
185*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++)
186*4882a593Smuzhiyun if (region_code_mapping_t[i].code == code)
187*4882a593Smuzhiyun return region_code_mapping_t[i].region;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return NULL;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * This function maps an index in supported rates table into
194*4882a593Smuzhiyun * the corresponding data rate.
195*4882a593Smuzhiyun */
mwifiex_index_to_acs_data_rate(struct mwifiex_private * priv,u8 index,u8 ht_info)196*4882a593Smuzhiyun u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
197*4882a593Smuzhiyun u8 index, u8 ht_info)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun u32 rate = 0;
200*4882a593Smuzhiyun u8 mcs_index = 0;
201*4882a593Smuzhiyun u8 bw = 0;
202*4882a593Smuzhiyun u8 gi = 0;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
205*4882a593Smuzhiyun mcs_index = min(index & 0xF, 9);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
208*4882a593Smuzhiyun bw = (ht_info & 0xC) >> 2;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* LGI: gi =0, SGI: gi = 1 */
211*4882a593Smuzhiyun gi = (ht_info & 0x10) >> 4;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if ((index >> 4) == 1) /* NSS = 2 */
214*4882a593Smuzhiyun rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
215*4882a593Smuzhiyun else /* NSS = 1 */
216*4882a593Smuzhiyun rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
217*4882a593Smuzhiyun } else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
218*4882a593Smuzhiyun /* 20M: bw=0, 40M: bw=1 */
219*4882a593Smuzhiyun bw = (ht_info & 0xC) >> 2;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* LGI: gi =0, SGI: gi = 1 */
222*4882a593Smuzhiyun gi = (ht_info & 0x10) >> 4;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (index == MWIFIEX_RATE_BITMAP_MCS0) {
225*4882a593Smuzhiyun if (gi == 1)
226*4882a593Smuzhiyun rate = 0x0D; /* MCS 32 SGI rate */
227*4882a593Smuzhiyun else
228*4882a593Smuzhiyun rate = 0x0C; /* MCS 32 LGI rate */
229*4882a593Smuzhiyun } else if (index < 16) {
230*4882a593Smuzhiyun if ((bw == 1) || (bw == 0))
231*4882a593Smuzhiyun rate = mcs_rate[2 * (1 - bw) + gi][index];
232*4882a593Smuzhiyun else
233*4882a593Smuzhiyun rate = mwifiex_data_rates[0];
234*4882a593Smuzhiyun } else {
235*4882a593Smuzhiyun rate = mwifiex_data_rates[0];
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun } else {
238*4882a593Smuzhiyun /* 11n non-HT rates */
239*4882a593Smuzhiyun if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
240*4882a593Smuzhiyun index = 0;
241*4882a593Smuzhiyun rate = mwifiex_data_rates[index];
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun return rate;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /* This function maps an index in supported rates table into
248*4882a593Smuzhiyun * the corresponding data rate.
249*4882a593Smuzhiyun */
mwifiex_index_to_data_rate(struct mwifiex_private * priv,u8 index,u8 ht_info)250*4882a593Smuzhiyun u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
251*4882a593Smuzhiyun u8 index, u8 ht_info)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun u32 mcs_num_supp =
254*4882a593Smuzhiyun (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
255*4882a593Smuzhiyun u32 rate;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (priv->adapter->is_hw_11ac_capable)
258*4882a593Smuzhiyun return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (ht_info & BIT(0)) {
261*4882a593Smuzhiyun if (index == MWIFIEX_RATE_BITMAP_MCS0) {
262*4882a593Smuzhiyun if (ht_info & BIT(2))
263*4882a593Smuzhiyun rate = 0x0D; /* MCS 32 SGI rate */
264*4882a593Smuzhiyun else
265*4882a593Smuzhiyun rate = 0x0C; /* MCS 32 LGI rate */
266*4882a593Smuzhiyun } else if (index < mcs_num_supp) {
267*4882a593Smuzhiyun if (ht_info & BIT(1)) {
268*4882a593Smuzhiyun if (ht_info & BIT(2))
269*4882a593Smuzhiyun /* SGI, 40M */
270*4882a593Smuzhiyun rate = mcs_rate[1][index];
271*4882a593Smuzhiyun else
272*4882a593Smuzhiyun /* LGI, 40M */
273*4882a593Smuzhiyun rate = mcs_rate[0][index];
274*4882a593Smuzhiyun } else {
275*4882a593Smuzhiyun if (ht_info & BIT(2))
276*4882a593Smuzhiyun /* SGI, 20M */
277*4882a593Smuzhiyun rate = mcs_rate[3][index];
278*4882a593Smuzhiyun else
279*4882a593Smuzhiyun /* LGI, 20M */
280*4882a593Smuzhiyun rate = mcs_rate[2][index];
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun } else
283*4882a593Smuzhiyun rate = mwifiex_data_rates[0];
284*4882a593Smuzhiyun } else {
285*4882a593Smuzhiyun if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
286*4882a593Smuzhiyun index = 0;
287*4882a593Smuzhiyun rate = mwifiex_data_rates[index];
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun return rate;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /*
293*4882a593Smuzhiyun * This function returns the current active data rates.
294*4882a593Smuzhiyun *
295*4882a593Smuzhiyun * The result may vary depending upon connection status.
296*4882a593Smuzhiyun */
mwifiex_get_active_data_rates(struct mwifiex_private * priv,u8 * rates)297*4882a593Smuzhiyun u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun if (!priv->media_connected)
300*4882a593Smuzhiyun return mwifiex_get_supported_rates(priv, rates);
301*4882a593Smuzhiyun else
302*4882a593Smuzhiyun return mwifiex_copy_rates(rates, 0,
303*4882a593Smuzhiyun priv->curr_bss_params.data_rates,
304*4882a593Smuzhiyun priv->curr_bss_params.num_of_rates);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /*
308*4882a593Smuzhiyun * This function locates the Channel-Frequency-Power triplet based upon
309*4882a593Smuzhiyun * band and channel/frequency parameters.
310*4882a593Smuzhiyun */
311*4882a593Smuzhiyun struct mwifiex_chan_freq_power *
mwifiex_get_cfp(struct mwifiex_private * priv,u8 band,u16 channel,u32 freq)312*4882a593Smuzhiyun mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun struct mwifiex_chan_freq_power *cfp = NULL;
315*4882a593Smuzhiyun struct ieee80211_supported_band *sband;
316*4882a593Smuzhiyun struct ieee80211_channel *ch = NULL;
317*4882a593Smuzhiyun int i;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (!channel && !freq)
320*4882a593Smuzhiyun return cfp;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
323*4882a593Smuzhiyun sband = priv->wdev.wiphy->bands[NL80211_BAND_2GHZ];
324*4882a593Smuzhiyun else
325*4882a593Smuzhiyun sband = priv->wdev.wiphy->bands[NL80211_BAND_5GHZ];
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (!sband) {
328*4882a593Smuzhiyun mwifiex_dbg(priv->adapter, ERROR,
329*4882a593Smuzhiyun "%s: cannot find cfp by band %d\n",
330*4882a593Smuzhiyun __func__, band);
331*4882a593Smuzhiyun return cfp;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun for (i = 0; i < sband->n_channels; i++) {
335*4882a593Smuzhiyun ch = &sband->channels[i];
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (ch->flags & IEEE80211_CHAN_DISABLED)
338*4882a593Smuzhiyun continue;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun if (freq) {
341*4882a593Smuzhiyun if (ch->center_freq == freq)
342*4882a593Smuzhiyun break;
343*4882a593Smuzhiyun } else {
344*4882a593Smuzhiyun /* find by valid channel*/
345*4882a593Smuzhiyun if (ch->hw_value == channel ||
346*4882a593Smuzhiyun channel == FIRST_VALID_CHANNEL)
347*4882a593Smuzhiyun break;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun if (i == sband->n_channels) {
351*4882a593Smuzhiyun mwifiex_dbg(priv->adapter, WARN,
352*4882a593Smuzhiyun "%s: cannot find cfp by band %d\t"
353*4882a593Smuzhiyun "& channel=%d freq=%d\n",
354*4882a593Smuzhiyun __func__, band, channel, freq);
355*4882a593Smuzhiyun } else {
356*4882a593Smuzhiyun if (!ch)
357*4882a593Smuzhiyun return cfp;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun priv->cfp.channel = ch->hw_value;
360*4882a593Smuzhiyun priv->cfp.freq = ch->center_freq;
361*4882a593Smuzhiyun priv->cfp.max_tx_power = ch->max_power;
362*4882a593Smuzhiyun cfp = &priv->cfp;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun return cfp;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /*
369*4882a593Smuzhiyun * This function checks if the data rate is set to auto.
370*4882a593Smuzhiyun */
371*4882a593Smuzhiyun u8
mwifiex_is_rate_auto(struct mwifiex_private * priv)372*4882a593Smuzhiyun mwifiex_is_rate_auto(struct mwifiex_private *priv)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun u32 i;
375*4882a593Smuzhiyun int rate_num = 0;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
378*4882a593Smuzhiyun if (priv->bitmap_rates[i])
379*4882a593Smuzhiyun rate_num++;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (rate_num > 1)
382*4882a593Smuzhiyun return true;
383*4882a593Smuzhiyun else
384*4882a593Smuzhiyun return false;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun /* This function gets the supported data rates from bitmask inside
388*4882a593Smuzhiyun * cfg80211_scan_request.
389*4882a593Smuzhiyun */
mwifiex_get_rates_from_cfg80211(struct mwifiex_private * priv,u8 * rates,u8 radio_type)390*4882a593Smuzhiyun u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
391*4882a593Smuzhiyun u8 *rates, u8 radio_type)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun struct wiphy *wiphy = priv->adapter->wiphy;
394*4882a593Smuzhiyun struct cfg80211_scan_request *request = priv->scan_request;
395*4882a593Smuzhiyun u32 num_rates, rate_mask;
396*4882a593Smuzhiyun struct ieee80211_supported_band *sband;
397*4882a593Smuzhiyun int i;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun if (radio_type) {
400*4882a593Smuzhiyun sband = wiphy->bands[NL80211_BAND_5GHZ];
401*4882a593Smuzhiyun if (WARN_ON_ONCE(!sband))
402*4882a593Smuzhiyun return 0;
403*4882a593Smuzhiyun rate_mask = request->rates[NL80211_BAND_5GHZ];
404*4882a593Smuzhiyun } else {
405*4882a593Smuzhiyun sband = wiphy->bands[NL80211_BAND_2GHZ];
406*4882a593Smuzhiyun if (WARN_ON_ONCE(!sband))
407*4882a593Smuzhiyun return 0;
408*4882a593Smuzhiyun rate_mask = request->rates[NL80211_BAND_2GHZ];
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun num_rates = 0;
412*4882a593Smuzhiyun for (i = 0; i < sband->n_bitrates; i++) {
413*4882a593Smuzhiyun if ((BIT(i) & rate_mask) == 0)
414*4882a593Smuzhiyun continue; /* skip rate */
415*4882a593Smuzhiyun rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun return num_rates;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /* This function gets the supported data rates. The function works in
422*4882a593Smuzhiyun * both Ad-Hoc and infra mode by printing the band and returning the
423*4882a593Smuzhiyun * data rates.
424*4882a593Smuzhiyun */
mwifiex_get_supported_rates(struct mwifiex_private * priv,u8 * rates)425*4882a593Smuzhiyun u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun u32 k = 0;
428*4882a593Smuzhiyun struct mwifiex_adapter *adapter = priv->adapter;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (priv->bss_mode == NL80211_IFTYPE_STATION ||
431*4882a593Smuzhiyun priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
432*4882a593Smuzhiyun switch (adapter->config_bands) {
433*4882a593Smuzhiyun case BAND_B:
434*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
435*4882a593Smuzhiyun "supported_rates_b\n",
436*4882a593Smuzhiyun adapter->config_bands);
437*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_b,
438*4882a593Smuzhiyun sizeof(supported_rates_b));
439*4882a593Smuzhiyun break;
440*4882a593Smuzhiyun case BAND_G:
441*4882a593Smuzhiyun case BAND_G | BAND_GN:
442*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
443*4882a593Smuzhiyun "supported_rates_g\n",
444*4882a593Smuzhiyun adapter->config_bands);
445*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_g,
446*4882a593Smuzhiyun sizeof(supported_rates_g));
447*4882a593Smuzhiyun break;
448*4882a593Smuzhiyun case BAND_B | BAND_G:
449*4882a593Smuzhiyun case BAND_A | BAND_B | BAND_G:
450*4882a593Smuzhiyun case BAND_A | BAND_B:
451*4882a593Smuzhiyun case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
452*4882a593Smuzhiyun case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
453*4882a593Smuzhiyun case BAND_B | BAND_G | BAND_GN:
454*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
455*4882a593Smuzhiyun "supported_rates_bg\n",
456*4882a593Smuzhiyun adapter->config_bands);
457*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_bg,
458*4882a593Smuzhiyun sizeof(supported_rates_bg));
459*4882a593Smuzhiyun break;
460*4882a593Smuzhiyun case BAND_A:
461*4882a593Smuzhiyun case BAND_A | BAND_G:
462*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
463*4882a593Smuzhiyun "supported_rates_a\n",
464*4882a593Smuzhiyun adapter->config_bands);
465*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_a,
466*4882a593Smuzhiyun sizeof(supported_rates_a));
467*4882a593Smuzhiyun break;
468*4882a593Smuzhiyun case BAND_AN:
469*4882a593Smuzhiyun case BAND_A | BAND_AN:
470*4882a593Smuzhiyun case BAND_A | BAND_AN | BAND_AAC:
471*4882a593Smuzhiyun case BAND_A | BAND_G | BAND_AN | BAND_GN:
472*4882a593Smuzhiyun case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
473*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
474*4882a593Smuzhiyun "supported_rates_a\n",
475*4882a593Smuzhiyun adapter->config_bands);
476*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_a,
477*4882a593Smuzhiyun sizeof(supported_rates_a));
478*4882a593Smuzhiyun break;
479*4882a593Smuzhiyun case BAND_GN:
480*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
481*4882a593Smuzhiyun "supported_rates_n\n",
482*4882a593Smuzhiyun adapter->config_bands);
483*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, supported_rates_n,
484*4882a593Smuzhiyun sizeof(supported_rates_n));
485*4882a593Smuzhiyun break;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun } else {
488*4882a593Smuzhiyun /* Ad-hoc mode */
489*4882a593Smuzhiyun switch (adapter->adhoc_start_band) {
490*4882a593Smuzhiyun case BAND_B:
491*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
492*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
493*4882a593Smuzhiyun sizeof(adhoc_rates_b));
494*4882a593Smuzhiyun break;
495*4882a593Smuzhiyun case BAND_G:
496*4882a593Smuzhiyun case BAND_G | BAND_GN:
497*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
498*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
499*4882a593Smuzhiyun sizeof(adhoc_rates_g));
500*4882a593Smuzhiyun break;
501*4882a593Smuzhiyun case BAND_B | BAND_G:
502*4882a593Smuzhiyun case BAND_B | BAND_G | BAND_GN:
503*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
504*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
505*4882a593Smuzhiyun sizeof(adhoc_rates_bg));
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun case BAND_A:
508*4882a593Smuzhiyun case BAND_A | BAND_AN:
509*4882a593Smuzhiyun mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
510*4882a593Smuzhiyun k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
511*4882a593Smuzhiyun sizeof(adhoc_rates_a));
512*4882a593Smuzhiyun break;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun return k;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
mwifiex_adjust_data_rate(struct mwifiex_private * priv,u8 rx_rate,u8 rate_info)519*4882a593Smuzhiyun u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
520*4882a593Smuzhiyun u8 rx_rate, u8 rate_info)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun u8 rate_index = 0;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /* HT40 */
525*4882a593Smuzhiyun if ((rate_info & BIT(0)) && (rate_info & BIT(1)))
526*4882a593Smuzhiyun rate_index = MWIFIEX_RATE_INDEX_MCS0 +
527*4882a593Smuzhiyun MWIFIEX_BW20_MCS_NUM + rx_rate;
528*4882a593Smuzhiyun else if (rate_info & BIT(0)) /* HT20 */
529*4882a593Smuzhiyun rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate;
530*4882a593Smuzhiyun else
531*4882a593Smuzhiyun rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
532*4882a593Smuzhiyun rx_rate - 1 : rx_rate;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
535*4882a593Smuzhiyun rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun return rate_index;
538*4882a593Smuzhiyun }
539