18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: Channel, Frequence and Power
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP
78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991
88c2ecf20Sopenharmony_ci * (the "License").  You may use, redistribute and/or modify this File in
98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which
108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc.,
118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
178c2ecf20Sopenharmony_ci * this warranty disclaimer.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "decl.h"
218c2ecf20Sopenharmony_ci#include "ioctl.h"
228c2ecf20Sopenharmony_ci#include "util.h"
238c2ecf20Sopenharmony_ci#include "fw.h"
248c2ecf20Sopenharmony_ci#include "main.h"
258c2ecf20Sopenharmony_ci#include "cfg80211.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* 100mW */
288c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_DEFAULT     20
298c2ecf20Sopenharmony_ci/* 100mW */
308c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_US_DEFAULT      20
318c2ecf20Sopenharmony_ci/* 50mW */
328c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_JP_DEFAULT      16
338c2ecf20Sopenharmony_ci/* 100mW */
348c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_FR_100MW        20
358c2ecf20Sopenharmony_ci/* 10mW */
368c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_FR_10MW         10
378c2ecf20Sopenharmony_ci/* 100mW */
388c2ecf20Sopenharmony_ci#define MWIFIEX_TX_PWR_EMEA_DEFAULT    20
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
438c2ecf20Sopenharmony_ci					       0xb0, 0x48, 0x60, 0x6c, 0 };
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
468c2ecf20Sopenharmony_ci						 0x0c, 0x12, 0x18, 0x24,
478c2ecf20Sopenharmony_ci						 0x30, 0x48, 0x60, 0x6c, 0 };
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
508c2ecf20Sopenharmony_ci					       0xb0, 0x48, 0x60, 0x6c, 0 };
518c2ecf20Sopenharmony_cistatic u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
528c2ecf20Sopenharmony_ci					0xb0, 0x48, 0x60, 0x6c, 0 };
538c2ecf20Sopenharmony_cistatic u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
548c2ecf20Sopenharmony_ci					0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
558c2ecf20Sopenharmony_ci					0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
568c2ecf20Sopenharmony_ci					0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
578c2ecf20Sopenharmony_ci					0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
588c2ecf20Sopenharmony_ci					0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
638c2ecf20Sopenharmony_ci					0x30, 0x48, 0x60, 0x6c, 0 };
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
668c2ecf20Sopenharmony_ci					0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
678c2ecf20Sopenharmony_ci					0x60, 0x6c, 0 };
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ciu16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30,
708c2ecf20Sopenharmony_ci						0x31, 0x32, 0x40, 0x41, 0x50 };
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/* For every mcs_rate line, the first 8 bytes are for stream 1x1,
758c2ecf20Sopenharmony_ci * and all 16 bytes are for stream 2x2.
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_cistatic const u16 mcs_rate[4][16] = {
788c2ecf20Sopenharmony_ci	/* LGI 40M */
798c2ecf20Sopenharmony_ci	{ 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
808c2ecf20Sopenharmony_ci	  0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* SGI 40M */
838c2ecf20Sopenharmony_ci	{ 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
848c2ecf20Sopenharmony_ci	  0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* LGI 20M */
878c2ecf20Sopenharmony_ci	{ 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
888c2ecf20Sopenharmony_ci	  0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* SGI 20M */
918c2ecf20Sopenharmony_ci	{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
928c2ecf20Sopenharmony_ci	  0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* AC rates */
968c2ecf20Sopenharmony_cistatic const u16 ac_mcs_rate_nss1[8][10] = {
978c2ecf20Sopenharmony_ci	/* LG 160M */
988c2ecf20Sopenharmony_ci	{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
998c2ecf20Sopenharmony_ci	  0x492, 0x57C, 0x618 },
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	/* SG 160M */
1028c2ecf20Sopenharmony_ci	{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
1038c2ecf20Sopenharmony_ci	  0x514, 0x618, 0x6C6 },
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* LG 80M */
1068c2ecf20Sopenharmony_ci	{ 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
1078c2ecf20Sopenharmony_ci	  0x249, 0x2BE, 0x30C },
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* SG 80M */
1108c2ecf20Sopenharmony_ci	{ 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
1118c2ecf20Sopenharmony_ci	  0x28A, 0x30C, 0x363 },
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* LG 40M */
1148c2ecf20Sopenharmony_ci	{ 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
1158c2ecf20Sopenharmony_ci	  0x10E, 0x144, 0x168 },
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* SG 40M */
1188c2ecf20Sopenharmony_ci	{ 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
1198c2ecf20Sopenharmony_ci	  0x12C, 0x168, 0x190 },
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* LG 20M */
1228c2ecf20Sopenharmony_ci	{ 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* SG 20M */
1258c2ecf20Sopenharmony_ci	{ 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
1268c2ecf20Sopenharmony_ci};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* NSS2 note: the value in the table is 2 multiplier of the actual rate */
1298c2ecf20Sopenharmony_cistatic const u16 ac_mcs_rate_nss2[8][10] = {
1308c2ecf20Sopenharmony_ci	/* LG 160M */
1318c2ecf20Sopenharmony_ci	{ 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
1328c2ecf20Sopenharmony_ci	  0x924, 0xAF8, 0xC30 },
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* SG 160M */
1358c2ecf20Sopenharmony_ci	{ 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
1368c2ecf20Sopenharmony_ci	  0xA28, 0xC30, 0xD8B },
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/* LG 80M */
1398c2ecf20Sopenharmony_ci	{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
1408c2ecf20Sopenharmony_ci	  0x492, 0x57C, 0x618 },
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* SG 80M */
1438c2ecf20Sopenharmony_ci	{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
1448c2ecf20Sopenharmony_ci	  0x514, 0x618, 0x6C6 },
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* LG 40M */
1478c2ecf20Sopenharmony_ci	{ 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
1488c2ecf20Sopenharmony_ci	  0x21C, 0x288, 0x2D0 },
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* SG 40M */
1518c2ecf20Sopenharmony_ci	{ 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
1528c2ecf20Sopenharmony_ci	  0x258, 0x2D0, 0x320 },
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/* LG 20M */
1558c2ecf20Sopenharmony_ci	{ 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
1568c2ecf20Sopenharmony_ci	  0x138, 0x00 },
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* SG 20M */
1598c2ecf20Sopenharmony_ci	{ 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
1608c2ecf20Sopenharmony_ci	  0x15B, 0x00 },
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistruct region_code_mapping {
1648c2ecf20Sopenharmony_ci	u8 code;
1658c2ecf20Sopenharmony_ci	u8 region[IEEE80211_COUNTRY_STRING_LEN];
1668c2ecf20Sopenharmony_ci};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic struct region_code_mapping region_code_mapping_t[] = {
1698c2ecf20Sopenharmony_ci	{ 0x10, "US " }, /* US FCC */
1708c2ecf20Sopenharmony_ci	{ 0x20, "CA " }, /* IC Canada */
1718c2ecf20Sopenharmony_ci	{ 0x30, "FR " }, /* France */
1728c2ecf20Sopenharmony_ci	{ 0x31, "ES " }, /* Spain */
1738c2ecf20Sopenharmony_ci	{ 0x32, "FR " }, /* France */
1748c2ecf20Sopenharmony_ci	{ 0x40, "JP " }, /* Japan */
1758c2ecf20Sopenharmony_ci	{ 0x41, "JP " }, /* Japan */
1768c2ecf20Sopenharmony_ci	{ 0x50, "CN " }, /* China */
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/* This function converts integer code to region string */
1808c2ecf20Sopenharmony_ciu8 *mwifiex_11d_code_2_region(u8 code)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	u8 i;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* Look for code in mapping table */
1858c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++)
1868c2ecf20Sopenharmony_ci		if (region_code_mapping_t[i].code == code)
1878c2ecf20Sopenharmony_ci			return region_code_mapping_t[i].region;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return NULL;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * This function maps an index in supported rates table into
1948c2ecf20Sopenharmony_ci * the corresponding data rate.
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_ciu32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
1978c2ecf20Sopenharmony_ci				   u8 index, u8 ht_info)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	u32 rate = 0;
2008c2ecf20Sopenharmony_ci	u8 mcs_index = 0;
2018c2ecf20Sopenharmony_ci	u8 bw = 0;
2028c2ecf20Sopenharmony_ci	u8 gi = 0;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
2058c2ecf20Sopenharmony_ci		mcs_index = min(index & 0xF, 9);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		/* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
2088c2ecf20Sopenharmony_ci		bw = (ht_info & 0xC) >> 2;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		/* LGI: gi =0, SGI: gi = 1 */
2118c2ecf20Sopenharmony_ci		gi = (ht_info & 0x10) >> 4;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		if ((index >> 4) == 1)	/* NSS = 2 */
2148c2ecf20Sopenharmony_ci			rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
2158c2ecf20Sopenharmony_ci		else			/* NSS = 1 */
2168c2ecf20Sopenharmony_ci			rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
2178c2ecf20Sopenharmony_ci	} else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
2188c2ecf20Sopenharmony_ci		/* 20M: bw=0, 40M: bw=1 */
2198c2ecf20Sopenharmony_ci		bw = (ht_info & 0xC) >> 2;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		/* LGI: gi =0, SGI: gi = 1 */
2228c2ecf20Sopenharmony_ci		gi = (ht_info & 0x10) >> 4;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
2258c2ecf20Sopenharmony_ci			if (gi == 1)
2268c2ecf20Sopenharmony_ci				rate = 0x0D;    /* MCS 32 SGI rate */
2278c2ecf20Sopenharmony_ci			else
2288c2ecf20Sopenharmony_ci				rate = 0x0C;    /* MCS 32 LGI rate */
2298c2ecf20Sopenharmony_ci		} else if (index < 16) {
2308c2ecf20Sopenharmony_ci			if ((bw == 1) || (bw == 0))
2318c2ecf20Sopenharmony_ci				rate = mcs_rate[2 * (1 - bw) + gi][index];
2328c2ecf20Sopenharmony_ci			else
2338c2ecf20Sopenharmony_ci				rate = mwifiex_data_rates[0];
2348c2ecf20Sopenharmony_ci		} else {
2358c2ecf20Sopenharmony_ci			rate = mwifiex_data_rates[0];
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci	} else {
2388c2ecf20Sopenharmony_ci		/* 11n non-HT rates */
2398c2ecf20Sopenharmony_ci		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
2408c2ecf20Sopenharmony_ci			index = 0;
2418c2ecf20Sopenharmony_ci		rate = mwifiex_data_rates[index];
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return rate;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/* This function maps an index in supported rates table into
2488c2ecf20Sopenharmony_ci * the corresponding data rate.
2498c2ecf20Sopenharmony_ci */
2508c2ecf20Sopenharmony_ciu32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
2518c2ecf20Sopenharmony_ci			       u8 index, u8 ht_info)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	u32 mcs_num_supp =
2548c2ecf20Sopenharmony_ci		(priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
2558c2ecf20Sopenharmony_ci	u32 rate;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (priv->adapter->is_hw_11ac_capable)
2588c2ecf20Sopenharmony_ci		return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (ht_info & BIT(0)) {
2618c2ecf20Sopenharmony_ci		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
2628c2ecf20Sopenharmony_ci			if (ht_info & BIT(2))
2638c2ecf20Sopenharmony_ci				rate = 0x0D;	/* MCS 32 SGI rate */
2648c2ecf20Sopenharmony_ci			else
2658c2ecf20Sopenharmony_ci				rate = 0x0C;	/* MCS 32 LGI rate */
2668c2ecf20Sopenharmony_ci		} else if (index < mcs_num_supp) {
2678c2ecf20Sopenharmony_ci			if (ht_info & BIT(1)) {
2688c2ecf20Sopenharmony_ci				if (ht_info & BIT(2))
2698c2ecf20Sopenharmony_ci					/* SGI, 40M */
2708c2ecf20Sopenharmony_ci					rate = mcs_rate[1][index];
2718c2ecf20Sopenharmony_ci				else
2728c2ecf20Sopenharmony_ci					/* LGI, 40M */
2738c2ecf20Sopenharmony_ci					rate = mcs_rate[0][index];
2748c2ecf20Sopenharmony_ci			} else {
2758c2ecf20Sopenharmony_ci				if (ht_info & BIT(2))
2768c2ecf20Sopenharmony_ci					/* SGI, 20M */
2778c2ecf20Sopenharmony_ci					rate = mcs_rate[3][index];
2788c2ecf20Sopenharmony_ci				else
2798c2ecf20Sopenharmony_ci					/* LGI, 20M */
2808c2ecf20Sopenharmony_ci					rate = mcs_rate[2][index];
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci		} else
2838c2ecf20Sopenharmony_ci			rate = mwifiex_data_rates[0];
2848c2ecf20Sopenharmony_ci	} else {
2858c2ecf20Sopenharmony_ci		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
2868c2ecf20Sopenharmony_ci			index = 0;
2878c2ecf20Sopenharmony_ci		rate = mwifiex_data_rates[index];
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	return rate;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/*
2938c2ecf20Sopenharmony_ci * This function returns the current active data rates.
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * The result may vary depending upon connection status.
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_ciu32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	if (!priv->media_connected)
3008c2ecf20Sopenharmony_ci		return mwifiex_get_supported_rates(priv, rates);
3018c2ecf20Sopenharmony_ci	else
3028c2ecf20Sopenharmony_ci		return mwifiex_copy_rates(rates, 0,
3038c2ecf20Sopenharmony_ci					  priv->curr_bss_params.data_rates,
3048c2ecf20Sopenharmony_ci					  priv->curr_bss_params.num_of_rates);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/*
3088c2ecf20Sopenharmony_ci * This function locates the Channel-Frequency-Power triplet based upon
3098c2ecf20Sopenharmony_ci * band and channel/frequency parameters.
3108c2ecf20Sopenharmony_ci */
3118c2ecf20Sopenharmony_cistruct mwifiex_chan_freq_power *
3128c2ecf20Sopenharmony_cimwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct mwifiex_chan_freq_power *cfp = NULL;
3158c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
3168c2ecf20Sopenharmony_ci	struct ieee80211_channel *ch = NULL;
3178c2ecf20Sopenharmony_ci	int i;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (!channel && !freq)
3208c2ecf20Sopenharmony_ci		return cfp;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
3238c2ecf20Sopenharmony_ci		sband = priv->wdev.wiphy->bands[NL80211_BAND_2GHZ];
3248c2ecf20Sopenharmony_ci	else
3258c2ecf20Sopenharmony_ci		sband = priv->wdev.wiphy->bands[NL80211_BAND_5GHZ];
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (!sband) {
3288c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
3298c2ecf20Sopenharmony_ci			    "%s: cannot find cfp by band %d\n",
3308c2ecf20Sopenharmony_ci			    __func__, band);
3318c2ecf20Sopenharmony_ci		return cfp;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	for (i = 0; i < sband->n_channels; i++) {
3358c2ecf20Sopenharmony_ci		ch = &sband->channels[i];
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		if (ch->flags & IEEE80211_CHAN_DISABLED)
3388c2ecf20Sopenharmony_ci			continue;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci		if (freq) {
3418c2ecf20Sopenharmony_ci			if (ch->center_freq == freq)
3428c2ecf20Sopenharmony_ci				break;
3438c2ecf20Sopenharmony_ci		} else {
3448c2ecf20Sopenharmony_ci			/* find by valid channel*/
3458c2ecf20Sopenharmony_ci			if (ch->hw_value == channel ||
3468c2ecf20Sopenharmony_ci			    channel == FIRST_VALID_CHANNEL)
3478c2ecf20Sopenharmony_ci				break;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci	if (i == sband->n_channels) {
3518c2ecf20Sopenharmony_ci		mwifiex_dbg(priv->adapter, WARN,
3528c2ecf20Sopenharmony_ci			    "%s: cannot find cfp by band %d\t"
3538c2ecf20Sopenharmony_ci			    "& channel=%d freq=%d\n",
3548c2ecf20Sopenharmony_ci			    __func__, band, channel, freq);
3558c2ecf20Sopenharmony_ci	} else {
3568c2ecf20Sopenharmony_ci		if (!ch)
3578c2ecf20Sopenharmony_ci			return cfp;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		priv->cfp.channel = ch->hw_value;
3608c2ecf20Sopenharmony_ci		priv->cfp.freq = ch->center_freq;
3618c2ecf20Sopenharmony_ci		priv->cfp.max_tx_power = ch->max_power;
3628c2ecf20Sopenharmony_ci		cfp = &priv->cfp;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return cfp;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci/*
3698c2ecf20Sopenharmony_ci * This function checks if the data rate is set to auto.
3708c2ecf20Sopenharmony_ci */
3718c2ecf20Sopenharmony_ciu8
3728c2ecf20Sopenharmony_cimwifiex_is_rate_auto(struct mwifiex_private *priv)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	u32 i;
3758c2ecf20Sopenharmony_ci	int rate_num = 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
3788c2ecf20Sopenharmony_ci		if (priv->bitmap_rates[i])
3798c2ecf20Sopenharmony_ci			rate_num++;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (rate_num > 1)
3828c2ecf20Sopenharmony_ci		return true;
3838c2ecf20Sopenharmony_ci	else
3848c2ecf20Sopenharmony_ci		return false;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/* This function gets the supported data rates from bitmask inside
3888c2ecf20Sopenharmony_ci * cfg80211_scan_request.
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_ciu32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
3918c2ecf20Sopenharmony_ci				    u8 *rates, u8 radio_type)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	struct wiphy *wiphy = priv->adapter->wiphy;
3948c2ecf20Sopenharmony_ci	struct cfg80211_scan_request *request = priv->scan_request;
3958c2ecf20Sopenharmony_ci	u32 num_rates, rate_mask;
3968c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
3978c2ecf20Sopenharmony_ci	int i;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (radio_type) {
4008c2ecf20Sopenharmony_ci		sband = wiphy->bands[NL80211_BAND_5GHZ];
4018c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(!sband))
4028c2ecf20Sopenharmony_ci			return 0;
4038c2ecf20Sopenharmony_ci		rate_mask = request->rates[NL80211_BAND_5GHZ];
4048c2ecf20Sopenharmony_ci	} else {
4058c2ecf20Sopenharmony_ci		sband = wiphy->bands[NL80211_BAND_2GHZ];
4068c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(!sband))
4078c2ecf20Sopenharmony_ci			return 0;
4088c2ecf20Sopenharmony_ci		rate_mask = request->rates[NL80211_BAND_2GHZ];
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	num_rates = 0;
4128c2ecf20Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
4138c2ecf20Sopenharmony_ci		if ((BIT(i) & rate_mask) == 0)
4148c2ecf20Sopenharmony_ci			continue; /* skip rate */
4158c2ecf20Sopenharmony_ci		rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5);
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	return num_rates;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/* This function gets the supported data rates. The function works in
4228c2ecf20Sopenharmony_ci * both Ad-Hoc and infra mode by printing the band and returning the
4238c2ecf20Sopenharmony_ci * data rates.
4248c2ecf20Sopenharmony_ci */
4258c2ecf20Sopenharmony_ciu32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	u32 k = 0;
4288c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
4318c2ecf20Sopenharmony_ci	    priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
4328c2ecf20Sopenharmony_ci		switch (adapter->config_bands) {
4338c2ecf20Sopenharmony_ci		case BAND_B:
4348c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4358c2ecf20Sopenharmony_ci				    "supported_rates_b\n",
4368c2ecf20Sopenharmony_ci				    adapter->config_bands);
4378c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_b,
4388c2ecf20Sopenharmony_ci					       sizeof(supported_rates_b));
4398c2ecf20Sopenharmony_ci			break;
4408c2ecf20Sopenharmony_ci		case BAND_G:
4418c2ecf20Sopenharmony_ci		case BAND_G | BAND_GN:
4428c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4438c2ecf20Sopenharmony_ci				    "supported_rates_g\n",
4448c2ecf20Sopenharmony_ci				    adapter->config_bands);
4458c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_g,
4468c2ecf20Sopenharmony_ci					       sizeof(supported_rates_g));
4478c2ecf20Sopenharmony_ci			break;
4488c2ecf20Sopenharmony_ci		case BAND_B | BAND_G:
4498c2ecf20Sopenharmony_ci		case BAND_A | BAND_B | BAND_G:
4508c2ecf20Sopenharmony_ci		case BAND_A | BAND_B:
4518c2ecf20Sopenharmony_ci		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
4528c2ecf20Sopenharmony_ci		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
4538c2ecf20Sopenharmony_ci		case BAND_B | BAND_G | BAND_GN:
4548c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4558c2ecf20Sopenharmony_ci				    "supported_rates_bg\n",
4568c2ecf20Sopenharmony_ci				    adapter->config_bands);
4578c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_bg,
4588c2ecf20Sopenharmony_ci					       sizeof(supported_rates_bg));
4598c2ecf20Sopenharmony_ci			break;
4608c2ecf20Sopenharmony_ci		case BAND_A:
4618c2ecf20Sopenharmony_ci		case BAND_A | BAND_G:
4628c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4638c2ecf20Sopenharmony_ci				    "supported_rates_a\n",
4648c2ecf20Sopenharmony_ci				    adapter->config_bands);
4658c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_a,
4668c2ecf20Sopenharmony_ci					       sizeof(supported_rates_a));
4678c2ecf20Sopenharmony_ci			break;
4688c2ecf20Sopenharmony_ci		case BAND_AN:
4698c2ecf20Sopenharmony_ci		case BAND_A | BAND_AN:
4708c2ecf20Sopenharmony_ci		case BAND_A | BAND_AN | BAND_AAC:
4718c2ecf20Sopenharmony_ci		case BAND_A | BAND_G | BAND_AN | BAND_GN:
4728c2ecf20Sopenharmony_ci		case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
4738c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4748c2ecf20Sopenharmony_ci				    "supported_rates_a\n",
4758c2ecf20Sopenharmony_ci				    adapter->config_bands);
4768c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_a,
4778c2ecf20Sopenharmony_ci					       sizeof(supported_rates_a));
4788c2ecf20Sopenharmony_ci			break;
4798c2ecf20Sopenharmony_ci		case BAND_GN:
4808c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
4818c2ecf20Sopenharmony_ci				    "supported_rates_n\n",
4828c2ecf20Sopenharmony_ci				    adapter->config_bands);
4838c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_n,
4848c2ecf20Sopenharmony_ci					       sizeof(supported_rates_n));
4858c2ecf20Sopenharmony_ci			break;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci	} else {
4888c2ecf20Sopenharmony_ci		/* Ad-hoc mode */
4898c2ecf20Sopenharmony_ci		switch (adapter->adhoc_start_band) {
4908c2ecf20Sopenharmony_ci		case BAND_B:
4918c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
4928c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
4938c2ecf20Sopenharmony_ci					       sizeof(adhoc_rates_b));
4948c2ecf20Sopenharmony_ci			break;
4958c2ecf20Sopenharmony_ci		case BAND_G:
4968c2ecf20Sopenharmony_ci		case BAND_G | BAND_GN:
4978c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
4988c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
4998c2ecf20Sopenharmony_ci					       sizeof(adhoc_rates_g));
5008c2ecf20Sopenharmony_ci			break;
5018c2ecf20Sopenharmony_ci		case BAND_B | BAND_G:
5028c2ecf20Sopenharmony_ci		case BAND_B | BAND_G | BAND_GN:
5038c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
5048c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
5058c2ecf20Sopenharmony_ci					       sizeof(adhoc_rates_bg));
5068c2ecf20Sopenharmony_ci			break;
5078c2ecf20Sopenharmony_ci		case BAND_A:
5088c2ecf20Sopenharmony_ci		case BAND_A | BAND_AN:
5098c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
5108c2ecf20Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
5118c2ecf20Sopenharmony_ci					       sizeof(adhoc_rates_a));
5128c2ecf20Sopenharmony_ci			break;
5138c2ecf20Sopenharmony_ci		}
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return k;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ciu8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
5208c2ecf20Sopenharmony_ci			    u8 rx_rate, u8 rate_info)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	u8 rate_index = 0;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* HT40 */
5258c2ecf20Sopenharmony_ci	if ((rate_info & BIT(0)) && (rate_info & BIT(1)))
5268c2ecf20Sopenharmony_ci		rate_index = MWIFIEX_RATE_INDEX_MCS0 +
5278c2ecf20Sopenharmony_ci			     MWIFIEX_BW20_MCS_NUM + rx_rate;
5288c2ecf20Sopenharmony_ci	else if (rate_info & BIT(0)) /* HT20 */
5298c2ecf20Sopenharmony_ci		rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate;
5308c2ecf20Sopenharmony_ci	else
5318c2ecf20Sopenharmony_ci		rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
5328c2ecf20Sopenharmony_ci			      rx_rate - 1 : rx_rate;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
5358c2ecf20Sopenharmony_ci		rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	return rate_index;
5388c2ecf20Sopenharmony_ci}
539