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