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