162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2014 Redpine Signals Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci#include "rsi_debugfs.h" 1962306a36Sopenharmony_ci#include "rsi_mgmt.h" 2062306a36Sopenharmony_ci#include "rsi_sdio.h" 2162306a36Sopenharmony_ci#include "rsi_common.h" 2262306a36Sopenharmony_ci#include "rsi_ps.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic const struct ieee80211_channel rsi_2ghz_channels[] = { 2562306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2412, 2662306a36Sopenharmony_ci .hw_value = 1 }, /* Channel 1 */ 2762306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2417, 2862306a36Sopenharmony_ci .hw_value = 2 }, /* Channel 2 */ 2962306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2422, 3062306a36Sopenharmony_ci .hw_value = 3 }, /* Channel 3 */ 3162306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2427, 3262306a36Sopenharmony_ci .hw_value = 4 }, /* Channel 4 */ 3362306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2432, 3462306a36Sopenharmony_ci .hw_value = 5 }, /* Channel 5 */ 3562306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2437, 3662306a36Sopenharmony_ci .hw_value = 6 }, /* Channel 6 */ 3762306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2442, 3862306a36Sopenharmony_ci .hw_value = 7 }, /* Channel 7 */ 3962306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2447, 4062306a36Sopenharmony_ci .hw_value = 8 }, /* Channel 8 */ 4162306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2452, 4262306a36Sopenharmony_ci .hw_value = 9 }, /* Channel 9 */ 4362306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2457, 4462306a36Sopenharmony_ci .hw_value = 10 }, /* Channel 10 */ 4562306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2462, 4662306a36Sopenharmony_ci .hw_value = 11 }, /* Channel 11 */ 4762306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2467, 4862306a36Sopenharmony_ci .hw_value = 12 }, /* Channel 12 */ 4962306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2472, 5062306a36Sopenharmony_ci .hw_value = 13 }, /* Channel 13 */ 5162306a36Sopenharmony_ci { .band = NL80211_BAND_2GHZ, .center_freq = 2484, 5262306a36Sopenharmony_ci .hw_value = 14 }, /* Channel 14 */ 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const struct ieee80211_channel rsi_5ghz_channels[] = { 5662306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5180, 5762306a36Sopenharmony_ci .hw_value = 36, }, /* Channel 36 */ 5862306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5200, 5962306a36Sopenharmony_ci .hw_value = 40, }, /* Channel 40 */ 6062306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5220, 6162306a36Sopenharmony_ci .hw_value = 44, }, /* Channel 44 */ 6262306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5240, 6362306a36Sopenharmony_ci .hw_value = 48, }, /* Channel 48 */ 6462306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5260, 6562306a36Sopenharmony_ci .hw_value = 52, }, /* Channel 52 */ 6662306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5280, 6762306a36Sopenharmony_ci .hw_value = 56, }, /* Channel 56 */ 6862306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5300, 6962306a36Sopenharmony_ci .hw_value = 60, }, /* Channel 60 */ 7062306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5320, 7162306a36Sopenharmony_ci .hw_value = 64, }, /* Channel 64 */ 7262306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5500, 7362306a36Sopenharmony_ci .hw_value = 100, }, /* Channel 100 */ 7462306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5520, 7562306a36Sopenharmony_ci .hw_value = 104, }, /* Channel 104 */ 7662306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5540, 7762306a36Sopenharmony_ci .hw_value = 108, }, /* Channel 108 */ 7862306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5560, 7962306a36Sopenharmony_ci .hw_value = 112, }, /* Channel 112 */ 8062306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5580, 8162306a36Sopenharmony_ci .hw_value = 116, }, /* Channel 116 */ 8262306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5600, 8362306a36Sopenharmony_ci .hw_value = 120, }, /* Channel 120 */ 8462306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5620, 8562306a36Sopenharmony_ci .hw_value = 124, }, /* Channel 124 */ 8662306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5640, 8762306a36Sopenharmony_ci .hw_value = 128, }, /* Channel 128 */ 8862306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5660, 8962306a36Sopenharmony_ci .hw_value = 132, }, /* Channel 132 */ 9062306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5680, 9162306a36Sopenharmony_ci .hw_value = 136, }, /* Channel 136 */ 9262306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5700, 9362306a36Sopenharmony_ci .hw_value = 140, }, /* Channel 140 */ 9462306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5745, 9562306a36Sopenharmony_ci .hw_value = 149, }, /* Channel 149 */ 9662306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5765, 9762306a36Sopenharmony_ci .hw_value = 153, }, /* Channel 153 */ 9862306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5785, 9962306a36Sopenharmony_ci .hw_value = 157, }, /* Channel 157 */ 10062306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5805, 10162306a36Sopenharmony_ci .hw_value = 161, }, /* Channel 161 */ 10262306a36Sopenharmony_ci { .band = NL80211_BAND_5GHZ, .center_freq = 5825, 10362306a36Sopenharmony_ci .hw_value = 165, }, /* Channel 165 */ 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistruct ieee80211_rate rsi_rates[12] = { 10762306a36Sopenharmony_ci { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 }, 10862306a36Sopenharmony_ci { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 }, 10962306a36Sopenharmony_ci { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 }, 11062306a36Sopenharmony_ci { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 }, 11162306a36Sopenharmony_ci { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 }, 11262306a36Sopenharmony_ci { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 }, 11362306a36Sopenharmony_ci { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 }, 11462306a36Sopenharmony_ci { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 }, 11562306a36Sopenharmony_ci { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 }, 11662306a36Sopenharmony_ci { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 }, 11762306a36Sopenharmony_ci { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 }, 11862306a36Sopenharmony_ci { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 }, 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ciconst u16 rsi_mcsrates[8] = { 12262306a36Sopenharmony_ci RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3, 12362306a36Sopenharmony_ci RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic const u32 rsi_max_ap_stas[16] = { 12762306a36Sopenharmony_ci 32, /* 1 - Wi-Fi alone */ 12862306a36Sopenharmony_ci 0, /* 2 */ 12962306a36Sopenharmony_ci 0, /* 3 */ 13062306a36Sopenharmony_ci 0, /* 4 - BT EDR alone */ 13162306a36Sopenharmony_ci 4, /* 5 - STA + BT EDR */ 13262306a36Sopenharmony_ci 32, /* 6 - AP + BT EDR */ 13362306a36Sopenharmony_ci 0, /* 7 */ 13462306a36Sopenharmony_ci 0, /* 8 - BT LE alone */ 13562306a36Sopenharmony_ci 4, /* 9 - STA + BE LE */ 13662306a36Sopenharmony_ci 0, /* 10 */ 13762306a36Sopenharmony_ci 0, /* 11 */ 13862306a36Sopenharmony_ci 0, /* 12 */ 13962306a36Sopenharmony_ci 1, /* 13 - STA + BT Dual */ 14062306a36Sopenharmony_ci 4, /* 14 - AP + BT Dual */ 14162306a36Sopenharmony_ci}; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic const struct ieee80211_iface_limit rsi_iface_limits[] = { 14462306a36Sopenharmony_ci { 14562306a36Sopenharmony_ci .max = 1, 14662306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci { 14962306a36Sopenharmony_ci .max = 1, 15062306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) | 15162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 15262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO), 15362306a36Sopenharmony_ci }, 15462306a36Sopenharmony_ci { 15562306a36Sopenharmony_ci .max = 1, 15662306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_DEVICE), 15762306a36Sopenharmony_ci }, 15862306a36Sopenharmony_ci}; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic const struct ieee80211_iface_combination rsi_iface_combinations[] = { 16162306a36Sopenharmony_ci { 16262306a36Sopenharmony_ci .num_different_channels = 1, 16362306a36Sopenharmony_ci .max_interfaces = 3, 16462306a36Sopenharmony_ci .limits = rsi_iface_limits, 16562306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(rsi_iface_limits), 16662306a36Sopenharmony_ci }, 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. 17162306a36Sopenharmony_ci * @common: Pointer to the driver private structure. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * Return: If cipher type is WEP, a value of 1 is returned, else 0. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cibool rsi_is_cipher_wep(struct rsi_common *common) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) || 17962306a36Sopenharmony_ci (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) && 18062306a36Sopenharmony_ci (!common->secinfo.ptk_cipher)) 18162306a36Sopenharmony_ci return true; 18262306a36Sopenharmony_ci else 18362306a36Sopenharmony_ci return false; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/** 18762306a36Sopenharmony_ci * rsi_register_rates_channels() - This function registers channels and rates. 18862306a36Sopenharmony_ci * @adapter: Pointer to the adapter structure. 18962306a36Sopenharmony_ci * @band: Operating band to be set. 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * Return: int - 0 on success, negative error on failure. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistatic int rsi_register_rates_channels(struct rsi_hw *adapter, int band) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct ieee80211_supported_band *sbands = &adapter->sbands[band]; 19662306a36Sopenharmony_ci void *channels = NULL; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (band == NL80211_BAND_2GHZ) { 19962306a36Sopenharmony_ci channels = kmemdup(rsi_2ghz_channels, sizeof(rsi_2ghz_channels), 20062306a36Sopenharmony_ci GFP_KERNEL); 20162306a36Sopenharmony_ci if (!channels) 20262306a36Sopenharmony_ci return -ENOMEM; 20362306a36Sopenharmony_ci sbands->band = NL80211_BAND_2GHZ; 20462306a36Sopenharmony_ci sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels); 20562306a36Sopenharmony_ci sbands->bitrates = rsi_rates; 20662306a36Sopenharmony_ci sbands->n_bitrates = ARRAY_SIZE(rsi_rates); 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci channels = kmemdup(rsi_5ghz_channels, sizeof(rsi_5ghz_channels), 20962306a36Sopenharmony_ci GFP_KERNEL); 21062306a36Sopenharmony_ci if (!channels) 21162306a36Sopenharmony_ci return -ENOMEM; 21262306a36Sopenharmony_ci sbands->band = NL80211_BAND_5GHZ; 21362306a36Sopenharmony_ci sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels); 21462306a36Sopenharmony_ci sbands->bitrates = &rsi_rates[4]; 21562306a36Sopenharmony_ci sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci sbands->channels = channels; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap)); 22162306a36Sopenharmony_ci sbands->ht_cap.ht_supported = true; 22262306a36Sopenharmony_ci sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 22362306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 22462306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40); 22562306a36Sopenharmony_ci sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K; 22662306a36Sopenharmony_ci sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 22762306a36Sopenharmony_ci sbands->ht_cap.mcs.rx_mask[0] = 0xff; 22862306a36Sopenharmony_ci sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 22962306a36Sopenharmony_ci /* sbands->ht_cap.mcs.rx_highest = 0x82; */ 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int rsi_mac80211_hw_scan_start(struct ieee80211_hw *hw, 23462306a36Sopenharmony_ci struct ieee80211_vif *vif, 23562306a36Sopenharmony_ci struct ieee80211_scan_request *hw_req) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct cfg80211_scan_request *scan_req = &hw_req->req; 23862306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 23962306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Hardware scan start *****\n"); 24262306a36Sopenharmony_ci common->mac_ops_resumed = false; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (common->fsm_state != FSM_MAC_INIT_DONE) 24562306a36Sopenharmony_ci return -ENODEV; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if ((common->wow_flags & RSI_WOW_ENABLED) || 24862306a36Sopenharmony_ci scan_req->n_channels == 0) 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Scan already in progress. So return */ 25262306a36Sopenharmony_ci if (common->bgscan_en) 25362306a36Sopenharmony_ci return -EBUSY; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* If STA is not connected, return with special value 1, in order 25662306a36Sopenharmony_ci * to start sw_scan in mac80211 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci if (!vif->cfg.assoc) 25962306a36Sopenharmony_ci return 1; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mutex_lock(&common->mutex); 26262306a36Sopenharmony_ci common->hwscan = scan_req; 26362306a36Sopenharmony_ci if (!rsi_send_bgscan_params(common, RSI_START_BGSCAN)) { 26462306a36Sopenharmony_ci if (!rsi_send_bgscan_probe_req(common, vif)) { 26562306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Background scan started...\n"); 26662306a36Sopenharmony_ci common->bgscan_en = true; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci mutex_unlock(&common->mutex); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void rsi_mac80211_cancel_hw_scan(struct ieee80211_hw *hw, 27562306a36Sopenharmony_ci struct ieee80211_vif *vif) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 27862306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 27962306a36Sopenharmony_ci struct cfg80211_scan_info info; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Hardware scan stop *****\n"); 28262306a36Sopenharmony_ci mutex_lock(&common->mutex); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (common->bgscan_en) { 28562306a36Sopenharmony_ci if (!rsi_send_bgscan_params(common, RSI_STOP_BGSCAN)) 28662306a36Sopenharmony_ci common->bgscan_en = false; 28762306a36Sopenharmony_ci info.aborted = false; 28862306a36Sopenharmony_ci ieee80211_scan_completed(adapter->hw, &info); 28962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Back ground scan cancelled\n"); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci common->hwscan = NULL; 29262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/** 29662306a36Sopenharmony_ci * rsi_mac80211_detach() - This function is used to de-initialize the 29762306a36Sopenharmony_ci * Mac80211 stack. 29862306a36Sopenharmony_ci * @adapter: Pointer to the adapter structure. 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * Return: None. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_civoid rsi_mac80211_detach(struct rsi_hw *adapter) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct ieee80211_hw *hw = adapter->hw; 30562306a36Sopenharmony_ci enum nl80211_band band; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (hw) { 30862306a36Sopenharmony_ci ieee80211_stop_queues(hw); 30962306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 31062306a36Sopenharmony_ci ieee80211_free_hw(hw); 31162306a36Sopenharmony_ci adapter->hw = NULL; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 31562306a36Sopenharmony_ci struct ieee80211_supported_band *sband = 31662306a36Sopenharmony_ci &adapter->sbands[band]; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci kfree(sband->channels); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci#ifdef CONFIG_RSI_DEBUGFS 32262306a36Sopenharmony_ci rsi_remove_dbgfs(adapter); 32362306a36Sopenharmony_ci kfree(adapter->dfsentry); 32462306a36Sopenharmony_ci#endif 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rsi_mac80211_detach); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/** 32962306a36Sopenharmony_ci * rsi_indicate_tx_status() - This function indicates the transmit status. 33062306a36Sopenharmony_ci * @adapter: Pointer to the adapter structure. 33162306a36Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 33262306a36Sopenharmony_ci * @status: Status 33362306a36Sopenharmony_ci * 33462306a36Sopenharmony_ci * Return: None. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_civoid rsi_indicate_tx_status(struct rsi_hw *adapter, 33762306a36Sopenharmony_ci struct sk_buff *skb, 33862306a36Sopenharmony_ci int status) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 34162306a36Sopenharmony_ci struct skb_info *tx_params; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!adapter->hw) { 34462306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "##### No MAC #####\n"); 34562306a36Sopenharmony_ci return; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!status) 34962306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci tx_params = (struct skb_info *)info->driver_data; 35262306a36Sopenharmony_ci skb_pull(skb, tx_params->internal_hdr_size); 35362306a36Sopenharmony_ci memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci ieee80211_tx_status_irqsafe(adapter->hw, skb); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/** 35962306a36Sopenharmony_ci * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each 36062306a36Sopenharmony_ci * transmitted frame.SKB contains the buffer starting 36162306a36Sopenharmony_ci * from the IEEE 802.11 header. 36262306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 36362306a36Sopenharmony_ci * @control: Pointer to the ieee80211_tx_control structure 36462306a36Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Return: None 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_cistatic void rsi_mac80211_tx(struct ieee80211_hw *hw, 36962306a36Sopenharmony_ci struct ieee80211_tx_control *control, 37062306a36Sopenharmony_ci struct sk_buff *skb) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 37362306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 37462306a36Sopenharmony_ci struct ieee80211_hdr *wlh = (struct ieee80211_hdr *)skb->data; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (ieee80211_is_auth(wlh->frame_control)) 37762306a36Sopenharmony_ci common->mac_ops_resumed = false; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci rsi_core_xmit(common, skb); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/** 38362306a36Sopenharmony_ci * rsi_mac80211_start() - This is first handler that 802.11 module calls, since 38462306a36Sopenharmony_ci * the driver init is complete by then, just 38562306a36Sopenharmony_ci * returns success. 38662306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * Return: 0 as success. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_cistatic int rsi_mac80211_start(struct ieee80211_hw *hw) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 39362306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "===> Interface UP <===\n"); 39662306a36Sopenharmony_ci mutex_lock(&common->mutex); 39762306a36Sopenharmony_ci if (common->hibernate_resume) { 39862306a36Sopenharmony_ci common->reinit_hw = true; 39962306a36Sopenharmony_ci adapter->host_intf_ops->reinit_device(adapter); 40062306a36Sopenharmony_ci wait_for_completion(&adapter->priv->wlan_init_completion); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci common->iface_down = false; 40362306a36Sopenharmony_ci wiphy_rfkill_start_polling(hw->wiphy); 40462306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, 0); 40562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return 0; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci/** 41162306a36Sopenharmony_ci * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. 41262306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * Return: None. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_cistatic void rsi_mac80211_stop(struct ieee80211_hw *hw) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 41962306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); 42262306a36Sopenharmony_ci mutex_lock(&common->mutex); 42362306a36Sopenharmony_ci common->iface_down = true; 42462306a36Sopenharmony_ci wiphy_rfkill_stop_polling(hw->wiphy); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Block all rx frames */ 42762306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, 0xffff); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci mutex_unlock(&common->mutex); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int rsi_map_intf_mode(enum nl80211_iftype vif_type) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci switch (vif_type) { 43562306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 43662306a36Sopenharmony_ci return RSI_OPMODE_STA; 43762306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 43862306a36Sopenharmony_ci return RSI_OPMODE_AP; 43962306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 44062306a36Sopenharmony_ci return RSI_OPMODE_P2P_CLIENT; 44162306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 44262306a36Sopenharmony_ci return RSI_OPMODE_P2P_CLIENT; 44362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_GO: 44462306a36Sopenharmony_ci return RSI_OPMODE_P2P_GO; 44562306a36Sopenharmony_ci default: 44662306a36Sopenharmony_ci return RSI_OPMODE_UNSUPPORTED; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/** 45162306a36Sopenharmony_ci * rsi_mac80211_add_interface() - This function is called when a netdevice 45262306a36Sopenharmony_ci * attached to the hardware is enabled. 45362306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 45462306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 45562306a36Sopenharmony_ci * 45662306a36Sopenharmony_ci * Return: ret: 0 on success, negative error code on failure. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_cistatic int rsi_mac80211_add_interface(struct ieee80211_hw *hw, 45962306a36Sopenharmony_ci struct ieee80211_vif *vif) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 46262306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 46362306a36Sopenharmony_ci struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; 46462306a36Sopenharmony_ci enum opmode intf_mode; 46562306a36Sopenharmony_ci enum vap_status vap_status; 46662306a36Sopenharmony_ci int vap_idx = -1, i; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; 46962306a36Sopenharmony_ci mutex_lock(&common->mutex); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci intf_mode = rsi_map_intf_mode(vif->type); 47262306a36Sopenharmony_ci if (intf_mode == RSI_OPMODE_UNSUPPORTED) { 47362306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 47462306a36Sopenharmony_ci "%s: Interface type %d not supported\n", __func__, 47562306a36Sopenharmony_ci vif->type); 47662306a36Sopenharmony_ci mutex_unlock(&common->mutex); 47762306a36Sopenharmony_ci return -EOPNOTSUPP; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_P2P_DEVICE) || 48062306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT) || 48162306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 48262306a36Sopenharmony_ci common->p2p_enabled = true; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Get free vap index */ 48562306a36Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 48662306a36Sopenharmony_ci if (!adapter->vifs[i] || 48762306a36Sopenharmony_ci !memcmp(vif->addr, adapter->vifs[i]->addr, ETH_ALEN)) { 48862306a36Sopenharmony_ci vap_idx = i; 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci if (vap_idx < 0) { 49362306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Reject: Max VAPs reached\n"); 49462306a36Sopenharmony_ci mutex_unlock(&common->mutex); 49562306a36Sopenharmony_ci return -EOPNOTSUPP; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci vif_info->vap_id = vap_idx; 49862306a36Sopenharmony_ci adapter->vifs[vap_idx] = vif; 49962306a36Sopenharmony_ci adapter->sc_nvifs++; 50062306a36Sopenharmony_ci vap_status = VAP_ADD; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (rsi_set_vap_capabilities(common, intf_mode, vif->addr, 50362306a36Sopenharmony_ci vif_info->vap_id, vap_status)) { 50462306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n"); 50562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 50662306a36Sopenharmony_ci return -EINVAL; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 51062306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 51162306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, DISALLOW_BEACONS); 51262306a36Sopenharmony_ci for (i = 0; i < common->max_stations; i++) 51362306a36Sopenharmony_ci common->stations[i].sta = NULL; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci mutex_unlock(&common->mutex); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/** 52262306a36Sopenharmony_ci * rsi_mac80211_remove_interface() - This function notifies driver that an 52362306a36Sopenharmony_ci * interface is going down. 52462306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 52562306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * Return: None. 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, 53062306a36Sopenharmony_ci struct ieee80211_vif *vif) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 53362306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 53462306a36Sopenharmony_ci enum opmode opmode; 53562306a36Sopenharmony_ci int i; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Remove Interface Called\n"); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci mutex_lock(&common->mutex); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (adapter->sc_nvifs <= 0) { 54262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 54362306a36Sopenharmony_ci return; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci opmode = rsi_map_intf_mode(vif->type); 54762306a36Sopenharmony_ci if (opmode == RSI_OPMODE_UNSUPPORTED) { 54862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Opmode error : %d\n", opmode); 54962306a36Sopenharmony_ci mutex_unlock(&common->mutex); 55062306a36Sopenharmony_ci return; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 55362306a36Sopenharmony_ci if (!adapter->vifs[i]) 55462306a36Sopenharmony_ci continue; 55562306a36Sopenharmony_ci if (vif == adapter->vifs[i]) { 55662306a36Sopenharmony_ci rsi_set_vap_capabilities(common, opmode, vif->addr, 55762306a36Sopenharmony_ci i, VAP_DELETE); 55862306a36Sopenharmony_ci adapter->sc_nvifs--; 55962306a36Sopenharmony_ci adapter->vifs[i] = NULL; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/** 56662306a36Sopenharmony_ci * rsi_channel_change() - This function is a performs the checks 56762306a36Sopenharmony_ci * required for changing a channel and sets 56862306a36Sopenharmony_ci * the channel accordingly. 56962306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_cistatic int rsi_channel_change(struct ieee80211_hw *hw) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 57662306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 57762306a36Sopenharmony_ci int status = -EOPNOTSUPP; 57862306a36Sopenharmony_ci struct ieee80211_channel *curchan = hw->conf.chandef.chan; 57962306a36Sopenharmony_ci u16 channel = curchan->hw_value; 58062306a36Sopenharmony_ci struct ieee80211_vif *vif; 58162306a36Sopenharmony_ci bool assoc = false; 58262306a36Sopenharmony_ci int i; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, 58562306a36Sopenharmony_ci "%s: Set channel: %d MHz type: %d channel_no %d\n", 58662306a36Sopenharmony_ci __func__, curchan->center_freq, 58762306a36Sopenharmony_ci curchan->flags, channel); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 59062306a36Sopenharmony_ci vif = adapter->vifs[i]; 59162306a36Sopenharmony_ci if (!vif) 59262306a36Sopenharmony_ci continue; 59362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 59462306a36Sopenharmony_ci if (vif->cfg.assoc) { 59562306a36Sopenharmony_ci assoc = true; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci if (assoc) { 60162306a36Sopenharmony_ci if (!common->hw_data_qs_blocked && 60262306a36Sopenharmony_ci (rsi_get_connected_channel(vif) != channel)) { 60362306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "blk data q %d\n", channel); 60462306a36Sopenharmony_ci if (!rsi_send_block_unblock_frame(common, true)) 60562306a36Sopenharmony_ci common->hw_data_qs_blocked = true; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci status = rsi_band_check(common, curchan); 61062306a36Sopenharmony_ci if (!status) 61162306a36Sopenharmony_ci status = rsi_set_channel(adapter->priv, curchan); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (assoc) { 61462306a36Sopenharmony_ci if (common->hw_data_qs_blocked && 61562306a36Sopenharmony_ci (rsi_get_connected_channel(vif) == channel)) { 61662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "unblk data q %d\n", channel); 61762306a36Sopenharmony_ci if (!rsi_send_block_unblock_frame(common, false)) 61862306a36Sopenharmony_ci common->hw_data_qs_blocked = false; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return status; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci/** 62662306a36Sopenharmony_ci * rsi_config_power() - This function configures tx power to device 62762306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 62862306a36Sopenharmony_ci * 62962306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_cistatic int rsi_config_power(struct ieee80211_hw *hw) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 63462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 63562306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (adapter->sc_nvifs <= 0) { 63862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: No virtual interface found\n", __func__); 63962306a36Sopenharmony_ci return -EINVAL; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, 64362306a36Sopenharmony_ci "%s: Set tx power: %d dBM\n", __func__, conf->power_level); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (conf->power_level == common->tx_power) 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci common->tx_power = conf->power_level; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return rsi_send_radio_params_update(common); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci/** 65462306a36Sopenharmony_ci * rsi_mac80211_config() - This function is a handler for configuration 65562306a36Sopenharmony_ci * requests. The stack calls this function to 65662306a36Sopenharmony_ci * change hardware configuration, e.g., channel. 65762306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 65862306a36Sopenharmony_ci * @changed: Changed flags set. 65962306a36Sopenharmony_ci * 66062306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistatic int rsi_mac80211_config(struct ieee80211_hw *hw, 66362306a36Sopenharmony_ci u32 changed) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 66662306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 66762306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 66862306a36Sopenharmony_ci int status = -EOPNOTSUPP; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci mutex_lock(&common->mutex); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) 67362306a36Sopenharmony_ci status = rsi_channel_change(hw); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* tx power */ 67662306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_POWER) { 67762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Configuring Power\n", __func__); 67862306a36Sopenharmony_ci status = rsi_config_power(hw); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Power save parameters */ 68262306a36Sopenharmony_ci if ((changed & IEEE80211_CONF_CHANGE_PS) && 68362306a36Sopenharmony_ci !common->mac_ops_resumed) { 68462306a36Sopenharmony_ci struct ieee80211_vif *vif, *sta_vif = NULL; 68562306a36Sopenharmony_ci unsigned long flags; 68662306a36Sopenharmony_ci int i, set_ps = 1; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 68962306a36Sopenharmony_ci vif = adapter->vifs[i]; 69062306a36Sopenharmony_ci if (!vif) 69162306a36Sopenharmony_ci continue; 69262306a36Sopenharmony_ci /* Don't go to power save if AP vap exists */ 69362306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 69462306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 69562306a36Sopenharmony_ci set_ps = 0; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION || 69962306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_P2P_CLIENT) && 70062306a36Sopenharmony_ci (!sta_vif || vif->cfg.assoc)) 70162306a36Sopenharmony_ci sta_vif = vif; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci if (set_ps && sta_vif) { 70462306a36Sopenharmony_ci spin_lock_irqsave(&adapter->ps_lock, flags); 70562306a36Sopenharmony_ci if (conf->flags & IEEE80211_CONF_PS) 70662306a36Sopenharmony_ci rsi_enable_ps(adapter, sta_vif); 70762306a36Sopenharmony_ci else 70862306a36Sopenharmony_ci rsi_disable_ps(adapter, sta_vif); 70962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->ps_lock, flags); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* RTS threshold */ 71462306a36Sopenharmony_ci if (changed & WIPHY_PARAM_RTS_THRESHOLD) { 71562306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "RTS threshold\n"); 71662306a36Sopenharmony_ci if ((common->rts_threshold) <= IEEE80211_MAX_RTS_THRESHOLD) { 71762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, 71862306a36Sopenharmony_ci "%s: Sending vap updates....\n", __func__); 71962306a36Sopenharmony_ci status = rsi_send_vap_dynamic_update(common); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return status; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/** 72862306a36Sopenharmony_ci * rsi_get_connected_channel() - This function is used to get the current 72962306a36Sopenharmony_ci * connected channel number. 73062306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * Return: Current connected AP's channel number is returned. 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ciu16 rsi_get_connected_channel(struct ieee80211_vif *vif) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct ieee80211_bss_conf *bss; 73762306a36Sopenharmony_ci struct ieee80211_channel *channel; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (!vif) 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci bss = &vif->bss_conf; 74362306a36Sopenharmony_ci channel = bss->chandef.chan; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!channel) 74662306a36Sopenharmony_ci return 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return channel->hw_value; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic void rsi_switch_channel(struct rsi_hw *adapter, 75262306a36Sopenharmony_ci struct ieee80211_vif *vif) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 75562306a36Sopenharmony_ci struct ieee80211_channel *channel; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (common->iface_down) 75862306a36Sopenharmony_ci return; 75962306a36Sopenharmony_ci if (!vif) 76062306a36Sopenharmony_ci return; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci channel = vif->bss_conf.chandef.chan; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (!channel) 76562306a36Sopenharmony_ci return; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci rsi_band_check(common, channel); 76862306a36Sopenharmony_ci rsi_set_channel(common, channel); 76962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Switched to channel - %d\n", channel->hw_value); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci/** 77362306a36Sopenharmony_ci * rsi_mac80211_bss_info_changed() - This function is a handler for config 77462306a36Sopenharmony_ci * requests related to BSS parameters that 77562306a36Sopenharmony_ci * may vary during BSS's lifespan. 77662306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 77762306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 77862306a36Sopenharmony_ci * @bss_conf: Pointer to the ieee80211_bss_conf structure. 77962306a36Sopenharmony_ci * @changed: Changed flags set. 78062306a36Sopenharmony_ci * 78162306a36Sopenharmony_ci * Return: None. 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_cistatic void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, 78462306a36Sopenharmony_ci struct ieee80211_vif *vif, 78562306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 78662306a36Sopenharmony_ci u64 changed) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 78962306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 79062306a36Sopenharmony_ci struct ieee80211_bss_conf *bss = &vif->bss_conf; 79162306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 79262306a36Sopenharmony_ci u16 rx_filter_word = 0; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci mutex_lock(&common->mutex); 79562306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 79662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", 79762306a36Sopenharmony_ci __func__, vif->cfg.assoc); 79862306a36Sopenharmony_ci if (vif->cfg.assoc) { 79962306a36Sopenharmony_ci /* Send the RX filter frame */ 80062306a36Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | 80162306a36Sopenharmony_ci ALLOW_CTRL_ASSOC_PEER | 80262306a36Sopenharmony_ci ALLOW_MGMT_ASSOC_PEER); 80362306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci rsi_inform_bss_status(common, 80662306a36Sopenharmony_ci RSI_OPMODE_STA, 80762306a36Sopenharmony_ci vif->cfg.assoc, 80862306a36Sopenharmony_ci bss_conf->bssid, 80962306a36Sopenharmony_ci bss_conf->qos, 81062306a36Sopenharmony_ci vif->cfg.aid, 81162306a36Sopenharmony_ci NULL, 0, 81262306a36Sopenharmony_ci bss_conf->assoc_capability, vif); 81362306a36Sopenharmony_ci adapter->ps_info.dtim_interval_duration = bss->dtim_period; 81462306a36Sopenharmony_ci adapter->ps_info.listen_interval = conf->listen_interval; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* If U-APSD is updated, send ps parameters to firmware */ 81762306a36Sopenharmony_ci if (vif->cfg.assoc) { 81862306a36Sopenharmony_ci if (common->uapsd_bitmap) { 81962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); 82062306a36Sopenharmony_ci rsi_conf_uapsd(adapter, vif); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci } else { 82362306a36Sopenharmony_ci common->uapsd_bitmap = 0; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (changed & BSS_CHANGED_CQM) { 82862306a36Sopenharmony_ci common->cqm_info.last_cqm_event_rssi = 0; 82962306a36Sopenharmony_ci common->cqm_info.rssi_thold = bss_conf->cqm_rssi_thold; 83062306a36Sopenharmony_ci common->cqm_info.rssi_hyst = bss_conf->cqm_rssi_hyst; 83162306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "RSSI threshold & hysteresis are: %d %d\n", 83262306a36Sopenharmony_ci common->cqm_info.rssi_thold, 83362306a36Sopenharmony_ci common->cqm_info.rssi_hyst); 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 83762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Changed Beacon interval: %d\n", 83862306a36Sopenharmony_ci __func__, bss_conf->beacon_int); 83962306a36Sopenharmony_ci if (common->beacon_interval != bss->beacon_int) { 84062306a36Sopenharmony_ci common->beacon_interval = bss->beacon_int; 84162306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) { 84262306a36Sopenharmony_ci struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci rsi_set_vap_capabilities(common, RSI_OPMODE_AP, 84562306a36Sopenharmony_ci vif->addr, vif_info->vap_id, 84662306a36Sopenharmony_ci VAP_UPDATE); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci adapter->ps_info.listen_interval = 85062306a36Sopenharmony_ci bss->beacon_int * adapter->ps_info.num_bcns_per_lis_int; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if ((changed & BSS_CHANGED_BEACON_ENABLED) && 85462306a36Sopenharmony_ci ((vif->type == NL80211_IFTYPE_AP) || 85562306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO))) { 85662306a36Sopenharmony_ci if (bss->enable_beacon) { 85762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "===> BEACON ENABLED <===\n"); 85862306a36Sopenharmony_ci common->beacon_enabled = 1; 85962306a36Sopenharmony_ci } else { 86062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "===> BEACON DISABLED <===\n"); 86162306a36Sopenharmony_ci common->beacon_enabled = 0; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/** 86962306a36Sopenharmony_ci * rsi_mac80211_conf_filter() - This function configure the device's RX filter. 87062306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 87162306a36Sopenharmony_ci * @changed_flags: Changed flags set. 87262306a36Sopenharmony_ci * @total_flags: Total initial flags set. 87362306a36Sopenharmony_ci * @multicast: Multicast. 87462306a36Sopenharmony_ci * 87562306a36Sopenharmony_ci * Return: None. 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_cistatic void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, 87862306a36Sopenharmony_ci u32 changed_flags, 87962306a36Sopenharmony_ci u32 *total_flags, 88062306a36Sopenharmony_ci u64 multicast) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci /* Not doing much here as of now */ 88362306a36Sopenharmony_ci *total_flags &= RSI_SUPP_FILTERS; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * rsi_mac80211_conf_tx() - This function configures TX queue parameters 88862306a36Sopenharmony_ci * (EDCF (aifs, cw_min, cw_max), bursting) 88962306a36Sopenharmony_ci * for a hardware TX queue. 89062306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure 89162306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 89262306a36Sopenharmony_ci * @link_id: the link ID if MLO is used, otherwise 0 89362306a36Sopenharmony_ci * @queue: Queue number. 89462306a36Sopenharmony_ci * @params: Pointer to ieee80211_tx_queue_params structure. 89562306a36Sopenharmony_ci * 89662306a36Sopenharmony_ci * Return: 0 on success, negative error code on failure. 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_cistatic int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, 89962306a36Sopenharmony_ci struct ieee80211_vif *vif, 90062306a36Sopenharmony_ci unsigned int link_id, u16 queue, 90162306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 90462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 90562306a36Sopenharmony_ci u8 idx = 0; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (queue >= IEEE80211_NUM_ACS) 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, 91162306a36Sopenharmony_ci "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", 91262306a36Sopenharmony_ci __func__, queue, params->aifs, 91362306a36Sopenharmony_ci params->cw_min, params->cw_max, params->txop); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci mutex_lock(&common->mutex); 91662306a36Sopenharmony_ci /* Map into the way the f/w expects */ 91762306a36Sopenharmony_ci switch (queue) { 91862306a36Sopenharmony_ci case IEEE80211_AC_VO: 91962306a36Sopenharmony_ci idx = VO_Q; 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci case IEEE80211_AC_VI: 92262306a36Sopenharmony_ci idx = VI_Q; 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci case IEEE80211_AC_BE: 92562306a36Sopenharmony_ci idx = BE_Q; 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci case IEEE80211_AC_BK: 92862306a36Sopenharmony_ci idx = BK_Q; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci default: 93162306a36Sopenharmony_ci idx = BE_Q; 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci memcpy(&common->edca_params[idx], 93662306a36Sopenharmony_ci params, 93762306a36Sopenharmony_ci sizeof(struct ieee80211_tx_queue_params)); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (params->uapsd) 94062306a36Sopenharmony_ci common->uapsd_bitmap |= idx; 94162306a36Sopenharmony_ci else 94262306a36Sopenharmony_ci common->uapsd_bitmap &= (~idx); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci mutex_unlock(&common->mutex); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return 0; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci/** 95062306a36Sopenharmony_ci * rsi_hal_key_config() - This function loads the keys into the firmware. 95162306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 95262306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 95362306a36Sopenharmony_ci * @key: Pointer to the ieee80211_key_conf structure. 95462306a36Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 95562306a36Sopenharmony_ci * 95662306a36Sopenharmony_ci * Return: status: 0 on success, negative error codes on failure. 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_cistatic int rsi_hal_key_config(struct ieee80211_hw *hw, 95962306a36Sopenharmony_ci struct ieee80211_vif *vif, 96062306a36Sopenharmony_ci struct ieee80211_key_conf *key, 96162306a36Sopenharmony_ci struct ieee80211_sta *sta) 96262306a36Sopenharmony_ci{ 96362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 96462306a36Sopenharmony_ci struct rsi_sta *rsta = NULL; 96562306a36Sopenharmony_ci int status; 96662306a36Sopenharmony_ci u8 key_type; 96762306a36Sopenharmony_ci s16 sta_id = 0; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 97062306a36Sopenharmony_ci key_type = RSI_PAIRWISE_KEY; 97162306a36Sopenharmony_ci else 97262306a36Sopenharmony_ci key_type = RSI_GROUP_KEY; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", 97562306a36Sopenharmony_ci __func__, key->cipher, key_type, key->keylen); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 97862306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 97962306a36Sopenharmony_ci if (sta) { 98062306a36Sopenharmony_ci rsta = rsi_find_sta(adapter->priv, sta->addr); 98162306a36Sopenharmony_ci if (rsta) 98262306a36Sopenharmony_ci sta_id = rsta->sta_id; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci adapter->priv->key = key; 98562306a36Sopenharmony_ci } else { 98662306a36Sopenharmony_ci if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || 98762306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { 98862306a36Sopenharmony_ci status = rsi_hal_load_key(adapter->priv, 98962306a36Sopenharmony_ci key->key, 99062306a36Sopenharmony_ci key->keylen, 99162306a36Sopenharmony_ci RSI_PAIRWISE_KEY, 99262306a36Sopenharmony_ci key->keyidx, 99362306a36Sopenharmony_ci key->cipher, 99462306a36Sopenharmony_ci sta_id, 99562306a36Sopenharmony_ci vif); 99662306a36Sopenharmony_ci if (status) 99762306a36Sopenharmony_ci return status; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci status = rsi_hal_load_key(adapter->priv, 100262306a36Sopenharmony_ci key->key, 100362306a36Sopenharmony_ci key->keylen, 100462306a36Sopenharmony_ci key_type, 100562306a36Sopenharmony_ci key->keyidx, 100662306a36Sopenharmony_ci key->cipher, 100762306a36Sopenharmony_ci sta_id, 100862306a36Sopenharmony_ci vif); 100962306a36Sopenharmony_ci if (status) 101062306a36Sopenharmony_ci return status; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && 101362306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP104 || 101462306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_WEP40)) { 101562306a36Sopenharmony_ci if (!rsi_send_block_unblock_frame(adapter->priv, false)) 101662306a36Sopenharmony_ci adapter->priv->hw_data_qs_blocked = false; 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return 0; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci/** 102362306a36Sopenharmony_ci * rsi_mac80211_set_key() - This function sets type of key to be loaded. 102462306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 102562306a36Sopenharmony_ci * @cmd: enum set_key_cmd. 102662306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 102762306a36Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 102862306a36Sopenharmony_ci * @key: Pointer to the ieee80211_key_conf structure. 102962306a36Sopenharmony_ci * 103062306a36Sopenharmony_ci * Return: status: 0 on success, negative error code on failure. 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_cistatic int rsi_mac80211_set_key(struct ieee80211_hw *hw, 103362306a36Sopenharmony_ci enum set_key_cmd cmd, 103462306a36Sopenharmony_ci struct ieee80211_vif *vif, 103562306a36Sopenharmony_ci struct ieee80211_sta *sta, 103662306a36Sopenharmony_ci struct ieee80211_key_conf *key) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 103962306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 104062306a36Sopenharmony_ci struct security_info *secinfo = &common->secinfo; 104162306a36Sopenharmony_ci int status; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci mutex_lock(&common->mutex); 104462306a36Sopenharmony_ci switch (cmd) { 104562306a36Sopenharmony_ci case SET_KEY: 104662306a36Sopenharmony_ci status = rsi_hal_key_config(hw, vif, key, sta); 104762306a36Sopenharmony_ci if (status) { 104862306a36Sopenharmony_ci mutex_unlock(&common->mutex); 104962306a36Sopenharmony_ci return status; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 105362306a36Sopenharmony_ci secinfo->ptk_cipher = key->cipher; 105462306a36Sopenharmony_ci else 105562306a36Sopenharmony_ci secinfo->gtk_cipher = key->cipher; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci key->hw_key_idx = key->keyidx; 105862306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci case DISABLE_KEY: 106462306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); 106562306a36Sopenharmony_ci memset(key, 0, sizeof(struct ieee80211_key_conf)); 106662306a36Sopenharmony_ci status = rsi_hal_key_config(hw, vif, key, sta); 106762306a36Sopenharmony_ci break; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci default: 107062306a36Sopenharmony_ci status = -EOPNOTSUPP; 107162306a36Sopenharmony_ci break; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci mutex_unlock(&common->mutex); 107562306a36Sopenharmony_ci return status; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for 108062306a36Sopenharmony_ci * the corresponding mlme_action flag and 108162306a36Sopenharmony_ci * informs the f/w regarding this. 108262306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 108362306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 108462306a36Sopenharmony_ci * @params: Pointer to A-MPDU action parameters 108562306a36Sopenharmony_ci * 108662306a36Sopenharmony_ci * Return: status: 0 on success, negative error code on failure. 108762306a36Sopenharmony_ci */ 108862306a36Sopenharmony_cistatic int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, 108962306a36Sopenharmony_ci struct ieee80211_vif *vif, 109062306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci int status = -EOPNOTSUPP; 109362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 109462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 109562306a36Sopenharmony_ci struct rsi_sta *rsta = NULL; 109662306a36Sopenharmony_ci u16 seq_no = 0, seq_start = 0; 109762306a36Sopenharmony_ci u8 ii = 0; 109862306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 109962306a36Sopenharmony_ci u8 sta_id = 0; 110062306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 110162306a36Sopenharmony_ci u16 tid = params->tid; 110262306a36Sopenharmony_ci u16 *ssn = ¶ms->ssn; 110362306a36Sopenharmony_ci u8 buf_size = params->buf_size; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci for (ii = 0; ii < RSI_MAX_VIFS; ii++) { 110662306a36Sopenharmony_ci if (vif == adapter->vifs[ii]) 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (ii >= RSI_MAX_VIFS) 111162306a36Sopenharmony_ci return status; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci mutex_lock(&common->mutex); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (ssn != NULL) 111662306a36Sopenharmony_ci seq_no = *ssn; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 111962306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 112062306a36Sopenharmony_ci rsta = rsi_find_sta(common, sta->addr); 112162306a36Sopenharmony_ci if (!rsta) { 112262306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "No station mapped\n"); 112362306a36Sopenharmony_ci status = 0; 112462306a36Sopenharmony_ci goto unlock; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci sta_id = rsta->sta_id; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, 113062306a36Sopenharmony_ci "%s: AMPDU action tid=%d ssn=0x%x, buf_size=%d sta_id=%d\n", 113162306a36Sopenharmony_ci __func__, tid, seq_no, buf_size, sta_id); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci switch (action) { 113462306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 113562306a36Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 113662306a36Sopenharmony_ci tid, 113762306a36Sopenharmony_ci seq_no, 113862306a36Sopenharmony_ci buf_size, 113962306a36Sopenharmony_ci STA_RX_ADDBA_DONE, 114062306a36Sopenharmony_ci sta_id); 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 114462306a36Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 114562306a36Sopenharmony_ci tid, 114662306a36Sopenharmony_ci 0, 114762306a36Sopenharmony_ci buf_size, 114862306a36Sopenharmony_ci STA_RX_DELBA, 114962306a36Sopenharmony_ci sta_id); 115062306a36Sopenharmony_ci break; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 115362306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 115462306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) 115562306a36Sopenharmony_ci common->vif_info[ii].seq_start = seq_no; 115662306a36Sopenharmony_ci else if ((vif->type == NL80211_IFTYPE_AP) || 115762306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 115862306a36Sopenharmony_ci rsta->seq_start[tid] = seq_no; 115962306a36Sopenharmony_ci status = IEEE80211_AMPDU_TX_START_IMMEDIATE; 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 116362306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 116462306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 116562306a36Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 116662306a36Sopenharmony_ci tid, 116762306a36Sopenharmony_ci seq_no, 116862306a36Sopenharmony_ci buf_size, 116962306a36Sopenharmony_ci STA_TX_DELBA, 117062306a36Sopenharmony_ci sta_id); 117162306a36Sopenharmony_ci if (!status) 117262306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 117662306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 117762306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) 117862306a36Sopenharmony_ci seq_start = common->vif_info[ii].seq_start; 117962306a36Sopenharmony_ci else if ((vif->type == NL80211_IFTYPE_AP) || 118062306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) 118162306a36Sopenharmony_ci seq_start = rsta->seq_start[tid]; 118262306a36Sopenharmony_ci status = rsi_send_aggregation_params_frame(common, 118362306a36Sopenharmony_ci tid, 118462306a36Sopenharmony_ci seq_start, 118562306a36Sopenharmony_ci buf_size, 118662306a36Sopenharmony_ci STA_TX_ADDBA_DONE, 118762306a36Sopenharmony_ci sta_id); 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci default: 119162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Unknown AMPDU action\n", __func__); 119262306a36Sopenharmony_ci break; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ciunlock: 119662306a36Sopenharmony_ci mutex_unlock(&common->mutex); 119762306a36Sopenharmony_ci return status; 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci/** 120162306a36Sopenharmony_ci * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. 120262306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 120362306a36Sopenharmony_ci * @value: Rts threshold value. 120462306a36Sopenharmony_ci * 120562306a36Sopenharmony_ci * Return: 0 on success. 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_cistatic int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, 120862306a36Sopenharmony_ci u32 value) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 121162306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci mutex_lock(&common->mutex); 121462306a36Sopenharmony_ci common->rts_threshold = value; 121562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci return 0; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci/** 122162306a36Sopenharmony_ci * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. 122262306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure 122362306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 122462306a36Sopenharmony_ci * @mask: Pointer to the cfg80211_bitrate_mask structure. 122562306a36Sopenharmony_ci * 122662306a36Sopenharmony_ci * Return: 0 on success. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_cistatic int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, 122962306a36Sopenharmony_ci struct ieee80211_vif *vif, 123062306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci const unsigned int mcs_offset = ARRAY_SIZE(rsi_rates); 123362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 123462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 123562306a36Sopenharmony_ci int i; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci mutex_lock(&common->mutex); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(common->rate_config); i++) { 124062306a36Sopenharmony_ci struct rsi_rate_config *cfg = &common->rate_config[i]; 124162306a36Sopenharmony_ci u32 bm; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci bm = mask->control[i].legacy | (mask->control[i].ht_mcs[0] << mcs_offset); 124462306a36Sopenharmony_ci if (hweight32(bm) == 1) { /* single rate */ 124562306a36Sopenharmony_ci int rate_index = ffs(bm) - 1; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (rate_index < mcs_offset) 124862306a36Sopenharmony_ci cfg->fixed_hw_rate = rsi_rates[rate_index].hw_value; 124962306a36Sopenharmony_ci else 125062306a36Sopenharmony_ci cfg->fixed_hw_rate = rsi_mcsrates[rate_index - mcs_offset]; 125162306a36Sopenharmony_ci cfg->fixed_enabled = true; 125262306a36Sopenharmony_ci } else { 125362306a36Sopenharmony_ci cfg->configured_mask = bm; 125462306a36Sopenharmony_ci cfg->fixed_enabled = false; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci mutex_unlock(&common->mutex); 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci/** 126462306a36Sopenharmony_ci * rsi_perform_cqm() - This function performs cqm. 126562306a36Sopenharmony_ci * @common: Pointer to the driver private structure. 126662306a36Sopenharmony_ci * @bssid: pointer to the bssid. 126762306a36Sopenharmony_ci * @rssi: RSSI value. 126862306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_cistatic void rsi_perform_cqm(struct rsi_common *common, 127162306a36Sopenharmony_ci u8 *bssid, 127262306a36Sopenharmony_ci s8 rssi, 127362306a36Sopenharmony_ci struct ieee80211_vif *vif) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci s8 last_event = common->cqm_info.last_cqm_event_rssi; 127662306a36Sopenharmony_ci int thold = common->cqm_info.rssi_thold; 127762306a36Sopenharmony_ci u32 hyst = common->cqm_info.rssi_hyst; 127862306a36Sopenharmony_ci enum nl80211_cqm_rssi_threshold_event event; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (rssi < thold && (last_event == 0 || rssi < (last_event - hyst))) 128162306a36Sopenharmony_ci event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; 128262306a36Sopenharmony_ci else if (rssi > thold && 128362306a36Sopenharmony_ci (last_event == 0 || rssi > (last_event + hyst))) 128462306a36Sopenharmony_ci event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; 128562306a36Sopenharmony_ci else 128662306a36Sopenharmony_ci return; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci common->cqm_info.last_cqm_event_rssi = rssi; 128962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event); 129062306a36Sopenharmony_ci ieee80211_cqm_rssi_notify(vif, event, rssi, GFP_KERNEL); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci return; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci/** 129662306a36Sopenharmony_ci * rsi_fill_rx_status() - This function fills rx status in 129762306a36Sopenharmony_ci * ieee80211_rx_status structure. 129862306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 129962306a36Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 130062306a36Sopenharmony_ci * @common: Pointer to the driver private structure. 130162306a36Sopenharmony_ci * @rxs: Pointer to the ieee80211_rx_status structure. 130262306a36Sopenharmony_ci * 130362306a36Sopenharmony_ci * Return: None. 130462306a36Sopenharmony_ci */ 130562306a36Sopenharmony_cistatic void rsi_fill_rx_status(struct ieee80211_hw *hw, 130662306a36Sopenharmony_ci struct sk_buff *skb, 130762306a36Sopenharmony_ci struct rsi_common *common, 130862306a36Sopenharmony_ci struct ieee80211_rx_status *rxs) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct rsi_hw *adapter = common->priv; 131162306a36Sopenharmony_ci struct ieee80211_vif *vif; 131262306a36Sopenharmony_ci struct ieee80211_bss_conf *bss = NULL; 131362306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 131462306a36Sopenharmony_ci struct skb_info *rx_params = (struct skb_info *)info->driver_data; 131562306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 131662306a36Sopenharmony_ci char rssi = rx_params->rssi; 131762306a36Sopenharmony_ci u8 hdrlen = 0; 131862306a36Sopenharmony_ci u8 channel = rx_params->channel; 131962306a36Sopenharmony_ci s32 freq; 132062306a36Sopenharmony_ci int i; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci hdr = ((struct ieee80211_hdr *)(skb->data)); 132362306a36Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci memset(info, 0, sizeof(struct ieee80211_tx_info)); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci rxs->signal = -(rssi); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci rxs->band = common->band; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci freq = ieee80211_channel_to_frequency(channel, rxs->band); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (freq) 133462306a36Sopenharmony_ci rxs->freq = freq; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci if (ieee80211_has_protected(hdr->frame_control)) { 133762306a36Sopenharmony_ci if (rsi_is_cipher_wep(common)) { 133862306a36Sopenharmony_ci memmove(skb->data + 4, skb->data, hdrlen); 133962306a36Sopenharmony_ci skb_pull(skb, 4); 134062306a36Sopenharmony_ci } else { 134162306a36Sopenharmony_ci memmove(skb->data + 8, skb->data, hdrlen); 134262306a36Sopenharmony_ci skb_pull(skb, 8); 134362306a36Sopenharmony_ci rxs->flag |= RX_FLAG_MMIC_STRIPPED; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci rxs->flag |= RX_FLAG_DECRYPTED; 134662306a36Sopenharmony_ci rxs->flag |= RX_FLAG_IV_STRIPPED; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci for (i = 0; i < RSI_MAX_VIFS; i++) { 135062306a36Sopenharmony_ci vif = adapter->vifs[i]; 135162306a36Sopenharmony_ci if (!vif) 135262306a36Sopenharmony_ci continue; 135362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) { 135462306a36Sopenharmony_ci bss = &vif->bss_conf; 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci } 135862306a36Sopenharmony_ci if (!bss) 135962306a36Sopenharmony_ci return; 136062306a36Sopenharmony_ci /* CQM only for connected AP beacons, the RSSI is a weighted avg */ 136162306a36Sopenharmony_ci if (vif->cfg.assoc && !(memcmp(bss->bssid, hdr->addr2, ETH_ALEN))) { 136262306a36Sopenharmony_ci if (ieee80211_is_beacon(hdr->frame_control)) 136362306a36Sopenharmony_ci rsi_perform_cqm(common, hdr->addr2, rxs->signal, vif); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci return; 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/** 137062306a36Sopenharmony_ci * rsi_indicate_pkt_to_os() - This function sends received packet to mac80211. 137162306a36Sopenharmony_ci * @common: Pointer to the driver private structure. 137262306a36Sopenharmony_ci * @skb: Pointer to the socket buffer structure. 137362306a36Sopenharmony_ci * 137462306a36Sopenharmony_ci * Return: None. 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_civoid rsi_indicate_pkt_to_os(struct rsi_common *common, 137762306a36Sopenharmony_ci struct sk_buff *skb) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct rsi_hw *adapter = common->priv; 138062306a36Sopenharmony_ci struct ieee80211_hw *hw = adapter->hw; 138162306a36Sopenharmony_ci struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if ((common->iface_down) || (!adapter->sc_nvifs)) { 138462306a36Sopenharmony_ci dev_kfree_skb(skb); 138562306a36Sopenharmony_ci return; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* filling in the ieee80211_rx_status flags */ 138962306a36Sopenharmony_ci rsi_fill_rx_status(hw, skb, common, rx_status); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci ieee80211_rx_irqsafe(hw, skb); 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci/** 139562306a36Sopenharmony_ci * rsi_mac80211_sta_add() - This function notifies driver about a peer getting 139662306a36Sopenharmony_ci * connected. 139762306a36Sopenharmony_ci * @hw: pointer to the ieee80211_hw structure. 139862306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 139962306a36Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 140062306a36Sopenharmony_ci * 140162306a36Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_cistatic int rsi_mac80211_sta_add(struct ieee80211_hw *hw, 140462306a36Sopenharmony_ci struct ieee80211_vif *vif, 140562306a36Sopenharmony_ci struct ieee80211_sta *sta) 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 140862306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 140962306a36Sopenharmony_ci bool sta_exist = false; 141062306a36Sopenharmony_ci struct rsi_sta *rsta; 141162306a36Sopenharmony_ci int status = 0; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station Add: %pM\n", sta->addr); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci mutex_lock(&common->mutex); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 141862306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 141962306a36Sopenharmony_ci u8 cnt; 142062306a36Sopenharmony_ci int sta_idx = -1; 142162306a36Sopenharmony_ci int free_index = -1; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci /* Check if max stations reached */ 142462306a36Sopenharmony_ci if (common->num_stations >= common->max_stations) { 142562306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Reject: Max Stations exists\n"); 142662306a36Sopenharmony_ci status = -EOPNOTSUPP; 142762306a36Sopenharmony_ci goto unlock; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci for (cnt = 0; cnt < common->max_stations; cnt++) { 143062306a36Sopenharmony_ci rsta = &common->stations[cnt]; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci if (!rsta->sta) { 143362306a36Sopenharmony_ci if (free_index < 0) 143462306a36Sopenharmony_ci free_index = cnt; 143562306a36Sopenharmony_ci continue; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { 143862306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station exists\n"); 143962306a36Sopenharmony_ci sta_idx = cnt; 144062306a36Sopenharmony_ci sta_exist = true; 144162306a36Sopenharmony_ci break; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci if (!sta_exist) { 144562306a36Sopenharmony_ci if (free_index >= 0) 144662306a36Sopenharmony_ci sta_idx = free_index; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci if (sta_idx < 0) { 144962306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 145062306a36Sopenharmony_ci "%s: Some problem reaching here...\n", 145162306a36Sopenharmony_ci __func__); 145262306a36Sopenharmony_ci status = -EINVAL; 145362306a36Sopenharmony_ci goto unlock; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci rsta = &common->stations[sta_idx]; 145662306a36Sopenharmony_ci rsta->sta = sta; 145762306a36Sopenharmony_ci rsta->sta_id = sta_idx; 145862306a36Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 145962306a36Sopenharmony_ci rsta->start_tx_aggr[cnt] = false; 146062306a36Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 146162306a36Sopenharmony_ci rsta->seq_start[cnt] = 0; 146262306a36Sopenharmony_ci if (!sta_exist) { 146362306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "New Station\n"); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* Send peer notify to device */ 146662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); 146762306a36Sopenharmony_ci rsi_inform_bss_status(common, RSI_OPMODE_AP, 1, 146862306a36Sopenharmony_ci sta->addr, sta->wme, sta->aid, 146962306a36Sopenharmony_ci sta, sta_idx, 0, vif); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (common->key) { 147262306a36Sopenharmony_ci struct ieee80211_key_conf *key = common->key; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || 147562306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_WEP40)) 147662306a36Sopenharmony_ci rsi_hal_load_key(adapter->priv, 147762306a36Sopenharmony_ci key->key, 147862306a36Sopenharmony_ci key->keylen, 147962306a36Sopenharmony_ci RSI_PAIRWISE_KEY, 148062306a36Sopenharmony_ci key->keyidx, 148162306a36Sopenharmony_ci key->cipher, 148262306a36Sopenharmony_ci sta_idx, 148362306a36Sopenharmony_ci vif); 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci common->num_stations++; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci } 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 149162306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { 149262306a36Sopenharmony_ci common->bitrate_mask[common->band] = sta->deflink.supp_rates[common->band]; 149362306a36Sopenharmony_ci common->vif_info[0].is_ht = sta->deflink.ht_cap.ht_supported; 149462306a36Sopenharmony_ci if (sta->deflink.ht_cap.ht_supported) { 149562306a36Sopenharmony_ci common->bitrate_mask[NL80211_BAND_2GHZ] = 149662306a36Sopenharmony_ci sta->deflink.supp_rates[NL80211_BAND_2GHZ]; 149762306a36Sopenharmony_ci if ((sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || 149862306a36Sopenharmony_ci (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) 149962306a36Sopenharmony_ci common->vif_info[0].sgi = true; 150062306a36Sopenharmony_ci ieee80211_start_tx_ba_session(sta, 0, 0); 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ciunlock: 150562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return status; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci/** 151162306a36Sopenharmony_ci * rsi_mac80211_sta_remove() - This function notifies driver about a peer 151262306a36Sopenharmony_ci * getting disconnected. 151362306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 151462306a36Sopenharmony_ci * @vif: Pointer to the ieee80211_vif structure. 151562306a36Sopenharmony_ci * @sta: Pointer to the ieee80211_sta structure. 151662306a36Sopenharmony_ci * 151762306a36Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_cistatic int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, 152062306a36Sopenharmony_ci struct ieee80211_vif *vif, 152162306a36Sopenharmony_ci struct ieee80211_sta *sta) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 152462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 152562306a36Sopenharmony_ci struct ieee80211_bss_conf *bss = &vif->bss_conf; 152662306a36Sopenharmony_ci struct rsi_sta *rsta; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Station Remove: %pM\n", sta->addr); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci mutex_lock(&common->mutex); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 153362306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 153462306a36Sopenharmony_ci u8 sta_idx, cnt; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci /* Send peer notify to device */ 153762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); 153862306a36Sopenharmony_ci for (sta_idx = 0; sta_idx < common->max_stations; sta_idx++) { 153962306a36Sopenharmony_ci rsta = &common->stations[sta_idx]; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (!rsta->sta) 154262306a36Sopenharmony_ci continue; 154362306a36Sopenharmony_ci if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { 154462306a36Sopenharmony_ci rsi_inform_bss_status(common, RSI_OPMODE_AP, 0, 154562306a36Sopenharmony_ci sta->addr, sta->wme, 154662306a36Sopenharmony_ci sta->aid, sta, sta_idx, 154762306a36Sopenharmony_ci 0, vif); 154862306a36Sopenharmony_ci rsta->sta = NULL; 154962306a36Sopenharmony_ci rsta->sta_id = -1; 155062306a36Sopenharmony_ci for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) 155162306a36Sopenharmony_ci rsta->start_tx_aggr[cnt] = false; 155262306a36Sopenharmony_ci if (common->num_stations > 0) 155362306a36Sopenharmony_ci common->num_stations--; 155462306a36Sopenharmony_ci break; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci if (sta_idx >= common->max_stations) 155862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: No station found\n", __func__); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_STATION) || 156262306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) { 156362306a36Sopenharmony_ci /* Resetting all the fields to default values */ 156462306a36Sopenharmony_ci memcpy((u8 *)bss->bssid, (u8 *)sta->addr, ETH_ALEN); 156562306a36Sopenharmony_ci bss->qos = sta->wme; 156662306a36Sopenharmony_ci common->bitrate_mask[NL80211_BAND_2GHZ] = 0; 156762306a36Sopenharmony_ci common->bitrate_mask[NL80211_BAND_5GHZ] = 0; 156862306a36Sopenharmony_ci common->vif_info[0].is_ht = false; 156962306a36Sopenharmony_ci common->vif_info[0].sgi = false; 157062306a36Sopenharmony_ci common->vif_info[0].seq_start = 0; 157162306a36Sopenharmony_ci common->secinfo.ptk_cipher = 0; 157262306a36Sopenharmony_ci common->secinfo.gtk_cipher = 0; 157362306a36Sopenharmony_ci if (!common->iface_down) 157462306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, 0); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci mutex_unlock(&common->mutex); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci return 0; 157962306a36Sopenharmony_ci} 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci/** 158262306a36Sopenharmony_ci * rsi_mac80211_set_antenna() - This function is used to configure 158362306a36Sopenharmony_ci * tx and rx antennas. 158462306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 158562306a36Sopenharmony_ci * @tx_ant: Bitmap for tx antenna 158662306a36Sopenharmony_ci * @rx_ant: Bitmap for rx antenna 158762306a36Sopenharmony_ci * 158862306a36Sopenharmony_ci * Return: 0 on success, Negative error code on failure. 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_cistatic int rsi_mac80211_set_antenna(struct ieee80211_hw *hw, 159162306a36Sopenharmony_ci u32 tx_ant, u32 rx_ant) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 159462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 159562306a36Sopenharmony_ci u8 antenna = 0; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (tx_ant > 1 || rx_ant > 1) { 159862306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 159962306a36Sopenharmony_ci "Invalid antenna selection (tx: %d, rx:%d)\n", 160062306a36Sopenharmony_ci tx_ant, rx_ant); 160162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 160262306a36Sopenharmony_ci "Use 0 for int_ant, 1 for ext_ant\n"); 160362306a36Sopenharmony_ci return -EINVAL; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Antenna map Tx %x Rx %d\n", 160762306a36Sopenharmony_ci __func__, tx_ant, rx_ant); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci mutex_lock(&common->mutex); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci antenna = tx_ant ? ANTENNA_SEL_UFL : ANTENNA_SEL_INT; 161262306a36Sopenharmony_ci if (common->ant_in_use != antenna) 161362306a36Sopenharmony_ci if (rsi_set_antenna(common, antenna)) 161462306a36Sopenharmony_ci goto fail_set_antenna; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "(%s) Antenna path configured successfully\n", 161762306a36Sopenharmony_ci tx_ant ? "UFL" : "INT"); 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci common->ant_in_use = antenna; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci mutex_unlock(&common->mutex); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci return 0; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_cifail_set_antenna: 162662306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: Failed.\n", __func__); 162762306a36Sopenharmony_ci mutex_unlock(&common->mutex); 162862306a36Sopenharmony_ci return -EINVAL; 162962306a36Sopenharmony_ci} 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci/** 163262306a36Sopenharmony_ci * rsi_mac80211_get_antenna() - This function is used to configure 163362306a36Sopenharmony_ci * tx and rx antennas. 163462306a36Sopenharmony_ci * 163562306a36Sopenharmony_ci * @hw: Pointer to the ieee80211_hw structure. 163662306a36Sopenharmony_ci * @tx_ant: Bitmap for tx antenna 163762306a36Sopenharmony_ci * @rx_ant: Bitmap for rx antenna 163862306a36Sopenharmony_ci * 163962306a36Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 164062306a36Sopenharmony_ci */ 164162306a36Sopenharmony_cistatic int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, 164262306a36Sopenharmony_ci u32 *tx_ant, u32 *rx_ant) 164362306a36Sopenharmony_ci{ 164462306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 164562306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci mutex_lock(&common->mutex); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci *tx_ant = (common->ant_in_use == ANTENNA_SEL_UFL) ? 1 : 0; 165062306a36Sopenharmony_ci *rx_ant = 0; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci return 0; 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic int rsi_map_region_code(enum nl80211_dfs_regions region_code) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci switch (region_code) { 166062306a36Sopenharmony_ci case NL80211_DFS_FCC: 166162306a36Sopenharmony_ci return RSI_REGION_FCC; 166262306a36Sopenharmony_ci case NL80211_DFS_ETSI: 166362306a36Sopenharmony_ci return RSI_REGION_ETSI; 166462306a36Sopenharmony_ci case NL80211_DFS_JP: 166562306a36Sopenharmony_ci return RSI_REGION_TELEC; 166662306a36Sopenharmony_ci case NL80211_DFS_UNSET: 166762306a36Sopenharmony_ci return RSI_REGION_WORLD; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci return RSI_REGION_WORLD; 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic void rsi_reg_notify(struct wiphy *wiphy, 167362306a36Sopenharmony_ci struct regulatory_request *request) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 167662306a36Sopenharmony_ci struct ieee80211_channel *ch; 167762306a36Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 167862306a36Sopenharmony_ci struct rsi_hw * adapter = hw->priv; 167962306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 168062306a36Sopenharmony_ci int i; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci mutex_lock(&common->mutex); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "country = %s dfs_region = %d\n", 168562306a36Sopenharmony_ci request->alpha2, request->dfs_region); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (common->num_supp_bands > 1) { 168862306a36Sopenharmony_ci sband = wiphy->bands[NL80211_BAND_5GHZ]; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 169162306a36Sopenharmony_ci ch = &sband->channels[i]; 169262306a36Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_DISABLED) 169362306a36Sopenharmony_ci continue; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_RADAR) 169662306a36Sopenharmony_ci ch->flags |= IEEE80211_CHAN_NO_IR; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci adapter->dfs_region = rsi_map_region_code(request->dfs_region); 170062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "RSI region code = %d\n", adapter->dfs_region); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci adapter->country[0] = request->alpha2[0]; 170362306a36Sopenharmony_ci adapter->country[1] = request->alpha2[1]; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic void rsi_mac80211_rfkill_poll(struct ieee80211_hw *hw) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 171162306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci mutex_lock(&common->mutex); 171462306a36Sopenharmony_ci if (common->fsm_state != FSM_MAC_INIT_DONE) 171562306a36Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, true); 171662306a36Sopenharmony_ci else 171762306a36Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, false); 171862306a36Sopenharmony_ci mutex_unlock(&common->mutex); 171962306a36Sopenharmony_ci} 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cistatic void rsi_resume_conn_channel(struct rsi_common *common) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci struct rsi_hw *adapter = common->priv; 172462306a36Sopenharmony_ci struct ieee80211_vif *vif; 172562306a36Sopenharmony_ci int cnt; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci for (cnt = 0; cnt < RSI_MAX_VIFS; cnt++) { 172862306a36Sopenharmony_ci vif = adapter->vifs[cnt]; 172962306a36Sopenharmony_ci if (!vif) 173062306a36Sopenharmony_ci continue; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_AP) || 173362306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_GO)) { 173462306a36Sopenharmony_ci rsi_switch_channel(adapter, vif); 173562306a36Sopenharmony_ci break; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci if (((vif->type == NL80211_IFTYPE_STATION) || 173862306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_P2P_CLIENT)) && 173962306a36Sopenharmony_ci vif->cfg.assoc) { 174062306a36Sopenharmony_ci rsi_switch_channel(adapter, vif); 174162306a36Sopenharmony_ci break; 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_civoid rsi_roc_timeout(struct timer_list *t) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct rsi_common *common = from_timer(common, t, roc_timer); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Remain on channel expired\n"); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci mutex_lock(&common->mutex); 175362306a36Sopenharmony_ci ieee80211_remain_on_channel_expired(common->priv->hw); 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (timer_pending(&common->roc_timer)) 175662306a36Sopenharmony_ci del_timer(&common->roc_timer); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci rsi_resume_conn_channel(common); 175962306a36Sopenharmony_ci mutex_unlock(&common->mutex); 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic int rsi_mac80211_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 176362306a36Sopenharmony_ci struct ieee80211_channel *chan, int duration, 176462306a36Sopenharmony_ci enum ieee80211_roc_type type) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 176762306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 176862306a36Sopenharmony_ci int status = 0; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "***** Remain on channel *****\n"); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci mutex_lock(&common->mutex); 177362306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: channel: %d duration: %dms\n", 177462306a36Sopenharmony_ci __func__, chan->hw_value, duration); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci if (timer_pending(&common->roc_timer)) { 177762306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Stop on-going ROC\n"); 177862306a36Sopenharmony_ci del_timer(&common->roc_timer); 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci common->roc_timer.expires = msecs_to_jiffies(duration) + jiffies; 178162306a36Sopenharmony_ci add_timer(&common->roc_timer); 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci /* Configure band */ 178462306a36Sopenharmony_ci if (rsi_band_check(common, chan)) { 178562306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set band\n"); 178662306a36Sopenharmony_ci status = -EINVAL; 178762306a36Sopenharmony_ci goto out; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* Configure channel */ 179162306a36Sopenharmony_ci if (rsi_set_channel(common, chan)) { 179262306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to set the channel\n"); 179362306a36Sopenharmony_ci status = -EINVAL; 179462306a36Sopenharmony_ci goto out; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci common->roc_vif = vif; 179862306a36Sopenharmony_ci ieee80211_ready_on_channel(hw); 179962306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: Ready on channel :%d\n", 180062306a36Sopenharmony_ci __func__, chan->hw_value); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ciout: 180362306a36Sopenharmony_ci mutex_unlock(&common->mutex); 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci return status; 180662306a36Sopenharmony_ci} 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_cistatic int rsi_mac80211_cancel_roc(struct ieee80211_hw *hw, 180962306a36Sopenharmony_ci struct ieee80211_vif *vif) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 181262306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Cancel remain on channel\n"); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci mutex_lock(&common->mutex); 181762306a36Sopenharmony_ci if (!timer_pending(&common->roc_timer)) { 181862306a36Sopenharmony_ci mutex_unlock(&common->mutex); 181962306a36Sopenharmony_ci return 0; 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci del_timer(&common->roc_timer); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci rsi_resume_conn_channel(common); 182562306a36Sopenharmony_ci mutex_unlock(&common->mutex); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci return 0; 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci#ifdef CONFIG_PM 183162306a36Sopenharmony_cistatic const struct wiphy_wowlan_support rsi_wowlan_support = { 183262306a36Sopenharmony_ci .flags = WIPHY_WOWLAN_ANY | 183362306a36Sopenharmony_ci WIPHY_WOWLAN_MAGIC_PKT | 183462306a36Sopenharmony_ci WIPHY_WOWLAN_DISCONNECT | 183562306a36Sopenharmony_ci WIPHY_WOWLAN_GTK_REKEY_FAILURE | 183662306a36Sopenharmony_ci WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | 183762306a36Sopenharmony_ci WIPHY_WOWLAN_EAP_IDENTITY_REQ | 183862306a36Sopenharmony_ci WIPHY_WOWLAN_4WAY_HANDSHAKE, 183962306a36Sopenharmony_ci}; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistatic u16 rsi_wow_map_triggers(struct rsi_common *common, 184262306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci u16 wow_triggers = 0; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Mapping wowlan triggers\n"); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci if (wowlan->any) 184962306a36Sopenharmony_ci wow_triggers |= RSI_WOW_ANY; 185062306a36Sopenharmony_ci if (wowlan->magic_pkt) 185162306a36Sopenharmony_ci wow_triggers |= RSI_WOW_MAGIC_PKT; 185262306a36Sopenharmony_ci if (wowlan->disconnect) 185362306a36Sopenharmony_ci wow_triggers |= RSI_WOW_DISCONNECT; 185462306a36Sopenharmony_ci if (wowlan->gtk_rekey_failure || wowlan->eap_identity_req || 185562306a36Sopenharmony_ci wowlan->four_way_handshake) 185662306a36Sopenharmony_ci wow_triggers |= RSI_WOW_GTK_REKEY; 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci return wow_triggers; 185962306a36Sopenharmony_ci} 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ciint rsi_config_wowlan(struct rsi_hw *adapter, struct cfg80211_wowlan *wowlan) 186262306a36Sopenharmony_ci{ 186362306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 186462306a36Sopenharmony_ci struct ieee80211_vif *vif = adapter->vifs[0]; 186562306a36Sopenharmony_ci u16 triggers = 0; 186662306a36Sopenharmony_ci u16 rx_filter_word = 0; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "Config WoWLAN to device\n"); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (!vif) 187162306a36Sopenharmony_ci return -EINVAL; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (WARN_ON(!wowlan)) { 187462306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "WoW triggers not enabled\n"); 187562306a36Sopenharmony_ci return -EINVAL; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci common->wow_flags |= RSI_WOW_ENABLED; 187962306a36Sopenharmony_ci triggers = rsi_wow_map_triggers(common, wowlan); 188062306a36Sopenharmony_ci if (!triggers) { 188162306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s:No valid WoW triggers\n", __func__); 188262306a36Sopenharmony_ci return -EINVAL; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci if (!vif->cfg.assoc) { 188562306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, 188662306a36Sopenharmony_ci "Cannot configure WoWLAN (Station not connected)\n"); 188762306a36Sopenharmony_ci common->wow_flags |= RSI_WOW_NO_CONNECTION; 188862306a36Sopenharmony_ci return 0; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "TRIGGERS %x\n", triggers); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (common->coex_mode > 1) 189362306a36Sopenharmony_ci rsi_disable_ps(adapter, adapter->vifs[0]); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci rsi_send_wowlan_request(common, triggers, 1); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /** 189862306a36Sopenharmony_ci * Increase the beacon_miss threshold & keep-alive timers in 189962306a36Sopenharmony_ci * vap_update frame 190062306a36Sopenharmony_ci */ 190162306a36Sopenharmony_ci rsi_send_vap_dynamic_update(common); 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | DISALLOW_BEACONS); 190462306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci return 0; 190762306a36Sopenharmony_ci} 190862306a36Sopenharmony_ciEXPORT_SYMBOL(rsi_config_wowlan); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_cistatic int rsi_mac80211_suspend(struct ieee80211_hw *hw, 191162306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 191262306a36Sopenharmony_ci{ 191362306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 191462306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: mac80211 suspend\n", __func__); 191762306a36Sopenharmony_ci mutex_lock(&common->mutex); 191862306a36Sopenharmony_ci if (rsi_config_wowlan(adapter, wowlan)) { 191962306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n"); 192062306a36Sopenharmony_ci mutex_unlock(&common->mutex); 192162306a36Sopenharmony_ci return 1; 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci mutex_unlock(&common->mutex); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci return 0; 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cistatic int rsi_mac80211_resume(struct ieee80211_hw *hw) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci u16 rx_filter_word = 0; 193162306a36Sopenharmony_ci struct rsi_hw *adapter = hw->priv; 193262306a36Sopenharmony_ci struct rsi_common *common = adapter->priv; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci common->wow_flags = 0; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci rsi_dbg(INFO_ZONE, "%s: mac80211 resume\n", __func__); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (common->hibernate_resume) { 193962306a36Sopenharmony_ci common->mac_ops_resumed = true; 194062306a36Sopenharmony_ci /* Device need a complete restart of all MAC operations. 194162306a36Sopenharmony_ci * returning 1 will serve this purpose. 194262306a36Sopenharmony_ci */ 194362306a36Sopenharmony_ci return 1; 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci mutex_lock(&common->mutex); 194762306a36Sopenharmony_ci rsi_send_wowlan_request(common, 0, 0); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci rx_filter_word = (ALLOW_DATA_ASSOC_PEER | ALLOW_CTRL_ASSOC_PEER | 195062306a36Sopenharmony_ci ALLOW_MGMT_ASSOC_PEER); 195162306a36Sopenharmony_ci rsi_send_rx_filter_frame(common, rx_filter_word); 195262306a36Sopenharmony_ci mutex_unlock(&common->mutex); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return 0; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci#endif 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_cistatic const struct ieee80211_ops mac80211_ops = { 196062306a36Sopenharmony_ci .tx = rsi_mac80211_tx, 196162306a36Sopenharmony_ci .wake_tx_queue = ieee80211_handle_wake_tx_queue, 196262306a36Sopenharmony_ci .start = rsi_mac80211_start, 196362306a36Sopenharmony_ci .stop = rsi_mac80211_stop, 196462306a36Sopenharmony_ci .add_interface = rsi_mac80211_add_interface, 196562306a36Sopenharmony_ci .remove_interface = rsi_mac80211_remove_interface, 196662306a36Sopenharmony_ci .config = rsi_mac80211_config, 196762306a36Sopenharmony_ci .bss_info_changed = rsi_mac80211_bss_info_changed, 196862306a36Sopenharmony_ci .conf_tx = rsi_mac80211_conf_tx, 196962306a36Sopenharmony_ci .configure_filter = rsi_mac80211_conf_filter, 197062306a36Sopenharmony_ci .set_key = rsi_mac80211_set_key, 197162306a36Sopenharmony_ci .set_rts_threshold = rsi_mac80211_set_rts_threshold, 197262306a36Sopenharmony_ci .set_bitrate_mask = rsi_mac80211_set_rate_mask, 197362306a36Sopenharmony_ci .ampdu_action = rsi_mac80211_ampdu_action, 197462306a36Sopenharmony_ci .sta_add = rsi_mac80211_sta_add, 197562306a36Sopenharmony_ci .sta_remove = rsi_mac80211_sta_remove, 197662306a36Sopenharmony_ci .set_antenna = rsi_mac80211_set_antenna, 197762306a36Sopenharmony_ci .get_antenna = rsi_mac80211_get_antenna, 197862306a36Sopenharmony_ci .rfkill_poll = rsi_mac80211_rfkill_poll, 197962306a36Sopenharmony_ci .remain_on_channel = rsi_mac80211_roc, 198062306a36Sopenharmony_ci .cancel_remain_on_channel = rsi_mac80211_cancel_roc, 198162306a36Sopenharmony_ci#ifdef CONFIG_PM 198262306a36Sopenharmony_ci .suspend = rsi_mac80211_suspend, 198362306a36Sopenharmony_ci .resume = rsi_mac80211_resume, 198462306a36Sopenharmony_ci#endif 198562306a36Sopenharmony_ci .hw_scan = rsi_mac80211_hw_scan_start, 198662306a36Sopenharmony_ci .cancel_hw_scan = rsi_mac80211_cancel_hw_scan, 198762306a36Sopenharmony_ci}; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci/** 199062306a36Sopenharmony_ci * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. 199162306a36Sopenharmony_ci * @common: Pointer to the driver private structure. 199262306a36Sopenharmony_ci * 199362306a36Sopenharmony_ci * Return: 0 on success, negative error codes on failure. 199462306a36Sopenharmony_ci */ 199562306a36Sopenharmony_ciint rsi_mac80211_attach(struct rsi_common *common) 199662306a36Sopenharmony_ci{ 199762306a36Sopenharmony_ci int status = 0; 199862306a36Sopenharmony_ci struct ieee80211_hw *hw = NULL; 199962306a36Sopenharmony_ci struct wiphy *wiphy = NULL; 200062306a36Sopenharmony_ci struct rsi_hw *adapter = common->priv; 200162306a36Sopenharmony_ci u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); 200662306a36Sopenharmony_ci if (!hw) { 200762306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); 200862306a36Sopenharmony_ci return -ENOMEM; 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci wiphy = hw->wiphy; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci SET_IEEE80211_DEV(hw, adapter->device); 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci hw->priv = adapter; 201662306a36Sopenharmony_ci adapter->hw = hw; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 201962306a36Sopenharmony_ci ieee80211_hw_set(hw, HAS_RATE_CONTROL); 202062306a36Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 202162306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 202262306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci hw->queues = MAX_HW_QUEUES; 202562306a36Sopenharmony_ci hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci hw->max_rates = 1; 202862306a36Sopenharmony_ci hw->max_rate_tries = MAX_RETRIES; 202962306a36Sopenharmony_ci hw->uapsd_queues = RSI_IEEE80211_UAPSD_QUEUES; 203062306a36Sopenharmony_ci hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci hw->max_tx_aggregation_subframes = RSI_MAX_TX_AGGR_FRMS; 203362306a36Sopenharmony_ci hw->max_rx_aggregation_subframes = RSI_MAX_RX_AGGR_FRMS; 203462306a36Sopenharmony_ci hw->rate_control_algorithm = "AARF"; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); 203762306a36Sopenharmony_ci ether_addr_copy(hw->wiphy->addr_mask, addr_mask); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 204062306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 204162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE) | 204262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 204362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO); 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 204662306a36Sopenharmony_ci wiphy->retry_short = RETRY_SHORT; 204762306a36Sopenharmony_ci wiphy->retry_long = RETRY_LONG; 204862306a36Sopenharmony_ci wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; 204962306a36Sopenharmony_ci wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; 205062306a36Sopenharmony_ci wiphy->flags = 0; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci wiphy->available_antennas_rx = 1; 205362306a36Sopenharmony_ci wiphy->available_antennas_tx = 1; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci status = rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); 205662306a36Sopenharmony_ci if (status) 205762306a36Sopenharmony_ci return status; 205862306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_2GHZ] = 205962306a36Sopenharmony_ci &adapter->sbands[NL80211_BAND_2GHZ]; 206062306a36Sopenharmony_ci if (common->num_supp_bands > 1) { 206162306a36Sopenharmony_ci status = rsi_register_rates_channels(adapter, 206262306a36Sopenharmony_ci NL80211_BAND_5GHZ); 206362306a36Sopenharmony_ci if (status) 206462306a36Sopenharmony_ci return status; 206562306a36Sopenharmony_ci wiphy->bands[NL80211_BAND_5GHZ] = 206662306a36Sopenharmony_ci &adapter->sbands[NL80211_BAND_5GHZ]; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci /* AP Parameters */ 207062306a36Sopenharmony_ci wiphy->max_ap_assoc_sta = rsi_max_ap_stas[common->oper_mode - 1]; 207162306a36Sopenharmony_ci common->max_stations = wiphy->max_ap_assoc_sta; 207262306a36Sopenharmony_ci rsi_dbg(ERR_ZONE, "Max Stations Allowed = %d\n", common->max_stations); 207362306a36Sopenharmony_ci hw->sta_data_size = sizeof(struct rsi_sta); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci wiphy->max_scan_ssids = RSI_MAX_SCAN_SSIDS; 207662306a36Sopenharmony_ci wiphy->max_scan_ie_len = RSI_MAX_SCAN_IE_LEN; 207762306a36Sopenharmony_ci wiphy->flags = WIPHY_FLAG_REPORTS_OBSS; 207862306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 207962306a36Sopenharmony_ci wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; 208062306a36Sopenharmony_ci wiphy->reg_notifier = rsi_reg_notify; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci#ifdef CONFIG_PM 208362306a36Sopenharmony_ci wiphy->wowlan = &rsi_wowlan_support; 208462306a36Sopenharmony_ci#endif 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci /* Wi-Fi direct parameters */ 208962306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 209062306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX; 209162306a36Sopenharmony_ci wiphy->max_remain_on_channel_duration = 10000; 209262306a36Sopenharmony_ci hw->max_listen_interval = 10; 209362306a36Sopenharmony_ci wiphy->iface_combinations = rsi_iface_combinations; 209462306a36Sopenharmony_ci wiphy->n_iface_combinations = ARRAY_SIZE(rsi_iface_combinations); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci if (common->coex_mode > 1) 209762306a36Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci status = ieee80211_register_hw(hw); 210062306a36Sopenharmony_ci if (status) 210162306a36Sopenharmony_ci return status; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci return rsi_init_dbgfs(adapter); 210462306a36Sopenharmony_ci} 2105