18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2014 Redpine Signals Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 188c2ecf20Sopenharmony_ci#include "rsi_debugfs.h" 198c2ecf20Sopenharmony_ci#include "rsi_mgmt.h" 208c2ecf20Sopenharmony_ci#include "rsi_sdio.h" 218c2ecf20Sopenharmony_ci#include "rsi_common.h" 228c2ecf20Sopenharmony_ci#include "rsi_ps.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic const struct ieee80211_channel rsi_2ghz_channels[] = { 258c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2412, 268c2ecf20Sopenharmony_ci .hw_value = 1 }, /* Channel 1 */ 278c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2417, 288c2ecf20Sopenharmony_ci .hw_value = 2 }, /* Channel 2 */ 298c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2422, 308c2ecf20Sopenharmony_ci .hw_value = 3 }, /* Channel 3 */ 318c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2427, 328c2ecf20Sopenharmony_ci .hw_value = 4 }, /* Channel 4 */ 338c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2432, 348c2ecf20Sopenharmony_ci .hw_value = 5 }, /* Channel 5 */ 358c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2437, 368c2ecf20Sopenharmony_ci .hw_value = 6 }, /* Channel 6 */ 378c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2442, 388c2ecf20Sopenharmony_ci .hw_value = 7 }, /* Channel 7 */ 398c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2447, 408c2ecf20Sopenharmony_ci .hw_value = 8 }, /* Channel 8 */ 418c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2452, 428c2ecf20Sopenharmony_ci .hw_value = 9 }, /* Channel 9 */ 438c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2457, 448c2ecf20Sopenharmony_ci .hw_value = 10 }, /* Channel 10 */ 458c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2462, 468c2ecf20Sopenharmony_ci .hw_value = 11 }, /* Channel 11 */ 478c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2467, 488c2ecf20Sopenharmony_ci .hw_value = 12 }, /* Channel 12 */ 498c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2472, 508c2ecf20Sopenharmony_ci .hw_value = 13 }, /* Channel 13 */ 518c2ecf20Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2484, 528c2ecf20Sopenharmony_ci .hw_value = 14 }, /* Channel 14 */ 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct ieee80211_channel rsi_5ghz_channels[] = { 568c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5180, 578c2ecf20Sopenharmony_ci .hw_value = 36, }, /* Channel 36 */ 588c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5200, 598c2ecf20Sopenharmony_ci .hw_value = 40, }, /* Channel 40 */ 608c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5220, 618c2ecf20Sopenharmony_ci .hw_value = 44, }, /* Channel 44 */ 628c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5240, 638c2ecf20Sopenharmony_ci .hw_value = 48, }, /* Channel 48 */ 648c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5260, 658c2ecf20Sopenharmony_ci .hw_value = 52, }, /* Channel 52 */ 668c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5280, 678c2ecf20Sopenharmony_ci .hw_value = 56, }, /* Channel 56 */ 688c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5300, 698c2ecf20Sopenharmony_ci .hw_value = 60, }, /* Channel 60 */ 708c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5320, 718c2ecf20Sopenharmony_ci .hw_value = 64, }, /* Channel 64 */ 728c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5500, 738c2ecf20Sopenharmony_ci .hw_value = 100, }, /* Channel 100 */ 748c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5520, 758c2ecf20Sopenharmony_ci .hw_value = 104, }, /* Channel 104 */ 768c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5540, 778c2ecf20Sopenharmony_ci .hw_value = 108, }, /* Channel 108 */ 788c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5560, 798c2ecf20Sopenharmony_ci .hw_value = 112, }, /* Channel 112 */ 808c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5580, 818c2ecf20Sopenharmony_ci .hw_value = 116, }, /* Channel 116 */ 828c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5600, 838c2ecf20Sopenharmony_ci .hw_value = 120, }, /* Channel 120 */ 848c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5620, 858c2ecf20Sopenharmony_ci .hw_value = 124, }, /* Channel 124 */ 868c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5640, 878c2ecf20Sopenharmony_ci .hw_value = 128, }, /* Channel 128 */ 888c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5660, 898c2ecf20Sopenharmony_ci .hw_value = 132, }, /* Channel 132 */ 908c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5680, 918c2ecf20Sopenharmony_ci .hw_value = 136, }, /* Channel 136 */ 928c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5700, 938c2ecf20Sopenharmony_ci .hw_value = 140, }, /* Channel 140 */ 948c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5745, 958c2ecf20Sopenharmony_ci .hw_value = 149, }, /* Channel 149 */ 968c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5765, 978c2ecf20Sopenharmony_ci .hw_value = 153, }, /* Channel 153 */ 988c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5785, 998c2ecf20Sopenharmony_ci .hw_value = 157, }, /* Channel 157 */ 1008c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5805, 1018c2ecf20Sopenharmony_ci .hw_value = 161, }, /* Channel 161 */ 1028c2ecf20Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5825, 1038c2ecf20Sopenharmony_ci .hw_value = 165, }, /* Channel 165 */ 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct ieee80211_rate rsi_rates[12] = { 1078c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 }, 1088c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 }, 1098c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 }, 1108c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 }, 1118c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 }, 1128c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 }, 1138c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 }, 1148c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 }, 1158c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 }, 1168c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 }, 1178c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 }, 1188c2ecf20Sopenharmony_ci { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 }, 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciconst u16 rsi_mcsrates[8] = { 1228c2ecf20Sopenharmony_ci RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3, 1238c2ecf20Sopenharmony_ci RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 1248c2ecf20Sopenharmony_ci}; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic const u32 rsi_max_ap_stas[16] = { 1278c2ecf20Sopenharmony_ci 32, /* 1 - Wi-Fi alone */ 1288c2ecf20Sopenharmony_ci 0, /* 2 */ 1298c2ecf20Sopenharmony_ci 0, /* 3 */ 1308c2ecf20Sopenharmony_ci 0, /* 4 - BT EDR alone */ 1318c2ecf20Sopenharmony_ci 4, /* 5 - STA + BT EDR */ 1328c2ecf20Sopenharmony_ci 32, /* 6 - AP + BT EDR */ 1338c2ecf20Sopenharmony_ci 0, /* 7 */ 1348c2ecf20Sopenharmony_ci 0, /* 8 - BT LE alone */ 1358c2ecf20Sopenharmony_ci 4, /* 9 - STA + BE LE */ 1368c2ecf20Sopenharmony_ci 0, /* 10 */ 1378c2ecf20Sopenharmony_ci 0, /* 11 */ 1388c2ecf20Sopenharmony_ci 0, /* 12 */ 1398c2ecf20Sopenharmony_ci 1, /* 13 - STA + BT Dual */ 1408c2ecf20Sopenharmony_ci 4, /* 14 - AP + BT Dual */ 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_limit rsi_iface_limits[] = { 1448c2ecf20Sopenharmony_ci { 1458c2ecf20Sopenharmony_ci .max = 1, 1468c2ecf20Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci .max = 1, 1508c2ecf20Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) | 1518c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 1528c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO), 1538c2ecf20Sopenharmony_ci }, 1548c2ecf20Sopenharmony_ci { 1558c2ecf20Sopenharmony_ci .max = 1, 1568c2ecf20Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_DEVICE), 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_combination rsi_iface_combinations[] = { 1618c2ecf20Sopenharmony_ci { 1628c2ecf20Sopenharmony_ci .num_different_channels = 1, 1638c2ecf20Sopenharmony_ci .max_interfaces = 3, 1648c2ecf20Sopenharmony_ci .limits = rsi_iface_limits, 1658c2ecf20Sopenharmony_ci .n_limits = ARRAY_SIZE(rsi_iface_limits), 1668c2ecf20Sopenharmony_ci }, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/** 1708c2ecf20Sopenharmony_ci * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. 1718c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * Return: If cipher type is WEP, a value of 1 is returned, else 0. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cibool rsi_is_cipher_wep(struct rsi_common *common) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) || 1798c2ecf20Sopenharmony_ci (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) && 1808c2ecf20Sopenharmony_ci (!common->secinfo.ptk_cipher)) 1818c2ecf20Sopenharmony_ci return true; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci return false; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * rsi_register_rates_channels() - This function registers channels and rates. 1888c2ecf20Sopenharmony_ci * @adapter: Pointer to the adapter structure. 1898c2ecf20Sopenharmony_ci * @band: Operating band to be set. 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * Return: int - 0 on success, negative error on failure. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_cistatic int rsi_register_rates_channels(struct rsi_hw *adapter, int band) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sbands = &adapter->sbands[band]; 1968c2ecf20Sopenharmony_ci void *channels = NULL; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (band == NL80211_BAND_2GHZ) { 1998c2ecf20Sopenharmony_ci channels = kmemdup(rsi_2ghz_channels, sizeof(rsi_2ghz_channels), 2008c2ecf20Sopenharmony_ci GFP_KERNEL); 2018c2ecf20Sopenharmony_ci if (!channels) 2028c2ecf20Sopenharmony_ci return -ENOMEM; 2038c2ecf20Sopenharmony_ci sbands->band = NL80211_BAND_2GHZ; 2048c2ecf20Sopenharmony_ci sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels); 2058c2ecf20Sopenharmony_ci sbands->bitrates = rsi_rates; 2068c2ecf20Sopenharmony_ci sbands->n_bitrates = ARRAY_SIZE(rsi_rates); 2078c2ecf20Sopenharmony_ci } else { 2088c2ecf20Sopenharmony_ci channels = kmemdup(rsi_5ghz_channels, sizeof(rsi_5ghz_channels), 2098c2ecf20Sopenharmony_ci GFP_KERNEL); 2108c2ecf20Sopenharmony_ci if (!channels) 2118c2ecf20Sopenharmony_ci return -ENOMEM; 2128c2ecf20Sopenharmony_ci sbands->band = NL80211_BAND_5GHZ; 2138c2ecf20Sopenharmony_ci sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels); 2148c2ecf20Sopenharmony_ci sbands->bitrates = &rsi_rates[4]; 2158c2ecf20Sopenharmony_ci sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci sbands->channels = channels; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap)); 2218c2ecf20Sopenharmony_ci sbands->ht_cap.ht_supported = true; 2228c2ecf20Sopenharmony_ci sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 2238c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 2248c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_40); 2258c2ecf20Sopenharmony_ci sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; 2268c2ecf20Sopenharmony_ci sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 2278c2ecf20Sopenharmony_ci sbands->ht_cap.mcs.rx_mask[0] = 0xff; 2288c2ecf20Sopenharmony_ci sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 2298c2ecf20Sopenharmony_ci /* sbands->ht_cap.mcs.rx_highest = 0x82; */ 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, 2348c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 2358c2ecf20Sopenharmony_ci struct ieee80211_scan_request *hw_req) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct cfg80211_scan_request *scan_req = &hw_req->req; 2388c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 2398c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 2408c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss = &vif->bss_conf; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Hardware scan start *****\n"); 2438c2ecf20Sopenharmony_ci common->mac_ops_resumed = false; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (common->fsm_state != FSM_MAC_INIT_DONE) 2468c2ecf20Sopenharmony_ci return -ENODEV; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if ((common->wow_flags & RSI_WOW_ENABLED) || 2498c2ecf20Sopenharmony_ci scan_req->n_channels == 0) 2508c2ecf20Sopenharmony_ci return -EINVAL; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* Scan already in progress. So return */ 2538c2ecf20Sopenharmony_ci if (common->bgscan_en) 2548c2ecf20Sopenharmony_ci return -EBUSY; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* If STA is not connected, return with special value 1, in order 2578c2ecf20Sopenharmony_ci * to start sw_scan in mac80211 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci if (!bss->assoc) 2608c2ecf20Sopenharmony_ci return 1; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 2638c2ecf20Sopenharmony_ci common->hwscan = scan_req; 2648c2ecf20Sopenharmony_ci if (!rsi_send_bgscan_params(common, RSI_START_BGSCAN)) { 2658c2ecf20Sopenharmony_ci if (!rsi_send_bgscan_probe_req(common, vif)) { 2668c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Background scan started...\n"); 2678c2ecf20Sopenharmony_ci common->bgscan_en = true; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void rsi_mac80211_cancel_hw_scan(struct ieee80211_hw *hw, 2768c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 2798c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 2808c2ecf20Sopenharmony_ci struct cfg80211_scan_info info; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Hardware scan stop *****\n"); 2838c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (common->bgscan_en) { 2868c2ecf20Sopenharmony_ci if (!rsi_send_bgscan_params(common, RSI_STOP_BGSCAN)) 2878c2ecf20Sopenharmony_ci common->bgscan_en = false; 2888c2ecf20Sopenharmony_ci info.aborted = false; 2898c2ecf20Sopenharmony_ci ieee80211_scan_completed(adapter->hw, &info); 2908c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Back ground scan cancelled\n"); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci common->hwscan = NULL; 2938c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/** 2978c2ecf20Sopenharmony_ci * rsi_mac80211_detach() - This function is used to de-initialize the 2988c2ecf20Sopenharmony_ci * Mac80211 stack. 2998c2ecf20Sopenharmony_ci * @adapter: Pointer to the adapter structure. 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Return: None. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_civoid rsi_mac80211_detach(struct rsi_hw *adapter) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = adapter->hw; 3068c2ecf20Sopenharmony_ci enum nl80211_band band; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (hw) { 3098c2ecf20Sopenharmony_ci ieee80211_stop_queues(hw); 3108c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 3118c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 3128c2ecf20Sopenharmony_ci adapter->hw = NULL; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 3168c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = 3178c2ecf20Sopenharmony_ci &adapter->sbands[band]; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci kfree(sband->channels); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci#ifdef CONFIG_RSI_DEBUGFS 3238c2ecf20Sopenharmony_ci rsi_remove_dbgfs(adapter); 3248c2ecf20Sopenharmony_ci kfree(adapter->dfsentry); 3258c2ecf20Sopenharmony_ci#endif 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rsi_mac80211_detach); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/** 3308c2ecf20Sopenharmony_ci * rsi_indicate_tx_status() - This function indicates the transmit status. 3318c2ecf20Sopenharmony_ci * @adapter: Pointer to the adapter structure. 3328c2ecf20Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 3338c2ecf20Sopenharmony_ci * @status: Status 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * Return: None. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_civoid rsi_indicate_tx_status(struct rsi_hw *adapter, 3388c2ecf20Sopenharmony_ci struct sk_buff *skb, 3398c2ecf20Sopenharmony_ci int status) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 3428c2ecf20Sopenharmony_ci struct skb_info *tx_params; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!adapter->hw) { 3458c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "##### No MAC #####\n"); 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!status) 3508c2ecf20Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci tx_params = (struct skb_info *)info->driver_data; 3538c2ecf20Sopenharmony_ci skb_pull(skb, tx_params->internal_hdr_size); 3548c2ecf20Sopenharmony_ci memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci ieee80211_tx_status_irqsafe(adapter->hw, skb); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci/** 3608c2ecf20Sopenharmony_ci * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each 3618c2ecf20Sopenharmony_ci * transmitted frame.SKB contains the buffer starting 3628c2ecf20Sopenharmony_ci * from the IEEE 802.11 header. 3638c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 3648c2ecf20Sopenharmony_ci * @control: Pointer to the ieee80211_tx_control structure 3658c2ecf20Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 3668c2ecf20Sopenharmony_ci * 3678c2ecf20Sopenharmony_ci * Return: None 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic void rsi_mac80211_tx(struct ieee80211_hw *hw, 3708c2ecf20Sopenharmony_ci struct ieee80211_tx_control *control, 3718c2ecf20Sopenharmony_ci struct sk_buff *skb) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 3748c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 3758c2ecf20Sopenharmony_ci struct ieee80211_hdr *wlh = (struct ieee80211_hdr *)skb->data; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (ieee80211_is_auth(wlh->frame_control)) 3788c2ecf20Sopenharmony_ci common->mac_ops_resumed = false; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci rsi_core_xmit(common, skb); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * rsi_mac80211_start() - This is first handler that 802.11 module calls, since 3858c2ecf20Sopenharmony_ci * the driver init is complete by then, just 3868c2ecf20Sopenharmony_ci * returns success. 3878c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * Return: 0 as success. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_cistatic int rsi_mac80211_start(struct ieee80211_hw *hw) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 3948c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "===> Interface UP <===\n"); 3978c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 3988c2ecf20Sopenharmony_ci if (common->hibernate_resume) { 3998c2ecf20Sopenharmony_ci common->reinit_hw = true; 4008c2ecf20Sopenharmony_ci adapter->host_intf_ops->reinit_device(adapter); 4018c2ecf20Sopenharmony_ci wait_for_completion(&adapter->priv->wlan_init_completion); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci common->iface_down = false; 4048c2ecf20Sopenharmony_ci wiphy_rfkill_start_polling(hw->wiphy); 4058c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, 0); 4068c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/** 4128c2ecf20Sopenharmony_ci * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. 4138c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 4148c2ecf20Sopenharmony_ci * 4158c2ecf20Sopenharmony_ci * Return: None. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_cistatic void rsi_mac80211_stop(struct ieee80211_hw *hw) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 4208c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); 4238c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 4248c2ecf20Sopenharmony_ci common->iface_down = true; 4258c2ecf20Sopenharmony_ci wiphy_rfkill_stop_polling(hw->wiphy); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Block all rx frames */ 4288c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, 0xffff); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int rsi_map_intf_mode(enum nl80211_iftype vif_type) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci switch (vif_type) { 4368c2ecf20Sopenharmony_ci case NL80211_IFTYPE_STATION: 4378c2ecf20Sopenharmony_ci return RSI_OPMODE_STA; 4388c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 4398c2ecf20Sopenharmony_ci return RSI_OPMODE_AP; 4408c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 4418c2ecf20Sopenharmony_ci return RSI_OPMODE_P2P_CLIENT; 4428c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 4438c2ecf20Sopenharmony_ci return RSI_OPMODE_P2P_CLIENT; 4448c2ecf20Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 4458c2ecf20Sopenharmony_ci return RSI_OPMODE_P2P_GO; 4468c2ecf20Sopenharmony_ci default: 4478c2ecf20Sopenharmony_ci return RSI_OPMODE_UNSUPPORTED; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci/** 4528c2ecf20Sopenharmony_ci * rsi_mac80211_add_interface() - This function is called when a netdevice 4538c2ecf20Sopenharmony_ci * attached to the hardware is enabled. 4548c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 4558c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 4568c2ecf20Sopenharmony_ci * 4578c2ecf20Sopenharmony_ci * Return: ret: 0 on success, negative error code on failure. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic int rsi_mac80211_add_interface(struct ieee80211_hw *hw, 4608c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 4638c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 4648c2ecf20Sopenharmony_ci struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; 4658c2ecf20Sopenharmony_ci enum opmode intf_mode; 4668c2ecf20Sopenharmony_ci enum vap_status vap_status; 4678c2ecf20Sopenharmony_ci int vap_idx = -1, i; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; 4708c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci intf_mode = rsi_map_intf_mode(vif->type); 4738c2ecf20Sopenharmony_ci if (intf_mode == RSI_OPMODE_UNSUPPORTED) { 4748c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 4758c2ecf20Sopenharmony_ci "%s: Interface type %d not supported\n", __func__, 4768c2ecf20Sopenharmony_ci vif->type); 4778c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 4788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_P2P_DEVICE) || 4818c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT) || 4828c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 4838c2ecf20Sopenharmony_ci common->p2p_enabled = true; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Get free vap index */ 4868c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 4878c2ecf20Sopenharmony_ci if (!adapter->vifs[i] || 4888c2ecf20Sopenharmony_ci !memcmp(vif->addr, adapter->vifs[i]->addr, ETH_ALEN)) { 4898c2ecf20Sopenharmony_ci vap_idx = i; 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci if (vap_idx < 0) { 4948c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Reject: Max VAPs reached\n"); 4958c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 4968c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci vif_info->vap_id = vap_idx; 4998c2ecf20Sopenharmony_ci adapter->vifs[vap_idx] = vif; 5008c2ecf20Sopenharmony_ci adapter->sc_nvifs++; 5018c2ecf20Sopenharmony_ci vap_status = VAP_ADD; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (rsi_set_vap_capabilities(common, intf_mode, vif->addr, 5048c2ecf20Sopenharmony_ci vif_info->vap_id, vap_status)) { 5058c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n"); 5068c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 5118c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 5128c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, DISALLOW_BEACONS); 5138c2ecf20Sopenharmony_ci for (i = 0; i < common->max_stations; i++) 5148c2ecf20Sopenharmony_ci common->stations[i].sta = NULL; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/** 5238c2ecf20Sopenharmony_ci * rsi_mac80211_remove_interface() - This function notifies driver that an 5248c2ecf20Sopenharmony_ci * interface is going down. 5258c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 5268c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Return: None. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cistatic void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, 5318c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 5348c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 5358c2ecf20Sopenharmony_ci enum opmode opmode; 5368c2ecf20Sopenharmony_ci int i; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Remove Interface Called\n"); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (adapter->sc_nvifs <= 0) { 5438c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 5448c2ecf20Sopenharmony_ci return; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci opmode = rsi_map_intf_mode(vif->type); 5488c2ecf20Sopenharmony_ci if (opmode == RSI_OPMODE_UNSUPPORTED) { 5498c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Opmode error : %d\n", opmode); 5508c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 5548c2ecf20Sopenharmony_ci if (!adapter->vifs[i]) 5558c2ecf20Sopenharmony_ci continue; 5568c2ecf20Sopenharmony_ci if (vif == adapter->vifs[i]) { 5578c2ecf20Sopenharmony_ci rsi_set_vap_capabilities(common, opmode, vif->addr, 5588c2ecf20Sopenharmony_ci i, VAP_DELETE); 5598c2ecf20Sopenharmony_ci adapter->sc_nvifs--; 5608c2ecf20Sopenharmony_ci adapter->vifs[i] = NULL; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/** 5678c2ecf20Sopenharmony_ci * rsi_channel_change() - This function is a performs the checks 5688c2ecf20Sopenharmony_ci * required for changing a channel and sets 5698c2ecf20Sopenharmony_ci * the channel accordingly. 5708c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code on failure. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_cistatic int rsi_channel_change(struct ieee80211_hw *hw) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 5778c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 5788c2ecf20Sopenharmony_ci int status = -EOPNOTSUPP; 5798c2ecf20Sopenharmony_ci struct ieee80211_channel *curchan = hw->conf.chandef.chan; 5808c2ecf20Sopenharmony_ci u16 channel = curchan->hw_value; 5818c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 5828c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss; 5838c2ecf20Sopenharmony_ci bool assoc = false; 5848c2ecf20Sopenharmony_ci int i; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 5878c2ecf20Sopenharmony_ci "%s: Set channel: %d MHz type: %d channel_no %d\n", 5888c2ecf20Sopenharmony_ci __func__, curchan->center_freq, 5898c2ecf20Sopenharmony_ci curchan->flags, channel); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 5928c2ecf20Sopenharmony_ci vif = adapter->vifs[i]; 5938c2ecf20Sopenharmony_ci if (!vif) 5948c2ecf20Sopenharmony_ci continue; 5958c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 5968c2ecf20Sopenharmony_ci bss = &vif->bss_conf; 5978c2ecf20Sopenharmony_ci if (bss->assoc) { 5988c2ecf20Sopenharmony_ci assoc = true; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci if (assoc) { 6048c2ecf20Sopenharmony_ci if (!common->hw_data_qs_blocked && 6058c2ecf20Sopenharmony_ci (rsi_get_connected_channel(vif) != channel)) { 6068c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); 6078c2ecf20Sopenharmony_ci if (!rsi_send_block_unblock_frame(common, true)) 6088c2ecf20Sopenharmony_ci common->hw_data_qs_blocked = true; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci status = rsi_band_check(common, curchan); 6138c2ecf20Sopenharmony_ci if (!status) 6148c2ecf20Sopenharmony_ci status = rsi_set_channel(adapter->priv, curchan); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (assoc) { 6178c2ecf20Sopenharmony_ci if (common->hw_data_qs_blocked && 6188c2ecf20Sopenharmony_ci (rsi_get_connected_channel(vif) == channel)) { 6198c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); 6208c2ecf20Sopenharmony_ci if (!rsi_send_block_unblock_frame(common, false)) 6218c2ecf20Sopenharmony_ci common->hw_data_qs_blocked = false; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return status; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/** 6298c2ecf20Sopenharmony_ci * rsi_config_power() - This function configures tx power to device 6308c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 6318c2ecf20Sopenharmony_ci * 6328c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code on failure. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_cistatic int rsi_config_power(struct ieee80211_hw *hw) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 6378c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 6388c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (adapter->sc_nvifs <= 0) { 6418c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: No virtual interface found\n", __func__); 6428c2ecf20Sopenharmony_ci return -EINVAL; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 6468c2ecf20Sopenharmony_ci "%s: Set tx power: %d dBM\n", __func__, conf->power_level); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (conf->power_level == common->tx_power) 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci common->tx_power = conf->power_level; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return rsi_send_radio_params_update(common); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/** 6578c2ecf20Sopenharmony_ci * rsi_mac80211_config() - This function is a handler for configuration 6588c2ecf20Sopenharmony_ci * requests. The stack calls this function to 6598c2ecf20Sopenharmony_ci * change hardware configuration, e.g., channel. 6608c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 6618c2ecf20Sopenharmony_ci * @changed: Changed flags set. 6628c2ecf20Sopenharmony_ci * 6638c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code on failure. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cistatic int rsi_mac80211_config(struct ieee80211_hw *hw, 6668c2ecf20Sopenharmony_ci u32 changed) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 6698c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 6708c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 6718c2ecf20Sopenharmony_ci int status = -EOPNOTSUPP; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) 6768c2ecf20Sopenharmony_ci status = rsi_channel_change(hw); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* tx power */ 6798c2ecf20Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_POWER) { 6808c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Configuring Power\n", __func__); 6818c2ecf20Sopenharmony_ci status = rsi_config_power(hw); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Power save parameters */ 6858c2ecf20Sopenharmony_ci if ((changed & IEEE80211_CONF_CHANGE_PS) && 6868c2ecf20Sopenharmony_ci !common->mac_ops_resumed) { 6878c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, *sta_vif = NULL; 6888c2ecf20Sopenharmony_ci unsigned long flags; 6898c2ecf20Sopenharmony_ci int i, set_ps = 1; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 6928c2ecf20Sopenharmony_ci vif = adapter->vifs[i]; 6938c2ecf20Sopenharmony_ci if (!vif) 6948c2ecf20Sopenharmony_ci continue; 6958c2ecf20Sopenharmony_ci /* Don't go to power save if AP vap exists */ 6968c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 6978c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 6988c2ecf20Sopenharmony_ci set_ps = 0; 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION || 7028c2ecf20Sopenharmony_ci vif->type == NL80211_IFTYPE_P2P_CLIENT) && 7038c2ecf20Sopenharmony_ci (!sta_vif || vif->bss_conf.assoc)) 7048c2ecf20Sopenharmony_ci sta_vif = vif; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci if (set_ps && sta_vif) { 7078c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->ps_lock, flags); 7088c2ecf20Sopenharmony_ci if (conf->flags & IEEE80211_CONF_PS) 7098c2ecf20Sopenharmony_ci rsi_enable_ps(adapter, sta_vif); 7108c2ecf20Sopenharmony_ci else 7118c2ecf20Sopenharmony_ci rsi_disable_ps(adapter, sta_vif); 7128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->ps_lock, flags); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* RTS threshold */ 7178c2ecf20Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 7188c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "RTS threshold\n"); 7198c2ecf20Sopenharmony_ci if ((common->rts_threshold) <= IEEE80211_MAX_RTS_THRESHOLD) { 7208c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 7218c2ecf20Sopenharmony_ci "%s: Sending vap updates....\n", __func__); 7228c2ecf20Sopenharmony_ci status = rsi_send_vap_dynamic_update(common); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return status; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci/** 7318c2ecf20Sopenharmony_ci * rsi_get_connected_channel() - This function is used to get the current 7328c2ecf20Sopenharmony_ci * connected channel number. 7338c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Return: Current connected AP's channel number is returned. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ciu16 rsi_get_connected_channel(struct ieee80211_vif *vif) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss; 7408c2ecf20Sopenharmony_ci struct ieee80211_channel *channel; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (!vif) 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci bss = &vif->bss_conf; 7468c2ecf20Sopenharmony_ci channel = bss->chandef.chan; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (!channel) 7498c2ecf20Sopenharmony_ci return 0; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return channel->hw_value; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic void rsi_switch_channel(struct rsi_hw *adapter, 7558c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 7588c2ecf20Sopenharmony_ci struct ieee80211_channel *channel; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (common->iface_down) 7618c2ecf20Sopenharmony_ci return; 7628c2ecf20Sopenharmony_ci if (!vif) 7638c2ecf20Sopenharmony_ci return; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci channel = vif->bss_conf.chandef.chan; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (!channel) 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci rsi_band_check(common, channel); 7718c2ecf20Sopenharmony_ci rsi_set_channel(common, channel); 7728c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Switched to channel - %d\n", channel->hw_value); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci/** 7768c2ecf20Sopenharmony_ci * rsi_mac80211_bss_info_changed() - This function is a handler for config 7778c2ecf20Sopenharmony_ci * requests related to BSS parameters that 7788c2ecf20Sopenharmony_ci * may vary during BSS's lifespan. 7798c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 7808c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 7818c2ecf20Sopenharmony_ci * @bss_conf: Pointer to the ieee80211_bss_conf structure. 7828c2ecf20Sopenharmony_ci * @changed: Changed flags set. 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * Return: None. 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_cistatic void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, 7878c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 7888c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 7898c2ecf20Sopenharmony_ci u32 changed) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 7928c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 7938c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss = &vif->bss_conf; 7948c2ecf20Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 7958c2ecf20Sopenharmony_ci u16 rx_filter_word = 0; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 7988c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 7998c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", 8008c2ecf20Sopenharmony_ci __func__, bss_conf->assoc); 8018c2ecf20Sopenharmony_ci if (bss_conf->assoc) { 8028c2ecf20Sopenharmony_ci /* Send the RX filter frame */ 8038c2ecf20Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | 8048c2ecf20Sopenharmony_ci ALLOW_CTRL_ASSOC_PEER | 8058c2ecf20Sopenharmony_ci ALLOW_MGMT_ASSOC_PEER); 8068c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci rsi_inform_bss_status(common, 8098c2ecf20Sopenharmony_ci RSI_OPMODE_STA, 8108c2ecf20Sopenharmony_ci bss_conf->assoc, 8118c2ecf20Sopenharmony_ci bss_conf->bssid, 8128c2ecf20Sopenharmony_ci bss_conf->qos, 8138c2ecf20Sopenharmony_ci bss_conf->aid, 8148c2ecf20Sopenharmony_ci NULL, 0, 8158c2ecf20Sopenharmony_ci bss_conf->assoc_capability, vif); 8168c2ecf20Sopenharmony_ci adapter->ps_info.dtim_interval_duration = bss->dtim_period; 8178c2ecf20Sopenharmony_ci adapter->ps_info.listen_interval = conf->listen_interval; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* If U-APSD is updated, send ps parameters to firmware */ 8208c2ecf20Sopenharmony_ci if (bss->assoc) { 8218c2ecf20Sopenharmony_ci if (common->uapsd_bitmap) { 8228c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); 8238c2ecf20Sopenharmony_ci rsi_conf_uapsd(adapter, vif); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci } else { 8268c2ecf20Sopenharmony_ci common->uapsd_bitmap = 0; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (changed & BSS_CHANGED_CQM) { 8318c2ecf20Sopenharmony_ci common->cqm_info.last_cqm_event_rssi = 0; 8328c2ecf20Sopenharmony_ci common->cqm_info.rssi_thold = bss_conf->cqm_rssi_thold; 8338c2ecf20Sopenharmony_ci common->cqm_info.rssi_hyst = bss_conf->cqm_rssi_hyst; 8348c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "RSSI threshold & hysteresis are: %d %d\n", 8358c2ecf20Sopenharmony_ci common->cqm_info.rssi_thold, 8368c2ecf20Sopenharmony_ci common->cqm_info.rssi_hyst); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci if ((changed & BSS_CHANGED_BEACON_ENABLED) && 8408c2ecf20Sopenharmony_ci ((vif->type == NL80211_IFTYPE_AP) || 8418c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO))) { 8428c2ecf20Sopenharmony_ci if (bss->enable_beacon) { 8438c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "===> BEACON ENABLED <===\n"); 8448c2ecf20Sopenharmony_ci common->beacon_enabled = 1; 8458c2ecf20Sopenharmony_ci } else { 8468c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "===> BEACON DISABLED <===\n"); 8478c2ecf20Sopenharmony_ci common->beacon_enabled = 0; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci/** 8558c2ecf20Sopenharmony_ci * rsi_mac80211_conf_filter() - This function configure the device's RX filter. 8568c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 8578c2ecf20Sopenharmony_ci * @changed_flags: Changed flags set. 8588c2ecf20Sopenharmony_ci * @total_flags: Total initial flags set. 8598c2ecf20Sopenharmony_ci * @multicast: Multicast. 8608c2ecf20Sopenharmony_ci * 8618c2ecf20Sopenharmony_ci * Return: None. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cistatic void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, 8648c2ecf20Sopenharmony_ci u32 changed_flags, 8658c2ecf20Sopenharmony_ci u32 *total_flags, 8668c2ecf20Sopenharmony_ci u64 multicast) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci /* Not doing much here as of now */ 8698c2ecf20Sopenharmony_ci *total_flags &= RSI_SUPP_FILTERS; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci/** 8738c2ecf20Sopenharmony_ci * rsi_mac80211_conf_tx() - This function configures TX queue parameters 8748c2ecf20Sopenharmony_ci * (EDCF (aifs, cw_min, cw_max), bursting) 8758c2ecf20Sopenharmony_ci * for a hardware TX queue. 8768c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure 8778c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 8788c2ecf20Sopenharmony_ci * @queue: Queue number. 8798c2ecf20Sopenharmony_ci * @params: Pointer to ieee80211_tx_queue_params structure. 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * Return: 0 on success, negative error code on failure. 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_cistatic int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, 8848c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, u16 queue, 8858c2ecf20Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 8888c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 8898c2ecf20Sopenharmony_ci u8 idx = 0; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (queue >= IEEE80211_NUM_ACS) 8928c2ecf20Sopenharmony_ci return 0; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 8958c2ecf20Sopenharmony_ci "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", 8968c2ecf20Sopenharmony_ci __func__, queue, params->aifs, 8978c2ecf20Sopenharmony_ci params->cw_min, params->cw_max, params->txop); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 9008c2ecf20Sopenharmony_ci /* Map into the way the f/w expects */ 9018c2ecf20Sopenharmony_ci switch (queue) { 9028c2ecf20Sopenharmony_ci case IEEE80211_AC_VO: 9038c2ecf20Sopenharmony_ci idx = VO_Q; 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci case IEEE80211_AC_VI: 9068c2ecf20Sopenharmony_ci idx = VI_Q; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci case IEEE80211_AC_BE: 9098c2ecf20Sopenharmony_ci idx = BE_Q; 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci case IEEE80211_AC_BK: 9128c2ecf20Sopenharmony_ci idx = BK_Q; 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci default: 9158c2ecf20Sopenharmony_ci idx = BE_Q; 9168c2ecf20Sopenharmony_ci break; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci memcpy(&common->edca_params[idx], 9208c2ecf20Sopenharmony_ci params, 9218c2ecf20Sopenharmony_ci sizeof(struct ieee80211_tx_queue_params)); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (params->uapsd) 9248c2ecf20Sopenharmony_ci common->uapsd_bitmap |= idx; 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci common->uapsd_bitmap &= (~idx); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/** 9348c2ecf20Sopenharmony_ci * rsi_hal_key_config() - This function loads the keys into the firmware. 9358c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 9368c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 9378c2ecf20Sopenharmony_ci * @key: Pointer to the ieee80211_key_conf structure. 9388c2ecf20Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 9398c2ecf20Sopenharmony_ci * 9408c2ecf20Sopenharmony_ci * Return: status: 0 on success, negative error codes on failure. 9418c2ecf20Sopenharmony_ci */ 9428c2ecf20Sopenharmony_cistatic int rsi_hal_key_config(struct ieee80211_hw *hw, 9438c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 9448c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key, 9458c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 9488c2ecf20Sopenharmony_ci struct rsi_sta *rsta = NULL; 9498c2ecf20Sopenharmony_ci int status; 9508c2ecf20Sopenharmony_ci u8 key_type; 9518c2ecf20Sopenharmony_ci s16 sta_id = 0; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 9548c2ecf20Sopenharmony_ci key_type = RSI_PAIRWISE_KEY; 9558c2ecf20Sopenharmony_ci else 9568c2ecf20Sopenharmony_ci key_type = RSI_GROUP_KEY; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", 9598c2ecf20Sopenharmony_ci __func__, key->cipher, key_type, key->keylen); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 9628c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 9638c2ecf20Sopenharmony_ci if (sta) { 9648c2ecf20Sopenharmony_ci rsta = rsi_find_sta(adapter->priv, sta->addr); 9658c2ecf20Sopenharmony_ci if (rsta) 9668c2ecf20Sopenharmony_ci sta_id = rsta->sta_id; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci adapter->priv->key = key; 9698c2ecf20Sopenharmony_ci } else { 9708c2ecf20Sopenharmony_ci if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || 9718c2ecf20Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { 9728c2ecf20Sopenharmony_ci status = rsi_hal_load_key(adapter->priv, 9738c2ecf20Sopenharmony_ci key->key, 9748c2ecf20Sopenharmony_ci key->keylen, 9758c2ecf20Sopenharmony_ci RSI_PAIRWISE_KEY, 9768c2ecf20Sopenharmony_ci key->keyidx, 9778c2ecf20Sopenharmony_ci key->cipher, 9788c2ecf20Sopenharmony_ci sta_id, 9798c2ecf20Sopenharmony_ci vif); 9808c2ecf20Sopenharmony_ci if (status) 9818c2ecf20Sopenharmony_ci return status; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci status = rsi_hal_load_key(adapter->priv, 9868c2ecf20Sopenharmony_ci key->key, 9878c2ecf20Sopenharmony_ci key->keylen, 9888c2ecf20Sopenharmony_ci key_type, 9898c2ecf20Sopenharmony_ci key->keyidx, 9908c2ecf20Sopenharmony_ci key->cipher, 9918c2ecf20Sopenharmony_ci sta_id, 9928c2ecf20Sopenharmony_ci vif); 9938c2ecf20Sopenharmony_ci if (status) 9948c2ecf20Sopenharmony_ci return status; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && 9978c2ecf20Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP104 || 9988c2ecf20Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_WEP40)) { 9998c2ecf20Sopenharmony_ci if (!rsi_send_block_unblock_frame(adapter->priv, false)) 10008c2ecf20Sopenharmony_ci adapter->priv->hw_data_qs_blocked = false; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/** 10078c2ecf20Sopenharmony_ci * rsi_mac80211_set_key() - This function sets type of key to be loaded. 10088c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 10098c2ecf20Sopenharmony_ci * @cmd: enum set_key_cmd. 10108c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 10118c2ecf20Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 10128c2ecf20Sopenharmony_ci * @key: Pointer to the ieee80211_key_conf structure. 10138c2ecf20Sopenharmony_ci * 10148c2ecf20Sopenharmony_ci * Return: status: 0 on success, negative error code on failure. 10158c2ecf20Sopenharmony_ci */ 10168c2ecf20Sopenharmony_cistatic int rsi_mac80211_set_key(struct ieee80211_hw *hw, 10178c2ecf20Sopenharmony_ci enum set_key_cmd cmd, 10188c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 10198c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 10208c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 10238c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 10248c2ecf20Sopenharmony_ci struct security_info *secinfo = &common->secinfo; 10258c2ecf20Sopenharmony_ci int status; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 10288c2ecf20Sopenharmony_ci switch (cmd) { 10298c2ecf20Sopenharmony_ci case SET_KEY: 10308c2ecf20Sopenharmony_ci status = rsi_hal_key_config(hw, vif, key, sta); 10318c2ecf20Sopenharmony_ci if (status) { 10328c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 10338c2ecf20Sopenharmony_ci return status; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 10378c2ecf20Sopenharmony_ci secinfo->ptk_cipher = key->cipher; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci secinfo->gtk_cipher = key->cipher; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci key->hw_key_idx = key->keyidx; 10428c2ecf20Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci case DISABLE_KEY: 10488c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); 10498c2ecf20Sopenharmony_ci memset(key, 0, sizeof(struct ieee80211_key_conf)); 10508c2ecf20Sopenharmony_ci status = rsi_hal_key_config(hw, vif, key, sta); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci default: 10548c2ecf20Sopenharmony_ci status = -EOPNOTSUPP; 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 10598c2ecf20Sopenharmony_ci return status; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci/** 10638c2ecf20Sopenharmony_ci * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for 10648c2ecf20Sopenharmony_ci * the corresponding mlme_action flag and 10658c2ecf20Sopenharmony_ci * informs the f/w regarding this. 10668c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 10678c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 10688c2ecf20Sopenharmony_ci * @params: Pointer to A-MPDU action parameters 10698c2ecf20Sopenharmony_ci * 10708c2ecf20Sopenharmony_ci * Return: status: 0 on success, negative error code on failure. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_cistatic int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, 10738c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 10748c2ecf20Sopenharmony_ci struct ieee80211_ampdu_params *params) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci int status = -EOPNOTSUPP; 10778c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 10788c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 10798c2ecf20Sopenharmony_ci struct rsi_sta *rsta = NULL; 10808c2ecf20Sopenharmony_ci u16 seq_no = 0, seq_start = 0; 10818c2ecf20Sopenharmony_ci u8 ii = 0; 10828c2ecf20Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 10838c2ecf20Sopenharmony_ci u8 sta_id = 0; 10848c2ecf20Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 10858c2ecf20Sopenharmony_ci u16 tid = params->tid; 10868c2ecf20Sopenharmony_ci u16 *ssn = ¶ms->ssn; 10878c2ecf20Sopenharmony_ci u8 buf_size = params->buf_size; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci for (ii = 0; ii < RSI_MAX_VIFS; ii++) { 10908c2ecf20Sopenharmony_ci if (vif == adapter->vifs[ii]) 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (ssn != NULL) 10978c2ecf20Sopenharmony_ci seq_no = *ssn; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 11008c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 11018c2ecf20Sopenharmony_ci rsta = rsi_find_sta(common, sta->addr); 11028c2ecf20Sopenharmony_ci if (!rsta) { 11038c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "No station mapped\n"); 11048c2ecf20Sopenharmony_ci status = 0; 11058c2ecf20Sopenharmony_ci goto unlock; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci sta_id = rsta->sta_id; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, 11118c2ecf20Sopenharmony_ci "%s: AMPDU action tid=%d ssn=0x%x, buf_size=%d sta_id=%d\n", 11128c2ecf20Sopenharmony_ci __func__, tid, seq_no, buf_size, sta_id); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci switch (action) { 11158c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 11168c2ecf20Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 11178c2ecf20Sopenharmony_ci tid, 11188c2ecf20Sopenharmony_ci seq_no, 11198c2ecf20Sopenharmony_ci buf_size, 11208c2ecf20Sopenharmony_ci STA_RX_ADDBA_DONE, 11218c2ecf20Sopenharmony_ci sta_id); 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 11258c2ecf20Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 11268c2ecf20Sopenharmony_ci tid, 11278c2ecf20Sopenharmony_ci 0, 11288c2ecf20Sopenharmony_ci buf_size, 11298c2ecf20Sopenharmony_ci STA_RX_DELBA, 11308c2ecf20Sopenharmony_ci sta_id); 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 11348c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 11358c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) 11368c2ecf20Sopenharmony_ci common->vif_info[ii].seq_start = seq_no; 11378c2ecf20Sopenharmony_ci else if ((vif->type == NL80211_IFTYPE_AP) || 11388c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 11398c2ecf20Sopenharmony_ci rsta->seq_start[tid] = seq_no; 11408c2ecf20Sopenharmony_ci status = IEEE80211_AMPDU_TX_START_IMMEDIATE; 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 11448c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 11458c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 11468c2ecf20Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 11478c2ecf20Sopenharmony_ci tid, 11488c2ecf20Sopenharmony_ci seq_no, 11498c2ecf20Sopenharmony_ci buf_size, 11508c2ecf20Sopenharmony_ci STA_TX_DELBA, 11518c2ecf20Sopenharmony_ci sta_id); 11528c2ecf20Sopenharmony_ci if (!status) 11538c2ecf20Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 11578c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 11588c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) 11598c2ecf20Sopenharmony_ci seq_start = common->vif_info[ii].seq_start; 11608c2ecf20Sopenharmony_ci else if ((vif->type == NL80211_IFTYPE_AP) || 11618c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 11628c2ecf20Sopenharmony_ci seq_start = rsta->seq_start[tid]; 11638c2ecf20Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 11648c2ecf20Sopenharmony_ci tid, 11658c2ecf20Sopenharmony_ci seq_start, 11668c2ecf20Sopenharmony_ci buf_size, 11678c2ecf20Sopenharmony_ci STA_TX_ADDBA_DONE, 11688c2ecf20Sopenharmony_ci sta_id); 11698c2ecf20Sopenharmony_ci break; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci default: 11728c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unknown AMPDU action\n", __func__); 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ciunlock: 11778c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 11788c2ecf20Sopenharmony_ci return status; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci/** 11828c2ecf20Sopenharmony_ci * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. 11838c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 11848c2ecf20Sopenharmony_ci * @value: Rts threshold value. 11858c2ecf20Sopenharmony_ci * 11868c2ecf20Sopenharmony_ci * Return: 0 on success. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_cistatic int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, 11898c2ecf20Sopenharmony_ci u32 value) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 11928c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 11958c2ecf20Sopenharmony_ci common->rts_threshold = value; 11968c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return 0; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/** 12028c2ecf20Sopenharmony_ci * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. 12038c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure 12048c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 12058c2ecf20Sopenharmony_ci * @mask: Pointer to the cfg80211_bitrate_mask structure. 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * Return: 0 on success. 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_cistatic int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, 12108c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 12118c2ecf20Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci const unsigned int mcs_offset = ARRAY_SIZE(rsi_rates); 12148c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 12158c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 12168c2ecf20Sopenharmony_ci int i; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(common->rate_config); i++) { 12218c2ecf20Sopenharmony_ci struct rsi_rate_config *cfg = &common->rate_config[i]; 12228c2ecf20Sopenharmony_ci u32 bm; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci bm = mask->control[i].legacy | (mask->control[i].ht_mcs[0] << mcs_offset); 12258c2ecf20Sopenharmony_ci if (hweight32(bm) == 1) { /* single rate */ 12268c2ecf20Sopenharmony_ci int rate_index = ffs(bm) - 1; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (rate_index < mcs_offset) 12298c2ecf20Sopenharmony_ci cfg->fixed_hw_rate = rsi_rates[rate_index].hw_value; 12308c2ecf20Sopenharmony_ci else 12318c2ecf20Sopenharmony_ci cfg->fixed_hw_rate = rsi_mcsrates[rate_index - mcs_offset]; 12328c2ecf20Sopenharmony_ci cfg->fixed_enabled = true; 12338c2ecf20Sopenharmony_ci } else { 12348c2ecf20Sopenharmony_ci cfg->configured_mask = bm; 12358c2ecf20Sopenharmony_ci cfg->fixed_enabled = false; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci/** 12458c2ecf20Sopenharmony_ci * rsi_perform_cqm() - This function performs cqm. 12468c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 12478c2ecf20Sopenharmony_ci * @bssid: pointer to the bssid. 12488c2ecf20Sopenharmony_ci * @rssi: RSSI value. 12498c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_cistatic void rsi_perform_cqm(struct rsi_common *common, 12528c2ecf20Sopenharmony_ci u8 *bssid, 12538c2ecf20Sopenharmony_ci s8 rssi, 12548c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci s8 last_event = common->cqm_info.last_cqm_event_rssi; 12578c2ecf20Sopenharmony_ci int thold = common->cqm_info.rssi_thold; 12588c2ecf20Sopenharmony_ci u32 hyst = common->cqm_info.rssi_hyst; 12598c2ecf20Sopenharmony_ci enum nl80211_cqm_rssi_threshold_event event; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (rssi < thold && (last_event == 0 || rssi < (last_event - hyst))) 12628c2ecf20Sopenharmony_ci event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; 12638c2ecf20Sopenharmony_ci else if (rssi > thold && 12648c2ecf20Sopenharmony_ci (last_event == 0 || rssi > (last_event + hyst))) 12658c2ecf20Sopenharmony_ci event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; 12668c2ecf20Sopenharmony_ci else 12678c2ecf20Sopenharmony_ci return; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci common->cqm_info.last_cqm_event_rssi = rssi; 12708c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); 12718c2ecf20Sopenharmony_ci ieee80211_cqm_rssi_notify(vif, event, rssi, GFP_KERNEL); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return; 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci/** 12778c2ecf20Sopenharmony_ci * rsi_fill_rx_status() - This function fills rx status in 12788c2ecf20Sopenharmony_ci * ieee80211_rx_status structure. 12798c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 12808c2ecf20Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 12818c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 12828c2ecf20Sopenharmony_ci * @rxs: Pointer to the ieee80211_rx_status structure. 12838c2ecf20Sopenharmony_ci * 12848c2ecf20Sopenharmony_ci * Return: None. 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_cistatic void rsi_fill_rx_status(struct ieee80211_hw *hw, 12878c2ecf20Sopenharmony_ci struct sk_buff *skb, 12888c2ecf20Sopenharmony_ci struct rsi_common *common, 12898c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rxs) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 12928c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 12938c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss = NULL; 12948c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 12958c2ecf20Sopenharmony_ci struct skb_info *rx_params = (struct skb_info *)info->driver_data; 12968c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 12978c2ecf20Sopenharmony_ci char rssi = rx_params->rssi; 12988c2ecf20Sopenharmony_ci u8 hdrlen = 0; 12998c2ecf20Sopenharmony_ci u8 channel = rx_params->channel; 13008c2ecf20Sopenharmony_ci s32 freq; 13018c2ecf20Sopenharmony_ci int i; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci hdr = ((struct ieee80211_hdr *)(skb->data)); 13048c2ecf20Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci memset(info, 0, sizeof(struct ieee80211_tx_info)); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci rxs->signal = -(rssi); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci rxs->band = common->band; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci freq = ieee80211_channel_to_frequency(channel, rxs->band); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (freq) 13158c2ecf20Sopenharmony_ci rxs->freq = freq; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (ieee80211_has_protected(hdr->frame_control)) { 13188c2ecf20Sopenharmony_ci if (rsi_is_cipher_wep(common)) { 13198c2ecf20Sopenharmony_ci memmove(skb->data + 4, skb->data, hdrlen); 13208c2ecf20Sopenharmony_ci skb_pull(skb, 4); 13218c2ecf20Sopenharmony_ci } else { 13228c2ecf20Sopenharmony_ci memmove(skb->data + 8, skb->data, hdrlen); 13238c2ecf20Sopenharmony_ci skb_pull(skb, 8); 13248c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_MMIC_STRIPPED; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_DECRYPTED; 13278c2ecf20Sopenharmony_ci rxs->flag |= RX_FLAG_IV_STRIPPED; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 13318c2ecf20Sopenharmony_ci vif = adapter->vifs[i]; 13328c2ecf20Sopenharmony_ci if (!vif) 13338c2ecf20Sopenharmony_ci continue; 13348c2ecf20Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 13358c2ecf20Sopenharmony_ci bss = &vif->bss_conf; 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci if (!bss) 13408c2ecf20Sopenharmony_ci return; 13418c2ecf20Sopenharmony_ci /* CQM only for connected AP beacons, the RSSI is a weighted avg */ 13428c2ecf20Sopenharmony_ci if (bss->assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { 13438c2ecf20Sopenharmony_ci if (ieee80211_is_beacon(hdr->frame_control)) 13448c2ecf20Sopenharmony_ci rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif); 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci/** 13518c2ecf20Sopenharmony_ci * rsi_indicate_pkt_to_os() - This function sends received packet to mac80211. 13528c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 13538c2ecf20Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 13548c2ecf20Sopenharmony_ci * 13558c2ecf20Sopenharmony_ci * Return: None. 13568c2ecf20Sopenharmony_ci */ 13578c2ecf20Sopenharmony_civoid rsi_indicate_pkt_to_os(struct rsi_common *common, 13588c2ecf20Sopenharmony_ci struct sk_buff *skb) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 13618c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = adapter->hw; 13628c2ecf20Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci if ((common->iface_down) || (!adapter->sc_nvifs)) { 13658c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 13668c2ecf20Sopenharmony_ci return; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* filling in the ieee80211_rx_status flags */ 13708c2ecf20Sopenharmony_ci rsi_fill_rx_status(hw, skb, common, rx_status); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci ieee80211_rx_irqsafe(hw, skb); 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci/** 13768c2ecf20Sopenharmony_ci * rsi_mac80211_sta_add() - This function notifies driver about a peer getting 13778c2ecf20Sopenharmony_ci * connected. 13788c2ecf20Sopenharmony_ci * @hw: pointer to the ieee80211_hw structure. 13798c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 13808c2ecf20Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 13818c2ecf20Sopenharmony_ci * 13828c2ecf20Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_cistatic int rsi_mac80211_sta_add(struct ieee80211_hw *hw, 13858c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 13868c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 13898c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 13908c2ecf20Sopenharmony_ci bool sta_exist = false; 13918c2ecf20Sopenharmony_ci struct rsi_sta *rsta; 13928c2ecf20Sopenharmony_ci int status = 0; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station Add: %pM\n", sta->addr); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 13998c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 14008c2ecf20Sopenharmony_ci u8 cnt; 14018c2ecf20Sopenharmony_ci int sta_idx = -1; 14028c2ecf20Sopenharmony_ci int free_index = -1; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* Check if max stations reached */ 14058c2ecf20Sopenharmony_ci if (common->num_stations >= common->max_stations) { 14068c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Reject: Max Stations exists\n"); 14078c2ecf20Sopenharmony_ci status = -EOPNOTSUPP; 14088c2ecf20Sopenharmony_ci goto unlock; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci for (cnt = 0; cnt < common->max_stations; cnt++) { 14118c2ecf20Sopenharmony_ci rsta = &common->stations[cnt]; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (!rsta->sta) { 14148c2ecf20Sopenharmony_ci if (free_index < 0) 14158c2ecf20Sopenharmony_ci free_index = cnt; 14168c2ecf20Sopenharmony_ci continue; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { 14198c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station exists\n"); 14208c2ecf20Sopenharmony_ci sta_idx = cnt; 14218c2ecf20Sopenharmony_ci sta_exist = true; 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci if (!sta_exist) { 14268c2ecf20Sopenharmony_ci if (free_index >= 0) 14278c2ecf20Sopenharmony_ci sta_idx = free_index; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci if (sta_idx < 0) { 14308c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 14318c2ecf20Sopenharmony_ci "%s: Some problem reaching here...\n", 14328c2ecf20Sopenharmony_ci __func__); 14338c2ecf20Sopenharmony_ci status = -EINVAL; 14348c2ecf20Sopenharmony_ci goto unlock; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci rsta = &common->stations[sta_idx]; 14378c2ecf20Sopenharmony_ci rsta->sta = sta; 14388c2ecf20Sopenharmony_ci rsta->sta_id = sta_idx; 14398c2ecf20Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 14408c2ecf20Sopenharmony_ci rsta->start_tx_aggr[cnt] = false; 14418c2ecf20Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 14428c2ecf20Sopenharmony_ci rsta->seq_start[cnt] = 0; 14438c2ecf20Sopenharmony_ci if (!sta_exist) { 14448c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "New Station\n"); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci /* Send peer notify to device */ 14478c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); 14488c2ecf20Sopenharmony_ci rsi_inform_bss_status(common, RSI_OPMODE_AP, 1, 14498c2ecf20Sopenharmony_ci sta->addr, sta->wme, sta->aid, 14508c2ecf20Sopenharmony_ci sta, sta_idx, 0, vif); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (common->key) { 14538c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key = common->key; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || 14568c2ecf20Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP40)) 14578c2ecf20Sopenharmony_ci rsi_hal_load_key(adapter->priv, 14588c2ecf20Sopenharmony_ci key->key, 14598c2ecf20Sopenharmony_ci key->keylen, 14608c2ecf20Sopenharmony_ci RSI_PAIRWISE_KEY, 14618c2ecf20Sopenharmony_ci key->keyidx, 14628c2ecf20Sopenharmony_ci key->cipher, 14638c2ecf20Sopenharmony_ci sta_idx, 14648c2ecf20Sopenharmony_ci vif); 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci common->num_stations++; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 14728c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { 14738c2ecf20Sopenharmony_ci common->bitrate_mask[common->band] = sta->supp_rates[common->band]; 14748c2ecf20Sopenharmony_ci common->vif_info[0].is_ht = sta->ht_cap.ht_supported; 14758c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported) { 14768c2ecf20Sopenharmony_ci common->bitrate_mask[NL80211_BAND_2GHZ] = 14778c2ecf20Sopenharmony_ci sta->supp_rates[NL80211_BAND_2GHZ]; 14788c2ecf20Sopenharmony_ci if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || 14798c2ecf20Sopenharmony_ci (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) 14808c2ecf20Sopenharmony_ci common->vif_info[0].sgi = true; 14818c2ecf20Sopenharmony_ci ieee80211_start_tx_ba_session(sta, 0, 0); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ciunlock: 14868c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci return status; 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci/** 14928c2ecf20Sopenharmony_ci * rsi_mac80211_sta_remove() - This function notifies driver about a peer 14938c2ecf20Sopenharmony_ci * getting disconnected. 14948c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 14958c2ecf20Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 14968c2ecf20Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 14978c2ecf20Sopenharmony_ci * 14988c2ecf20Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 14998c2ecf20Sopenharmony_ci */ 15008c2ecf20Sopenharmony_cistatic int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, 15018c2ecf20Sopenharmony_ci struct ieee80211_vif *vif, 15028c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 15058c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 15068c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss = &vif->bss_conf; 15078c2ecf20Sopenharmony_ci struct rsi_sta *rsta; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station Remove: %pM\n", sta->addr); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 15148c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 15158c2ecf20Sopenharmony_ci u8 sta_idx, cnt; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci /* Send peer notify to device */ 15188c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); 15198c2ecf20Sopenharmony_ci for (sta_idx = 0; sta_idx < common->max_stations; sta_idx++) { 15208c2ecf20Sopenharmony_ci rsta = &common->stations[sta_idx]; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (!rsta->sta) 15238c2ecf20Sopenharmony_ci continue; 15248c2ecf20Sopenharmony_ci if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { 15258c2ecf20Sopenharmony_ci rsi_inform_bss_status(common, RSI_OPMODE_AP, 0, 15268c2ecf20Sopenharmony_ci sta->addr, sta->wme, 15278c2ecf20Sopenharmony_ci sta->aid, sta, sta_idx, 15288c2ecf20Sopenharmony_ci 0, vif); 15298c2ecf20Sopenharmony_ci rsta->sta = NULL; 15308c2ecf20Sopenharmony_ci rsta->sta_id = -1; 15318c2ecf20Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 15328c2ecf20Sopenharmony_ci rsta->start_tx_aggr[cnt] = false; 15338c2ecf20Sopenharmony_ci if (common->num_stations > 0) 15348c2ecf20Sopenharmony_ci common->num_stations--; 15358c2ecf20Sopenharmony_ci break; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci if (sta_idx >= common->max_stations) 15398c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: No station found\n", __func__); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 15438c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { 15448c2ecf20Sopenharmony_ci /* Resetting all the fields to default values */ 15458c2ecf20Sopenharmony_ci memcpy((u8 *)bss->bssid, (u8 *)sta->addr, ETH_ALEN); 15468c2ecf20Sopenharmony_ci bss->qos = sta->wme; 15478c2ecf20Sopenharmony_ci common->bitrate_mask[NL80211_BAND_2GHZ] = 0; 15488c2ecf20Sopenharmony_ci common->bitrate_mask[NL80211_BAND_5GHZ] = 0; 15498c2ecf20Sopenharmony_ci common->vif_info[0].is_ht = false; 15508c2ecf20Sopenharmony_ci common->vif_info[0].sgi = false; 15518c2ecf20Sopenharmony_ci common->vif_info[0].seq_start = 0; 15528c2ecf20Sopenharmony_ci common->secinfo.ptk_cipher = 0; 15538c2ecf20Sopenharmony_ci common->secinfo.gtk_cipher = 0; 15548c2ecf20Sopenharmony_ci if (!common->iface_down) 15558c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, 0); 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci return 0; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci/** 15638c2ecf20Sopenharmony_ci * rsi_mac80211_set_antenna() - This function is used to configure 15648c2ecf20Sopenharmony_ci * tx and rx antennas. 15658c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 15668c2ecf20Sopenharmony_ci * @tx_ant: Bitmap for tx antenna 15678c2ecf20Sopenharmony_ci * @rx_ant: Bitmap for rx antenna 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * Return: 0 on success, Negative error code on failure. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_cistatic int rsi_mac80211_set_antenna(struct ieee80211_hw *hw, 15728c2ecf20Sopenharmony_ci u32 tx_ant, u32 rx_ant) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 15758c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 15768c2ecf20Sopenharmony_ci u8 antenna = 0; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (tx_ant > 1 || rx_ant > 1) { 15798c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 15808c2ecf20Sopenharmony_ci "Invalid antenna selection (tx: %d, rx:%d)\n", 15818c2ecf20Sopenharmony_ci tx_ant, rx_ant); 15828c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 15838c2ecf20Sopenharmony_ci "Use 0 for int_ant, 1 for ext_ant\n"); 15848c2ecf20Sopenharmony_ci return -EINVAL; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Antenna map Tx %x Rx %d\n", 15888c2ecf20Sopenharmony_ci __func__, tx_ant, rx_ant); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci antenna = tx_ant ? ANTENNA_SEL_UFL : ANTENNA_SEL_INT; 15938c2ecf20Sopenharmony_ci if (common->ant_in_use != antenna) 15948c2ecf20Sopenharmony_ci if (rsi_set_antenna(common, antenna)) 15958c2ecf20Sopenharmony_ci goto fail_set_antenna; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "(%s) Antenna path configured successfully\n", 15988c2ecf20Sopenharmony_ci tx_ant ? "UFL" : "INT"); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci common->ant_in_use = antenna; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci return 0; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_cifail_set_antenna: 16078c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed.\n", __func__); 16088c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 16098c2ecf20Sopenharmony_ci return -EINVAL; 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci/** 16138c2ecf20Sopenharmony_ci * rsi_mac80211_get_antenna() - This function is used to configure 16148c2ecf20Sopenharmony_ci * tx and rx antennas. 16158c2ecf20Sopenharmony_ci * 16168c2ecf20Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 16178c2ecf20Sopenharmony_ci * @tx_ant: Bitmap for tx antenna 16188c2ecf20Sopenharmony_ci * @rx_ant: Bitmap for rx antenna 16198c2ecf20Sopenharmony_ci * 16208c2ecf20Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 16218c2ecf20Sopenharmony_ci */ 16228c2ecf20Sopenharmony_cistatic int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, 16238c2ecf20Sopenharmony_ci u32 *tx_ant, u32 *rx_ant) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 16268c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci *tx_ant = (common->ant_in_use == ANTENNA_SEL_UFL) ? 1 : 0; 16318c2ecf20Sopenharmony_ci *rx_ant = 0; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci return 0; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic int rsi_map_region_code(enum nl80211_dfs_regions region_code) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci switch (region_code) { 16418c2ecf20Sopenharmony_ci case NL80211_DFS_FCC: 16428c2ecf20Sopenharmony_ci return RSI_REGION_FCC; 16438c2ecf20Sopenharmony_ci case NL80211_DFS_ETSI: 16448c2ecf20Sopenharmony_ci return RSI_REGION_ETSI; 16458c2ecf20Sopenharmony_ci case NL80211_DFS_JP: 16468c2ecf20Sopenharmony_ci return RSI_REGION_TELEC; 16478c2ecf20Sopenharmony_ci case NL80211_DFS_UNSET: 16488c2ecf20Sopenharmony_ci return RSI_REGION_WORLD; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci return RSI_REGION_WORLD; 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_cistatic void rsi_reg_notify(struct wiphy *wiphy, 16548c2ecf20Sopenharmony_ci struct regulatory_request *request) 16558c2ecf20Sopenharmony_ci{ 16568c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 16578c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 16588c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 16598c2ecf20Sopenharmony_ci struct rsi_hw * adapter = hw->priv; 16608c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 16618c2ecf20Sopenharmony_ci int i; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "country = %s dfs_region = %d\n", 16668c2ecf20Sopenharmony_ci request->alpha2, request->dfs_region); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (common->num_supp_bands > 1) { 16698c2ecf20Sopenharmony_ci sband = wiphy->bands[NL80211_BAND_5GHZ]; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 16728c2ecf20Sopenharmony_ci ch = &sband->channels[i]; 16738c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_DISABLED) 16748c2ecf20Sopenharmony_ci continue; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_RADAR) 16778c2ecf20Sopenharmony_ci ch->flags |= IEEE80211_CHAN_NO_IR; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci adapter->dfs_region = rsi_map_region_code(request->dfs_region); 16818c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "RSI region code = %d\n", adapter->dfs_region); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci adapter->country[0] = request->alpha2[0]; 16848c2ecf20Sopenharmony_ci adapter->country[1] = request->alpha2[1]; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic void rsi_mac80211_rfkill_poll(struct ieee80211_hw *hw) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 16928c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 16958c2ecf20Sopenharmony_ci if (common->fsm_state != FSM_MAC_INIT_DONE) 16968c2ecf20Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, true); 16978c2ecf20Sopenharmony_ci else 16988c2ecf20Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, false); 16998c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic void rsi_resume_conn_channel(struct rsi_common *common) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 17058c2ecf20Sopenharmony_ci struct ieee80211_vif *vif; 17068c2ecf20Sopenharmony_ci int cnt; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci for (cnt = 0; cnt < RSI_MAX_VIFS; cnt++) { 17098c2ecf20Sopenharmony_ci vif = adapter->vifs[cnt]; 17108c2ecf20Sopenharmony_ci if (!vif) 17118c2ecf20Sopenharmony_ci continue; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 17148c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 17158c2ecf20Sopenharmony_ci rsi_switch_channel(adapter, vif); 17168c2ecf20Sopenharmony_ci break; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_STATION) || 17198c2ecf20Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && 17208c2ecf20Sopenharmony_ci vif->bss_conf.assoc) { 17218c2ecf20Sopenharmony_ci rsi_switch_channel(adapter, vif); 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_civoid rsi_roc_timeout(struct timer_list *t) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci struct rsi_common *common = from_timer(common, t, roc_timer); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Remain on channel expired\n"); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 17348c2ecf20Sopenharmony_ci ieee80211_remain_on_channel_expired(common->priv->hw); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (timer_pending(&common->roc_timer)) 17378c2ecf20Sopenharmony_ci del_timer(&common->roc_timer); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci rsi_resume_conn_channel(common); 17408c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic int rsi_mac80211_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 17448c2ecf20Sopenharmony_ci struct ieee80211_channel *chan, int duration, 17458c2ecf20Sopenharmony_ci enum ieee80211_roc_type type) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct rsi_hw *adapter = (struct rsi_hw *)hw->priv; 17488c2ecf20Sopenharmony_ci struct rsi_common *common = (struct rsi_common *)adapter->priv; 17498c2ecf20Sopenharmony_ci int status = 0; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Remain on channel *****\n"); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 17548c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: channel: %d duration: %dms\n", 17558c2ecf20Sopenharmony_ci __func__, chan->hw_value, duration); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (timer_pending(&common->roc_timer)) { 17588c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Stop on-going ROC\n"); 17598c2ecf20Sopenharmony_ci del_timer(&common->roc_timer); 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci common->roc_timer.expires = msecs_to_jiffies(duration) + jiffies; 17628c2ecf20Sopenharmony_ci add_timer(&common->roc_timer); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* Configure band */ 17658c2ecf20Sopenharmony_ci if (rsi_band_check(common, chan)) { 17668c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set band\n"); 17678c2ecf20Sopenharmony_ci status = -EINVAL; 17688c2ecf20Sopenharmony_ci goto out; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci /* Configure channel */ 17728c2ecf20Sopenharmony_ci if (rsi_set_channel(common, chan)) { 17738c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set the channel\n"); 17748c2ecf20Sopenharmony_ci status = -EINVAL; 17758c2ecf20Sopenharmony_ci goto out; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci common->roc_vif = vif; 17798c2ecf20Sopenharmony_ci ieee80211_ready_on_channel(hw); 17808c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Ready on channel :%d\n", 17818c2ecf20Sopenharmony_ci __func__, chan->hw_value); 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ciout: 17848c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci return status; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_cistatic int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw, 17908c2ecf20Sopenharmony_ci struct ieee80211_vif *vif) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 17938c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Cancel remain on channel\n"); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 17988c2ecf20Sopenharmony_ci if (!timer_pending(&common->roc_timer)) { 17998c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 18008c2ecf20Sopenharmony_ci return 0; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci del_timer(&common->roc_timer); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci rsi_resume_conn_channel(common); 18068c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci return 0; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 18128c2ecf20Sopenharmony_cistatic const struct wiphy_wowlan_support rsi_wowlan_support = { 18138c2ecf20Sopenharmony_ci .flags = WIPHY_WOWLAN_ANY | 18148c2ecf20Sopenharmony_ci WIPHY_WOWLAN_MAGIC_PKT | 18158c2ecf20Sopenharmony_ci WIPHY_WOWLAN_DISCONNECT | 18168c2ecf20Sopenharmony_ci WIPHY_WOWLAN_GTK_REKEY_FAILURE | 18178c2ecf20Sopenharmony_ci WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | 18188c2ecf20Sopenharmony_ci WIPHY_WOWLAN_EAP_IDENTITY_REQ | 18198c2ecf20Sopenharmony_ci WIPHY_WOWLAN_4WAY_HANDSHAKE, 18208c2ecf20Sopenharmony_ci}; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic u16 rsi_wow_map_triggers(struct rsi_common *common, 18238c2ecf20Sopenharmony_ci struct cfg80211_wowlan *wowlan) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci u16 wow_triggers = 0; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Mapping wowlan triggers\n"); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (wowlan->any) 18308c2ecf20Sopenharmony_ci wow_triggers |= RSI_WOW_ANY; 18318c2ecf20Sopenharmony_ci if (wowlan->magic_pkt) 18328c2ecf20Sopenharmony_ci wow_triggers |= RSI_WOW_MAGIC_PKT; 18338c2ecf20Sopenharmony_ci if (wowlan->disconnect) 18348c2ecf20Sopenharmony_ci wow_triggers |= RSI_WOW_DISCONNECT; 18358c2ecf20Sopenharmony_ci if (wowlan->gtk_rekey_failure || wowlan->eap_identity_req || 18368c2ecf20Sopenharmony_ci wowlan->four_way_handshake) 18378c2ecf20Sopenharmony_ci wow_triggers |= RSI_WOW_GTK_REKEY; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci return wow_triggers; 18408c2ecf20Sopenharmony_ci} 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ciint rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 18458c2ecf20Sopenharmony_ci u16 triggers = 0; 18468c2ecf20Sopenharmony_ci u16 rx_filter_word = 0; 18478c2ecf20Sopenharmony_ci struct ieee80211_bss_conf *bss = NULL; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci if (!adapter->vifs[0]) 18528c2ecf20Sopenharmony_ci return -EINVAL; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci bss = &adapter->vifs[0]->bss_conf; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (WARN_ON(!wowlan)) { 18578c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); 18588c2ecf20Sopenharmony_ci return -EINVAL; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci common->wow_flags |= RSI_WOW_ENABLED; 18628c2ecf20Sopenharmony_ci triggers = rsi_wow_map_triggers(common, wowlan); 18638c2ecf20Sopenharmony_ci if (!triggers) { 18648c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); 18658c2ecf20Sopenharmony_ci return -EINVAL; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci if (!bss->assoc) { 18688c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, 18698c2ecf20Sopenharmony_ci "Cannot configure WoWLAN (Station not connected)\n"); 18708c2ecf20Sopenharmony_ci common->wow_flags |= RSI_WOW_NO_CONNECTION; 18718c2ecf20Sopenharmony_ci return 0; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "TRIGGERS %x\n", triggers); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (common->coex_mode > 1) 18768c2ecf20Sopenharmony_ci rsi_disable_ps(adapter, adapter->vifs[0]); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci rsi_send_wowlan_request(common, triggers, 1); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci /** 18818c2ecf20Sopenharmony_ci * Increase the beacon_miss threshold & keep-alive timers in 18828c2ecf20Sopenharmony_ci * vap_update frame 18838c2ecf20Sopenharmony_ci */ 18848c2ecf20Sopenharmony_ci rsi_send_vap_dynamic_update(common); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | DISALLOW_BEACONS); 18878c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci return 0; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rsi_config_wowlan); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic int rsi_mac80211_suspend(struct ieee80211_hw *hw, 18948c2ecf20Sopenharmony_ci struct cfg80211_wowlan *wowlan) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 18978c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: mac80211 suspend\n", __func__); 19008c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 19018c2ecf20Sopenharmony_ci if (rsi_config_wowlan(adapter, wowlan)) { 19028c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n"); 19038c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 19048c2ecf20Sopenharmony_ci return 1; 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return 0; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_cistatic int rsi_mac80211_resume(struct ieee80211_hw *hw) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci u16 rx_filter_word = 0; 19148c2ecf20Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 19158c2ecf20Sopenharmony_ci struct rsi_common *common = adapter->priv; 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci common->wow_flags = 0; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (common->hibernate_resume) { 19228c2ecf20Sopenharmony_ci common->mac_ops_resumed = true; 19238c2ecf20Sopenharmony_ci /* Device need a complete restart of all MAC operations. 19248c2ecf20Sopenharmony_ci * returning 1 will serve this purpose. 19258c2ecf20Sopenharmony_ci */ 19268c2ecf20Sopenharmony_ci return 1; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci mutex_lock(&common->mutex); 19308c2ecf20Sopenharmony_ci rsi_send_wowlan_request(common, 0, 0); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER | 19338c2ecf20Sopenharmony_ci ALLOW_MGMT_ASSOC_PEER); 19348c2ecf20Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 19358c2ecf20Sopenharmony_ci mutex_unlock(&common->mutex); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci return 0; 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci#endif 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic const struct ieee80211_ops mac80211_ops = { 19438c2ecf20Sopenharmony_ci .tx = rsi_mac80211_tx, 19448c2ecf20Sopenharmony_ci .start = rsi_mac80211_start, 19458c2ecf20Sopenharmony_ci .stop = rsi_mac80211_stop, 19468c2ecf20Sopenharmony_ci .add_interface = rsi_mac80211_add_interface, 19478c2ecf20Sopenharmony_ci .remove_interface = rsi_mac80211_remove_interface, 19488c2ecf20Sopenharmony_ci .config = rsi_mac80211_config, 19498c2ecf20Sopenharmony_ci .bss_info_changed = rsi_mac80211_bss_info_changed, 19508c2ecf20Sopenharmony_ci .conf_tx = rsi_mac80211_conf_tx, 19518c2ecf20Sopenharmony_ci .configure_filter = rsi_mac80211_conf_filter, 19528c2ecf20Sopenharmony_ci .set_key = rsi_mac80211_set_key, 19538c2ecf20Sopenharmony_ci .set_rts_threshold = rsi_mac80211_set_rts_threshold, 19548c2ecf20Sopenharmony_ci .set_bitrate_mask = rsi_mac80211_set_rate_mask, 19558c2ecf20Sopenharmony_ci .ampdu_action = rsi_mac80211_ampdu_action, 19568c2ecf20Sopenharmony_ci .sta_add = rsi_mac80211_sta_add, 19578c2ecf20Sopenharmony_ci .sta_remove = rsi_mac80211_sta_remove, 19588c2ecf20Sopenharmony_ci .set_antenna = rsi_mac80211_set_antenna, 19598c2ecf20Sopenharmony_ci .get_antenna = rsi_mac80211_get_antenna, 19608c2ecf20Sopenharmony_ci .rfkill_poll = rsi_mac80211_rfkill_poll, 19618c2ecf20Sopenharmony_ci .remain_on_channel = rsi_mac80211_roc, 19628c2ecf20Sopenharmony_ci .cancel_remain_on_channel = rsi_mac80211_cancel_roc, 19638c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 19648c2ecf20Sopenharmony_ci .suspend = rsi_mac80211_suspend, 19658c2ecf20Sopenharmony_ci .resume = rsi_mac80211_resume, 19668c2ecf20Sopenharmony_ci#endif 19678c2ecf20Sopenharmony_ci .hw_scan = rsi_mac80211_hw_scan_start, 19688c2ecf20Sopenharmony_ci .cancel_hw_scan = rsi_mac80211_cancel_hw_scan, 19698c2ecf20Sopenharmony_ci}; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci/** 19728c2ecf20Sopenharmony_ci * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. 19738c2ecf20Sopenharmony_ci * @common: Pointer to the driver private structure. 19748c2ecf20Sopenharmony_ci * 19758c2ecf20Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 19768c2ecf20Sopenharmony_ci */ 19778c2ecf20Sopenharmony_ciint rsi_mac80211_attach(struct rsi_common *common) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci int status = 0; 19808c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = NULL; 19818c2ecf20Sopenharmony_ci struct wiphy *wiphy = NULL; 19828c2ecf20Sopenharmony_ci struct rsi_hw *adapter = common->priv; 19838c2ecf20Sopenharmony_ci u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); 19888c2ecf20Sopenharmony_ci if (!hw) { 19898c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); 19908c2ecf20Sopenharmony_ci return -ENOMEM; 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci wiphy = hw->wiphy; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(hw, adapter->device); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci hw->priv = adapter; 19988c2ecf20Sopenharmony_ci adapter->hw = hw; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 20018c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, HAS_RATE_CONTROL); 20028c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 20038c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 20048c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci hw->queues = MAX_HW_QUEUES; 20078c2ecf20Sopenharmony_ci hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci hw->max_rates = 1; 20108c2ecf20Sopenharmony_ci hw->max_rate_tries = MAX_RETRIES; 20118c2ecf20Sopenharmony_ci hw->uapsd_queues = RSI_IEEE80211_UAPSD_QUEUES; 20128c2ecf20Sopenharmony_ci hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci hw->max_tx_aggregation_subframes = RSI_MAX_TX_AGGR_FRMS; 20158c2ecf20Sopenharmony_ci hw->max_rx_aggregation_subframes = RSI_MAX_RX_AGGR_FRMS; 20168c2ecf20Sopenharmony_ci hw->rate_control_algorithm = "AARF"; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); 20198c2ecf20Sopenharmony_ci ether_addr_copy(hw->wiphy->addr_mask, addr_mask); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 20228c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 20238c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE) | 20248c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 20258c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 20288c2ecf20Sopenharmony_ci wiphy->retry_short = RETRY_SHORT; 20298c2ecf20Sopenharmony_ci wiphy->retry_long = RETRY_LONG; 20308c2ecf20Sopenharmony_ci wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; 20318c2ecf20Sopenharmony_ci wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; 20328c2ecf20Sopenharmony_ci wiphy->flags = 0; 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci wiphy->available_antennas_rx = 1; 20358c2ecf20Sopenharmony_ci wiphy->available_antennas_tx = 1; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci status = rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); 20388c2ecf20Sopenharmony_ci if (status) 20398c2ecf20Sopenharmony_ci return status; 20408c2ecf20Sopenharmony_ci wiphy->bands[NL80211_BAND_2GHZ] = 20418c2ecf20Sopenharmony_ci &adapter->sbands[NL80211_BAND_2GHZ]; 20428c2ecf20Sopenharmony_ci if (common->num_supp_bands > 1) { 20438c2ecf20Sopenharmony_ci status = rsi_register_rates_channels(adapter, 20448c2ecf20Sopenharmony_ci NL80211_BAND_5GHZ); 20458c2ecf20Sopenharmony_ci if (status) 20468c2ecf20Sopenharmony_ci return status; 20478c2ecf20Sopenharmony_ci wiphy->bands[NL80211_BAND_5GHZ] = 20488c2ecf20Sopenharmony_ci &adapter->sbands[NL80211_BAND_5GHZ]; 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* AP Parameters */ 20528c2ecf20Sopenharmony_ci wiphy->max_ap_assoc_sta = rsi_max_ap_stas[common->oper_mode - 1]; 20538c2ecf20Sopenharmony_ci common->max_stations = wiphy->max_ap_assoc_sta; 20548c2ecf20Sopenharmony_ci rsi_dbg(ERR_ZONE, "Max Stations Allowed = %d\n", common->max_stations); 20558c2ecf20Sopenharmony_ci hw->sta_data_size = sizeof(struct rsi_sta); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci wiphy->max_scan_ssids = RSI_MAX_SCAN_SSIDS; 20588c2ecf20Sopenharmony_ci wiphy->max_scan_ie_len = RSI_MAX_SCAN_IE_LEN; 20598c2ecf20Sopenharmony_ci wiphy->flags = WIPHY_FLAG_REPORTS_OBSS; 20608c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 20618c2ecf20Sopenharmony_ci wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; 20628c2ecf20Sopenharmony_ci wiphy->reg_notifier = rsi_reg_notify; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 20658c2ecf20Sopenharmony_ci wiphy->wowlan = &rsi_wowlan_support; 20668c2ecf20Sopenharmony_ci#endif 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci /* Wi-Fi direct parameters */ 20718c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 20728c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX; 20738c2ecf20Sopenharmony_ci wiphy->max_remain_on_channel_duration = 10000; 20748c2ecf20Sopenharmony_ci hw->max_listen_interval = 10; 20758c2ecf20Sopenharmony_ci wiphy->iface_combinations = rsi_iface_combinations; 20768c2ecf20Sopenharmony_ci wiphy->n_iface_combinations = ARRAY_SIZE(rsi_iface_combinations); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (common->coex_mode > 1) 20798c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci status = ieee80211_register_hw(hw); 20828c2ecf20Sopenharmony_ci if (status) 20838c2ecf20Sopenharmony_ci return status; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci return rsi_init_dbgfs(adapter); 20868c2ecf20Sopenharmony_ci} 2087