1*828c91f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2277b024eSKalle Valo /*
3932183aaSGanapathi Bhat * NXP Wireless LAN device driver: Channel, Frequence and Power
4277b024eSKalle Valo *
5932183aaSGanapathi Bhat * Copyright 2011-2020 NXP
6277b024eSKalle Valo */
7277b024eSKalle Valo
8277b024eSKalle Valo #include "decl.h"
9277b024eSKalle Valo #include "ioctl.h"
10277b024eSKalle Valo #include "util.h"
11277b024eSKalle Valo #include "fw.h"
12277b024eSKalle Valo #include "main.h"
13277b024eSKalle Valo #include "cfg80211.h"
14277b024eSKalle Valo
15277b024eSKalle Valo /* 100mW */
16277b024eSKalle Valo #define MWIFIEX_TX_PWR_DEFAULT 20
17277b024eSKalle Valo /* 100mW */
18277b024eSKalle Valo #define MWIFIEX_TX_PWR_US_DEFAULT 20
19277b024eSKalle Valo /* 50mW */
20277b024eSKalle Valo #define MWIFIEX_TX_PWR_JP_DEFAULT 16
21277b024eSKalle Valo /* 100mW */
22277b024eSKalle Valo #define MWIFIEX_TX_PWR_FR_100MW 20
23277b024eSKalle Valo /* 10mW */
24277b024eSKalle Valo #define MWIFIEX_TX_PWR_FR_10MW 10
25277b024eSKalle Valo /* 100mW */
26277b024eSKalle Valo #define MWIFIEX_TX_PWR_EMEA_DEFAULT 20
27277b024eSKalle Valo
28277b024eSKalle Valo static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
29277b024eSKalle Valo
30277b024eSKalle Valo static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
31277b024eSKalle Valo 0xb0, 0x48, 0x60, 0x6c, 0 };
32277b024eSKalle Valo
33277b024eSKalle Valo static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
34277b024eSKalle Valo 0x0c, 0x12, 0x18, 0x24,
35277b024eSKalle Valo 0x30, 0x48, 0x60, 0x6c, 0 };
36277b024eSKalle Valo
37277b024eSKalle Valo static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
38277b024eSKalle Valo 0xb0, 0x48, 0x60, 0x6c, 0 };
39277b024eSKalle Valo static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
40277b024eSKalle Valo 0xb0, 0x48, 0x60, 0x6c, 0 };
41277b024eSKalle Valo static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
42277b024eSKalle Valo 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
43277b024eSKalle Valo 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
44277b024eSKalle Valo 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
45277b024eSKalle Valo 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
46277b024eSKalle Valo 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
47277b024eSKalle Valo
48277b024eSKalle Valo static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
49277b024eSKalle Valo
50277b024eSKalle Valo static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
51277b024eSKalle Valo 0x30, 0x48, 0x60, 0x6c, 0 };
52277b024eSKalle Valo
53277b024eSKalle Valo static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
54277b024eSKalle Valo 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
55277b024eSKalle Valo 0x60, 0x6c, 0 };
56277b024eSKalle Valo
57658cb592SAmitkumar Karwar u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30,
58610d0af8SAmitkumar Karwar 0x31, 0x32, 0x40, 0x41, 0x50 };
59277b024eSKalle Valo
60277b024eSKalle Valo static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
61277b024eSKalle Valo
62277b024eSKalle Valo /* For every mcs_rate line, the first 8 bytes are for stream 1x1,
63277b024eSKalle Valo * and all 16 bytes are for stream 2x2.
64277b024eSKalle Valo */
65277b024eSKalle Valo static const u16 mcs_rate[4][16] = {
66277b024eSKalle Valo /* LGI 40M */
67277b024eSKalle Valo { 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
68277b024eSKalle Valo 0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
69277b024eSKalle Valo
70277b024eSKalle Valo /* SGI 40M */
71277b024eSKalle Valo { 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
72277b024eSKalle Valo 0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
73277b024eSKalle Valo
74277b024eSKalle Valo /* LGI 20M */
75277b024eSKalle Valo { 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
76277b024eSKalle Valo 0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
77277b024eSKalle Valo
78277b024eSKalle Valo /* SGI 20M */
79277b024eSKalle Valo { 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
80277b024eSKalle Valo 0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
81277b024eSKalle Valo };
82277b024eSKalle Valo
83277b024eSKalle Valo /* AC rates */
84277b024eSKalle Valo static const u16 ac_mcs_rate_nss1[8][10] = {
85277b024eSKalle Valo /* LG 160M */
86277b024eSKalle Valo { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
87277b024eSKalle Valo 0x492, 0x57C, 0x618 },
88277b024eSKalle Valo
89277b024eSKalle Valo /* SG 160M */
90277b024eSKalle Valo { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
91277b024eSKalle Valo 0x514, 0x618, 0x6C6 },
92277b024eSKalle Valo
93277b024eSKalle Valo /* LG 80M */
94277b024eSKalle Valo { 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
95277b024eSKalle Valo 0x249, 0x2BE, 0x30C },
96277b024eSKalle Valo
97277b024eSKalle Valo /* SG 80M */
98277b024eSKalle Valo { 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
99277b024eSKalle Valo 0x28A, 0x30C, 0x363 },
100277b024eSKalle Valo
101277b024eSKalle Valo /* LG 40M */
102277b024eSKalle Valo { 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
103277b024eSKalle Valo 0x10E, 0x144, 0x168 },
104277b024eSKalle Valo
105277b024eSKalle Valo /* SG 40M */
106277b024eSKalle Valo { 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
107277b024eSKalle Valo 0x12C, 0x168, 0x190 },
108277b024eSKalle Valo
109277b024eSKalle Valo /* LG 20M */
110277b024eSKalle Valo { 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
111277b024eSKalle Valo
112277b024eSKalle Valo /* SG 20M */
113277b024eSKalle Valo { 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
114277b024eSKalle Valo };
115277b024eSKalle Valo
116277b024eSKalle Valo /* NSS2 note: the value in the table is 2 multiplier of the actual rate */
117277b024eSKalle Valo static const u16 ac_mcs_rate_nss2[8][10] = {
118277b024eSKalle Valo /* LG 160M */
119277b024eSKalle Valo { 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
120277b024eSKalle Valo 0x924, 0xAF8, 0xC30 },
121277b024eSKalle Valo
122277b024eSKalle Valo /* SG 160M */
123277b024eSKalle Valo { 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
124277b024eSKalle Valo 0xA28, 0xC30, 0xD8B },
125277b024eSKalle Valo
126277b024eSKalle Valo /* LG 80M */
127277b024eSKalle Valo { 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
128277b024eSKalle Valo 0x492, 0x57C, 0x618 },
129277b024eSKalle Valo
130277b024eSKalle Valo /* SG 80M */
131277b024eSKalle Valo { 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
132277b024eSKalle Valo 0x514, 0x618, 0x6C6 },
133277b024eSKalle Valo
134277b024eSKalle Valo /* LG 40M */
135277b024eSKalle Valo { 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
136277b024eSKalle Valo 0x21C, 0x288, 0x2D0 },
137277b024eSKalle Valo
138277b024eSKalle Valo /* SG 40M */
139277b024eSKalle Valo { 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
140277b024eSKalle Valo 0x258, 0x2D0, 0x320 },
141277b024eSKalle Valo
142277b024eSKalle Valo /* LG 20M */
143277b024eSKalle Valo { 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
144277b024eSKalle Valo 0x138, 0x00 },
145277b024eSKalle Valo
146277b024eSKalle Valo /* SG 20M */
147277b024eSKalle Valo { 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
148277b024eSKalle Valo 0x15B, 0x00 },
149277b024eSKalle Valo };
150277b024eSKalle Valo
151277b024eSKalle Valo struct region_code_mapping {
152277b024eSKalle Valo u8 code;
153277b024eSKalle Valo u8 region[IEEE80211_COUNTRY_STRING_LEN];
154277b024eSKalle Valo };
155277b024eSKalle Valo
156277b024eSKalle Valo static struct region_code_mapping region_code_mapping_t[] = {
157277b024eSKalle Valo { 0x10, "US " }, /* US FCC */
158277b024eSKalle Valo { 0x20, "CA " }, /* IC Canada */
1597cfd829cSAmitkumar Karwar { 0x30, "FR " }, /* France */
160277b024eSKalle Valo { 0x31, "ES " }, /* Spain */
161277b024eSKalle Valo { 0x32, "FR " }, /* France */
162277b024eSKalle Valo { 0x40, "JP " }, /* Japan */
163277b024eSKalle Valo { 0x41, "JP " }, /* Japan */
164277b024eSKalle Valo { 0x50, "CN " }, /* China */
165277b024eSKalle Valo };
166277b024eSKalle Valo
167277b024eSKalle Valo /* This function converts integer code to region string */
mwifiex_11d_code_2_region(u8 code)168277b024eSKalle Valo u8 *mwifiex_11d_code_2_region(u8 code)
169277b024eSKalle Valo {
170277b024eSKalle Valo u8 i;
171277b024eSKalle Valo
172277b024eSKalle Valo /* Look for code in mapping table */
1738395fd9bSBrian Norris for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++)
174277b024eSKalle Valo if (region_code_mapping_t[i].code == code)
175277b024eSKalle Valo return region_code_mapping_t[i].region;
176277b024eSKalle Valo
177277b024eSKalle Valo return NULL;
178277b024eSKalle Valo }
179277b024eSKalle Valo
180277b024eSKalle Valo /*
181277b024eSKalle Valo * This function maps an index in supported rates table into
182277b024eSKalle Valo * the corresponding data rate.
183277b024eSKalle Valo */
mwifiex_index_to_acs_data_rate(struct mwifiex_private * priv,u8 index,u8 ht_info)184277b024eSKalle Valo u32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
185277b024eSKalle Valo u8 index, u8 ht_info)
186277b024eSKalle Valo {
187277b024eSKalle Valo u32 rate = 0;
188277b024eSKalle Valo u8 mcs_index = 0;
189277b024eSKalle Valo u8 bw = 0;
190277b024eSKalle Valo u8 gi = 0;
191277b024eSKalle Valo
192277b024eSKalle Valo if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
193277b024eSKalle Valo mcs_index = min(index & 0xF, 9);
194277b024eSKalle Valo
195277b024eSKalle Valo /* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
196277b024eSKalle Valo bw = (ht_info & 0xC) >> 2;
197277b024eSKalle Valo
198277b024eSKalle Valo /* LGI: gi =0, SGI: gi = 1 */
199277b024eSKalle Valo gi = (ht_info & 0x10) >> 4;
200277b024eSKalle Valo
201277b024eSKalle Valo if ((index >> 4) == 1) /* NSS = 2 */
202277b024eSKalle Valo rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
203277b024eSKalle Valo else /* NSS = 1 */
204277b024eSKalle Valo rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
205277b024eSKalle Valo } else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
206277b024eSKalle Valo /* 20M: bw=0, 40M: bw=1 */
207277b024eSKalle Valo bw = (ht_info & 0xC) >> 2;
208277b024eSKalle Valo
209277b024eSKalle Valo /* LGI: gi =0, SGI: gi = 1 */
210277b024eSKalle Valo gi = (ht_info & 0x10) >> 4;
211277b024eSKalle Valo
212277b024eSKalle Valo if (index == MWIFIEX_RATE_BITMAP_MCS0) {
213277b024eSKalle Valo if (gi == 1)
214277b024eSKalle Valo rate = 0x0D; /* MCS 32 SGI rate */
215277b024eSKalle Valo else
216277b024eSKalle Valo rate = 0x0C; /* MCS 32 LGI rate */
217277b024eSKalle Valo } else if (index < 16) {
218277b024eSKalle Valo if ((bw == 1) || (bw == 0))
219277b024eSKalle Valo rate = mcs_rate[2 * (1 - bw) + gi][index];
220277b024eSKalle Valo else
221277b024eSKalle Valo rate = mwifiex_data_rates[0];
222277b024eSKalle Valo } else {
223277b024eSKalle Valo rate = mwifiex_data_rates[0];
224277b024eSKalle Valo }
225277b024eSKalle Valo } else {
226277b024eSKalle Valo /* 11n non-HT rates */
227277b024eSKalle Valo if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
228277b024eSKalle Valo index = 0;
229277b024eSKalle Valo rate = mwifiex_data_rates[index];
230277b024eSKalle Valo }
231277b024eSKalle Valo
232277b024eSKalle Valo return rate;
233277b024eSKalle Valo }
234277b024eSKalle Valo
235277b024eSKalle Valo /* This function maps an index in supported rates table into
236277b024eSKalle Valo * the corresponding data rate.
237277b024eSKalle Valo */
mwifiex_index_to_data_rate(struct mwifiex_private * priv,u8 index,u8 ht_info)238277b024eSKalle Valo u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
239277b024eSKalle Valo u8 index, u8 ht_info)
240277b024eSKalle Valo {
241277b024eSKalle Valo u32 mcs_num_supp =
242277b024eSKalle Valo (priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
243277b024eSKalle Valo u32 rate;
244277b024eSKalle Valo
245277b024eSKalle Valo if (priv->adapter->is_hw_11ac_capable)
246277b024eSKalle Valo return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
247277b024eSKalle Valo
248277b024eSKalle Valo if (ht_info & BIT(0)) {
249277b024eSKalle Valo if (index == MWIFIEX_RATE_BITMAP_MCS0) {
250277b024eSKalle Valo if (ht_info & BIT(2))
251277b024eSKalle Valo rate = 0x0D; /* MCS 32 SGI rate */
252277b024eSKalle Valo else
253277b024eSKalle Valo rate = 0x0C; /* MCS 32 LGI rate */
254277b024eSKalle Valo } else if (index < mcs_num_supp) {
255277b024eSKalle Valo if (ht_info & BIT(1)) {
256277b024eSKalle Valo if (ht_info & BIT(2))
257277b024eSKalle Valo /* SGI, 40M */
258277b024eSKalle Valo rate = mcs_rate[1][index];
259277b024eSKalle Valo else
260277b024eSKalle Valo /* LGI, 40M */
261277b024eSKalle Valo rate = mcs_rate[0][index];
262277b024eSKalle Valo } else {
263277b024eSKalle Valo if (ht_info & BIT(2))
264277b024eSKalle Valo /* SGI, 20M */
265277b024eSKalle Valo rate = mcs_rate[3][index];
266277b024eSKalle Valo else
267277b024eSKalle Valo /* LGI, 20M */
268277b024eSKalle Valo rate = mcs_rate[2][index];
269277b024eSKalle Valo }
270277b024eSKalle Valo } else
271277b024eSKalle Valo rate = mwifiex_data_rates[0];
272277b024eSKalle Valo } else {
273277b024eSKalle Valo if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
274277b024eSKalle Valo index = 0;
275277b024eSKalle Valo rate = mwifiex_data_rates[index];
276277b024eSKalle Valo }
277277b024eSKalle Valo return rate;
278277b024eSKalle Valo }
279277b024eSKalle Valo
280277b024eSKalle Valo /*
281277b024eSKalle Valo * This function returns the current active data rates.
282277b024eSKalle Valo *
283277b024eSKalle Valo * The result may vary depending upon connection status.
284277b024eSKalle Valo */
mwifiex_get_active_data_rates(struct mwifiex_private * priv,u8 * rates)285277b024eSKalle Valo u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
286277b024eSKalle Valo {
287277b024eSKalle Valo if (!priv->media_connected)
288277b024eSKalle Valo return mwifiex_get_supported_rates(priv, rates);
289277b024eSKalle Valo else
290277b024eSKalle Valo return mwifiex_copy_rates(rates, 0,
291277b024eSKalle Valo priv->curr_bss_params.data_rates,
292277b024eSKalle Valo priv->curr_bss_params.num_of_rates);
293277b024eSKalle Valo }
294277b024eSKalle Valo
295277b024eSKalle Valo /*
296277b024eSKalle Valo * This function locates the Channel-Frequency-Power triplet based upon
297277b024eSKalle Valo * band and channel/frequency parameters.
298277b024eSKalle Valo */
299277b024eSKalle Valo struct mwifiex_chan_freq_power *
mwifiex_get_cfp(struct mwifiex_private * priv,u8 band,u16 channel,u32 freq)300277b024eSKalle Valo mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
301277b024eSKalle Valo {
302277b024eSKalle Valo struct mwifiex_chan_freq_power *cfp = NULL;
303277b024eSKalle Valo struct ieee80211_supported_band *sband;
304277b024eSKalle Valo struct ieee80211_channel *ch = NULL;
305277b024eSKalle Valo int i;
306277b024eSKalle Valo
307277b024eSKalle Valo if (!channel && !freq)
308277b024eSKalle Valo return cfp;
309277b024eSKalle Valo
310277b024eSKalle Valo if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
31157fbcce3SJohannes Berg sband = priv->wdev.wiphy->bands[NL80211_BAND_2GHZ];
312277b024eSKalle Valo else
31357fbcce3SJohannes Berg sband = priv->wdev.wiphy->bands[NL80211_BAND_5GHZ];
314277b024eSKalle Valo
315277b024eSKalle Valo if (!sband) {
316277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR,
317277b024eSKalle Valo "%s: cannot find cfp by band %d\n",
318277b024eSKalle Valo __func__, band);
319277b024eSKalle Valo return cfp;
320277b024eSKalle Valo }
321277b024eSKalle Valo
322277b024eSKalle Valo for (i = 0; i < sband->n_channels; i++) {
323277b024eSKalle Valo ch = &sband->channels[i];
324277b024eSKalle Valo
325277b024eSKalle Valo if (ch->flags & IEEE80211_CHAN_DISABLED)
326277b024eSKalle Valo continue;
327277b024eSKalle Valo
328277b024eSKalle Valo if (freq) {
329277b024eSKalle Valo if (ch->center_freq == freq)
330277b024eSKalle Valo break;
331277b024eSKalle Valo } else {
332277b024eSKalle Valo /* find by valid channel*/
333277b024eSKalle Valo if (ch->hw_value == channel ||
334277b024eSKalle Valo channel == FIRST_VALID_CHANNEL)
335277b024eSKalle Valo break;
336277b024eSKalle Valo }
337277b024eSKalle Valo }
338277b024eSKalle Valo if (i == sband->n_channels) {
339421ba82cSCaesar Wang mwifiex_dbg(priv->adapter, WARN,
340277b024eSKalle Valo "%s: cannot find cfp by band %d\t"
341277b024eSKalle Valo "& channel=%d freq=%d\n",
342277b024eSKalle Valo __func__, band, channel, freq);
343277b024eSKalle Valo } else {
344277b024eSKalle Valo if (!ch)
345277b024eSKalle Valo return cfp;
346277b024eSKalle Valo
347277b024eSKalle Valo priv->cfp.channel = ch->hw_value;
348277b024eSKalle Valo priv->cfp.freq = ch->center_freq;
349277b024eSKalle Valo priv->cfp.max_tx_power = ch->max_power;
350277b024eSKalle Valo cfp = &priv->cfp;
351277b024eSKalle Valo }
352277b024eSKalle Valo
353277b024eSKalle Valo return cfp;
354277b024eSKalle Valo }
355277b024eSKalle Valo
356277b024eSKalle Valo /*
357277b024eSKalle Valo * This function checks if the data rate is set to auto.
358277b024eSKalle Valo */
359277b024eSKalle Valo u8
mwifiex_is_rate_auto(struct mwifiex_private * priv)360277b024eSKalle Valo mwifiex_is_rate_auto(struct mwifiex_private *priv)
361277b024eSKalle Valo {
362277b024eSKalle Valo u32 i;
363277b024eSKalle Valo int rate_num = 0;
364277b024eSKalle Valo
365277b024eSKalle Valo for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
366277b024eSKalle Valo if (priv->bitmap_rates[i])
367277b024eSKalle Valo rate_num++;
368277b024eSKalle Valo
369277b024eSKalle Valo if (rate_num > 1)
370277b024eSKalle Valo return true;
371277b024eSKalle Valo else
372277b024eSKalle Valo return false;
373277b024eSKalle Valo }
374277b024eSKalle Valo
375277b024eSKalle Valo /* This function gets the supported data rates from bitmask inside
376277b024eSKalle Valo * cfg80211_scan_request.
377277b024eSKalle Valo */
mwifiex_get_rates_from_cfg80211(struct mwifiex_private * priv,u8 * rates,u8 radio_type)378277b024eSKalle Valo u32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
379277b024eSKalle Valo u8 *rates, u8 radio_type)
380277b024eSKalle Valo {
381277b024eSKalle Valo struct wiphy *wiphy = priv->adapter->wiphy;
382277b024eSKalle Valo struct cfg80211_scan_request *request = priv->scan_request;
383277b024eSKalle Valo u32 num_rates, rate_mask;
384277b024eSKalle Valo struct ieee80211_supported_band *sband;
385277b024eSKalle Valo int i;
386277b024eSKalle Valo
387277b024eSKalle Valo if (radio_type) {
38857fbcce3SJohannes Berg sband = wiphy->bands[NL80211_BAND_5GHZ];
389277b024eSKalle Valo if (WARN_ON_ONCE(!sband))
390277b024eSKalle Valo return 0;
39157fbcce3SJohannes Berg rate_mask = request->rates[NL80211_BAND_5GHZ];
392277b024eSKalle Valo } else {
39357fbcce3SJohannes Berg sband = wiphy->bands[NL80211_BAND_2GHZ];
394277b024eSKalle Valo if (WARN_ON_ONCE(!sband))
395277b024eSKalle Valo return 0;
39657fbcce3SJohannes Berg rate_mask = request->rates[NL80211_BAND_2GHZ];
397277b024eSKalle Valo }
398277b024eSKalle Valo
399277b024eSKalle Valo num_rates = 0;
400277b024eSKalle Valo for (i = 0; i < sband->n_bitrates; i++) {
401277b024eSKalle Valo if ((BIT(i) & rate_mask) == 0)
402277b024eSKalle Valo continue; /* skip rate */
403277b024eSKalle Valo rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5);
404277b024eSKalle Valo }
405277b024eSKalle Valo
406277b024eSKalle Valo return num_rates;
407277b024eSKalle Valo }
408277b024eSKalle Valo
409277b024eSKalle Valo /* This function gets the supported data rates. The function works in
410277b024eSKalle Valo * both Ad-Hoc and infra mode by printing the band and returning the
411277b024eSKalle Valo * data rates.
412277b024eSKalle Valo */
mwifiex_get_supported_rates(struct mwifiex_private * priv,u8 * rates)413277b024eSKalle Valo u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
414277b024eSKalle Valo {
415277b024eSKalle Valo u32 k = 0;
416277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter;
417277b024eSKalle Valo
418277b024eSKalle Valo if (priv->bss_mode == NL80211_IFTYPE_STATION ||
419277b024eSKalle Valo priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
420277b024eSKalle Valo switch (adapter->config_bands) {
421277b024eSKalle Valo case BAND_B:
422277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
423277b024eSKalle Valo "supported_rates_b\n",
424277b024eSKalle Valo adapter->config_bands);
425277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_b,
426277b024eSKalle Valo sizeof(supported_rates_b));
427277b024eSKalle Valo break;
428277b024eSKalle Valo case BAND_G:
429277b024eSKalle Valo case BAND_G | BAND_GN:
430277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
431277b024eSKalle Valo "supported_rates_g\n",
432277b024eSKalle Valo adapter->config_bands);
433277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_g,
434277b024eSKalle Valo sizeof(supported_rates_g));
435277b024eSKalle Valo break;
436277b024eSKalle Valo case BAND_B | BAND_G:
437277b024eSKalle Valo case BAND_A | BAND_B | BAND_G:
438277b024eSKalle Valo case BAND_A | BAND_B:
439277b024eSKalle Valo case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
440277b024eSKalle Valo case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
441277b024eSKalle Valo case BAND_B | BAND_G | BAND_GN:
442277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
443277b024eSKalle Valo "supported_rates_bg\n",
444277b024eSKalle Valo adapter->config_bands);
445277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_bg,
446277b024eSKalle Valo sizeof(supported_rates_bg));
447277b024eSKalle Valo break;
448277b024eSKalle Valo case BAND_A:
449277b024eSKalle Valo case BAND_A | BAND_G:
450277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
451277b024eSKalle Valo "supported_rates_a\n",
452277b024eSKalle Valo adapter->config_bands);
453277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_a,
454277b024eSKalle Valo sizeof(supported_rates_a));
455277b024eSKalle Valo break;
456277b024eSKalle Valo case BAND_AN:
457277b024eSKalle Valo case BAND_A | BAND_AN:
458277b024eSKalle Valo case BAND_A | BAND_AN | BAND_AAC:
459277b024eSKalle Valo case BAND_A | BAND_G | BAND_AN | BAND_GN:
460277b024eSKalle Valo case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
461277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
462277b024eSKalle Valo "supported_rates_a\n",
463277b024eSKalle Valo adapter->config_bands);
464277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_a,
465277b024eSKalle Valo sizeof(supported_rates_a));
466277b024eSKalle Valo break;
467277b024eSKalle Valo case BAND_GN:
468277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
469277b024eSKalle Valo "supported_rates_n\n",
470277b024eSKalle Valo adapter->config_bands);
471277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, supported_rates_n,
472277b024eSKalle Valo sizeof(supported_rates_n));
473277b024eSKalle Valo break;
474277b024eSKalle Valo }
475277b024eSKalle Valo } else {
476277b024eSKalle Valo /* Ad-hoc mode */
477277b024eSKalle Valo switch (adapter->adhoc_start_band) {
478277b024eSKalle Valo case BAND_B:
479277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
480277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
481277b024eSKalle Valo sizeof(adhoc_rates_b));
482277b024eSKalle Valo break;
483277b024eSKalle Valo case BAND_G:
484277b024eSKalle Valo case BAND_G | BAND_GN:
485277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
486277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
487277b024eSKalle Valo sizeof(adhoc_rates_g));
488277b024eSKalle Valo break;
489277b024eSKalle Valo case BAND_B | BAND_G:
490277b024eSKalle Valo case BAND_B | BAND_G | BAND_GN:
491277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
492277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
493277b024eSKalle Valo sizeof(adhoc_rates_bg));
494277b024eSKalle Valo break;
495277b024eSKalle Valo case BAND_A:
496277b024eSKalle Valo case BAND_A | BAND_AN:
497277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
498277b024eSKalle Valo k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
499277b024eSKalle Valo sizeof(adhoc_rates_a));
500277b024eSKalle Valo break;
501277b024eSKalle Valo }
502277b024eSKalle Valo }
503277b024eSKalle Valo
504277b024eSKalle Valo return k;
505277b024eSKalle Valo }
506277b024eSKalle Valo
mwifiex_adjust_data_rate(struct mwifiex_private * priv,u8 rx_rate,u8 rate_info)507277b024eSKalle Valo u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
508277b024eSKalle Valo u8 rx_rate, u8 rate_info)
509277b024eSKalle Valo {
510277b024eSKalle Valo u8 rate_index = 0;
511277b024eSKalle Valo
512277b024eSKalle Valo /* HT40 */
513277b024eSKalle Valo if ((rate_info & BIT(0)) && (rate_info & BIT(1)))
514277b024eSKalle Valo rate_index = MWIFIEX_RATE_INDEX_MCS0 +
515277b024eSKalle Valo MWIFIEX_BW20_MCS_NUM + rx_rate;
516277b024eSKalle Valo else if (rate_info & BIT(0)) /* HT20 */
517277b024eSKalle Valo rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate;
518277b024eSKalle Valo else
519277b024eSKalle Valo rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
520277b024eSKalle Valo rx_rate - 1 : rx_rate;
521277b024eSKalle Valo
522b4c35c17SDan Carpenter if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
523b4c35c17SDan Carpenter rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
524b4c35c17SDan Carpenter
525277b024eSKalle Valo return rate_index;
526277b024eSKalle Valo }
527