xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/marvell/mwifiex/cfp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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