162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NXP Wireless LAN device driver: Channel, Frequence and Power
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2011-2020 NXP
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "decl.h"
962306a36Sopenharmony_ci#include "ioctl.h"
1062306a36Sopenharmony_ci#include "util.h"
1162306a36Sopenharmony_ci#include "fw.h"
1262306a36Sopenharmony_ci#include "main.h"
1362306a36Sopenharmony_ci#include "cfg80211.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* 100mW */
1662306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_DEFAULT     20
1762306a36Sopenharmony_ci/* 100mW */
1862306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_US_DEFAULT      20
1962306a36Sopenharmony_ci/* 50mW */
2062306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_JP_DEFAULT      16
2162306a36Sopenharmony_ci/* 100mW */
2262306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_FR_100MW        20
2362306a36Sopenharmony_ci/* 10mW */
2462306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_FR_10MW         10
2562306a36Sopenharmony_ci/* 100mW */
2662306a36Sopenharmony_ci#define MWIFIEX_TX_PWR_EMEA_DEFAULT    20
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
3162306a36Sopenharmony_ci					       0xb0, 0x48, 0x60, 0x6c, 0 };
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
3462306a36Sopenharmony_ci						 0x0c, 0x12, 0x18, 0x24,
3562306a36Sopenharmony_ci						 0x30, 0x48, 0x60, 0x6c, 0 };
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
3862306a36Sopenharmony_ci					       0xb0, 0x48, 0x60, 0x6c, 0 };
3962306a36Sopenharmony_cistatic u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
4062306a36Sopenharmony_ci					0xb0, 0x48, 0x60, 0x6c, 0 };
4162306a36Sopenharmony_cistatic u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
4262306a36Sopenharmony_ci					0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
4362306a36Sopenharmony_ci					0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
4462306a36Sopenharmony_ci					0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
4562306a36Sopenharmony_ci					0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
4662306a36Sopenharmony_ci					0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
5162306a36Sopenharmony_ci					0x30, 0x48, 0x60, 0x6c, 0 };
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
5462306a36Sopenharmony_ci					0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
5562306a36Sopenharmony_ci					0x60, 0x6c, 0 };
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciu16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x00, 0x10, 0x20, 0x30,
5862306a36Sopenharmony_ci						0x31, 0x32, 0x40, 0x41, 0x50 };
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* For every mcs_rate line, the first 8 bytes are for stream 1x1,
6362306a36Sopenharmony_ci * and all 16 bytes are for stream 2x2.
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_cistatic const u16 mcs_rate[4][16] = {
6662306a36Sopenharmony_ci	/* LGI 40M */
6762306a36Sopenharmony_ci	{ 0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e,
6862306a36Sopenharmony_ci	  0x36, 0x6c, 0xa2, 0xd8, 0x144, 0x1b0, 0x1e6, 0x21c },
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* SGI 40M */
7162306a36Sopenharmony_ci	{ 0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c,
7262306a36Sopenharmony_ci	  0x3c, 0x78, 0xb4, 0xf0, 0x168, 0x1e0, 0x21c, 0x258 },
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* LGI 20M */
7562306a36Sopenharmony_ci	{ 0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82,
7662306a36Sopenharmony_ci	  0x1a, 0x34, 0x4e, 0x68, 0x9c, 0xd0, 0xea, 0x104 },
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* SGI 20M */
7962306a36Sopenharmony_ci	{ 0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90,
8062306a36Sopenharmony_ci	  0x1c, 0x39, 0x56, 0x73, 0xad, 0xe7, 0x104, 0x120 }
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* AC rates */
8462306a36Sopenharmony_cistatic const u16 ac_mcs_rate_nss1[8][10] = {
8562306a36Sopenharmony_ci	/* LG 160M */
8662306a36Sopenharmony_ci	{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
8762306a36Sopenharmony_ci	  0x492, 0x57C, 0x618 },
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* SG 160M */
9062306a36Sopenharmony_ci	{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
9162306a36Sopenharmony_ci	  0x514, 0x618, 0x6C6 },
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* LG 80M */
9462306a36Sopenharmony_ci	{ 0x3B, 0x75, 0xB0, 0xEA, 0x15F, 0x1D4, 0x20F,
9562306a36Sopenharmony_ci	  0x249, 0x2BE, 0x30C },
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* SG 80M */
9862306a36Sopenharmony_ci	{ 0x41, 0x82, 0xC3, 0x104, 0x186, 0x208, 0x249,
9962306a36Sopenharmony_ci	  0x28A, 0x30C, 0x363 },
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* LG 40M */
10262306a36Sopenharmony_ci	{ 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3,
10362306a36Sopenharmony_ci	  0x10E, 0x144, 0x168 },
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* SG 40M */
10662306a36Sopenharmony_ci	{ 0x1E, 0x3C, 0x5A, 0x78, 0xB4, 0xF0, 0x10E,
10762306a36Sopenharmony_ci	  0x12C, 0x168, 0x190 },
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* LG 20M */
11062306a36Sopenharmony_ci	{ 0xD, 0x1A, 0x27, 0x34, 0x4E, 0x68, 0x75, 0x82, 0x9C, 0x00 },
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* SG 20M */
11362306a36Sopenharmony_ci	{ 0xF, 0x1D, 0x2C, 0x3A, 0x57, 0x74, 0x82, 0x91, 0xAE, 0x00 },
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/* NSS2 note: the value in the table is 2 multiplier of the actual rate */
11762306a36Sopenharmony_cistatic const u16 ac_mcs_rate_nss2[8][10] = {
11862306a36Sopenharmony_ci	/* LG 160M */
11962306a36Sopenharmony_ci	{ 0xEA, 0x1D4, 0x2BE, 0x3A8, 0x57C, 0x750, 0x83A,
12062306a36Sopenharmony_ci	  0x924, 0xAF8, 0xC30 },
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* SG 160M */
12362306a36Sopenharmony_ci	{ 0x104, 0x208, 0x30C, 0x410, 0x618, 0x820, 0x924,
12462306a36Sopenharmony_ci	  0xA28, 0xC30, 0xD8B },
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* LG 80M */
12762306a36Sopenharmony_ci	{ 0x75, 0xEA, 0x15F, 0x1D4, 0x2BE, 0x3A8, 0x41D,
12862306a36Sopenharmony_ci	  0x492, 0x57C, 0x618 },
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* SG 80M */
13162306a36Sopenharmony_ci	{ 0x82, 0x104, 0x186, 0x208, 0x30C, 0x410, 0x492,
13262306a36Sopenharmony_ci	  0x514, 0x618, 0x6C6 },
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* LG 40M */
13562306a36Sopenharmony_ci	{ 0x36, 0x6C, 0xA2, 0xD8, 0x144, 0x1B0, 0x1E6,
13662306a36Sopenharmony_ci	  0x21C, 0x288, 0x2D0 },
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* SG 40M */
13962306a36Sopenharmony_ci	{ 0x3C, 0x78, 0xB4, 0xF0, 0x168, 0x1E0, 0x21C,
14062306a36Sopenharmony_ci	  0x258, 0x2D0, 0x320 },
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* LG 20M */
14362306a36Sopenharmony_ci	{ 0x1A, 0x34, 0x4A, 0x68, 0x9C, 0xD0, 0xEA, 0x104,
14462306a36Sopenharmony_ci	  0x138, 0x00 },
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* SG 20M */
14762306a36Sopenharmony_ci	{ 0x1D, 0x3A, 0x57, 0x74, 0xAE, 0xE6, 0x104, 0x121,
14862306a36Sopenharmony_ci	  0x15B, 0x00 },
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistruct region_code_mapping {
15262306a36Sopenharmony_ci	u8 code;
15362306a36Sopenharmony_ci	u8 region[IEEE80211_COUNTRY_STRING_LEN];
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic struct region_code_mapping region_code_mapping_t[] = {
15762306a36Sopenharmony_ci	{ 0x10, "US " }, /* US FCC */
15862306a36Sopenharmony_ci	{ 0x20, "CA " }, /* IC Canada */
15962306a36Sopenharmony_ci	{ 0x30, "FR " }, /* France */
16062306a36Sopenharmony_ci	{ 0x31, "ES " }, /* Spain */
16162306a36Sopenharmony_ci	{ 0x32, "FR " }, /* France */
16262306a36Sopenharmony_ci	{ 0x40, "JP " }, /* Japan */
16362306a36Sopenharmony_ci	{ 0x41, "JP " }, /* Japan */
16462306a36Sopenharmony_ci	{ 0x50, "CN " }, /* China */
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* This function converts integer code to region string */
16862306a36Sopenharmony_ciu8 *mwifiex_11d_code_2_region(u8 code)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	u8 i;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Look for code in mapping table */
17362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++)
17462306a36Sopenharmony_ci		if (region_code_mapping_t[i].code == code)
17562306a36Sopenharmony_ci			return region_code_mapping_t[i].region;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return NULL;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * This function maps an index in supported rates table into
18262306a36Sopenharmony_ci * the corresponding data rate.
18362306a36Sopenharmony_ci */
18462306a36Sopenharmony_ciu32 mwifiex_index_to_acs_data_rate(struct mwifiex_private *priv,
18562306a36Sopenharmony_ci				   u8 index, u8 ht_info)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	u32 rate = 0;
18862306a36Sopenharmony_ci	u8 mcs_index = 0;
18962306a36Sopenharmony_ci	u8 bw = 0;
19062306a36Sopenharmony_ci	u8 gi = 0;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_VHT) {
19362306a36Sopenharmony_ci		mcs_index = min(index & 0xF, 9);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		/* 20M: bw=0, 40M: bw=1, 80M: bw=2, 160M: bw=3 */
19662306a36Sopenharmony_ci		bw = (ht_info & 0xC) >> 2;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		/* LGI: gi =0, SGI: gi = 1 */
19962306a36Sopenharmony_ci		gi = (ht_info & 0x10) >> 4;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if ((index >> 4) == 1)	/* NSS = 2 */
20262306a36Sopenharmony_ci			rate = ac_mcs_rate_nss2[2 * (3 - bw) + gi][mcs_index];
20362306a36Sopenharmony_ci		else			/* NSS = 1 */
20462306a36Sopenharmony_ci			rate = ac_mcs_rate_nss1[2 * (3 - bw) + gi][mcs_index];
20562306a36Sopenharmony_ci	} else if ((ht_info & 0x3) == MWIFIEX_RATE_FORMAT_HT) {
20662306a36Sopenharmony_ci		/* 20M: bw=0, 40M: bw=1 */
20762306a36Sopenharmony_ci		bw = (ht_info & 0xC) >> 2;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		/* LGI: gi =0, SGI: gi = 1 */
21062306a36Sopenharmony_ci		gi = (ht_info & 0x10) >> 4;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
21362306a36Sopenharmony_ci			if (gi == 1)
21462306a36Sopenharmony_ci				rate = 0x0D;    /* MCS 32 SGI rate */
21562306a36Sopenharmony_ci			else
21662306a36Sopenharmony_ci				rate = 0x0C;    /* MCS 32 LGI rate */
21762306a36Sopenharmony_ci		} else if (index < 16) {
21862306a36Sopenharmony_ci			if ((bw == 1) || (bw == 0))
21962306a36Sopenharmony_ci				rate = mcs_rate[2 * (1 - bw) + gi][index];
22062306a36Sopenharmony_ci			else
22162306a36Sopenharmony_ci				rate = mwifiex_data_rates[0];
22262306a36Sopenharmony_ci		} else {
22362306a36Sopenharmony_ci			rate = mwifiex_data_rates[0];
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci	} else {
22662306a36Sopenharmony_ci		/* 11n non-HT rates */
22762306a36Sopenharmony_ci		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
22862306a36Sopenharmony_ci			index = 0;
22962306a36Sopenharmony_ci		rate = mwifiex_data_rates[index];
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return rate;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/* This function maps an index in supported rates table into
23662306a36Sopenharmony_ci * the corresponding data rate.
23762306a36Sopenharmony_ci */
23862306a36Sopenharmony_ciu32 mwifiex_index_to_data_rate(struct mwifiex_private *priv,
23962306a36Sopenharmony_ci			       u8 index, u8 ht_info)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	u32 mcs_num_supp =
24262306a36Sopenharmony_ci		(priv->adapter->user_dev_mcs_support == HT_STREAM_2X2) ? 16 : 8;
24362306a36Sopenharmony_ci	u32 rate;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (priv->adapter->is_hw_11ac_capable)
24662306a36Sopenharmony_ci		return mwifiex_index_to_acs_data_rate(priv, index, ht_info);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (ht_info & BIT(0)) {
24962306a36Sopenharmony_ci		if (index == MWIFIEX_RATE_BITMAP_MCS0) {
25062306a36Sopenharmony_ci			if (ht_info & BIT(2))
25162306a36Sopenharmony_ci				rate = 0x0D;	/* MCS 32 SGI rate */
25262306a36Sopenharmony_ci			else
25362306a36Sopenharmony_ci				rate = 0x0C;	/* MCS 32 LGI rate */
25462306a36Sopenharmony_ci		} else if (index < mcs_num_supp) {
25562306a36Sopenharmony_ci			if (ht_info & BIT(1)) {
25662306a36Sopenharmony_ci				if (ht_info & BIT(2))
25762306a36Sopenharmony_ci					/* SGI, 40M */
25862306a36Sopenharmony_ci					rate = mcs_rate[1][index];
25962306a36Sopenharmony_ci				else
26062306a36Sopenharmony_ci					/* LGI, 40M */
26162306a36Sopenharmony_ci					rate = mcs_rate[0][index];
26262306a36Sopenharmony_ci			} else {
26362306a36Sopenharmony_ci				if (ht_info & BIT(2))
26462306a36Sopenharmony_ci					/* SGI, 20M */
26562306a36Sopenharmony_ci					rate = mcs_rate[3][index];
26662306a36Sopenharmony_ci				else
26762306a36Sopenharmony_ci					/* LGI, 20M */
26862306a36Sopenharmony_ci					rate = mcs_rate[2][index];
26962306a36Sopenharmony_ci			}
27062306a36Sopenharmony_ci		} else
27162306a36Sopenharmony_ci			rate = mwifiex_data_rates[0];
27262306a36Sopenharmony_ci	} else {
27362306a36Sopenharmony_ci		if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
27462306a36Sopenharmony_ci			index = 0;
27562306a36Sopenharmony_ci		rate = mwifiex_data_rates[index];
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci	return rate;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/*
28162306a36Sopenharmony_ci * This function returns the current active data rates.
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * The result may vary depending upon connection status.
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_ciu32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (!priv->media_connected)
28862306a36Sopenharmony_ci		return mwifiex_get_supported_rates(priv, rates);
28962306a36Sopenharmony_ci	else
29062306a36Sopenharmony_ci		return mwifiex_copy_rates(rates, 0,
29162306a36Sopenharmony_ci					  priv->curr_bss_params.data_rates,
29262306a36Sopenharmony_ci					  priv->curr_bss_params.num_of_rates);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/*
29662306a36Sopenharmony_ci * This function locates the Channel-Frequency-Power triplet based upon
29762306a36Sopenharmony_ci * band and channel/frequency parameters.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_cistruct mwifiex_chan_freq_power *
30062306a36Sopenharmony_cimwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct mwifiex_chan_freq_power *cfp = NULL;
30362306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
30462306a36Sopenharmony_ci	struct ieee80211_channel *ch = NULL;
30562306a36Sopenharmony_ci	int i;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (!channel && !freq)
30862306a36Sopenharmony_ci		return cfp;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
31162306a36Sopenharmony_ci		sband = priv->wdev.wiphy->bands[NL80211_BAND_2GHZ];
31262306a36Sopenharmony_ci	else
31362306a36Sopenharmony_ci		sband = priv->wdev.wiphy->bands[NL80211_BAND_5GHZ];
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (!sband) {
31662306a36Sopenharmony_ci		mwifiex_dbg(priv->adapter, ERROR,
31762306a36Sopenharmony_ci			    "%s: cannot find cfp by band %d\n",
31862306a36Sopenharmony_ci			    __func__, band);
31962306a36Sopenharmony_ci		return cfp;
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	for (i = 0; i < sband->n_channels; i++) {
32362306a36Sopenharmony_ci		ch = &sband->channels[i];
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		if (ch->flags & IEEE80211_CHAN_DISABLED)
32662306a36Sopenharmony_ci			continue;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		if (freq) {
32962306a36Sopenharmony_ci			if (ch->center_freq == freq)
33062306a36Sopenharmony_ci				break;
33162306a36Sopenharmony_ci		} else {
33262306a36Sopenharmony_ci			/* find by valid channel*/
33362306a36Sopenharmony_ci			if (ch->hw_value == channel ||
33462306a36Sopenharmony_ci			    channel == FIRST_VALID_CHANNEL)
33562306a36Sopenharmony_ci				break;
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	if (i == sband->n_channels) {
33962306a36Sopenharmony_ci		mwifiex_dbg(priv->adapter, WARN,
34062306a36Sopenharmony_ci			    "%s: cannot find cfp by band %d\t"
34162306a36Sopenharmony_ci			    "& channel=%d freq=%d\n",
34262306a36Sopenharmony_ci			    __func__, band, channel, freq);
34362306a36Sopenharmony_ci	} else {
34462306a36Sopenharmony_ci		if (!ch)
34562306a36Sopenharmony_ci			return cfp;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci		priv->cfp.channel = ch->hw_value;
34862306a36Sopenharmony_ci		priv->cfp.freq = ch->center_freq;
34962306a36Sopenharmony_ci		priv->cfp.max_tx_power = ch->max_power;
35062306a36Sopenharmony_ci		cfp = &priv->cfp;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return cfp;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/*
35762306a36Sopenharmony_ci * This function checks if the data rate is set to auto.
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_ciu8
36062306a36Sopenharmony_cimwifiex_is_rate_auto(struct mwifiex_private *priv)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	u32 i;
36362306a36Sopenharmony_ci	int rate_num = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
36662306a36Sopenharmony_ci		if (priv->bitmap_rates[i])
36762306a36Sopenharmony_ci			rate_num++;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (rate_num > 1)
37062306a36Sopenharmony_ci		return true;
37162306a36Sopenharmony_ci	else
37262306a36Sopenharmony_ci		return false;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci/* This function gets the supported data rates from bitmask inside
37662306a36Sopenharmony_ci * cfg80211_scan_request.
37762306a36Sopenharmony_ci */
37862306a36Sopenharmony_ciu32 mwifiex_get_rates_from_cfg80211(struct mwifiex_private *priv,
37962306a36Sopenharmony_ci				    u8 *rates, u8 radio_type)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	struct wiphy *wiphy = priv->adapter->wiphy;
38262306a36Sopenharmony_ci	struct cfg80211_scan_request *request = priv->scan_request;
38362306a36Sopenharmony_ci	u32 num_rates, rate_mask;
38462306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
38562306a36Sopenharmony_ci	int i;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (radio_type) {
38862306a36Sopenharmony_ci		sband = wiphy->bands[NL80211_BAND_5GHZ];
38962306a36Sopenharmony_ci		if (WARN_ON_ONCE(!sband))
39062306a36Sopenharmony_ci			return 0;
39162306a36Sopenharmony_ci		rate_mask = request->rates[NL80211_BAND_5GHZ];
39262306a36Sopenharmony_ci	} else {
39362306a36Sopenharmony_ci		sband = wiphy->bands[NL80211_BAND_2GHZ];
39462306a36Sopenharmony_ci		if (WARN_ON_ONCE(!sband))
39562306a36Sopenharmony_ci			return 0;
39662306a36Sopenharmony_ci		rate_mask = request->rates[NL80211_BAND_2GHZ];
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	num_rates = 0;
40062306a36Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
40162306a36Sopenharmony_ci		if ((BIT(i) & rate_mask) == 0)
40262306a36Sopenharmony_ci			continue; /* skip rate */
40362306a36Sopenharmony_ci		rates[num_rates++] = (u8)(sband->bitrates[i].bitrate / 5);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	return num_rates;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci/* This function gets the supported data rates. The function works in
41062306a36Sopenharmony_ci * both Ad-Hoc and infra mode by printing the band and returning the
41162306a36Sopenharmony_ci * data rates.
41262306a36Sopenharmony_ci */
41362306a36Sopenharmony_ciu32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	u32 k = 0;
41662306a36Sopenharmony_ci	struct mwifiex_adapter *adapter = priv->adapter;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (priv->bss_mode == NL80211_IFTYPE_STATION ||
41962306a36Sopenharmony_ci	    priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
42062306a36Sopenharmony_ci		switch (adapter->config_bands) {
42162306a36Sopenharmony_ci		case BAND_B:
42262306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
42362306a36Sopenharmony_ci				    "supported_rates_b\n",
42462306a36Sopenharmony_ci				    adapter->config_bands);
42562306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_b,
42662306a36Sopenharmony_ci					       sizeof(supported_rates_b));
42762306a36Sopenharmony_ci			break;
42862306a36Sopenharmony_ci		case BAND_G:
42962306a36Sopenharmony_ci		case BAND_G | BAND_GN:
43062306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
43162306a36Sopenharmony_ci				    "supported_rates_g\n",
43262306a36Sopenharmony_ci				    adapter->config_bands);
43362306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_g,
43462306a36Sopenharmony_ci					       sizeof(supported_rates_g));
43562306a36Sopenharmony_ci			break;
43662306a36Sopenharmony_ci		case BAND_B | BAND_G:
43762306a36Sopenharmony_ci		case BAND_A | BAND_B | BAND_G:
43862306a36Sopenharmony_ci		case BAND_A | BAND_B:
43962306a36Sopenharmony_ci		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
44062306a36Sopenharmony_ci		case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN | BAND_AAC:
44162306a36Sopenharmony_ci		case BAND_B | BAND_G | BAND_GN:
44262306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
44362306a36Sopenharmony_ci				    "supported_rates_bg\n",
44462306a36Sopenharmony_ci				    adapter->config_bands);
44562306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_bg,
44662306a36Sopenharmony_ci					       sizeof(supported_rates_bg));
44762306a36Sopenharmony_ci			break;
44862306a36Sopenharmony_ci		case BAND_A:
44962306a36Sopenharmony_ci		case BAND_A | BAND_G:
45062306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
45162306a36Sopenharmony_ci				    "supported_rates_a\n",
45262306a36Sopenharmony_ci				    adapter->config_bands);
45362306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_a,
45462306a36Sopenharmony_ci					       sizeof(supported_rates_a));
45562306a36Sopenharmony_ci			break;
45662306a36Sopenharmony_ci		case BAND_AN:
45762306a36Sopenharmony_ci		case BAND_A | BAND_AN:
45862306a36Sopenharmony_ci		case BAND_A | BAND_AN | BAND_AAC:
45962306a36Sopenharmony_ci		case BAND_A | BAND_G | BAND_AN | BAND_GN:
46062306a36Sopenharmony_ci		case BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC:
46162306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
46262306a36Sopenharmony_ci				    "supported_rates_a\n",
46362306a36Sopenharmony_ci				    adapter->config_bands);
46462306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_a,
46562306a36Sopenharmony_ci					       sizeof(supported_rates_a));
46662306a36Sopenharmony_ci			break;
46762306a36Sopenharmony_ci		case BAND_GN:
46862306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: infra band=%d\t"
46962306a36Sopenharmony_ci				    "supported_rates_n\n",
47062306a36Sopenharmony_ci				    adapter->config_bands);
47162306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, supported_rates_n,
47262306a36Sopenharmony_ci					       sizeof(supported_rates_n));
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	} else {
47662306a36Sopenharmony_ci		/* Ad-hoc mode */
47762306a36Sopenharmony_ci		switch (adapter->adhoc_start_band) {
47862306a36Sopenharmony_ci		case BAND_B:
47962306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc B\n");
48062306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
48162306a36Sopenharmony_ci					       sizeof(adhoc_rates_b));
48262306a36Sopenharmony_ci			break;
48362306a36Sopenharmony_ci		case BAND_G:
48462306a36Sopenharmony_ci		case BAND_G | BAND_GN:
48562306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc G only\n");
48662306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
48762306a36Sopenharmony_ci					       sizeof(adhoc_rates_g));
48862306a36Sopenharmony_ci			break;
48962306a36Sopenharmony_ci		case BAND_B | BAND_G:
49062306a36Sopenharmony_ci		case BAND_B | BAND_G | BAND_GN:
49162306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc BG\n");
49262306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
49362306a36Sopenharmony_ci					       sizeof(adhoc_rates_bg));
49462306a36Sopenharmony_ci			break;
49562306a36Sopenharmony_ci		case BAND_A:
49662306a36Sopenharmony_ci		case BAND_A | BAND_AN:
49762306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO, "info: adhoc A\n");
49862306a36Sopenharmony_ci			k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
49962306a36Sopenharmony_ci					       sizeof(adhoc_rates_a));
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return k;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ciu8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
50862306a36Sopenharmony_ci			    u8 rx_rate, u8 rate_info)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	u8 rate_index = 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* HT40 */
51362306a36Sopenharmony_ci	if ((rate_info & BIT(0)) && (rate_info & BIT(1)))
51462306a36Sopenharmony_ci		rate_index = MWIFIEX_RATE_INDEX_MCS0 +
51562306a36Sopenharmony_ci			     MWIFIEX_BW20_MCS_NUM + rx_rate;
51662306a36Sopenharmony_ci	else if (rate_info & BIT(0)) /* HT20 */
51762306a36Sopenharmony_ci		rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate;
51862306a36Sopenharmony_ci	else
51962306a36Sopenharmony_ci		rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
52062306a36Sopenharmony_ci			      rx_rate - 1 : rx_rate;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (rate_index >= MWIFIEX_MAX_AC_RX_RATES)
52362306a36Sopenharmony_ci		rate_index = MWIFIEX_MAX_AC_RX_RATES - 1;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return rate_index;
52662306a36Sopenharmony_ci}
527