162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2005-2011 Atheros Communications Inc. 462306a36Sopenharmony_ci * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 562306a36Sopenharmony_ci * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "mac.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <net/cfg80211.h> 1162306a36Sopenharmony_ci#include <net/mac80211.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/acpi.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/bitfield.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "hif.h" 1862306a36Sopenharmony_ci#include "core.h" 1962306a36Sopenharmony_ci#include "debug.h" 2062306a36Sopenharmony_ci#include "wmi.h" 2162306a36Sopenharmony_ci#include "htt.h" 2262306a36Sopenharmony_ci#include "txrx.h" 2362306a36Sopenharmony_ci#include "testmode.h" 2462306a36Sopenharmony_ci#include "wmi-tlv.h" 2562306a36Sopenharmony_ci#include "wmi-ops.h" 2662306a36Sopenharmony_ci#include "wow.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/*********/ 2962306a36Sopenharmony_ci/* Rates */ 3062306a36Sopenharmony_ci/*********/ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic struct ieee80211_rate ath10k_rates[] = { 3362306a36Sopenharmony_ci { .bitrate = 10, 3462306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_CCK_LP_1M }, 3562306a36Sopenharmony_ci { .bitrate = 20, 3662306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_CCK_LP_2M, 3762306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_CCK_SP_2M, 3862306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 3962306a36Sopenharmony_ci { .bitrate = 55, 4062306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_CCK_LP_5_5M, 4162306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_CCK_SP_5_5M, 4262306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 4362306a36Sopenharmony_ci { .bitrate = 110, 4462306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_CCK_LP_11M, 4562306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_CCK_SP_11M, 4662306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M }, 4962306a36Sopenharmony_ci { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M }, 5062306a36Sopenharmony_ci { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M }, 5162306a36Sopenharmony_ci { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M }, 5262306a36Sopenharmony_ci { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M }, 5362306a36Sopenharmony_ci { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M }, 5462306a36Sopenharmony_ci { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M }, 5562306a36Sopenharmony_ci { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M }, 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic struct ieee80211_rate ath10k_rates_rev2[] = { 5962306a36Sopenharmony_ci { .bitrate = 10, 6062306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_1M }, 6162306a36Sopenharmony_ci { .bitrate = 20, 6262306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_2M, 6362306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_2M, 6462306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 6562306a36Sopenharmony_ci { .bitrate = 55, 6662306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_5_5M, 6762306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_5_5M, 6862306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 6962306a36Sopenharmony_ci { .bitrate = 110, 7062306a36Sopenharmony_ci .hw_value = ATH10K_HW_RATE_REV2_CCK_LP_11M, 7162306a36Sopenharmony_ci .hw_value_short = ATH10K_HW_RATE_REV2_CCK_SP_11M, 7262306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci { .bitrate = 60, .hw_value = ATH10K_HW_RATE_OFDM_6M }, 7562306a36Sopenharmony_ci { .bitrate = 90, .hw_value = ATH10K_HW_RATE_OFDM_9M }, 7662306a36Sopenharmony_ci { .bitrate = 120, .hw_value = ATH10K_HW_RATE_OFDM_12M }, 7762306a36Sopenharmony_ci { .bitrate = 180, .hw_value = ATH10K_HW_RATE_OFDM_18M }, 7862306a36Sopenharmony_ci { .bitrate = 240, .hw_value = ATH10K_HW_RATE_OFDM_24M }, 7962306a36Sopenharmony_ci { .bitrate = 360, .hw_value = ATH10K_HW_RATE_OFDM_36M }, 8062306a36Sopenharmony_ci { .bitrate = 480, .hw_value = ATH10K_HW_RATE_OFDM_48M }, 8162306a36Sopenharmony_ci { .bitrate = 540, .hw_value = ATH10K_HW_RATE_OFDM_54M }, 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic const struct cfg80211_sar_freq_ranges ath10k_sar_freq_ranges[] = { 8562306a36Sopenharmony_ci {.start_freq = 2402, .end_freq = 2494 }, 8662306a36Sopenharmony_ci {.start_freq = 5170, .end_freq = 5875 }, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct cfg80211_sar_capa ath10k_sar_capa = { 9062306a36Sopenharmony_ci .type = NL80211_SAR_TYPE_POWER, 9162306a36Sopenharmony_ci .num_freq_ranges = (ARRAY_SIZE(ath10k_sar_freq_ranges)), 9262306a36Sopenharmony_ci .freq_ranges = &ath10k_sar_freq_ranges[0], 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define ATH10K_MAC_FIRST_OFDM_RATE_IDX 4 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define ath10k_a_rates (ath10k_rates + ATH10K_MAC_FIRST_OFDM_RATE_IDX) 9862306a36Sopenharmony_ci#define ath10k_a_rates_size (ARRAY_SIZE(ath10k_rates) - \ 9962306a36Sopenharmony_ci ATH10K_MAC_FIRST_OFDM_RATE_IDX) 10062306a36Sopenharmony_ci#define ath10k_g_rates (ath10k_rates + 0) 10162306a36Sopenharmony_ci#define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates)) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define ath10k_g_rates_rev2 (ath10k_rates_rev2 + 0) 10462306a36Sopenharmony_ci#define ath10k_g_rates_rev2_size (ARRAY_SIZE(ath10k_rates_rev2)) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define ath10k_wmi_legacy_rates ath10k_rates 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic bool ath10k_mac_bitrate_is_cck(int bitrate) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci switch (bitrate) { 11162306a36Sopenharmony_ci case 10: 11262306a36Sopenharmony_ci case 20: 11362306a36Sopenharmony_ci case 55: 11462306a36Sopenharmony_ci case 110: 11562306a36Sopenharmony_ci return true; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return false; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic u8 ath10k_mac_bitrate_to_rate(int bitrate) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci return DIV_ROUND_UP(bitrate, 5) | 12462306a36Sopenharmony_ci (ath10k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ciu8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, 12862306a36Sopenharmony_ci u8 hw_rate, bool cck) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci const struct ieee80211_rate *rate; 13162306a36Sopenharmony_ci int i; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 13462306a36Sopenharmony_ci rate = &sband->bitrates[i]; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (ath10k_mac_bitrate_is_cck(rate->bitrate) != cck) 13762306a36Sopenharmony_ci continue; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (rate->hw_value == hw_rate) 14062306a36Sopenharmony_ci return i; 14162306a36Sopenharmony_ci else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && 14262306a36Sopenharmony_ci rate->hw_value_short == hw_rate) 14362306a36Sopenharmony_ci return i; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ciu8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, 15062306a36Sopenharmony_ci u32 bitrate) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci int i; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) 15562306a36Sopenharmony_ci if (sband->bitrates[i].bitrate == bitrate) 15662306a36Sopenharmony_ci return i; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int ath10k_mac_get_rate_hw_value(int bitrate) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int i; 16462306a36Sopenharmony_ci u8 hw_value_prefix = 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (ath10k_mac_bitrate_is_cck(bitrate)) 16762306a36Sopenharmony_ci hw_value_prefix = WMI_RATE_PREAMBLE_CCK << 6; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ath10k_rates); i++) { 17062306a36Sopenharmony_ci if (ath10k_rates[i].bitrate == bitrate) 17162306a36Sopenharmony_ci return hw_value_prefix | ath10k_rates[i].hw_value; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int ath10k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci switch ((mcs_map >> (2 * nss)) & 0x3) { 18062306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1; 18162306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1; 18262306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic u32 18862306a36Sopenharmony_ciath10k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci int nss; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--) 19362306a36Sopenharmony_ci if (ht_mcs_mask[nss]) 19462306a36Sopenharmony_ci return nss + 1; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 1; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic u32 20062306a36Sopenharmony_ciath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int nss; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--) 20562306a36Sopenharmony_ci if (vht_mcs_mask[nss]) 20662306a36Sopenharmony_ci return nss + 1; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return 1; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ciint ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci enum wmi_host_platform_type platform_type; 21462306a36Sopenharmony_ci int ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TX_MODE_DYNAMIC, ar->wmi.svc_map)) 21762306a36Sopenharmony_ci platform_type = WMI_HOST_PLATFORM_LOW_PERF; 21862306a36Sopenharmony_ci else 21962306a36Sopenharmony_ci platform_type = WMI_HOST_PLATFORM_HIGH_PERF; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ret = ath10k_wmi_ext_resource_config(ar, platform_type, val); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 22462306a36Sopenharmony_ci ath10k_warn(ar, "failed to configure ext resource: %d\n", ret); 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/**********/ 23262306a36Sopenharmony_ci/* Crypto */ 23362306a36Sopenharmony_ci/**********/ 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int ath10k_send_key(struct ath10k_vif *arvif, 23662306a36Sopenharmony_ci struct ieee80211_key_conf *key, 23762306a36Sopenharmony_ci enum set_key_cmd cmd, 23862306a36Sopenharmony_ci const u8 *macaddr, u32 flags) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 24162306a36Sopenharmony_ci struct wmi_vdev_install_key_arg arg = { 24262306a36Sopenharmony_ci .vdev_id = arvif->vdev_id, 24362306a36Sopenharmony_ci .key_idx = key->keyidx, 24462306a36Sopenharmony_ci .key_len = key->keylen, 24562306a36Sopenharmony_ci .key_data = key->key, 24662306a36Sopenharmony_ci .key_flags = flags, 24762306a36Sopenharmony_ci .macaddr = macaddr, 24862306a36Sopenharmony_ci }; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci switch (key->cipher) { 25362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 25462306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_CCM]; 25562306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 25862306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_TKIP]; 25962306a36Sopenharmony_ci arg.key_txmic_len = 8; 26062306a36Sopenharmony_ci arg.key_rxmic_len = 8; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 26362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 26462306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_WEP]; 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 26762306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_CCM]; 26862306a36Sopenharmony_ci break; 26962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 27062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 27162306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_AES_GCM]; 27262306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_128: 27562306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_GMAC_256: 27662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_BIP_CMAC_256: 27762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 27862306a36Sopenharmony_ci WARN_ON(1); 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci default: 28162306a36Sopenharmony_ci ath10k_warn(ar, "cipher %d is not supported\n", key->cipher); 28262306a36Sopenharmony_ci return -EOPNOTSUPP; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) 28662306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (cmd == DISABLE_KEY) { 28962306a36Sopenharmony_ci arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE]; 29062306a36Sopenharmony_ci arg.key_data = NULL; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return ath10k_wmi_vdev_install_key(arvif->ar, &arg); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int ath10k_install_key(struct ath10k_vif *arvif, 29762306a36Sopenharmony_ci struct ieee80211_key_conf *key, 29862306a36Sopenharmony_ci enum set_key_cmd cmd, 29962306a36Sopenharmony_ci const u8 *macaddr, u32 flags) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 30262306a36Sopenharmony_ci int ret; 30362306a36Sopenharmony_ci unsigned long time_left; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci reinit_completion(&ar->install_key_done); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (arvif->nohwcrypt) 31062306a36Sopenharmony_ci return 1; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = ath10k_send_key(arvif, key, cmd, macaddr, flags); 31362306a36Sopenharmony_ci if (ret) 31462306a36Sopenharmony_ci return ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->install_key_done, 3 * HZ); 31762306a36Sopenharmony_ci if (time_left == 0) 31862306a36Sopenharmony_ci return -ETIMEDOUT; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, 32462306a36Sopenharmony_ci const u8 *addr) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 32762306a36Sopenharmony_ci struct ath10k_peer *peer; 32862306a36Sopenharmony_ci int ret; 32962306a36Sopenharmony_ci int i; 33062306a36Sopenharmony_ci u32 flags; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (WARN_ON(arvif->vif->type != NL80211_IFTYPE_AP && 33562306a36Sopenharmony_ci arvif->vif->type != NL80211_IFTYPE_ADHOC && 33662306a36Sopenharmony_ci arvif->vif->type != NL80211_IFTYPE_MESH_POINT)) 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 34062306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, addr); 34162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!peer) 34462306a36Sopenharmony_ci return -ENOENT; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) { 34762306a36Sopenharmony_ci if (arvif->wep_keys[i] == NULL) 34862306a36Sopenharmony_ci continue; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci switch (arvif->vif->type) { 35162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 35262306a36Sopenharmony_ci flags = WMI_KEY_PAIRWISE; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (arvif->def_wep_key_idx == i) 35562306a36Sopenharmony_ci flags |= WMI_KEY_TX_USAGE; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ret = ath10k_install_key(arvif, arvif->wep_keys[i], 35862306a36Sopenharmony_ci SET_KEY, addr, flags); 35962306a36Sopenharmony_ci if (ret < 0) 36062306a36Sopenharmony_ci return ret; 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 36362306a36Sopenharmony_ci ret = ath10k_install_key(arvif, arvif->wep_keys[i], 36462306a36Sopenharmony_ci SET_KEY, addr, 36562306a36Sopenharmony_ci WMI_KEY_PAIRWISE); 36662306a36Sopenharmony_ci if (ret < 0) 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = ath10k_install_key(arvif, arvif->wep_keys[i], 37062306a36Sopenharmony_ci SET_KEY, addr, WMI_KEY_GROUP); 37162306a36Sopenharmony_ci if (ret < 0) 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci default: 37562306a36Sopenharmony_ci WARN_ON(1); 37662306a36Sopenharmony_ci return -EINVAL; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 38062306a36Sopenharmony_ci peer->keys[i] = arvif->wep_keys[i]; 38162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* In some cases (notably with static WEP IBSS with multiple keys) 38562306a36Sopenharmony_ci * multicast Tx becomes broken. Both pairwise and groupwise keys are 38662306a36Sopenharmony_ci * installed already. Using WMI_KEY_TX_USAGE in different combinations 38762306a36Sopenharmony_ci * didn't seem help. Using def_keyid vdev parameter seems to be 38862306a36Sopenharmony_ci * effective so use that. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * FIXME: Revisit. Perhaps this can be done in a less hacky way. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci if (arvif->vif->type != NL80211_IFTYPE_ADHOC) 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (arvif->def_wep_key_idx == -1) 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(arvif->ar, 39962306a36Sopenharmony_ci arvif->vdev_id, 40062306a36Sopenharmony_ci arvif->ar->wmi.vdev_param->def_keyid, 40162306a36Sopenharmony_ci arvif->def_wep_key_idx); 40262306a36Sopenharmony_ci if (ret) { 40362306a36Sopenharmony_ci ath10k_warn(ar, "failed to re-set def wpa key idxon vdev %i: %d\n", 40462306a36Sopenharmony_ci arvif->vdev_id, ret); 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int ath10k_clear_peer_keys(struct ath10k_vif *arvif, 41262306a36Sopenharmony_ci const u8 *addr) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 41562306a36Sopenharmony_ci struct ath10k_peer *peer; 41662306a36Sopenharmony_ci int first_errno = 0; 41762306a36Sopenharmony_ci int ret; 41862306a36Sopenharmony_ci int i; 41962306a36Sopenharmony_ci u32 flags = 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 42462306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, addr); 42562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (!peer) 42862306a36Sopenharmony_ci return -ENOENT; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { 43162306a36Sopenharmony_ci if (peer->keys[i] == NULL) 43262306a36Sopenharmony_ci continue; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* key flags are not required to delete the key */ 43562306a36Sopenharmony_ci ret = ath10k_install_key(arvif, peer->keys[i], 43662306a36Sopenharmony_ci DISABLE_KEY, addr, flags); 43762306a36Sopenharmony_ci if (ret < 0 && first_errno == 0) 43862306a36Sopenharmony_ci first_errno = ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (ret < 0) 44162306a36Sopenharmony_ci ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", 44262306a36Sopenharmony_ci i, ret); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 44562306a36Sopenharmony_ci peer->keys[i] = NULL; 44662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return first_errno; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cibool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr, 45362306a36Sopenharmony_ci u8 keyidx) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct ath10k_peer *peer; 45662306a36Sopenharmony_ci int i; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* We don't know which vdev this peer belongs to, 46162306a36Sopenharmony_ci * since WMI doesn't give us that information. 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * FIXME: multi-bss needs to be handled. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci peer = ath10k_peer_find(ar, 0, addr); 46662306a36Sopenharmony_ci if (!peer) 46762306a36Sopenharmony_ci return false; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { 47062306a36Sopenharmony_ci if (peer->keys[i] && peer->keys[i]->keyidx == keyidx) 47162306a36Sopenharmony_ci return true; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return false; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int ath10k_clear_vdev_key(struct ath10k_vif *arvif, 47862306a36Sopenharmony_ci struct ieee80211_key_conf *key) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 48162306a36Sopenharmony_ci struct ath10k_peer *peer; 48262306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 48362306a36Sopenharmony_ci int first_errno = 0; 48462306a36Sopenharmony_ci int ret; 48562306a36Sopenharmony_ci int i; 48662306a36Sopenharmony_ci u32 flags = 0; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci for (;;) { 49162306a36Sopenharmony_ci /* since ath10k_install_key we can't hold data_lock all the 49262306a36Sopenharmony_ci * time, so we try to remove the keys incrementally 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 49562306a36Sopenharmony_ci i = 0; 49662306a36Sopenharmony_ci list_for_each_entry(peer, &ar->peers, list) { 49762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { 49862306a36Sopenharmony_ci if (peer->keys[i] == key) { 49962306a36Sopenharmony_ci ether_addr_copy(addr, peer->addr); 50062306a36Sopenharmony_ci peer->keys[i] = NULL; 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (i < ARRAY_SIZE(peer->keys)) 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (i == ARRAY_SIZE(peer->keys)) 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci /* key flags are not required to delete the key */ 51362306a36Sopenharmony_ci ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags); 51462306a36Sopenharmony_ci if (ret < 0 && first_errno == 0) 51562306a36Sopenharmony_ci first_errno = ret; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (ret) 51862306a36Sopenharmony_ci ath10k_warn(ar, "failed to remove key for %pM: %d\n", 51962306a36Sopenharmony_ci addr, ret); 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return first_errno; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_cistatic int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif, 52662306a36Sopenharmony_ci struct ieee80211_key_conf *key) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 52962306a36Sopenharmony_ci struct ath10k_peer *peer; 53062306a36Sopenharmony_ci int ret; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci list_for_each_entry(peer, &ar->peers, list) { 53562306a36Sopenharmony_ci if (ether_addr_equal(peer->addr, arvif->vif->addr)) 53662306a36Sopenharmony_ci continue; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (ether_addr_equal(peer->addr, arvif->bssid)) 53962306a36Sopenharmony_ci continue; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (peer->keys[key->keyidx] == key) 54262306a36Sopenharmony_ci continue; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vif vdev %i update key %i needs update\n", 54562306a36Sopenharmony_ci arvif->vdev_id, key->keyidx); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci ret = ath10k_install_peer_wep_keys(arvif, peer->addr); 54862306a36Sopenharmony_ci if (ret) { 54962306a36Sopenharmony_ci ath10k_warn(ar, "failed to update wep keys on vdev %i for peer %pM: %d\n", 55062306a36Sopenharmony_ci arvif->vdev_id, peer->addr, ret); 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/*********************/ 55962306a36Sopenharmony_ci/* General utilities */ 56062306a36Sopenharmony_ci/*********************/ 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic inline enum wmi_phy_mode 56362306a36Sopenharmony_cichan_to_phymode(const struct cfg80211_chan_def *chandef) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci enum wmi_phy_mode phymode = MODE_UNKNOWN; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci switch (chandef->chan->band) { 56862306a36Sopenharmony_ci case NL80211_BAND_2GHZ: 56962306a36Sopenharmony_ci switch (chandef->width) { 57062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 57162306a36Sopenharmony_ci if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM) 57262306a36Sopenharmony_ci phymode = MODE_11B; 57362306a36Sopenharmony_ci else 57462306a36Sopenharmony_ci phymode = MODE_11G; 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 57762306a36Sopenharmony_ci phymode = MODE_11NG_HT20; 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 58062306a36Sopenharmony_ci phymode = MODE_11NG_HT40; 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci default: 58362306a36Sopenharmony_ci phymode = MODE_UNKNOWN; 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci case NL80211_BAND_5GHZ: 58862306a36Sopenharmony_ci switch (chandef->width) { 58962306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 59062306a36Sopenharmony_ci phymode = MODE_11A; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 59362306a36Sopenharmony_ci phymode = MODE_11NA_HT20; 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 59662306a36Sopenharmony_ci phymode = MODE_11NA_HT40; 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 59962306a36Sopenharmony_ci phymode = MODE_11AC_VHT80; 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 60262306a36Sopenharmony_ci phymode = MODE_11AC_VHT160; 60362306a36Sopenharmony_ci break; 60462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 60562306a36Sopenharmony_ci phymode = MODE_11AC_VHT80_80; 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci default: 60862306a36Sopenharmony_ci phymode = MODE_UNKNOWN; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci default: 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci WARN_ON(phymode == MODE_UNKNOWN); 61762306a36Sopenharmony_ci return phymode; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic u8 ath10k_parse_mpdudensity(u8 mpdudensity) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci/* 62362306a36Sopenharmony_ci * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": 62462306a36Sopenharmony_ci * 0 for no restriction 62562306a36Sopenharmony_ci * 1 for 1/4 us 62662306a36Sopenharmony_ci * 2 for 1/2 us 62762306a36Sopenharmony_ci * 3 for 1 us 62862306a36Sopenharmony_ci * 4 for 2 us 62962306a36Sopenharmony_ci * 5 for 4 us 63062306a36Sopenharmony_ci * 6 for 8 us 63162306a36Sopenharmony_ci * 7 for 16 us 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ci switch (mpdudensity) { 63462306a36Sopenharmony_ci case 0: 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci case 1: 63762306a36Sopenharmony_ci case 2: 63862306a36Sopenharmony_ci case 3: 63962306a36Sopenharmony_ci /* Our lower layer calculations limit our precision to 64062306a36Sopenharmony_ci * 1 microsecond 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci return 1; 64362306a36Sopenharmony_ci case 4: 64462306a36Sopenharmony_ci return 2; 64562306a36Sopenharmony_ci case 5: 64662306a36Sopenharmony_ci return 4; 64762306a36Sopenharmony_ci case 6: 64862306a36Sopenharmony_ci return 8; 64962306a36Sopenharmony_ci case 7: 65062306a36Sopenharmony_ci return 16; 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci return 0; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ciint ath10k_mac_vif_chan(struct ieee80211_vif *vif, 65762306a36Sopenharmony_ci struct cfg80211_chan_def *def) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci rcu_read_lock(); 66262306a36Sopenharmony_ci conf = rcu_dereference(vif->bss_conf.chanctx_conf); 66362306a36Sopenharmony_ci if (!conf) { 66462306a36Sopenharmony_ci rcu_read_unlock(); 66562306a36Sopenharmony_ci return -ENOENT; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci *def = conf->def; 66962306a36Sopenharmony_ci rcu_read_unlock(); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return 0; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void ath10k_mac_num_chanctxs_iter(struct ieee80211_hw *hw, 67562306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf, 67662306a36Sopenharmony_ci void *data) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci int *num = data; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci (*num)++; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int ath10k_mac_num_chanctxs(struct ath10k *ar) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int num = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ieee80211_iter_chan_contexts_atomic(ar->hw, 68862306a36Sopenharmony_ci ath10k_mac_num_chanctxs_iter, 68962306a36Sopenharmony_ci &num); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return num; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic void 69562306a36Sopenharmony_ciath10k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, 69662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf, 69762306a36Sopenharmony_ci void *data) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct cfg80211_chan_def **def = data; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci *def = &conf->def; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void ath10k_wait_for_peer_delete_done(struct ath10k *ar, u32 vdev_id, 70562306a36Sopenharmony_ci const u8 *addr) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci unsigned long time_left; 70862306a36Sopenharmony_ci int ret; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { 71162306a36Sopenharmony_ci ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); 71262306a36Sopenharmony_ci if (ret) { 71362306a36Sopenharmony_ci ath10k_warn(ar, "failed wait for peer deleted"); 71462306a36Sopenharmony_ci return; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->peer_delete_done, 71862306a36Sopenharmony_ci 5 * HZ); 71962306a36Sopenharmony_ci if (!time_left) 72062306a36Sopenharmony_ci ath10k_warn(ar, "Timeout in receiving peer delete response\n"); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int ath10k_peer_create(struct ath10k *ar, 72562306a36Sopenharmony_ci struct ieee80211_vif *vif, 72662306a36Sopenharmony_ci struct ieee80211_sta *sta, 72762306a36Sopenharmony_ci u32 vdev_id, 72862306a36Sopenharmony_ci const u8 *addr, 72962306a36Sopenharmony_ci enum wmi_peer_type peer_type) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct ath10k_vif *arvif; 73262306a36Sopenharmony_ci struct ath10k_peer *peer; 73362306a36Sopenharmony_ci int num_peers = 0; 73462306a36Sopenharmony_ci int ret; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci num_peers = ar->num_peers; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* Each vdev consumes a peer entry as well */ 74162306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) 74262306a36Sopenharmony_ci num_peers++; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (num_peers >= ar->max_num_peers) 74562306a36Sopenharmony_ci return -ENOBUFS; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci ret = ath10k_wmi_peer_create(ar, vdev_id, addr, peer_type); 74862306a36Sopenharmony_ci if (ret) { 74962306a36Sopenharmony_ci ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n", 75062306a36Sopenharmony_ci addr, vdev_id, ret); 75162306a36Sopenharmony_ci return ret; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = ath10k_wait_for_peer_created(ar, vdev_id, addr); 75562306a36Sopenharmony_ci if (ret) { 75662306a36Sopenharmony_ci ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n", 75762306a36Sopenharmony_ci addr, vdev_id, ret); 75862306a36Sopenharmony_ci return ret; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci peer = ath10k_peer_find(ar, vdev_id, addr); 76462306a36Sopenharmony_ci if (!peer) { 76562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 76662306a36Sopenharmony_ci ath10k_warn(ar, "failed to find peer %pM on vdev %i after creation\n", 76762306a36Sopenharmony_ci addr, vdev_id); 76862306a36Sopenharmony_ci ath10k_wait_for_peer_delete_done(ar, vdev_id, addr); 76962306a36Sopenharmony_ci return -ENOENT; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci peer->vif = vif; 77362306a36Sopenharmony_ci peer->sta = sta; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci ar->num_peers++; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int ath10k_mac_set_kickout(struct ath10k_vif *arvif) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 78562306a36Sopenharmony_ci u32 param; 78662306a36Sopenharmony_ci int ret; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci param = ar->wmi.pdev_param->sta_kickout_th; 78962306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 79062306a36Sopenharmony_ci ATH10K_KICKOUT_THRESHOLD); 79162306a36Sopenharmony_ci if (ret) { 79262306a36Sopenharmony_ci ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n", 79362306a36Sopenharmony_ci arvif->vdev_id, ret); 79462306a36Sopenharmony_ci return ret; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs; 79862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, 79962306a36Sopenharmony_ci ATH10K_KEEPALIVE_MIN_IDLE); 80062306a36Sopenharmony_ci if (ret) { 80162306a36Sopenharmony_ci ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n", 80262306a36Sopenharmony_ci arvif->vdev_id, ret); 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs; 80762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, 80862306a36Sopenharmony_ci ATH10K_KEEPALIVE_MAX_IDLE); 80962306a36Sopenharmony_ci if (ret) { 81062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n", 81162306a36Sopenharmony_ci arvif->vdev_id, ret); 81262306a36Sopenharmony_ci return ret; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs; 81662306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, 81762306a36Sopenharmony_ci ATH10K_KEEPALIVE_MAX_UNRESPONSIVE); 81862306a36Sopenharmony_ci if (ret) { 81962306a36Sopenharmony_ci ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n", 82062306a36Sopenharmony_ci arvif->vdev_id, ret); 82162306a36Sopenharmony_ci return ret; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci return 0; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 83062306a36Sopenharmony_ci u32 vdev_param; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->rts_threshold; 83362306a36Sopenharmony_ci return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci int ret; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ret = ath10k_wmi_peer_delete(ar, vdev_id, addr); 84362306a36Sopenharmony_ci if (ret) 84462306a36Sopenharmony_ci return ret; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr); 84762306a36Sopenharmony_ci if (ret) 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { 85162306a36Sopenharmony_ci unsigned long time_left; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci time_left = wait_for_completion_timeout 85462306a36Sopenharmony_ci (&ar->peer_delete_done, 5 * HZ); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (!time_left) { 85762306a36Sopenharmony_ci ath10k_warn(ar, "Timeout in receiving peer delete response\n"); 85862306a36Sopenharmony_ci return -ETIMEDOUT; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ar->num_peers--; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci return 0; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic void ath10k_peer_map_cleanup(struct ath10k *ar, struct ath10k_peer *peer) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci int peer_id, i; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci for_each_set_bit(peer_id, peer->peer_ids, 87462306a36Sopenharmony_ci ATH10K_MAX_NUM_PEER_IDS) { 87562306a36Sopenharmony_ci ar->peer_map[peer_id] = NULL; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Double check that peer is properly un-referenced from 87962306a36Sopenharmony_ci * the peer_map 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) { 88262306a36Sopenharmony_ci if (ar->peer_map[i] == peer) { 88362306a36Sopenharmony_ci ath10k_warn(ar, "removing stale peer_map entry for %pM (ptr %pK idx %d)\n", 88462306a36Sopenharmony_ci peer->addr, peer, i); 88562306a36Sopenharmony_ci ar->peer_map[i] = NULL; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci list_del(&peer->list); 89062306a36Sopenharmony_ci kfree(peer); 89162306a36Sopenharmony_ci ar->num_peers--; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct ath10k_peer *peer, *tmp; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 90162306a36Sopenharmony_ci list_for_each_entry_safe(peer, tmp, &ar->peers, list) { 90262306a36Sopenharmony_ci if (peer->vdev_id != vdev_id) 90362306a36Sopenharmony_ci continue; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n", 90662306a36Sopenharmony_ci peer->addr, vdev_id); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci ath10k_peer_map_cleanup(ar, peer); 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void ath10k_peer_cleanup_all(struct ath10k *ar) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct ath10k_peer *peer, *tmp; 91662306a36Sopenharmony_ci int i; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 92162306a36Sopenharmony_ci list_for_each_entry_safe(peer, tmp, &ar->peers, list) { 92262306a36Sopenharmony_ci list_del(&peer->list); 92362306a36Sopenharmony_ci kfree(peer); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) 92762306a36Sopenharmony_ci ar->peer_map[i] = NULL; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci ar->num_peers = 0; 93262306a36Sopenharmony_ci ar->num_stations = 0; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_cistatic int ath10k_mac_tdls_peer_update(struct ath10k *ar, u32 vdev_id, 93662306a36Sopenharmony_ci struct ieee80211_sta *sta, 93762306a36Sopenharmony_ci enum wmi_tdls_peer_state state) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci int ret; 94062306a36Sopenharmony_ci struct wmi_tdls_peer_update_cmd_arg arg = {}; 94162306a36Sopenharmony_ci struct wmi_tdls_peer_capab_arg cap = {}; 94262306a36Sopenharmony_ci struct wmi_channel_arg chan_arg = {}; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci arg.vdev_id = vdev_id; 94762306a36Sopenharmony_ci arg.peer_state = state; 94862306a36Sopenharmony_ci ether_addr_copy(arg.addr, sta->addr); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci cap.peer_max_sp = sta->max_sp; 95162306a36Sopenharmony_ci cap.peer_uapsd_queues = sta->uapsd_queues; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (state == WMI_TDLS_PEER_STATE_CONNECTED && 95462306a36Sopenharmony_ci !sta->tdls_initiator) 95562306a36Sopenharmony_ci cap.is_peer_responder = 1; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci ret = ath10k_wmi_tdls_peer_update(ar, &arg, &cap, &chan_arg); 95862306a36Sopenharmony_ci if (ret) { 95962306a36Sopenharmony_ci ath10k_warn(ar, "failed to update tdls peer %pM on vdev %i: %i\n", 96062306a36Sopenharmony_ci arg.addr, vdev_id, ret); 96162306a36Sopenharmony_ci return ret; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return 0; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/************************/ 96862306a36Sopenharmony_ci/* Interface management */ 96962306a36Sopenharmony_ci/************************/ 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_civoid ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (!arvif->beacon) 97862306a36Sopenharmony_ci return; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (!arvif->beacon_buf) 98162306a36Sopenharmony_ci dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, 98262306a36Sopenharmony_ci arvif->beacon->len, DMA_TO_DEVICE); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED && 98562306a36Sopenharmony_ci arvif->beacon_state != ATH10K_BEACON_SENT)) 98662306a36Sopenharmony_ci return; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci dev_kfree_skb_any(arvif->beacon); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci arvif->beacon = NULL; 99162306a36Sopenharmony_ci arvif->beacon_state = ATH10K_BEACON_SCHEDULED; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ath10k_mac_vif_beacon_free(arvif); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (arvif->beacon_buf) { 100362306a36Sopenharmony_ci if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) 100462306a36Sopenharmony_ci kfree(arvif->beacon_buf); 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, 100762306a36Sopenharmony_ci arvif->beacon_buf, 100862306a36Sopenharmony_ci arvif->beacon_paddr); 100962306a36Sopenharmony_ci arvif->beacon_buf = NULL; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic inline int ath10k_vdev_setup_sync(struct ath10k *ar) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci unsigned long time_left; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) 102062306a36Sopenharmony_ci return -ESHUTDOWN; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->vdev_setup_done, 102362306a36Sopenharmony_ci ATH10K_VDEV_SETUP_TIMEOUT_HZ); 102462306a36Sopenharmony_ci if (time_left == 0) 102562306a36Sopenharmony_ci return -ETIMEDOUT; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return ar->last_wmi_vdev_start_status; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = NULL; 103362306a36Sopenharmony_ci struct ieee80211_channel *channel = NULL; 103462306a36Sopenharmony_ci struct wmi_vdev_start_request_arg arg = {}; 103562306a36Sopenharmony_ci int ret = 0; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci ieee80211_iter_chan_contexts_atomic(ar->hw, 104062306a36Sopenharmony_ci ath10k_mac_get_any_chandef_iter, 104162306a36Sopenharmony_ci &chandef); 104262306a36Sopenharmony_ci if (WARN_ON_ONCE(!chandef)) 104362306a36Sopenharmony_ci return -ENOENT; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci channel = chandef->chan; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci arg.vdev_id = vdev_id; 104862306a36Sopenharmony_ci arg.channel.freq = channel->center_freq; 104962306a36Sopenharmony_ci arg.channel.band_center_freq1 = chandef->center_freq1; 105062306a36Sopenharmony_ci arg.channel.band_center_freq2 = chandef->center_freq2; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* TODO setup this dynamically, what in case we 105362306a36Sopenharmony_ci * don't have any vifs? 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_ci arg.channel.mode = chan_to_phymode(chandef); 105662306a36Sopenharmony_ci arg.channel.chan_radar = 105762306a36Sopenharmony_ci !!(channel->flags & IEEE80211_CHAN_RADAR); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci arg.channel.min_power = 0; 106062306a36Sopenharmony_ci arg.channel.max_power = channel->max_power * 2; 106162306a36Sopenharmony_ci arg.channel.max_reg_power = channel->max_reg_power * 2; 106262306a36Sopenharmony_ci arg.channel.max_antenna_gain = channel->max_antenna_gain; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 106562306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_start(ar, &arg); 106862306a36Sopenharmony_ci if (ret) { 106962306a36Sopenharmony_ci ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", 107062306a36Sopenharmony_ci vdev_id, ret); 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci ret = ath10k_vdev_setup_sync(ar); 107562306a36Sopenharmony_ci if (ret) { 107662306a36Sopenharmony_ci ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n", 107762306a36Sopenharmony_ci vdev_id, ret); 107862306a36Sopenharmony_ci return ret; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); 108262306a36Sopenharmony_ci if (ret) { 108362306a36Sopenharmony_ci ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n", 108462306a36Sopenharmony_ci vdev_id, ret); 108562306a36Sopenharmony_ci goto vdev_stop; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ar->monitor_vdev_id = vdev_id; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n", 109162306a36Sopenharmony_ci ar->monitor_vdev_id); 109262306a36Sopenharmony_ci return 0; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_civdev_stop: 109562306a36Sopenharmony_ci ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); 109662306a36Sopenharmony_ci if (ret) 109762306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n", 109862306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci return ret; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int ath10k_monitor_vdev_stop(struct ath10k *ar) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci int ret = 0; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id); 111062306a36Sopenharmony_ci if (ret) 111162306a36Sopenharmony_ci ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", 111262306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 111562306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); 111862306a36Sopenharmony_ci if (ret) 111962306a36Sopenharmony_ci ath10k_warn(ar, "failed to request monitor vdev %i stop: %d\n", 112062306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ret = ath10k_vdev_setup_sync(ar); 112362306a36Sopenharmony_ci if (ret) 112462306a36Sopenharmony_ci ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n", 112562306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", 112862306a36Sopenharmony_ci ar->monitor_vdev_id); 112962306a36Sopenharmony_ci return ret; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic int ath10k_monitor_vdev_create(struct ath10k *ar) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci int bit, ret = 0; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (ar->free_vdev_map == 0) { 113962306a36Sopenharmony_ci ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n"); 114062306a36Sopenharmony_ci return -ENOMEM; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci bit = __ffs64(ar->free_vdev_map); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci ar->monitor_vdev_id = bit; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id, 114862306a36Sopenharmony_ci WMI_VDEV_TYPE_MONITOR, 114962306a36Sopenharmony_ci 0, ar->mac_addr); 115062306a36Sopenharmony_ci if (ret) { 115162306a36Sopenharmony_ci ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n", 115262306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 115362306a36Sopenharmony_ci return ret; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); 115762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n", 115862306a36Sopenharmony_ci ar->monitor_vdev_id); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int ath10k_monitor_vdev_delete(struct ath10k *ar) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci int ret = 0; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id); 117062306a36Sopenharmony_ci if (ret) { 117162306a36Sopenharmony_ci ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n", 117262306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 117362306a36Sopenharmony_ci return ret; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci ar->free_vdev_map |= 1LL << ar->monitor_vdev_id; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", 117962306a36Sopenharmony_ci ar->monitor_vdev_id); 118062306a36Sopenharmony_ci return ret; 118162306a36Sopenharmony_ci} 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_cistatic int ath10k_monitor_start(struct ath10k *ar) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci int ret; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci ret = ath10k_monitor_vdev_create(ar); 119062306a36Sopenharmony_ci if (ret) { 119162306a36Sopenharmony_ci ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret); 119262306a36Sopenharmony_ci return ret; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id); 119662306a36Sopenharmony_ci if (ret) { 119762306a36Sopenharmony_ci ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret); 119862306a36Sopenharmony_ci ath10k_monitor_vdev_delete(ar); 119962306a36Sopenharmony_ci return ret; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci ar->monitor_started = true; 120362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n"); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci return 0; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic int ath10k_monitor_stop(struct ath10k *ar) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci int ret; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci ret = ath10k_monitor_vdev_stop(ar); 121562306a36Sopenharmony_ci if (ret) { 121662306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret); 121762306a36Sopenharmony_ci return ret; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci ret = ath10k_monitor_vdev_delete(ar); 122162306a36Sopenharmony_ci if (ret) { 122262306a36Sopenharmony_ci ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret); 122362306a36Sopenharmony_ci return ret; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci ar->monitor_started = false; 122762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n"); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return 0; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci int num_ctx; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* At least one chanctx is required to derive a channel to start 123762306a36Sopenharmony_ci * monitor vdev on. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci num_ctx = ath10k_mac_num_chanctxs(ar); 124062306a36Sopenharmony_ci if (num_ctx == 0) 124162306a36Sopenharmony_ci return false; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* If there's already an existing special monitor interface then don't 124462306a36Sopenharmony_ci * bother creating another monitor vdev. 124562306a36Sopenharmony_ci */ 124662306a36Sopenharmony_ci if (ar->monitor_arvif) 124762306a36Sopenharmony_ci return false; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return ar->monitor || 125062306a36Sopenharmony_ci (!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST, 125162306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features) && 125262306a36Sopenharmony_ci (ar->filter_flags & FIF_OTHER_BSS)) || 125362306a36Sopenharmony_ci test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic bool ath10k_mac_monitor_vdev_is_allowed(struct ath10k *ar) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci int num_ctx; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci num_ctx = ath10k_mac_num_chanctxs(ar); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* FIXME: Current interface combinations and cfg80211/mac80211 code 126362306a36Sopenharmony_ci * shouldn't allow this but make sure to prevent handling the following 126462306a36Sopenharmony_ci * case anyway since multi-channel DFS hasn't been tested at all. 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_ci if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags) && num_ctx > 1) 126762306a36Sopenharmony_ci return false; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci return true; 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic int ath10k_monitor_recalc(struct ath10k *ar) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci bool needed; 127562306a36Sopenharmony_ci bool allowed; 127662306a36Sopenharmony_ci int ret; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci needed = ath10k_mac_monitor_vdev_is_needed(ar); 128162306a36Sopenharmony_ci allowed = ath10k_mac_monitor_vdev_is_allowed(ar); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 128462306a36Sopenharmony_ci "mac monitor recalc started? %d needed? %d allowed? %d\n", 128562306a36Sopenharmony_ci ar->monitor_started, needed, allowed); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (WARN_ON(needed && !allowed)) { 128862306a36Sopenharmony_ci if (ar->monitor_started) { 128962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopping disallowed monitor\n"); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci ret = ath10k_monitor_stop(ar); 129262306a36Sopenharmony_ci if (ret) 129362306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop disallowed monitor: %d\n", 129462306a36Sopenharmony_ci ret); 129562306a36Sopenharmony_ci /* not serious */ 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci return -EPERM; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (needed == ar->monitor_started) 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (needed) 130562306a36Sopenharmony_ci return ath10k_monitor_start(ar); 130662306a36Sopenharmony_ci else 130762306a36Sopenharmony_ci return ath10k_monitor_stop(ar); 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic bool ath10k_mac_can_set_cts_prot(struct ath10k_vif *arvif) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (!arvif->is_started) { 131762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "defer cts setup, vdev is not ready yet\n"); 131862306a36Sopenharmony_ci return false; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci return true; 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_cistatic int ath10k_mac_set_cts_prot(struct ath10k_vif *arvif) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 132762306a36Sopenharmony_ci u32 vdev_param; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->protection_mode; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_protection %d\n", 133462306a36Sopenharmony_ci arvif->vdev_id, arvif->use_cts_prot); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 133762306a36Sopenharmony_ci arvif->use_cts_prot ? 1 : 0); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 134362306a36Sopenharmony_ci u32 vdev_param, rts_cts = 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->enable_rtscts; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (arvif->num_legacy_stations > 0) 135262306a36Sopenharmony_ci rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES, 135362306a36Sopenharmony_ci WMI_RTSCTS_PROFILE); 135462306a36Sopenharmony_ci else 135562306a36Sopenharmony_ci rts_cts |= SM(WMI_RTSCTS_FOR_SECOND_RATESERIES, 135662306a36Sopenharmony_ci WMI_RTSCTS_PROFILE); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d recalc rts/cts prot %d\n", 135962306a36Sopenharmony_ci arvif->vdev_id, rts_cts); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 136262306a36Sopenharmony_ci rts_cts); 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int ath10k_start_cac(struct ath10k *ar) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci int ret; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci ret = ath10k_monitor_recalc(ar); 137462306a36Sopenharmony_ci if (ret) { 137562306a36Sopenharmony_ci ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret); 137662306a36Sopenharmony_ci clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); 137762306a36Sopenharmony_ci return ret; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n", 138162306a36Sopenharmony_ci ar->monitor_vdev_id); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic int ath10k_stop_cac(struct ath10k *ar) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* CAC is not running - do nothing */ 139162306a36Sopenharmony_ci if (!test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) 139262306a36Sopenharmony_ci return 0; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); 139562306a36Sopenharmony_ci ath10k_monitor_stop(ar); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n"); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic void ath10k_mac_has_radar_iter(struct ieee80211_hw *hw, 140362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf, 140462306a36Sopenharmony_ci void *data) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci bool *ret = data; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (!*ret && conf->radar_enabled) 140962306a36Sopenharmony_ci *ret = true; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic bool ath10k_mac_has_radar_enabled(struct ath10k *ar) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci bool has_radar = false; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci ieee80211_iter_chan_contexts_atomic(ar->hw, 141762306a36Sopenharmony_ci ath10k_mac_has_radar_iter, 141862306a36Sopenharmony_ci &has_radar); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci return has_radar; 142162306a36Sopenharmony_ci} 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_cistatic void ath10k_recalc_radar_detection(struct ath10k *ar) 142462306a36Sopenharmony_ci{ 142562306a36Sopenharmony_ci int ret; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci ath10k_stop_cac(ar); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (!ath10k_mac_has_radar_enabled(ar)) 143262306a36Sopenharmony_ci return; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (ar->num_started_vdevs > 0) 143562306a36Sopenharmony_ci return; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci ret = ath10k_start_cac(ar); 143862306a36Sopenharmony_ci if (ret) { 143962306a36Sopenharmony_ci /* 144062306a36Sopenharmony_ci * Not possible to start CAC on current channel so starting 144162306a36Sopenharmony_ci * radiation is not allowed, make this channel DFS_UNAVAILABLE 144262306a36Sopenharmony_ci * by indicating that radar was detected. 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_ci ath10k_warn(ar, "failed to start CAC: %d\n", ret); 144562306a36Sopenharmony_ci ieee80211_radar_detected(ar->hw); 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_cistatic int ath10k_vdev_stop(struct ath10k_vif *arvif) 145062306a36Sopenharmony_ci{ 145162306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 145262306a36Sopenharmony_ci int ret; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 145762306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id); 146062306a36Sopenharmony_ci if (ret) { 146162306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n", 146262306a36Sopenharmony_ci arvif->vdev_id, ret); 146362306a36Sopenharmony_ci return ret; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci ret = ath10k_vdev_setup_sync(ar); 146762306a36Sopenharmony_ci if (ret) { 146862306a36Sopenharmony_ci ath10k_warn(ar, "failed to synchronize setup for vdev %i: %d\n", 146962306a36Sopenharmony_ci arvif->vdev_id, ret); 147062306a36Sopenharmony_ci return ret; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci WARN_ON(ar->num_started_vdevs == 0); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci if (ar->num_started_vdevs != 0) { 147662306a36Sopenharmony_ci ar->num_started_vdevs--; 147762306a36Sopenharmony_ci ath10k_recalc_radar_detection(ar); 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return ret; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_cistatic int ath10k_vdev_start_restart(struct ath10k_vif *arvif, 148462306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef, 148562306a36Sopenharmony_ci bool restart) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 148862306a36Sopenharmony_ci struct wmi_vdev_start_request_arg arg = {}; 148962306a36Sopenharmony_ci int ret = 0; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 149462306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 149762306a36Sopenharmony_ci arg.dtim_period = arvif->dtim_period; 149862306a36Sopenharmony_ci arg.bcn_intval = arvif->beacon_interval; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci arg.channel.freq = chandef->chan->center_freq; 150162306a36Sopenharmony_ci arg.channel.band_center_freq1 = chandef->center_freq1; 150262306a36Sopenharmony_ci arg.channel.band_center_freq2 = chandef->center_freq2; 150362306a36Sopenharmony_ci arg.channel.mode = chan_to_phymode(chandef); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci arg.channel.min_power = 0; 150662306a36Sopenharmony_ci arg.channel.max_power = chandef->chan->max_power * 2; 150762306a36Sopenharmony_ci arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; 150862306a36Sopenharmony_ci arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { 151162306a36Sopenharmony_ci arg.ssid = arvif->u.ap.ssid; 151262306a36Sopenharmony_ci arg.ssid_len = arvif->u.ap.ssid_len; 151362306a36Sopenharmony_ci arg.hidden_ssid = arvif->u.ap.hidden_ssid; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* For now allow DFS for AP mode */ 151662306a36Sopenharmony_ci arg.channel.chan_radar = 151762306a36Sopenharmony_ci !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); 151862306a36Sopenharmony_ci } else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { 151962306a36Sopenharmony_ci arg.ssid = arvif->vif->cfg.ssid; 152062306a36Sopenharmony_ci arg.ssid_len = arvif->vif->cfg.ssid_len; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 152462306a36Sopenharmony_ci "mac vdev %d start center_freq %d phymode %s\n", 152562306a36Sopenharmony_ci arg.vdev_id, arg.channel.freq, 152662306a36Sopenharmony_ci ath10k_wmi_phymode_str(arg.channel.mode)); 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci if (restart) 152962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_restart(ar, &arg); 153062306a36Sopenharmony_ci else 153162306a36Sopenharmony_ci ret = ath10k_wmi_vdev_start(ar, &arg); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (ret) { 153462306a36Sopenharmony_ci ath10k_warn(ar, "failed to start WMI vdev %i: %d\n", 153562306a36Sopenharmony_ci arg.vdev_id, ret); 153662306a36Sopenharmony_ci return ret; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci ret = ath10k_vdev_setup_sync(ar); 154062306a36Sopenharmony_ci if (ret) { 154162306a36Sopenharmony_ci ath10k_warn(ar, 154262306a36Sopenharmony_ci "failed to synchronize setup for vdev %i restart %d: %d\n", 154362306a36Sopenharmony_ci arg.vdev_id, restart, ret); 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci ar->num_started_vdevs++; 154862306a36Sopenharmony_ci ath10k_recalc_radar_detection(ar); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci return ret; 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic int ath10k_vdev_start(struct ath10k_vif *arvif, 155462306a36Sopenharmony_ci const struct cfg80211_chan_def *def) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci return ath10k_vdev_start_restart(arvif, def, false); 155762306a36Sopenharmony_ci} 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic int ath10k_vdev_restart(struct ath10k_vif *arvif, 156062306a36Sopenharmony_ci const struct cfg80211_chan_def *def) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci return ath10k_vdev_start_restart(arvif, def, true); 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif, 156662306a36Sopenharmony_ci struct sk_buff *bcn) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 156962306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt; 157062306a36Sopenharmony_ci const u8 *p2p_ie; 157162306a36Sopenharmony_ci int ret; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci if (arvif->vif->type != NL80211_IFTYPE_AP || !arvif->vif->p2p) 157462306a36Sopenharmony_ci return 0; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci mgmt = (void *)bcn->data; 157762306a36Sopenharmony_ci p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, 157862306a36Sopenharmony_ci mgmt->u.beacon.variable, 157962306a36Sopenharmony_ci bcn->len - (mgmt->u.beacon.variable - 158062306a36Sopenharmony_ci bcn->data)); 158162306a36Sopenharmony_ci if (!p2p_ie) 158262306a36Sopenharmony_ci return -ENOENT; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); 158562306a36Sopenharmony_ci if (ret) { 158662306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n", 158762306a36Sopenharmony_ci arvif->vdev_id, ret); 158862306a36Sopenharmony_ci return ret; 158962306a36Sopenharmony_ci } 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci return 0; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, 159562306a36Sopenharmony_ci u8 oui_type, size_t ie_offset) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci size_t len; 159862306a36Sopenharmony_ci const u8 *next; 159962306a36Sopenharmony_ci const u8 *end; 160062306a36Sopenharmony_ci u8 *ie; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (WARN_ON(skb->len < ie_offset)) 160362306a36Sopenharmony_ci return -EINVAL; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, 160662306a36Sopenharmony_ci skb->data + ie_offset, 160762306a36Sopenharmony_ci skb->len - ie_offset); 160862306a36Sopenharmony_ci if (!ie) 160962306a36Sopenharmony_ci return -ENOENT; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci len = ie[1] + 2; 161262306a36Sopenharmony_ci end = skb->data + skb->len; 161362306a36Sopenharmony_ci next = ie + len; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (WARN_ON(next > end)) 161662306a36Sopenharmony_ci return -EINVAL; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci memmove(ie, next, end - next); 161962306a36Sopenharmony_ci skb_trim(skb, skb->len - len); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 162762306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 162862306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 162962306a36Sopenharmony_ci struct ieee80211_mutable_offsets offs = {}; 163062306a36Sopenharmony_ci struct sk_buff *bcn; 163162306a36Sopenharmony_ci int ret; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) 163462306a36Sopenharmony_ci return 0; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_AP && 163762306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_IBSS) 163862306a36Sopenharmony_ci return 0; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); 164162306a36Sopenharmony_ci if (!bcn) { 164262306a36Sopenharmony_ci ath10k_warn(ar, "failed to get beacon template from mac80211\n"); 164362306a36Sopenharmony_ci return -EPERM; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn); 164762306a36Sopenharmony_ci if (ret) { 164862306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret); 164962306a36Sopenharmony_ci kfree_skb(bcn); 165062306a36Sopenharmony_ci return ret; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* P2P IE is inserted by firmware automatically (as configured above) 165462306a36Sopenharmony_ci * so remove it from the base beacon template to avoid duplicate P2P 165562306a36Sopenharmony_ci * IEs in beacon frames. 165662306a36Sopenharmony_ci */ 165762306a36Sopenharmony_ci ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, 165862306a36Sopenharmony_ci offsetof(struct ieee80211_mgmt, 165962306a36Sopenharmony_ci u.beacon.variable)); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0, 166262306a36Sopenharmony_ci 0, NULL, 0); 166362306a36Sopenharmony_ci kfree_skb(bcn); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (ret) { 166662306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit beacon template command: %d\n", 166762306a36Sopenharmony_ci ret); 166862306a36Sopenharmony_ci return ret; 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci return 0; 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 167762306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 167862306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 167962306a36Sopenharmony_ci struct sk_buff *prb; 168062306a36Sopenharmony_ci int ret; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) 168362306a36Sopenharmony_ci return 0; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_AP) 168662306a36Sopenharmony_ci return 0; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci /* For mesh, probe response and beacon share the same template */ 168962306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(vif)) 169062306a36Sopenharmony_ci return 0; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci prb = ieee80211_proberesp_get(hw, vif); 169362306a36Sopenharmony_ci if (!prb) { 169462306a36Sopenharmony_ci ath10k_warn(ar, "failed to get probe resp template from mac80211\n"); 169562306a36Sopenharmony_ci return -EPERM; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb); 169962306a36Sopenharmony_ci kfree_skb(prb); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if (ret) { 170262306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit probe resp template command: %d\n", 170362306a36Sopenharmony_ci ret); 170462306a36Sopenharmony_ci return ret; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci return 0; 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic int ath10k_mac_vif_fix_hidden_ssid(struct ath10k_vif *arvif) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 171362306a36Sopenharmony_ci struct cfg80211_chan_def def; 171462306a36Sopenharmony_ci int ret; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* When originally vdev is started during assign_vif_chanctx() some 171762306a36Sopenharmony_ci * information is missing, notably SSID. Firmware revisions with beacon 171862306a36Sopenharmony_ci * offloading require the SSID to be provided during vdev (re)start to 171962306a36Sopenharmony_ci * handle hidden SSID properly. 172062306a36Sopenharmony_ci * 172162306a36Sopenharmony_ci * Vdev restart must be done after vdev has been both started and 172262306a36Sopenharmony_ci * upped. Otherwise some firmware revisions (at least 10.2) fail to 172362306a36Sopenharmony_ci * deliver vdev restart response event causing timeouts during vdev 172462306a36Sopenharmony_ci * syncing in ath10k. 172562306a36Sopenharmony_ci * 172662306a36Sopenharmony_ci * Note: The vdev down/up and template reinstallation could be skipped 172762306a36Sopenharmony_ci * since only wmi-tlv firmware are known to have beacon offload and 172862306a36Sopenharmony_ci * wmi-tlv doesn't seem to misbehave like 10.2 wrt vdev restart 172962306a36Sopenharmony_ci * response delivery. It's probably more robust to keep it as is. 173062306a36Sopenharmony_ci */ 173162306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) 173262306a36Sopenharmony_ci return 0; 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (WARN_ON(!arvif->is_started)) 173562306a36Sopenharmony_ci return -EINVAL; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (WARN_ON(!arvif->is_up)) 173862306a36Sopenharmony_ci return -EINVAL; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) 174162306a36Sopenharmony_ci return -EINVAL; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 174462306a36Sopenharmony_ci if (ret) { 174562306a36Sopenharmony_ci ath10k_warn(ar, "failed to bring down ap vdev %i: %d\n", 174662306a36Sopenharmony_ci arvif->vdev_id, ret); 174762306a36Sopenharmony_ci return ret; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci /* Vdev down reset beacon & presp templates. Reinstall them. Otherwise 175162306a36Sopenharmony_ci * firmware will crash upon vdev up. 175262306a36Sopenharmony_ci */ 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci ret = ath10k_mac_setup_bcn_tmpl(arvif); 175562306a36Sopenharmony_ci if (ret) { 175662306a36Sopenharmony_ci ath10k_warn(ar, "failed to update beacon template: %d\n", ret); 175762306a36Sopenharmony_ci return ret; 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci ret = ath10k_mac_setup_prb_tmpl(arvif); 176162306a36Sopenharmony_ci if (ret) { 176262306a36Sopenharmony_ci ath10k_warn(ar, "failed to update presp template: %d\n", ret); 176362306a36Sopenharmony_ci return ret; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci ret = ath10k_vdev_restart(arvif, &def); 176762306a36Sopenharmony_ci if (ret) { 176862306a36Sopenharmony_ci ath10k_warn(ar, "failed to restart ap vdev %i: %d\n", 176962306a36Sopenharmony_ci arvif->vdev_id, ret); 177062306a36Sopenharmony_ci return ret; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, 177462306a36Sopenharmony_ci arvif->bssid); 177562306a36Sopenharmony_ci if (ret) { 177662306a36Sopenharmony_ci ath10k_warn(ar, "failed to bring up ap vdev %i: %d\n", 177762306a36Sopenharmony_ci arvif->vdev_id, ret); 177862306a36Sopenharmony_ci return ret; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci} 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_cistatic void ath10k_control_beaconing(struct ath10k_vif *arvif, 178562306a36Sopenharmony_ci struct ieee80211_bss_conf *info) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 178862306a36Sopenharmony_ci int ret = 0; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (!info->enable_beacon) { 179362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 179462306a36Sopenharmony_ci if (ret) 179562306a36Sopenharmony_ci ath10k_warn(ar, "failed to down vdev_id %i: %d\n", 179662306a36Sopenharmony_ci arvif->vdev_id, ret); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci arvif->is_up = false; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci spin_lock_bh(&arvif->ar->data_lock); 180162306a36Sopenharmony_ci ath10k_mac_vif_beacon_free(arvif); 180262306a36Sopenharmony_ci spin_unlock_bh(&arvif->ar->data_lock); 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci return; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci arvif->tx_seq_no = 0x1000; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci arvif->aid = 0; 181062306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, info->bssid); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, 181362306a36Sopenharmony_ci arvif->bssid); 181462306a36Sopenharmony_ci if (ret) { 181562306a36Sopenharmony_ci ath10k_warn(ar, "failed to bring up vdev %d: %i\n", 181662306a36Sopenharmony_ci arvif->vdev_id, ret); 181762306a36Sopenharmony_ci return; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci arvif->is_up = true; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci ret = ath10k_mac_vif_fix_hidden_ssid(arvif); 182362306a36Sopenharmony_ci if (ret) { 182462306a36Sopenharmony_ci ath10k_warn(ar, "failed to fix hidden ssid for vdev %i, expect trouble: %d\n", 182562306a36Sopenharmony_ci arvif->vdev_id, ret); 182662306a36Sopenharmony_ci return; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cistatic void ath10k_control_ibss(struct ath10k_vif *arvif, 183362306a36Sopenharmony_ci struct ieee80211_vif *vif) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 183662306a36Sopenharmony_ci u32 vdev_param; 183762306a36Sopenharmony_ci int ret = 0; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci if (!vif->cfg.ibss_joined) { 184262306a36Sopenharmony_ci if (is_zero_ether_addr(arvif->bssid)) 184362306a36Sopenharmony_ci return; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci eth_zero_addr(arvif->bssid); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci return; 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci vdev_param = arvif->ar->wmi.vdev_param->atim_window; 185162306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param, 185262306a36Sopenharmony_ci ATH10K_DEFAULT_ATIM); 185362306a36Sopenharmony_ci if (ret) 185462306a36Sopenharmony_ci ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n", 185562306a36Sopenharmony_ci arvif->vdev_id, ret); 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_cistatic int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif) 185962306a36Sopenharmony_ci{ 186062306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 186162306a36Sopenharmony_ci u32 param; 186262306a36Sopenharmony_ci u32 value; 186362306a36Sopenharmony_ci int ret; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci if (arvif->u.sta.uapsd) 186862306a36Sopenharmony_ci value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; 186962306a36Sopenharmony_ci else 187062306a36Sopenharmony_ci value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; 187362306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value); 187462306a36Sopenharmony_ci if (ret) { 187562306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n", 187662306a36Sopenharmony_ci value, arvif->vdev_id, ret); 187762306a36Sopenharmony_ci return ret; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci return 0; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_cistatic int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) 188462306a36Sopenharmony_ci{ 188562306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 188662306a36Sopenharmony_ci u32 param; 188762306a36Sopenharmony_ci u32 value; 188862306a36Sopenharmony_ci int ret; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (arvif->u.sta.uapsd) 189362306a36Sopenharmony_ci value = WMI_STA_PS_PSPOLL_COUNT_UAPSD; 189462306a36Sopenharmony_ci else 189562306a36Sopenharmony_ci value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci param = WMI_STA_PS_PARAM_PSPOLL_COUNT; 189862306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 189962306a36Sopenharmony_ci param, value); 190062306a36Sopenharmony_ci if (ret) { 190162306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n", 190262306a36Sopenharmony_ci value, arvif->vdev_id, ret); 190362306a36Sopenharmony_ci return ret; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci return 0; 190762306a36Sopenharmony_ci} 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_cistatic int ath10k_mac_num_vifs_started(struct ath10k *ar) 191062306a36Sopenharmony_ci{ 191162306a36Sopenharmony_ci struct ath10k_vif *arvif; 191262306a36Sopenharmony_ci int num = 0; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) 191762306a36Sopenharmony_ci if (arvif->is_started) 191862306a36Sopenharmony_ci num++; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci return num; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_cistatic int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) 192462306a36Sopenharmony_ci{ 192562306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 192662306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 192762306a36Sopenharmony_ci struct ieee80211_conf *conf = &ar->hw->conf; 192862306a36Sopenharmony_ci enum wmi_sta_powersave_param param; 192962306a36Sopenharmony_ci enum wmi_sta_ps_mode psmode; 193062306a36Sopenharmony_ci int ret; 193162306a36Sopenharmony_ci int ps_timeout; 193262306a36Sopenharmony_ci bool enable_ps; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci if (arvif->vif->type != NL80211_IFTYPE_STATION) 193762306a36Sopenharmony_ci return 0; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci enable_ps = arvif->ps; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 && 194262306a36Sopenharmony_ci !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, 194362306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 194462306a36Sopenharmony_ci ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", 194562306a36Sopenharmony_ci arvif->vdev_id); 194662306a36Sopenharmony_ci enable_ps = false; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (!arvif->is_started) { 195062306a36Sopenharmony_ci /* mac80211 can update vif powersave state while disconnected. 195162306a36Sopenharmony_ci * Firmware doesn't behave nicely and consumes more power than 195262306a36Sopenharmony_ci * necessary if PS is disabled on a non-started vdev. Hence 195362306a36Sopenharmony_ci * force-enable PS for non-running vdevs. 195462306a36Sopenharmony_ci */ 195562306a36Sopenharmony_ci psmode = WMI_STA_PS_MODE_ENABLED; 195662306a36Sopenharmony_ci } else if (enable_ps) { 195762306a36Sopenharmony_ci psmode = WMI_STA_PS_MODE_ENABLED; 195862306a36Sopenharmony_ci param = WMI_STA_PS_PARAM_INACTIVITY_TIME; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci ps_timeout = conf->dynamic_ps_timeout; 196162306a36Sopenharmony_ci if (ps_timeout == 0) { 196262306a36Sopenharmony_ci /* Firmware doesn't like 0 */ 196362306a36Sopenharmony_ci ps_timeout = ieee80211_tu_to_usec( 196462306a36Sopenharmony_ci vif->bss_conf.beacon_int) / 1000; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, 196862306a36Sopenharmony_ci ps_timeout); 196962306a36Sopenharmony_ci if (ret) { 197062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n", 197162306a36Sopenharmony_ci arvif->vdev_id, ret); 197262306a36Sopenharmony_ci return ret; 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci } else { 197562306a36Sopenharmony_ci psmode = WMI_STA_PS_MODE_DISABLED; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n", 197962306a36Sopenharmony_ci arvif->vdev_id, psmode ? "enable" : "disable"); 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode); 198262306a36Sopenharmony_ci if (ret) { 198362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n", 198462306a36Sopenharmony_ci psmode, arvif->vdev_id, ret); 198562306a36Sopenharmony_ci return ret; 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci return 0; 198962306a36Sopenharmony_ci} 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_cistatic int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 199462306a36Sopenharmony_ci struct wmi_sta_keepalive_arg arg = {}; 199562306a36Sopenharmony_ci int ret; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_STA) 200062306a36Sopenharmony_ci return 0; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map)) 200362306a36Sopenharmony_ci return 0; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci /* Some firmware revisions have a bug and ignore the `enabled` field. 200662306a36Sopenharmony_ci * Instead use the interval to disable the keepalive. 200762306a36Sopenharmony_ci */ 200862306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 200962306a36Sopenharmony_ci arg.enabled = 1; 201062306a36Sopenharmony_ci arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; 201162306a36Sopenharmony_ci arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci ret = ath10k_wmi_sta_keepalive(ar, &arg); 201462306a36Sopenharmony_ci if (ret) { 201562306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n", 201662306a36Sopenharmony_ci arvif->vdev_id, ret); 201762306a36Sopenharmony_ci return ret; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci return 0; 202162306a36Sopenharmony_ci} 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_cistatic void ath10k_mac_vif_ap_csa_count_down(struct ath10k_vif *arvif) 202462306a36Sopenharmony_ci{ 202562306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 202662306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 202762306a36Sopenharmony_ci int ret; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci if (WARN_ON(!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))) 203262306a36Sopenharmony_ci return; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_AP) 203562306a36Sopenharmony_ci return; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci if (!vif->bss_conf.csa_active) 203862306a36Sopenharmony_ci return; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (!arvif->is_up) 204162306a36Sopenharmony_ci return; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (!ieee80211_beacon_cntdwn_is_complete(vif)) { 204462306a36Sopenharmony_ci ieee80211_beacon_update_cntdwn(vif); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci ret = ath10k_mac_setup_bcn_tmpl(arvif); 204762306a36Sopenharmony_ci if (ret) 204862306a36Sopenharmony_ci ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", 204962306a36Sopenharmony_ci ret); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci ret = ath10k_mac_setup_prb_tmpl(arvif); 205262306a36Sopenharmony_ci if (ret) 205362306a36Sopenharmony_ci ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", 205462306a36Sopenharmony_ci ret); 205562306a36Sopenharmony_ci } else { 205662306a36Sopenharmony_ci ieee80211_csa_finish(vif); 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci} 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_cistatic void ath10k_mac_vif_ap_csa_work(struct work_struct *work) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, 206362306a36Sopenharmony_ci ap_csa_work); 206462306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 206762306a36Sopenharmony_ci ath10k_mac_vif_ap_csa_count_down(arvif); 206862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_cistatic void ath10k_mac_handle_beacon_iter(void *data, u8 *mac, 207262306a36Sopenharmony_ci struct ieee80211_vif *vif) 207362306a36Sopenharmony_ci{ 207462306a36Sopenharmony_ci struct sk_buff *skb = data; 207562306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt = (void *)skb->data; 207662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION) 207962306a36Sopenharmony_ci return; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid)) 208262306a36Sopenharmony_ci return; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci cancel_delayed_work(&arvif->connection_loss_work); 208562306a36Sopenharmony_ci} 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_civoid ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb) 208862306a36Sopenharmony_ci{ 208962306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 209062306a36Sopenharmony_ci ATH10K_ITER_NORMAL_FLAGS, 209162306a36Sopenharmony_ci ath10k_mac_handle_beacon_iter, 209262306a36Sopenharmony_ci skb); 209362306a36Sopenharmony_ci} 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_cistatic void ath10k_mac_handle_beacon_miss_iter(void *data, u8 *mac, 209662306a36Sopenharmony_ci struct ieee80211_vif *vif) 209762306a36Sopenharmony_ci{ 209862306a36Sopenharmony_ci u32 *vdev_id = data; 209962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 210062306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 210162306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci if (arvif->vdev_id != *vdev_id) 210462306a36Sopenharmony_ci return; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci if (!arvif->is_up) 210762306a36Sopenharmony_ci return; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci ieee80211_beacon_loss(vif); 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci /* Firmware doesn't report beacon loss events repeatedly. If AP probe 211262306a36Sopenharmony_ci * (done by mac80211) succeeds but beacons do not resume then it 211362306a36Sopenharmony_ci * doesn't make sense to continue operation. Queue connection loss work 211462306a36Sopenharmony_ci * which can be cancelled when beacon is received. 211562306a36Sopenharmony_ci */ 211662306a36Sopenharmony_ci ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work, 211762306a36Sopenharmony_ci ATH10K_CONNECTION_LOSS_HZ); 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_civoid ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 212362306a36Sopenharmony_ci ATH10K_ITER_NORMAL_FLAGS, 212462306a36Sopenharmony_ci ath10k_mac_handle_beacon_miss_iter, 212562306a36Sopenharmony_ci &vdev_id); 212662306a36Sopenharmony_ci} 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_cistatic void ath10k_mac_vif_sta_connection_loss_work(struct work_struct *work) 212962306a36Sopenharmony_ci{ 213062306a36Sopenharmony_ci struct ath10k_vif *arvif = container_of(work, struct ath10k_vif, 213162306a36Sopenharmony_ci connection_loss_work.work); 213262306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci if (!arvif->is_up) 213562306a36Sopenharmony_ci return; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci ieee80211_connection_loss(vif); 213862306a36Sopenharmony_ci} 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci/**********************/ 214162306a36Sopenharmony_ci/* Station management */ 214262306a36Sopenharmony_ci/**********************/ 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_cistatic u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar, 214562306a36Sopenharmony_ci struct ieee80211_vif *vif) 214662306a36Sopenharmony_ci{ 214762306a36Sopenharmony_ci /* Some firmware revisions have unstable STA powersave when listen 214862306a36Sopenharmony_ci * interval is set too high (e.g. 5). The symptoms are firmware doesn't 214962306a36Sopenharmony_ci * generate NullFunc frames properly even if buffered frames have been 215062306a36Sopenharmony_ci * indicated in Beacon TIM. Firmware would seldom wake up to pull 215162306a36Sopenharmony_ci * buffered frames. Often pinging the device from AP would simply fail. 215262306a36Sopenharmony_ci * 215362306a36Sopenharmony_ci * As a workaround set it to 1. 215462306a36Sopenharmony_ci */ 215562306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 215662306a36Sopenharmony_ci return 1; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return ar->hw->conf.listen_interval; 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_basic(struct ath10k *ar, 216262306a36Sopenharmony_ci struct ieee80211_vif *vif, 216362306a36Sopenharmony_ci struct ieee80211_sta *sta, 216462306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 216762306a36Sopenharmony_ci u32 aid; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 217262306a36Sopenharmony_ci aid = vif->cfg.aid; 217362306a36Sopenharmony_ci else 217462306a36Sopenharmony_ci aid = sta->aid; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci ether_addr_copy(arg->addr, sta->addr); 217762306a36Sopenharmony_ci arg->vdev_id = arvif->vdev_id; 217862306a36Sopenharmony_ci arg->peer_aid = aid; 217962306a36Sopenharmony_ci arg->peer_flags |= arvif->ar->wmi.peer_flags->auth; 218062306a36Sopenharmony_ci arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif); 218162306a36Sopenharmony_ci arg->peer_num_spatial_streams = 1; 218262306a36Sopenharmony_ci arg->peer_caps = vif->bss_conf.assoc_capability; 218362306a36Sopenharmony_ci} 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_crypto(struct ath10k *ar, 218662306a36Sopenharmony_ci struct ieee80211_vif *vif, 218762306a36Sopenharmony_ci struct ieee80211_sta *sta, 218862306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 218962306a36Sopenharmony_ci{ 219062306a36Sopenharmony_ci struct ieee80211_bss_conf *info = &vif->bss_conf; 219162306a36Sopenharmony_ci struct cfg80211_chan_def def; 219262306a36Sopenharmony_ci struct cfg80211_bss *bss; 219362306a36Sopenharmony_ci const u8 *rsnie = NULL; 219462306a36Sopenharmony_ci const u8 *wpaie = NULL; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 219962306a36Sopenharmony_ci return; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, 220262306a36Sopenharmony_ci vif->cfg.ssid_len ? vif->cfg.ssid : NULL, 220362306a36Sopenharmony_ci vif->cfg.ssid_len, 220462306a36Sopenharmony_ci IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); 220562306a36Sopenharmony_ci if (bss) { 220662306a36Sopenharmony_ci const struct cfg80211_bss_ies *ies; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci rcu_read_lock(); 220962306a36Sopenharmony_ci rsnie = ieee80211_bss_get_ie(bss, WLAN_EID_RSN); 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci ies = rcu_dereference(bss->ies); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, 221462306a36Sopenharmony_ci WLAN_OUI_TYPE_MICROSOFT_WPA, 221562306a36Sopenharmony_ci ies->data, 221662306a36Sopenharmony_ci ies->len); 221762306a36Sopenharmony_ci rcu_read_unlock(); 221862306a36Sopenharmony_ci cfg80211_put_bss(ar->hw->wiphy, bss); 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci /* FIXME: base on RSN IE/WPA IE is a correct idea? */ 222262306a36Sopenharmony_ci if (rsnie || wpaie) { 222362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__); 222462306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->need_ptk_4_way; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci if (wpaie) { 222862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__); 222962306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->need_gtk_2_way; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (sta->mfp && 223362306a36Sopenharmony_ci test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, 223462306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 223562306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->pmf; 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci} 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_rates(struct ath10k *ar, 224062306a36Sopenharmony_ci struct ieee80211_vif *vif, 224162306a36Sopenharmony_ci struct ieee80211_sta *sta, 224262306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 224362306a36Sopenharmony_ci{ 224462306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 224562306a36Sopenharmony_ci struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates; 224662306a36Sopenharmony_ci struct cfg80211_chan_def def; 224762306a36Sopenharmony_ci const struct ieee80211_supported_band *sband; 224862306a36Sopenharmony_ci const struct ieee80211_rate *rates; 224962306a36Sopenharmony_ci enum nl80211_band band; 225062306a36Sopenharmony_ci u32 ratemask; 225162306a36Sopenharmony_ci u8 rate; 225262306a36Sopenharmony_ci int i; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 225762306a36Sopenharmony_ci return; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci band = def.chan->band; 226062306a36Sopenharmony_ci sband = ar->hw->wiphy->bands[band]; 226162306a36Sopenharmony_ci ratemask = sta->deflink.supp_rates[band]; 226262306a36Sopenharmony_ci ratemask &= arvif->bitrate_mask.control[band].legacy; 226362306a36Sopenharmony_ci rates = sband->bitrates; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci rateset->num_rates = 0; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci for (i = 0; i < 32; i++, ratemask >>= 1, rates++) { 226862306a36Sopenharmony_ci if (!(ratemask & 1)) 226962306a36Sopenharmony_ci continue; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci rate = ath10k_mac_bitrate_to_rate(rates->bitrate); 227262306a36Sopenharmony_ci rateset->rates[rateset->num_rates] = rate; 227362306a36Sopenharmony_ci rateset->num_rates++; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci} 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_cistatic bool 227862306a36Sopenharmony_ciath10k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) 227962306a36Sopenharmony_ci{ 228062306a36Sopenharmony_ci int nss; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++) 228362306a36Sopenharmony_ci if (ht_mcs_mask[nss]) 228462306a36Sopenharmony_ci return false; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci return true; 228762306a36Sopenharmony_ci} 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_cistatic bool 229062306a36Sopenharmony_ciath10k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci int nss; 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) 229562306a36Sopenharmony_ci if (vht_mcs_mask[nss]) 229662306a36Sopenharmony_ci return false; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci return true; 229962306a36Sopenharmony_ci} 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_ht(struct ath10k *ar, 230262306a36Sopenharmony_ci struct ieee80211_vif *vif, 230362306a36Sopenharmony_ci struct ieee80211_sta *sta, 230462306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 230562306a36Sopenharmony_ci{ 230662306a36Sopenharmony_ci const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; 230762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 230862306a36Sopenharmony_ci struct cfg80211_chan_def def; 230962306a36Sopenharmony_ci enum nl80211_band band; 231062306a36Sopenharmony_ci const u8 *ht_mcs_mask; 231162306a36Sopenharmony_ci const u16 *vht_mcs_mask; 231262306a36Sopenharmony_ci int i, n; 231362306a36Sopenharmony_ci u8 max_nss; 231462306a36Sopenharmony_ci u32 stbc; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 231962306a36Sopenharmony_ci return; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci if (!ht_cap->ht_supported) 232262306a36Sopenharmony_ci return; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci band = def.chan->band; 232562306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 232662306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (ath10k_peer_assoc_h_ht_masked(ht_mcs_mask) && 232962306a36Sopenharmony_ci ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) 233062306a36Sopenharmony_ci return; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->ht; 233362306a36Sopenharmony_ci arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 233462306a36Sopenharmony_ci ht_cap->ampdu_factor)) - 1; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci arg->peer_mpdu_density = 233762306a36Sopenharmony_ci ath10k_parse_mpdudensity(ht_cap->ampdu_density); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci arg->peer_ht_caps = ht_cap->cap; 234062306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_HT_FLAG; 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) 234362306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->ldbc; 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) { 234662306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->bw40; 234762306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_CW40_FLAG; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { 235162306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) 235262306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_SGI_FLAG; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_SGI_40) 235562306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_SGI_FLAG; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) { 235962306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_TX_STBC_FLAG; 236062306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->stbc; 236162306a36Sopenharmony_ci } 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) { 236462306a36Sopenharmony_ci stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC; 236562306a36Sopenharmony_ci stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT; 236662306a36Sopenharmony_ci stbc = stbc << WMI_RC_RX_STBC_FLAG_S; 236762306a36Sopenharmony_ci arg->peer_rate_caps |= stbc; 236862306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->stbc; 236962306a36Sopenharmony_ci } 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) 237262306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_TS_FLAG; 237362306a36Sopenharmony_ci else if (ht_cap->mcs.rx_mask[1]) 237462306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_DS_FLAG; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++) 237762306a36Sopenharmony_ci if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) && 237862306a36Sopenharmony_ci (ht_mcs_mask[i / 8] & BIT(i % 8))) { 237962306a36Sopenharmony_ci max_nss = (i / 8) + 1; 238062306a36Sopenharmony_ci arg->peer_ht_rates.rates[n++] = i; 238162306a36Sopenharmony_ci } 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci /* 238462306a36Sopenharmony_ci * This is a workaround for HT-enabled STAs which break the spec 238562306a36Sopenharmony_ci * and have no HT capabilities RX mask (no HT RX MCS map). 238662306a36Sopenharmony_ci * 238762306a36Sopenharmony_ci * As per spec, in section 20.3.5 Modulation and coding scheme (MCS), 238862306a36Sopenharmony_ci * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. 238962306a36Sopenharmony_ci * 239062306a36Sopenharmony_ci * Firmware asserts if such situation occurs. 239162306a36Sopenharmony_ci */ 239262306a36Sopenharmony_ci if (n == 0) { 239362306a36Sopenharmony_ci arg->peer_ht_rates.num_rates = 8; 239462306a36Sopenharmony_ci for (i = 0; i < arg->peer_ht_rates.num_rates; i++) 239562306a36Sopenharmony_ci arg->peer_ht_rates.rates[i] = i; 239662306a36Sopenharmony_ci } else { 239762306a36Sopenharmony_ci arg->peer_ht_rates.num_rates = n; 239862306a36Sopenharmony_ci arg->peer_num_spatial_streams = min(sta->deflink.rx_nss, 239962306a36Sopenharmony_ci max_nss); 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", 240362306a36Sopenharmony_ci arg->addr, 240462306a36Sopenharmony_ci arg->peer_ht_rates.num_rates, 240562306a36Sopenharmony_ci arg->peer_num_spatial_streams); 240662306a36Sopenharmony_ci} 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cistatic int ath10k_peer_assoc_qos_ap(struct ath10k *ar, 240962306a36Sopenharmony_ci struct ath10k_vif *arvif, 241062306a36Sopenharmony_ci struct ieee80211_sta *sta) 241162306a36Sopenharmony_ci{ 241262306a36Sopenharmony_ci u32 uapsd = 0; 241362306a36Sopenharmony_ci u32 max_sp = 0; 241462306a36Sopenharmony_ci int ret = 0; 241562306a36Sopenharmony_ci 241662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci if (sta->wme && sta->uapsd_queues) { 241962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", 242062306a36Sopenharmony_ci sta->uapsd_queues, sta->max_sp); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) 242362306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | 242462306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; 242562306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) 242662306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN | 242762306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC2_TRIGGER_EN; 242862306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) 242962306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN | 243062306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC1_TRIGGER_EN; 243162306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) 243262306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | 243362306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) 243662306a36Sopenharmony_ci max_sp = sta->max_sp; 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, 243962306a36Sopenharmony_ci sta->addr, 244062306a36Sopenharmony_ci WMI_AP_PS_PEER_PARAM_UAPSD, 244162306a36Sopenharmony_ci uapsd); 244262306a36Sopenharmony_ci if (ret) { 244362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n", 244462306a36Sopenharmony_ci arvif->vdev_id, ret); 244562306a36Sopenharmony_ci return ret; 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, 244962306a36Sopenharmony_ci sta->addr, 245062306a36Sopenharmony_ci WMI_AP_PS_PEER_PARAM_MAX_SP, 245162306a36Sopenharmony_ci max_sp); 245262306a36Sopenharmony_ci if (ret) { 245362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n", 245462306a36Sopenharmony_ci arvif->vdev_id, ret); 245562306a36Sopenharmony_ci return ret; 245662306a36Sopenharmony_ci } 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci /* TODO setup this based on STA listen interval and 245962306a36Sopenharmony_ci * beacon interval. Currently we don't know 246062306a36Sopenharmony_ci * sta->listen_interval - mac80211 patch required. 246162306a36Sopenharmony_ci * Currently use 10 seconds 246262306a36Sopenharmony_ci */ 246362306a36Sopenharmony_ci ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr, 246462306a36Sopenharmony_ci WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 246562306a36Sopenharmony_ci 10); 246662306a36Sopenharmony_ci if (ret) { 246762306a36Sopenharmony_ci ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n", 246862306a36Sopenharmony_ci arvif->vdev_id, ret); 246962306a36Sopenharmony_ci return ret; 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci return 0; 247462306a36Sopenharmony_ci} 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_cistatic u16 247762306a36Sopenharmony_ciath10k_peer_assoc_h_vht_limit(u16 tx_mcs_set, 247862306a36Sopenharmony_ci const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX]) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci int idx_limit; 248162306a36Sopenharmony_ci int nss; 248262306a36Sopenharmony_ci u16 mcs_map; 248362306a36Sopenharmony_ci u16 mcs; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) { 248662306a36Sopenharmony_ci mcs_map = ath10k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) & 248762306a36Sopenharmony_ci vht_mcs_limit[nss]; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci if (mcs_map) 249062306a36Sopenharmony_ci idx_limit = fls(mcs_map) - 1; 249162306a36Sopenharmony_ci else 249262306a36Sopenharmony_ci idx_limit = -1; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci switch (idx_limit) { 249562306a36Sopenharmony_ci case 0: 249662306a36Sopenharmony_ci case 1: 249762306a36Sopenharmony_ci case 2: 249862306a36Sopenharmony_ci case 3: 249962306a36Sopenharmony_ci case 4: 250062306a36Sopenharmony_ci case 5: 250162306a36Sopenharmony_ci case 6: 250262306a36Sopenharmony_ci default: 250362306a36Sopenharmony_ci /* see ath10k_mac_can_set_bitrate_mask() */ 250462306a36Sopenharmony_ci WARN_ON(1); 250562306a36Sopenharmony_ci fallthrough; 250662306a36Sopenharmony_ci case -1: 250762306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; 250862306a36Sopenharmony_ci break; 250962306a36Sopenharmony_ci case 7: 251062306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_7; 251162306a36Sopenharmony_ci break; 251262306a36Sopenharmony_ci case 8: 251362306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_8; 251462306a36Sopenharmony_ci break; 251562306a36Sopenharmony_ci case 9: 251662306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_9; 251762306a36Sopenharmony_ci break; 251862306a36Sopenharmony_ci } 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci tx_mcs_set &= ~(0x3 << (nss * 2)); 252162306a36Sopenharmony_ci tx_mcs_set |= mcs << (nss * 2); 252262306a36Sopenharmony_ci } 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci return tx_mcs_set; 252562306a36Sopenharmony_ci} 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_cistatic u32 get_160mhz_nss_from_maxrate(int rate) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci u32 nss; 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci switch (rate) { 253262306a36Sopenharmony_ci case 780: 253362306a36Sopenharmony_ci nss = 1; 253462306a36Sopenharmony_ci break; 253562306a36Sopenharmony_ci case 1560: 253662306a36Sopenharmony_ci nss = 2; 253762306a36Sopenharmony_ci break; 253862306a36Sopenharmony_ci case 2106: 253962306a36Sopenharmony_ci nss = 3; /* not support MCS9 from spec*/ 254062306a36Sopenharmony_ci break; 254162306a36Sopenharmony_ci case 3120: 254262306a36Sopenharmony_ci nss = 4; 254362306a36Sopenharmony_ci break; 254462306a36Sopenharmony_ci default: 254562306a36Sopenharmony_ci nss = 1; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci return nss; 254962306a36Sopenharmony_ci} 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_vht(struct ath10k *ar, 255262306a36Sopenharmony_ci struct ieee80211_vif *vif, 255362306a36Sopenharmony_ci struct ieee80211_sta *sta, 255462306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; 255762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 255862306a36Sopenharmony_ci struct ath10k_hw_params *hw = &ar->hw_params; 255962306a36Sopenharmony_ci struct cfg80211_chan_def def; 256062306a36Sopenharmony_ci enum nl80211_band band; 256162306a36Sopenharmony_ci const u16 *vht_mcs_mask; 256262306a36Sopenharmony_ci u8 ampdu_factor; 256362306a36Sopenharmony_ci u8 max_nss, vht_mcs; 256462306a36Sopenharmony_ci int i; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 256762306a36Sopenharmony_ci return; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci if (!vht_cap->vht_supported) 257062306a36Sopenharmony_ci return; 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci band = def.chan->band; 257362306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci if (ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) 257662306a36Sopenharmony_ci return; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->vht; 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci if (def.chan->band == NL80211_BAND_2GHZ) 258162306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->vht_2g; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_ci arg->peer_vht_caps = vht_cap->cap; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci ampdu_factor = (vht_cap->cap & 258662306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> 258762306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci /* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to 259062306a36Sopenharmony_ci * zero in VHT IE. Using it would result in degraded throughput. 259162306a36Sopenharmony_ci * arg->peer_max_mpdu at this point contains HT max_mpdu so keep 259262306a36Sopenharmony_ci * it if VHT max_mpdu is smaller. 259362306a36Sopenharmony_ci */ 259462306a36Sopenharmony_ci arg->peer_max_mpdu = max(arg->peer_max_mpdu, 259562306a36Sopenharmony_ci (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + 259662306a36Sopenharmony_ci ampdu_factor)) - 1); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 259962306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->bw80; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 260262306a36Sopenharmony_ci arg->peer_flags |= ar->wmi.peer_flags->bw160; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci /* Calculate peer NSS capability from VHT capabilities if STA 260562306a36Sopenharmony_ci * supports VHT. 260662306a36Sopenharmony_ci */ 260762306a36Sopenharmony_ci for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) { 260862306a36Sopenharmony_ci vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >> 260962306a36Sopenharmony_ci (2 * i) & 3; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci if ((vht_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) && 261262306a36Sopenharmony_ci vht_mcs_mask[i]) 261362306a36Sopenharmony_ci max_nss = i + 1; 261462306a36Sopenharmony_ci } 261562306a36Sopenharmony_ci arg->peer_num_spatial_streams = min(sta->deflink.rx_nss, max_nss); 261662306a36Sopenharmony_ci arg->peer_vht_rates.rx_max_rate = 261762306a36Sopenharmony_ci __le16_to_cpu(vht_cap->vht_mcs.rx_highest); 261862306a36Sopenharmony_ci arg->peer_vht_rates.rx_mcs_set = 261962306a36Sopenharmony_ci __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); 262062306a36Sopenharmony_ci arg->peer_vht_rates.tx_max_rate = 262162306a36Sopenharmony_ci __le16_to_cpu(vht_cap->vht_mcs.tx_highest); 262262306a36Sopenharmony_ci arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit( 262362306a36Sopenharmony_ci __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask); 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci /* Configure bandwidth-NSS mapping to FW 262662306a36Sopenharmony_ci * for the chip's tx chains setting on 160Mhz bw 262762306a36Sopenharmony_ci */ 262862306a36Sopenharmony_ci if (arg->peer_phymode == MODE_11AC_VHT160 || 262962306a36Sopenharmony_ci arg->peer_phymode == MODE_11AC_VHT80_80) { 263062306a36Sopenharmony_ci u32 rx_nss; 263162306a36Sopenharmony_ci u32 max_rate; 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci max_rate = arg->peer_vht_rates.rx_max_rate; 263462306a36Sopenharmony_ci rx_nss = get_160mhz_nss_from_maxrate(max_rate); 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci if (rx_nss == 0) 263762306a36Sopenharmony_ci rx_nss = arg->peer_num_spatial_streams; 263862306a36Sopenharmony_ci else 263962306a36Sopenharmony_ci rx_nss = min(arg->peer_num_spatial_streams, rx_nss); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci max_rate = hw->vht160_mcs_tx_highest; 264262306a36Sopenharmony_ci rx_nss = min(rx_nss, get_160mhz_nss_from_maxrate(max_rate)); 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci arg->peer_bw_rxnss_override = 264562306a36Sopenharmony_ci FIELD_PREP(WMI_PEER_NSS_MAP_ENABLE, 1) | 264662306a36Sopenharmony_ci FIELD_PREP(WMI_PEER_NSS_160MHZ_MASK, (rx_nss - 1)); 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (arg->peer_phymode == MODE_11AC_VHT80_80) { 264962306a36Sopenharmony_ci arg->peer_bw_rxnss_override |= 265062306a36Sopenharmony_ci FIELD_PREP(WMI_PEER_NSS_80_80MHZ_MASK, (rx_nss - 1)); 265162306a36Sopenharmony_ci } 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 265462306a36Sopenharmony_ci "mac vht peer %pM max_mpdu %d flags 0x%x peer_rx_nss_override 0x%x\n", 265562306a36Sopenharmony_ci sta->addr, arg->peer_max_mpdu, 265662306a36Sopenharmony_ci arg->peer_flags, arg->peer_bw_rxnss_override); 265762306a36Sopenharmony_ci} 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_qos(struct ath10k *ar, 266062306a36Sopenharmony_ci struct ieee80211_vif *vif, 266162306a36Sopenharmony_ci struct ieee80211_sta *sta, 266262306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 266362306a36Sopenharmony_ci{ 266462306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci switch (arvif->vdev_type) { 266762306a36Sopenharmony_ci case WMI_VDEV_TYPE_AP: 266862306a36Sopenharmony_ci if (sta->wme) 266962306a36Sopenharmony_ci arg->peer_flags |= arvif->ar->wmi.peer_flags->qos; 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci if (sta->wme && sta->uapsd_queues) { 267262306a36Sopenharmony_ci arg->peer_flags |= arvif->ar->wmi.peer_flags->apsd; 267362306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG; 267462306a36Sopenharmony_ci } 267562306a36Sopenharmony_ci break; 267662306a36Sopenharmony_ci case WMI_VDEV_TYPE_STA: 267762306a36Sopenharmony_ci if (sta->wme) 267862306a36Sopenharmony_ci arg->peer_flags |= arvif->ar->wmi.peer_flags->qos; 267962306a36Sopenharmony_ci break; 268062306a36Sopenharmony_ci case WMI_VDEV_TYPE_IBSS: 268162306a36Sopenharmony_ci if (sta->wme) 268262306a36Sopenharmony_ci arg->peer_flags |= arvif->ar->wmi.peer_flags->qos; 268362306a36Sopenharmony_ci break; 268462306a36Sopenharmony_ci default: 268562306a36Sopenharmony_ci break; 268662306a36Sopenharmony_ci } 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n", 268962306a36Sopenharmony_ci sta->addr, !!(arg->peer_flags & 269062306a36Sopenharmony_ci arvif->ar->wmi.peer_flags->qos)); 269162306a36Sopenharmony_ci} 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_cistatic bool ath10k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta) 269462306a36Sopenharmony_ci{ 269562306a36Sopenharmony_ci return sta->deflink.supp_rates[NL80211_BAND_2GHZ] >> 269662306a36Sopenharmony_ci ATH10K_MAC_FIRST_OFDM_RATE_IDX; 269762306a36Sopenharmony_ci} 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_cistatic enum wmi_phy_mode ath10k_mac_get_phymode_vht(struct ath10k *ar, 270062306a36Sopenharmony_ci struct ieee80211_sta *sta) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { 270562306a36Sopenharmony_ci switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 270662306a36Sopenharmony_ci case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 270762306a36Sopenharmony_ci return MODE_11AC_VHT160; 270862306a36Sopenharmony_ci case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 270962306a36Sopenharmony_ci return MODE_11AC_VHT80_80; 271062306a36Sopenharmony_ci default: 271162306a36Sopenharmony_ci /* not sure if this is a valid case? */ 271262306a36Sopenharmony_ci return MODE_11AC_VHT160; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci } 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 271762306a36Sopenharmony_ci return MODE_11AC_VHT80; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 272062306a36Sopenharmony_ci return MODE_11AC_VHT40; 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) 272362306a36Sopenharmony_ci return MODE_11AC_VHT20; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci return MODE_UNKNOWN; 272662306a36Sopenharmony_ci} 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_cistatic void ath10k_peer_assoc_h_phymode(struct ath10k *ar, 272962306a36Sopenharmony_ci struct ieee80211_vif *vif, 273062306a36Sopenharmony_ci struct ieee80211_sta *sta, 273162306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 273262306a36Sopenharmony_ci{ 273362306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 273462306a36Sopenharmony_ci struct cfg80211_chan_def def; 273562306a36Sopenharmony_ci enum nl80211_band band; 273662306a36Sopenharmony_ci const u8 *ht_mcs_mask; 273762306a36Sopenharmony_ci const u16 *vht_mcs_mask; 273862306a36Sopenharmony_ci enum wmi_phy_mode phymode = MODE_UNKNOWN; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 274162306a36Sopenharmony_ci return; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci band = def.chan->band; 274462306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 274562306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci switch (band) { 274862306a36Sopenharmony_ci case NL80211_BAND_2GHZ: 274962306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported && 275062306a36Sopenharmony_ci !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) { 275162306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 275262306a36Sopenharmony_ci phymode = MODE_11AC_VHT40; 275362306a36Sopenharmony_ci else 275462306a36Sopenharmony_ci phymode = MODE_11AC_VHT20; 275562306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported && 275662306a36Sopenharmony_ci !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) { 275762306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 275862306a36Sopenharmony_ci phymode = MODE_11NG_HT40; 275962306a36Sopenharmony_ci else 276062306a36Sopenharmony_ci phymode = MODE_11NG_HT20; 276162306a36Sopenharmony_ci } else if (ath10k_mac_sta_has_ofdm_only(sta)) { 276262306a36Sopenharmony_ci phymode = MODE_11G; 276362306a36Sopenharmony_ci } else { 276462306a36Sopenharmony_ci phymode = MODE_11B; 276562306a36Sopenharmony_ci } 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci break; 276862306a36Sopenharmony_ci case NL80211_BAND_5GHZ: 276962306a36Sopenharmony_ci /* 277062306a36Sopenharmony_ci * Check VHT first. 277162306a36Sopenharmony_ci */ 277262306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported && 277362306a36Sopenharmony_ci !ath10k_peer_assoc_h_vht_masked(vht_mcs_mask)) { 277462306a36Sopenharmony_ci phymode = ath10k_mac_get_phymode_vht(ar, sta); 277562306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported && 277662306a36Sopenharmony_ci !ath10k_peer_assoc_h_ht_masked(ht_mcs_mask)) { 277762306a36Sopenharmony_ci if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) 277862306a36Sopenharmony_ci phymode = MODE_11NA_HT40; 277962306a36Sopenharmony_ci else 278062306a36Sopenharmony_ci phymode = MODE_11NA_HT20; 278162306a36Sopenharmony_ci } else { 278262306a36Sopenharmony_ci phymode = MODE_11A; 278362306a36Sopenharmony_ci } 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci break; 278662306a36Sopenharmony_ci default: 278762306a36Sopenharmony_ci break; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n", 279162306a36Sopenharmony_ci sta->addr, ath10k_wmi_phymode_str(phymode)); 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci arg->peer_phymode = phymode; 279462306a36Sopenharmony_ci WARN_ON(phymode == MODE_UNKNOWN); 279562306a36Sopenharmony_ci} 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_cistatic int ath10k_peer_assoc_prepare(struct ath10k *ar, 279862306a36Sopenharmony_ci struct ieee80211_vif *vif, 279962306a36Sopenharmony_ci struct ieee80211_sta *sta, 280062306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg *arg) 280162306a36Sopenharmony_ci{ 280262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci ath10k_peer_assoc_h_basic(ar, vif, sta, arg); 280762306a36Sopenharmony_ci ath10k_peer_assoc_h_crypto(ar, vif, sta, arg); 280862306a36Sopenharmony_ci ath10k_peer_assoc_h_rates(ar, vif, sta, arg); 280962306a36Sopenharmony_ci ath10k_peer_assoc_h_ht(ar, vif, sta, arg); 281062306a36Sopenharmony_ci ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); 281162306a36Sopenharmony_ci ath10k_peer_assoc_h_vht(ar, vif, sta, arg); 281262306a36Sopenharmony_ci ath10k_peer_assoc_h_qos(ar, vif, sta, arg); 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci return 0; 281562306a36Sopenharmony_ci} 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_cistatic const u32 ath10k_smps_map[] = { 281862306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, 281962306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC, 282062306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE, 282162306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, 282262306a36Sopenharmony_ci}; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_cistatic int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, 282562306a36Sopenharmony_ci const u8 *addr, 282662306a36Sopenharmony_ci const struct ieee80211_sta_ht_cap *ht_cap) 282762306a36Sopenharmony_ci{ 282862306a36Sopenharmony_ci int smps; 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci if (!ht_cap->ht_supported) 283162306a36Sopenharmony_ci return 0; 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; 283462306a36Sopenharmony_ci smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci if (smps >= ARRAY_SIZE(ath10k_smps_map)) 283762306a36Sopenharmony_ci return -EINVAL; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, 284062306a36Sopenharmony_ci ar->wmi.peer_param->smps_state, 284162306a36Sopenharmony_ci ath10k_smps_map[smps]); 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_cistatic int ath10k_mac_vif_recalc_txbf(struct ath10k *ar, 284562306a36Sopenharmony_ci struct ieee80211_vif *vif, 284662306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap) 284762306a36Sopenharmony_ci{ 284862306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 284962306a36Sopenharmony_ci int ret; 285062306a36Sopenharmony_ci u32 param; 285162306a36Sopenharmony_ci u32 value; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_AFTER_ASSOC) 285462306a36Sopenharmony_ci return 0; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci if (!(ar->vht_cap_info & 285762306a36Sopenharmony_ci (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 285862306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | 285962306a36Sopenharmony_ci IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 286062306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))) 286162306a36Sopenharmony_ci return 0; 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci param = ar->wmi.vdev_param->txbf; 286462306a36Sopenharmony_ci value = 0; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED)) 286762306a36Sopenharmony_ci return 0; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci /* The following logic is correct. If a remote STA advertises support 287062306a36Sopenharmony_ci * for being a beamformer then we should enable us being a beamformee. 287162306a36Sopenharmony_ci */ 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci if (ar->vht_cap_info & 287462306a36Sopenharmony_ci (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 287562306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) { 287662306a36Sopenharmony_ci if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) 287762306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) 288062306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; 288162306a36Sopenharmony_ci } 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci if (ar->vht_cap_info & 288462306a36Sopenharmony_ci (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 288562306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { 288662306a36Sopenharmony_ci if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) 288762306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) 289062306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE) 289462306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER) 289762306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value); 290062306a36Sopenharmony_ci if (ret) { 290162306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n", 290262306a36Sopenharmony_ci value, ret); 290362306a36Sopenharmony_ci return ret; 290462306a36Sopenharmony_ci } 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci return 0; 290762306a36Sopenharmony_ci} 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_cistatic bool ath10k_mac_is_connected(struct ath10k *ar) 291062306a36Sopenharmony_ci{ 291162306a36Sopenharmony_ci struct ath10k_vif *arvif; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 291462306a36Sopenharmony_ci if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) 291562306a36Sopenharmony_ci return true; 291662306a36Sopenharmony_ci } 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci return false; 291962306a36Sopenharmony_ci} 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_cistatic int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) 292262306a36Sopenharmony_ci{ 292362306a36Sopenharmony_ci int ret; 292462306a36Sopenharmony_ci u32 param; 292562306a36Sopenharmony_ci int tx_power_2g, tx_power_5g; 292662306a36Sopenharmony_ci bool connected; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci /* ath10k internally uses unit of 0.5 dBm so multiply by 2 */ 293162306a36Sopenharmony_ci tx_power_2g = txpower * 2; 293262306a36Sopenharmony_ci tx_power_5g = txpower * 2; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci connected = ath10k_mac_is_connected(ar); 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci if (connected && ar->tx_power_2g_limit) 293762306a36Sopenharmony_ci if (tx_power_2g > ar->tx_power_2g_limit) 293862306a36Sopenharmony_ci tx_power_2g = ar->tx_power_2g_limit; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci if (connected && ar->tx_power_5g_limit) 294162306a36Sopenharmony_ci if (tx_power_5g > ar->tx_power_5g_limit) 294262306a36Sopenharmony_ci tx_power_5g = ar->tx_power_5g_limit; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower 2g: %d, 5g: %d\n", 294562306a36Sopenharmony_ci tx_power_2g, tx_power_5g); 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci param = ar->wmi.pdev_param->txpower_limit2g; 294862306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, tx_power_2g); 294962306a36Sopenharmony_ci if (ret) { 295062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set 2g txpower %d: %d\n", 295162306a36Sopenharmony_ci tx_power_2g, ret); 295262306a36Sopenharmony_ci return ret; 295362306a36Sopenharmony_ci } 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci param = ar->wmi.pdev_param->txpower_limit5g; 295662306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, tx_power_5g); 295762306a36Sopenharmony_ci if (ret) { 295862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set 5g txpower %d: %d\n", 295962306a36Sopenharmony_ci tx_power_5g, ret); 296062306a36Sopenharmony_ci return ret; 296162306a36Sopenharmony_ci } 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci return 0; 296462306a36Sopenharmony_ci} 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_cistatic int ath10k_mac_txpower_recalc(struct ath10k *ar) 296762306a36Sopenharmony_ci{ 296862306a36Sopenharmony_ci struct ath10k_vif *arvif; 296962306a36Sopenharmony_ci int ret, txpower = -1; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 297462306a36Sopenharmony_ci /* txpower not initialized yet? */ 297562306a36Sopenharmony_ci if (arvif->txpower == INT_MIN) 297662306a36Sopenharmony_ci continue; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci if (txpower == -1) 297962306a36Sopenharmony_ci txpower = arvif->txpower; 298062306a36Sopenharmony_ci else 298162306a36Sopenharmony_ci txpower = min(txpower, arvif->txpower); 298262306a36Sopenharmony_ci } 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci if (txpower == -1) 298562306a36Sopenharmony_ci return 0; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci ret = ath10k_mac_txpower_setup(ar, txpower); 298862306a36Sopenharmony_ci if (ret) { 298962306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup tx power %d: %d\n", 299062306a36Sopenharmony_ci txpower, ret); 299162306a36Sopenharmony_ci return ret; 299262306a36Sopenharmony_ci } 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci return 0; 299562306a36Sopenharmony_ci} 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_cistatic int ath10k_mac_set_sar_power(struct ath10k *ar) 299862306a36Sopenharmony_ci{ 299962306a36Sopenharmony_ci if (!ar->hw_params.dynamic_sar_support) 300062306a36Sopenharmony_ci return -EOPNOTSUPP; 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci if (!ath10k_mac_is_connected(ar)) 300362306a36Sopenharmony_ci return 0; 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* if connected, then arvif->txpower must be valid */ 300662306a36Sopenharmony_ci return ath10k_mac_txpower_recalc(ar); 300762306a36Sopenharmony_ci} 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_cistatic int ath10k_mac_set_sar_specs(struct ieee80211_hw *hw, 301062306a36Sopenharmony_ci const struct cfg80211_sar_specs *sar) 301162306a36Sopenharmony_ci{ 301262306a36Sopenharmony_ci const struct cfg80211_sar_sub_specs *sub_specs; 301362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 301462306a36Sopenharmony_ci u32 i; 301562306a36Sopenharmony_ci int ret; 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 301862306a36Sopenharmony_ci 301962306a36Sopenharmony_ci if (!ar->hw_params.dynamic_sar_support) { 302062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 302162306a36Sopenharmony_ci goto err; 302262306a36Sopenharmony_ci } 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci if (!sar || sar->type != NL80211_SAR_TYPE_POWER || 302562306a36Sopenharmony_ci sar->num_sub_specs == 0) { 302662306a36Sopenharmony_ci ret = -EINVAL; 302762306a36Sopenharmony_ci goto err; 302862306a36Sopenharmony_ci } 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci sub_specs = sar->sub_specs; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci /* 0dbm is not a practical value for ath10k, so use 0 303362306a36Sopenharmony_ci * as no SAR limitation on it. 303462306a36Sopenharmony_ci */ 303562306a36Sopenharmony_ci ar->tx_power_2g_limit = 0; 303662306a36Sopenharmony_ci ar->tx_power_5g_limit = 0; 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci /* note the power is in 0.25dbm unit, while ath10k uses 303962306a36Sopenharmony_ci * 0.5dbm unit. 304062306a36Sopenharmony_ci */ 304162306a36Sopenharmony_ci for (i = 0; i < sar->num_sub_specs; i++) { 304262306a36Sopenharmony_ci if (sub_specs->freq_range_index == 0) 304362306a36Sopenharmony_ci ar->tx_power_2g_limit = sub_specs->power / 2; 304462306a36Sopenharmony_ci else if (sub_specs->freq_range_index == 1) 304562306a36Sopenharmony_ci ar->tx_power_5g_limit = sub_specs->power / 2; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci sub_specs++; 304862306a36Sopenharmony_ci } 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci ret = ath10k_mac_set_sar_power(ar); 305162306a36Sopenharmony_ci if (ret) { 305262306a36Sopenharmony_ci ath10k_warn(ar, "failed to set sar power: %d", ret); 305362306a36Sopenharmony_ci goto err; 305462306a36Sopenharmony_ci } 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_cierr: 305762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 305862306a36Sopenharmony_ci return ret; 305962306a36Sopenharmony_ci} 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci/* can be called only in mac80211 callbacks due to `key_count` usage */ 306262306a36Sopenharmony_cistatic void ath10k_bss_assoc(struct ieee80211_hw *hw, 306362306a36Sopenharmony_ci struct ieee80211_vif *vif, 306462306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf) 306562306a36Sopenharmony_ci{ 306662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 306762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 306862306a36Sopenharmony_ci struct ieee80211_sta_ht_cap ht_cap; 306962306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap; 307062306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg peer_arg; 307162306a36Sopenharmony_ci struct ieee80211_sta *ap_sta; 307262306a36Sopenharmony_ci int ret; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", 307762306a36Sopenharmony_ci arvif->vdev_id, arvif->bssid, arvif->aid); 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci rcu_read_lock(); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); 308262306a36Sopenharmony_ci if (!ap_sta) { 308362306a36Sopenharmony_ci ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n", 308462306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id); 308562306a36Sopenharmony_ci rcu_read_unlock(); 308662306a36Sopenharmony_ci return; 308762306a36Sopenharmony_ci } 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci /* ap_sta must be accessed only within rcu section which must be left 309062306a36Sopenharmony_ci * before calling ath10k_setup_peer_smps() which might sleep. 309162306a36Sopenharmony_ci */ 309262306a36Sopenharmony_ci ht_cap = ap_sta->deflink.ht_cap; 309362306a36Sopenharmony_ci vht_cap = ap_sta->deflink.vht_cap; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); 309662306a36Sopenharmony_ci if (ret) { 309762306a36Sopenharmony_ci ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n", 309862306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id, ret); 309962306a36Sopenharmony_ci rcu_read_unlock(); 310062306a36Sopenharmony_ci return; 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci rcu_read_unlock(); 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci ret = ath10k_wmi_peer_assoc(ar, &peer_arg); 310662306a36Sopenharmony_ci if (ret) { 310762306a36Sopenharmony_ci ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n", 310862306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id, ret); 310962306a36Sopenharmony_ci return; 311062306a36Sopenharmony_ci } 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap); 311362306a36Sopenharmony_ci if (ret) { 311462306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n", 311562306a36Sopenharmony_ci arvif->vdev_id, ret); 311662306a36Sopenharmony_ci return; 311762306a36Sopenharmony_ci } 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); 312062306a36Sopenharmony_ci if (ret) { 312162306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n", 312262306a36Sopenharmony_ci arvif->vdev_id, bss_conf->bssid, ret); 312362306a36Sopenharmony_ci return; 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci 312662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 312762306a36Sopenharmony_ci "mac vdev %d up (associated) bssid %pM aid %d\n", 312862306a36Sopenharmony_ci arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci WARN_ON(arvif->is_up); 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci arvif->aid = vif->cfg.aid; 313362306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, bss_conf->bssid); 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, 313662306a36Sopenharmony_ci ar->wmi.pdev_param->peer_stats_info_enable, 1); 313762306a36Sopenharmony_ci if (ret) 313862306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable peer stats info: %d\n", ret); 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); 314162306a36Sopenharmony_ci if (ret) { 314262306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %d up: %d\n", 314362306a36Sopenharmony_ci arvif->vdev_id, ret); 314462306a36Sopenharmony_ci return; 314562306a36Sopenharmony_ci } 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci arvif->is_up = true; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci ath10k_mac_set_sar_power(ar); 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci /* Workaround: Some firmware revisions (tested with qca6174 315262306a36Sopenharmony_ci * WLAN.RM.2.0-00073) have buggy powersave state machine and must be 315362306a36Sopenharmony_ci * poked with peer param command. 315462306a36Sopenharmony_ci */ 315562306a36Sopenharmony_ci ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, 315662306a36Sopenharmony_ci ar->wmi.peer_param->dummy_var, 1); 315762306a36Sopenharmony_ci if (ret) { 315862306a36Sopenharmony_ci ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n", 315962306a36Sopenharmony_ci arvif->bssid, arvif->vdev_id, ret); 316062306a36Sopenharmony_ci return; 316162306a36Sopenharmony_ci } 316262306a36Sopenharmony_ci} 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_cistatic void ath10k_bss_disassoc(struct ieee80211_hw *hw, 316562306a36Sopenharmony_ci struct ieee80211_vif *vif) 316662306a36Sopenharmony_ci{ 316762306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 316862306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 316962306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap = {}; 317062306a36Sopenharmony_ci int ret; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", 317562306a36Sopenharmony_ci arvif->vdev_id, arvif->bssid); 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 317862306a36Sopenharmony_ci if (ret) 317962306a36Sopenharmony_ci ath10k_warn(ar, "failed to down vdev %i: %d\n", 318062306a36Sopenharmony_ci arvif->vdev_id, ret); 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci arvif->def_wep_key_idx = -1; 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap); 318562306a36Sopenharmony_ci if (ret) { 318662306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n", 318762306a36Sopenharmony_ci arvif->vdev_id, ret); 318862306a36Sopenharmony_ci return; 318962306a36Sopenharmony_ci } 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci arvif->is_up = false; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci ath10k_mac_txpower_recalc(ar); 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci cancel_delayed_work_sync(&arvif->connection_loss_work); 319662306a36Sopenharmony_ci} 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_cistatic int ath10k_new_peer_tid_config(struct ath10k *ar, 319962306a36Sopenharmony_ci struct ieee80211_sta *sta, 320062306a36Sopenharmony_ci struct ath10k_vif *arvif) 320162306a36Sopenharmony_ci{ 320262306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg arg = {}; 320362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 320462306a36Sopenharmony_ci bool config_apply; 320562306a36Sopenharmony_ci int ret, i; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci for (i = 0; i < ATH10K_TID_MAX; i++) { 320862306a36Sopenharmony_ci config_apply = false; 320962306a36Sopenharmony_ci if (arvif->retry_long[i] || arvif->ampdu[i] || 321062306a36Sopenharmony_ci arvif->rate_ctrl[i] || arvif->rtscts[i]) { 321162306a36Sopenharmony_ci config_apply = true; 321262306a36Sopenharmony_ci arg.tid = i; 321362306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 321462306a36Sopenharmony_ci arg.retry_count = arvif->retry_long[i]; 321562306a36Sopenharmony_ci arg.aggr_control = arvif->ampdu[i]; 321662306a36Sopenharmony_ci arg.rate_ctrl = arvif->rate_ctrl[i]; 321762306a36Sopenharmony_ci arg.rcode_flags = arvif->rate_code[i]; 321862306a36Sopenharmony_ci 321962306a36Sopenharmony_ci if (arvif->rtscts[i]) 322062306a36Sopenharmony_ci arg.ext_tid_cfg_bitmap = 322162306a36Sopenharmony_ci WMI_EXT_TID_RTS_CTS_CONFIG; 322262306a36Sopenharmony_ci else 322362306a36Sopenharmony_ci arg.ext_tid_cfg_bitmap = 0; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci arg.rtscts_ctrl = arvif->rtscts[i]; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci if (arvif->noack[i]) { 322962306a36Sopenharmony_ci arg.ack_policy = arvif->noack[i]; 323062306a36Sopenharmony_ci arg.rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE; 323162306a36Sopenharmony_ci arg.aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; 323262306a36Sopenharmony_ci config_apply = true; 323362306a36Sopenharmony_ci } 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci /* Assign default value(-1) to newly connected station. 323662306a36Sopenharmony_ci * This is to identify station specific tid configuration not 323762306a36Sopenharmony_ci * configured for the station. 323862306a36Sopenharmony_ci */ 323962306a36Sopenharmony_ci arsta->retry_long[i] = -1; 324062306a36Sopenharmony_ci arsta->noack[i] = -1; 324162306a36Sopenharmony_ci arsta->ampdu[i] = -1; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci if (!config_apply) 324462306a36Sopenharmony_ci continue; 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci ether_addr_copy(arg.peer_macaddr.addr, sta->addr); 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); 324962306a36Sopenharmony_ci if (ret) { 325062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set per tid retry/aggr config for sta %pM: %d\n", 325162306a36Sopenharmony_ci sta->addr, ret); 325262306a36Sopenharmony_ci return ret; 325362306a36Sopenharmony_ci } 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci memset(&arg, 0, sizeof(arg)); 325662306a36Sopenharmony_ci } 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci return 0; 325962306a36Sopenharmony_ci} 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_cistatic int ath10k_station_assoc(struct ath10k *ar, 326262306a36Sopenharmony_ci struct ieee80211_vif *vif, 326362306a36Sopenharmony_ci struct ieee80211_sta *sta, 326462306a36Sopenharmony_ci bool reassoc) 326562306a36Sopenharmony_ci{ 326662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 326762306a36Sopenharmony_ci struct wmi_peer_assoc_complete_arg peer_arg; 326862306a36Sopenharmony_ci int ret = 0; 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg); 327362306a36Sopenharmony_ci if (ret) { 327462306a36Sopenharmony_ci ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n", 327562306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 327662306a36Sopenharmony_ci return ret; 327762306a36Sopenharmony_ci } 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci ret = ath10k_wmi_peer_assoc(ar, &peer_arg); 328062306a36Sopenharmony_ci if (ret) { 328162306a36Sopenharmony_ci ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n", 328262306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 328362306a36Sopenharmony_ci return ret; 328462306a36Sopenharmony_ci } 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci /* Re-assoc is run only to update supported rates for given station. It 328762306a36Sopenharmony_ci * doesn't make much sense to reconfigure the peer completely. 328862306a36Sopenharmony_ci */ 328962306a36Sopenharmony_ci if (!reassoc) { 329062306a36Sopenharmony_ci ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, 329162306a36Sopenharmony_ci &sta->deflink.ht_cap); 329262306a36Sopenharmony_ci if (ret) { 329362306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", 329462306a36Sopenharmony_ci arvif->vdev_id, ret); 329562306a36Sopenharmony_ci return ret; 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci 329862306a36Sopenharmony_ci ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); 329962306a36Sopenharmony_ci if (ret) { 330062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n", 330162306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 330262306a36Sopenharmony_ci return ret; 330362306a36Sopenharmony_ci } 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci if (!sta->wme) { 330662306a36Sopenharmony_ci arvif->num_legacy_stations++; 330762306a36Sopenharmony_ci ret = ath10k_recalc_rtscts_prot(arvif); 330862306a36Sopenharmony_ci if (ret) { 330962306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", 331062306a36Sopenharmony_ci arvif->vdev_id, ret); 331162306a36Sopenharmony_ci return ret; 331262306a36Sopenharmony_ci } 331362306a36Sopenharmony_ci } 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci /* Plumb cached keys only for static WEP */ 331662306a36Sopenharmony_ci if ((arvif->def_wep_key_idx != -1) && (!sta->tdls)) { 331762306a36Sopenharmony_ci ret = ath10k_install_peer_wep_keys(arvif, sta->addr); 331862306a36Sopenharmony_ci if (ret) { 331962306a36Sopenharmony_ci ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", 332062306a36Sopenharmony_ci arvif->vdev_id, ret); 332162306a36Sopenharmony_ci return ret; 332262306a36Sopenharmony_ci } 332362306a36Sopenharmony_ci } 332462306a36Sopenharmony_ci } 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) 332762306a36Sopenharmony_ci return ret; 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_ci return ath10k_new_peer_tid_config(ar, sta, arvif); 333062306a36Sopenharmony_ci} 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_cistatic int ath10k_station_disassoc(struct ath10k *ar, 333362306a36Sopenharmony_ci struct ieee80211_vif *vif, 333462306a36Sopenharmony_ci struct ieee80211_sta *sta) 333562306a36Sopenharmony_ci{ 333662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 333762306a36Sopenharmony_ci int ret = 0; 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci if (!sta->wme) { 334262306a36Sopenharmony_ci arvif->num_legacy_stations--; 334362306a36Sopenharmony_ci ret = ath10k_recalc_rtscts_prot(arvif); 334462306a36Sopenharmony_ci if (ret) { 334562306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", 334662306a36Sopenharmony_ci arvif->vdev_id, ret); 334762306a36Sopenharmony_ci return ret; 334862306a36Sopenharmony_ci } 334962306a36Sopenharmony_ci } 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci ret = ath10k_clear_peer_keys(arvif, sta->addr); 335262306a36Sopenharmony_ci if (ret) { 335362306a36Sopenharmony_ci ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n", 335462306a36Sopenharmony_ci arvif->vdev_id, ret); 335562306a36Sopenharmony_ci return ret; 335662306a36Sopenharmony_ci } 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci return ret; 335962306a36Sopenharmony_ci} 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci/**************/ 336262306a36Sopenharmony_ci/* Regulatory */ 336362306a36Sopenharmony_ci/**************/ 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_cistatic int ath10k_update_channel_list(struct ath10k *ar) 336662306a36Sopenharmony_ci{ 336762306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 336862306a36Sopenharmony_ci struct ieee80211_supported_band **bands; 336962306a36Sopenharmony_ci enum nl80211_band band; 337062306a36Sopenharmony_ci struct ieee80211_channel *channel; 337162306a36Sopenharmony_ci struct wmi_scan_chan_list_arg arg = {0}; 337262306a36Sopenharmony_ci struct wmi_channel_arg *ch; 337362306a36Sopenharmony_ci bool passive; 337462306a36Sopenharmony_ci int len; 337562306a36Sopenharmony_ci int ret; 337662306a36Sopenharmony_ci int i; 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci bands = hw->wiphy->bands; 338162306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 338262306a36Sopenharmony_ci if (!bands[band]) 338362306a36Sopenharmony_ci continue; 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci for (i = 0; i < bands[band]->n_channels; i++) { 338662306a36Sopenharmony_ci if (bands[band]->channels[i].flags & 338762306a36Sopenharmony_ci IEEE80211_CHAN_DISABLED) 338862306a36Sopenharmony_ci continue; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci arg.n_channels++; 339162306a36Sopenharmony_ci } 339262306a36Sopenharmony_ci } 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci len = sizeof(struct wmi_channel_arg) * arg.n_channels; 339562306a36Sopenharmony_ci arg.channels = kzalloc(len, GFP_KERNEL); 339662306a36Sopenharmony_ci if (!arg.channels) 339762306a36Sopenharmony_ci return -ENOMEM; 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci ch = arg.channels; 340062306a36Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 340162306a36Sopenharmony_ci if (!bands[band]) 340262306a36Sopenharmony_ci continue; 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci for (i = 0; i < bands[band]->n_channels; i++) { 340562306a36Sopenharmony_ci channel = &bands[band]->channels[i]; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (channel->flags & IEEE80211_CHAN_DISABLED) 340862306a36Sopenharmony_ci continue; 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci ch->allow_ht = true; 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci /* FIXME: when should we really allow VHT? */ 341362306a36Sopenharmony_ci ch->allow_vht = true; 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci ch->allow_ibss = 341662306a36Sopenharmony_ci !(channel->flags & IEEE80211_CHAN_NO_IR); 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci ch->ht40plus = 341962306a36Sopenharmony_ci !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci ch->chan_radar = 342262306a36Sopenharmony_ci !!(channel->flags & IEEE80211_CHAN_RADAR); 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci passive = channel->flags & IEEE80211_CHAN_NO_IR; 342562306a36Sopenharmony_ci ch->passive = passive; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci /* the firmware is ignoring the "radar" flag of the 342862306a36Sopenharmony_ci * channel and is scanning actively using Probe Requests 342962306a36Sopenharmony_ci * on "Radar detection"/DFS channels which are not 343062306a36Sopenharmony_ci * marked as "available" 343162306a36Sopenharmony_ci */ 343262306a36Sopenharmony_ci ch->passive |= ch->chan_radar; 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci ch->freq = channel->center_freq; 343562306a36Sopenharmony_ci ch->band_center_freq1 = channel->center_freq; 343662306a36Sopenharmony_ci ch->min_power = 0; 343762306a36Sopenharmony_ci ch->max_power = channel->max_power * 2; 343862306a36Sopenharmony_ci ch->max_reg_power = channel->max_reg_power * 2; 343962306a36Sopenharmony_ci ch->max_antenna_gain = channel->max_antenna_gain; 344062306a36Sopenharmony_ci ch->reg_class_id = 0; /* FIXME */ 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci /* FIXME: why use only legacy modes, why not any 344362306a36Sopenharmony_ci * HT/VHT modes? Would that even make any 344462306a36Sopenharmony_ci * difference? 344562306a36Sopenharmony_ci */ 344662306a36Sopenharmony_ci if (channel->band == NL80211_BAND_2GHZ) 344762306a36Sopenharmony_ci ch->mode = MODE_11G; 344862306a36Sopenharmony_ci else 344962306a36Sopenharmony_ci ch->mode = MODE_11A; 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_ci if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN)) 345262306a36Sopenharmony_ci continue; 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_WMI, 345562306a36Sopenharmony_ci "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", 345662306a36Sopenharmony_ci ch - arg.channels, arg.n_channels, 345762306a36Sopenharmony_ci ch->freq, ch->max_power, ch->max_reg_power, 345862306a36Sopenharmony_ci ch->max_antenna_gain, ch->mode); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci ch++; 346162306a36Sopenharmony_ci } 346262306a36Sopenharmony_ci } 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci ret = ath10k_wmi_scan_chan_list(ar, &arg); 346562306a36Sopenharmony_ci kfree(arg.channels); 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci return ret; 346862306a36Sopenharmony_ci} 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_cistatic enum wmi_dfs_region 347162306a36Sopenharmony_ciath10k_mac_get_dfs_region(enum nl80211_dfs_regions dfs_region) 347262306a36Sopenharmony_ci{ 347362306a36Sopenharmony_ci switch (dfs_region) { 347462306a36Sopenharmony_ci case NL80211_DFS_UNSET: 347562306a36Sopenharmony_ci return WMI_UNINIT_DFS_DOMAIN; 347662306a36Sopenharmony_ci case NL80211_DFS_FCC: 347762306a36Sopenharmony_ci return WMI_FCC_DFS_DOMAIN; 347862306a36Sopenharmony_ci case NL80211_DFS_ETSI: 347962306a36Sopenharmony_ci return WMI_ETSI_DFS_DOMAIN; 348062306a36Sopenharmony_ci case NL80211_DFS_JP: 348162306a36Sopenharmony_ci return WMI_MKK4_DFS_DOMAIN; 348262306a36Sopenharmony_ci } 348362306a36Sopenharmony_ci return WMI_UNINIT_DFS_DOMAIN; 348462306a36Sopenharmony_ci} 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_cistatic void ath10k_regd_update(struct ath10k *ar) 348762306a36Sopenharmony_ci{ 348862306a36Sopenharmony_ci struct reg_dmn_pair_mapping *regpair; 348962306a36Sopenharmony_ci int ret; 349062306a36Sopenharmony_ci enum wmi_dfs_region wmi_dfs_reg; 349162306a36Sopenharmony_ci enum nl80211_dfs_regions nl_dfs_reg; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 349462306a36Sopenharmony_ci 349562306a36Sopenharmony_ci ret = ath10k_update_channel_list(ar); 349662306a36Sopenharmony_ci if (ret) 349762306a36Sopenharmony_ci ath10k_warn(ar, "failed to update channel list: %d\n", ret); 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci regpair = ar->ath_common.regulatory.regpair; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { 350262306a36Sopenharmony_ci nl_dfs_reg = ar->dfs_detector->region; 350362306a36Sopenharmony_ci wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg); 350462306a36Sopenharmony_ci } else { 350562306a36Sopenharmony_ci wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN; 350662306a36Sopenharmony_ci } 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_ci /* Target allows setting up per-band regdomain but ath_common provides 350962306a36Sopenharmony_ci * a combined one only 351062306a36Sopenharmony_ci */ 351162306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_regdomain(ar, 351262306a36Sopenharmony_ci regpair->reg_domain, 351362306a36Sopenharmony_ci regpair->reg_domain, /* 2ghz */ 351462306a36Sopenharmony_ci regpair->reg_domain, /* 5ghz */ 351562306a36Sopenharmony_ci regpair->reg_2ghz_ctl, 351662306a36Sopenharmony_ci regpair->reg_5ghz_ctl, 351762306a36Sopenharmony_ci wmi_dfs_reg); 351862306a36Sopenharmony_ci if (ret) 351962306a36Sopenharmony_ci ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret); 352062306a36Sopenharmony_ci} 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_cistatic void ath10k_mac_update_channel_list(struct ath10k *ar, 352362306a36Sopenharmony_ci struct ieee80211_supported_band *band) 352462306a36Sopenharmony_ci{ 352562306a36Sopenharmony_ci int i; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci if (ar->low_5ghz_chan && ar->high_5ghz_chan) { 352862306a36Sopenharmony_ci for (i = 0; i < band->n_channels; i++) { 352962306a36Sopenharmony_ci if (band->channels[i].center_freq < ar->low_5ghz_chan || 353062306a36Sopenharmony_ci band->channels[i].center_freq > ar->high_5ghz_chan) 353162306a36Sopenharmony_ci band->channels[i].flags |= 353262306a36Sopenharmony_ci IEEE80211_CHAN_DISABLED; 353362306a36Sopenharmony_ci } 353462306a36Sopenharmony_ci } 353562306a36Sopenharmony_ci} 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_cistatic void ath10k_reg_notifier(struct wiphy *wiphy, 353862306a36Sopenharmony_ci struct regulatory_request *request) 353962306a36Sopenharmony_ci{ 354062306a36Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 354162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 354262306a36Sopenharmony_ci bool result; 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { 354762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", 354862306a36Sopenharmony_ci request->dfs_region); 354962306a36Sopenharmony_ci result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, 355062306a36Sopenharmony_ci request->dfs_region); 355162306a36Sopenharmony_ci if (!result) 355262306a36Sopenharmony_ci ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n", 355362306a36Sopenharmony_ci request->dfs_region); 355462306a36Sopenharmony_ci } 355562306a36Sopenharmony_ci 355662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 355762306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_ON) 355862306a36Sopenharmony_ci ath10k_regd_update(ar); 355962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) 356262306a36Sopenharmony_ci ath10k_mac_update_channel_list(ar, 356362306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_5GHZ]); 356462306a36Sopenharmony_ci} 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_cistatic void ath10k_stop_radar_confirmation(struct ath10k *ar) 356762306a36Sopenharmony_ci{ 356862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 356962306a36Sopenharmony_ci ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_STOPPED; 357062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci cancel_work_sync(&ar->radar_confirmation_work); 357362306a36Sopenharmony_ci} 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci/***************/ 357662306a36Sopenharmony_ci/* TX handlers */ 357762306a36Sopenharmony_ci/***************/ 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_cienum ath10k_mac_tx_path { 358062306a36Sopenharmony_ci ATH10K_MAC_TX_HTT, 358162306a36Sopenharmony_ci ATH10K_MAC_TX_HTT_MGMT, 358262306a36Sopenharmony_ci ATH10K_MAC_TX_WMI_MGMT, 358362306a36Sopenharmony_ci ATH10K_MAC_TX_UNKNOWN, 358462306a36Sopenharmony_ci}; 358562306a36Sopenharmony_ci 358662306a36Sopenharmony_civoid ath10k_mac_tx_lock(struct ath10k *ar, int reason) 358762306a36Sopenharmony_ci{ 358862306a36Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci WARN_ON(reason >= ATH10K_TX_PAUSE_MAX); 359162306a36Sopenharmony_ci ar->tx_paused |= BIT(reason); 359262306a36Sopenharmony_ci ieee80211_stop_queues(ar->hw); 359362306a36Sopenharmony_ci} 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_cistatic void ath10k_mac_tx_unlock_iter(void *data, u8 *mac, 359662306a36Sopenharmony_ci struct ieee80211_vif *vif) 359762306a36Sopenharmony_ci{ 359862306a36Sopenharmony_ci struct ath10k *ar = data; 359962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci if (arvif->tx_paused) 360262306a36Sopenharmony_ci return; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci ieee80211_wake_queue(ar->hw, arvif->vdev_id); 360562306a36Sopenharmony_ci} 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_civoid ath10k_mac_tx_unlock(struct ath10k *ar, int reason) 360862306a36Sopenharmony_ci{ 360962306a36Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci WARN_ON(reason >= ATH10K_TX_PAUSE_MAX); 361262306a36Sopenharmony_ci ar->tx_paused &= ~BIT(reason); 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_ci if (ar->tx_paused) 361562306a36Sopenharmony_ci return; 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 361862306a36Sopenharmony_ci ATH10K_ITER_RESUME_FLAGS, 361962306a36Sopenharmony_ci ath10k_mac_tx_unlock_iter, 362062306a36Sopenharmony_ci ar); 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci ieee80211_wake_queue(ar->hw, ar->hw->offchannel_tx_hw_queue); 362362306a36Sopenharmony_ci} 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_civoid ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason) 362662306a36Sopenharmony_ci{ 362762306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 363062306a36Sopenharmony_ci 363162306a36Sopenharmony_ci WARN_ON(reason >= BITS_PER_LONG); 363262306a36Sopenharmony_ci arvif->tx_paused |= BIT(reason); 363362306a36Sopenharmony_ci ieee80211_stop_queue(ar->hw, arvif->vdev_id); 363462306a36Sopenharmony_ci} 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_civoid ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason) 363762306a36Sopenharmony_ci{ 363862306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci WARN_ON(reason >= BITS_PER_LONG); 364362306a36Sopenharmony_ci arvif->tx_paused &= ~BIT(reason); 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci if (ar->tx_paused) 364662306a36Sopenharmony_ci return; 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci if (arvif->tx_paused) 364962306a36Sopenharmony_ci return; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci ieee80211_wake_queue(ar->hw, arvif->vdev_id); 365262306a36Sopenharmony_ci} 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_cistatic void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif, 365562306a36Sopenharmony_ci enum wmi_tlv_tx_pause_id pause_id, 365662306a36Sopenharmony_ci enum wmi_tlv_tx_pause_action action) 365762306a36Sopenharmony_ci{ 365862306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 365962306a36Sopenharmony_ci 366062306a36Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci switch (action) { 366362306a36Sopenharmony_ci case WMI_TLV_TX_PAUSE_ACTION_STOP: 366462306a36Sopenharmony_ci ath10k_mac_vif_tx_lock(arvif, pause_id); 366562306a36Sopenharmony_ci break; 366662306a36Sopenharmony_ci case WMI_TLV_TX_PAUSE_ACTION_WAKE: 366762306a36Sopenharmony_ci ath10k_mac_vif_tx_unlock(arvif, pause_id); 366862306a36Sopenharmony_ci break; 366962306a36Sopenharmony_ci default: 367062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, 367162306a36Sopenharmony_ci "received unknown tx pause action %d on vdev %i, ignoring\n", 367262306a36Sopenharmony_ci action, arvif->vdev_id); 367362306a36Sopenharmony_ci break; 367462306a36Sopenharmony_ci } 367562306a36Sopenharmony_ci} 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_cistruct ath10k_mac_tx_pause { 367862306a36Sopenharmony_ci u32 vdev_id; 367962306a36Sopenharmony_ci enum wmi_tlv_tx_pause_id pause_id; 368062306a36Sopenharmony_ci enum wmi_tlv_tx_pause_action action; 368162306a36Sopenharmony_ci}; 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_cistatic void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac, 368462306a36Sopenharmony_ci struct ieee80211_vif *vif) 368562306a36Sopenharmony_ci{ 368662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 368762306a36Sopenharmony_ci struct ath10k_mac_tx_pause *arg = data; 368862306a36Sopenharmony_ci 368962306a36Sopenharmony_ci if (arvif->vdev_id != arg->vdev_id) 369062306a36Sopenharmony_ci return; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action); 369362306a36Sopenharmony_ci} 369462306a36Sopenharmony_ci 369562306a36Sopenharmony_civoid ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, 369662306a36Sopenharmony_ci enum wmi_tlv_tx_pause_id pause_id, 369762306a36Sopenharmony_ci enum wmi_tlv_tx_pause_action action) 369862306a36Sopenharmony_ci{ 369962306a36Sopenharmony_ci struct ath10k_mac_tx_pause arg = { 370062306a36Sopenharmony_ci .vdev_id = vdev_id, 370162306a36Sopenharmony_ci .pause_id = pause_id, 370262306a36Sopenharmony_ci .action = action, 370362306a36Sopenharmony_ci }; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 370662306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 370762306a36Sopenharmony_ci ATH10K_ITER_RESUME_FLAGS, 370862306a36Sopenharmony_ci ath10k_mac_handle_tx_pause_iter, 370962306a36Sopenharmony_ci &arg); 371062306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 371162306a36Sopenharmony_ci} 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_cistatic enum ath10k_hw_txrx_mode 371462306a36Sopenharmony_ciath10k_mac_tx_h_get_txmode(struct ath10k *ar, 371562306a36Sopenharmony_ci struct ieee80211_vif *vif, 371662306a36Sopenharmony_ci struct ieee80211_sta *sta, 371762306a36Sopenharmony_ci struct sk_buff *skb) 371862306a36Sopenharmony_ci{ 371962306a36Sopenharmony_ci const struct ieee80211_hdr *hdr = (void *)skb->data; 372062306a36Sopenharmony_ci const struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); 372162306a36Sopenharmony_ci __le16 fc = hdr->frame_control; 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci if (IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) 372462306a36Sopenharmony_ci return ATH10K_HW_TXRX_ETHERNET; 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci if (!vif || vif->type == NL80211_IFTYPE_MONITOR) 372762306a36Sopenharmony_ci return ATH10K_HW_TXRX_RAW; 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci if (ieee80211_is_mgmt(fc)) 373062306a36Sopenharmony_ci return ATH10K_HW_TXRX_MGMT; 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci /* Workaround: 373362306a36Sopenharmony_ci * 373462306a36Sopenharmony_ci * NullFunc frames are mostly used to ping if a client or AP are still 373562306a36Sopenharmony_ci * reachable and responsive. This implies tx status reports must be 373662306a36Sopenharmony_ci * accurate - otherwise either mac80211 or userspace (e.g. hostapd) can 373762306a36Sopenharmony_ci * come to a conclusion that the other end disappeared and tear down 373862306a36Sopenharmony_ci * BSS connection or it can never disconnect from BSS/client (which is 373962306a36Sopenharmony_ci * the case). 374062306a36Sopenharmony_ci * 374162306a36Sopenharmony_ci * Firmware with HTT older than 3.0 delivers incorrect tx status for 374262306a36Sopenharmony_ci * NullFunc frames to driver. However there's a HTT Mgmt Tx command 374362306a36Sopenharmony_ci * which seems to deliver correct tx reports for NullFunc frames. The 374462306a36Sopenharmony_ci * downside of using it is it ignores client powersave state so it can 374562306a36Sopenharmony_ci * end up disconnecting sleeping clients in AP mode. It should fix STA 374662306a36Sopenharmony_ci * mode though because AP don't sleep. 374762306a36Sopenharmony_ci */ 374862306a36Sopenharmony_ci if (ar->htt.target_version_major < 3 && 374962306a36Sopenharmony_ci (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) && 375062306a36Sopenharmony_ci !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, 375162306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) 375262306a36Sopenharmony_ci return ATH10K_HW_TXRX_MGMT; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci /* Workaround: 375562306a36Sopenharmony_ci * 375662306a36Sopenharmony_ci * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for 375762306a36Sopenharmony_ci * NativeWifi txmode - it selects AP key instead of peer key. It seems 375862306a36Sopenharmony_ci * to work with Ethernet txmode so use it. 375962306a36Sopenharmony_ci * 376062306a36Sopenharmony_ci * FIXME: Check if raw mode works with TDLS. 376162306a36Sopenharmony_ci */ 376262306a36Sopenharmony_ci if (ieee80211_is_data_present(fc) && sta && sta->tdls) 376362306a36Sopenharmony_ci return ATH10K_HW_TXRX_ETHERNET; 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags) || 376662306a36Sopenharmony_ci skb_cb->flags & ATH10K_SKB_F_RAW_TX) 376762306a36Sopenharmony_ci return ATH10K_HW_TXRX_RAW; 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci return ATH10K_HW_TXRX_NATIVE_WIFI; 377062306a36Sopenharmony_ci} 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_cistatic bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif, 377362306a36Sopenharmony_ci struct sk_buff *skb) 377462306a36Sopenharmony_ci{ 377562306a36Sopenharmony_ci const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 377662306a36Sopenharmony_ci const struct ieee80211_hdr *hdr = (void *)skb->data; 377762306a36Sopenharmony_ci const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT | 377862306a36Sopenharmony_ci IEEE80211_TX_CTL_INJECTED; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci if (!ieee80211_has_protected(hdr->frame_control)) 378162306a36Sopenharmony_ci return false; 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci if ((info->flags & mask) == mask) 378462306a36Sopenharmony_ci return false; 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci if (vif) 378762306a36Sopenharmony_ci return !((struct ath10k_vif *)vif->drv_priv)->nohwcrypt; 378862306a36Sopenharmony_ci 378962306a36Sopenharmony_ci return true; 379062306a36Sopenharmony_ci} 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS 379362306a36Sopenharmony_ci * Control in the header. 379462306a36Sopenharmony_ci */ 379562306a36Sopenharmony_cistatic void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb) 379662306a36Sopenharmony_ci{ 379762306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 379862306a36Sopenharmony_ci struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); 379962306a36Sopenharmony_ci u8 *qos_ctl; 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci if (!ieee80211_is_data_qos(hdr->frame_control)) 380262306a36Sopenharmony_ci return; 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci qos_ctl = ieee80211_get_qos_ctl(hdr); 380562306a36Sopenharmony_ci memmove(skb->data + IEEE80211_QOS_CTL_LEN, 380662306a36Sopenharmony_ci skb->data, (void *)qos_ctl - (void *)skb->data); 380762306a36Sopenharmony_ci skb_pull(skb, IEEE80211_QOS_CTL_LEN); 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ci /* Some firmware revisions don't handle sending QoS NullFunc well. 381062306a36Sopenharmony_ci * These frames are mainly used for CQM purposes so it doesn't really 381162306a36Sopenharmony_ci * matter whether QoS NullFunc or NullFunc are sent. 381262306a36Sopenharmony_ci */ 381362306a36Sopenharmony_ci hdr = (void *)skb->data; 381462306a36Sopenharmony_ci if (ieee80211_is_qos_nullfunc(hdr->frame_control)) 381562306a36Sopenharmony_ci cb->flags &= ~ATH10K_SKB_F_QOS; 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 381862306a36Sopenharmony_ci} 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_cistatic void ath10k_tx_h_8023(struct sk_buff *skb) 382162306a36Sopenharmony_ci{ 382262306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 382362306a36Sopenharmony_ci struct rfc1042_hdr *rfc1042; 382462306a36Sopenharmony_ci struct ethhdr *eth; 382562306a36Sopenharmony_ci size_t hdrlen; 382662306a36Sopenharmony_ci u8 da[ETH_ALEN]; 382762306a36Sopenharmony_ci u8 sa[ETH_ALEN]; 382862306a36Sopenharmony_ci __be16 type; 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci hdr = (void *)skb->data; 383162306a36Sopenharmony_ci hdrlen = ieee80211_hdrlen(hdr->frame_control); 383262306a36Sopenharmony_ci rfc1042 = (void *)skb->data + hdrlen; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci ether_addr_copy(da, ieee80211_get_DA(hdr)); 383562306a36Sopenharmony_ci ether_addr_copy(sa, ieee80211_get_SA(hdr)); 383662306a36Sopenharmony_ci type = rfc1042->snap_type; 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci skb_pull(skb, hdrlen + sizeof(*rfc1042)); 383962306a36Sopenharmony_ci skb_push(skb, sizeof(*eth)); 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_ci eth = (void *)skb->data; 384262306a36Sopenharmony_ci ether_addr_copy(eth->h_dest, da); 384362306a36Sopenharmony_ci ether_addr_copy(eth->h_source, sa); 384462306a36Sopenharmony_ci eth->h_proto = type; 384562306a36Sopenharmony_ci} 384662306a36Sopenharmony_ci 384762306a36Sopenharmony_cistatic void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, 384862306a36Sopenharmony_ci struct ieee80211_vif *vif, 384962306a36Sopenharmony_ci struct sk_buff *skb) 385062306a36Sopenharmony_ci{ 385162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 385262306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci /* This is case only for P2P_GO */ 385562306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP || !vif->p2p) 385662306a36Sopenharmony_ci return; 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { 385962306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 386062306a36Sopenharmony_ci if (arvif->u.ap.noa_data) 386162306a36Sopenharmony_ci if (!pskb_expand_head(skb, 0, arvif->u.ap.noa_len, 386262306a36Sopenharmony_ci GFP_ATOMIC)) 386362306a36Sopenharmony_ci skb_put_data(skb, arvif->u.ap.noa_data, 386462306a36Sopenharmony_ci arvif->u.ap.noa_len); 386562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 386662306a36Sopenharmony_ci } 386762306a36Sopenharmony_ci} 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_cistatic void ath10k_mac_tx_h_fill_cb(struct ath10k *ar, 387062306a36Sopenharmony_ci struct ieee80211_vif *vif, 387162306a36Sopenharmony_ci struct ieee80211_txq *txq, 387262306a36Sopenharmony_ci struct ieee80211_sta *sta, 387362306a36Sopenharmony_ci struct sk_buff *skb, u16 airtime) 387462306a36Sopenharmony_ci{ 387562306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 387662306a36Sopenharmony_ci struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); 387762306a36Sopenharmony_ci const struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 387862306a36Sopenharmony_ci bool is_data = ieee80211_is_data(hdr->frame_control) || 387962306a36Sopenharmony_ci ieee80211_is_data_qos(hdr->frame_control); 388062306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 388162306a36Sopenharmony_ci struct ath10k_sta *arsta; 388262306a36Sopenharmony_ci u8 tid, *qos_ctl; 388362306a36Sopenharmony_ci bool noack = false; 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci cb->flags = 0; 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { 388862306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_QOS; /* Assume data frames are QoS */ 388962306a36Sopenharmony_ci goto finish_cb_fill; 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci 389262306a36Sopenharmony_ci if (!ath10k_tx_h_use_hwcrypto(vif, skb)) 389362306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_NO_HWCRYPT; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci if (ieee80211_is_mgmt(hdr->frame_control)) 389662306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_MGMT; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci if (ieee80211_is_data_qos(hdr->frame_control)) { 389962306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_QOS; 390062306a36Sopenharmony_ci qos_ctl = ieee80211_get_qos_ctl(hdr); 390162306a36Sopenharmony_ci tid = (*qos_ctl) & IEEE80211_QOS_CTL_TID_MASK; 390262306a36Sopenharmony_ci 390362306a36Sopenharmony_ci if (arvif->noack[tid] == WMI_PEER_TID_CONFIG_NOACK) 390462306a36Sopenharmony_ci noack = true; 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci if (sta) { 390762306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci if (arsta->noack[tid] == WMI_PEER_TID_CONFIG_NOACK) 391062306a36Sopenharmony_ci noack = true; 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci if (arsta->noack[tid] == WMI_PEER_TID_CONFIG_ACK) 391362306a36Sopenharmony_ci noack = false; 391462306a36Sopenharmony_ci } 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci if (noack) 391762306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_NOACK_TID; 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci /* Data frames encrypted in software will be posted to firmware 392162306a36Sopenharmony_ci * with tx encap mode set to RAW. Ex: Multicast traffic generated 392262306a36Sopenharmony_ci * for a specific VLAN group will always be encrypted in software. 392362306a36Sopenharmony_ci */ 392462306a36Sopenharmony_ci if (is_data && ieee80211_has_protected(hdr->frame_control) && 392562306a36Sopenharmony_ci !info->control.hw_key) { 392662306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_NO_HWCRYPT; 392762306a36Sopenharmony_ci cb->flags |= ATH10K_SKB_F_RAW_TX; 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_cifinish_cb_fill: 393162306a36Sopenharmony_ci cb->vif = vif; 393262306a36Sopenharmony_ci cb->txq = txq; 393362306a36Sopenharmony_ci cb->airtime_est = airtime; 393462306a36Sopenharmony_ci if (sta) { 393562306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 393662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 393762306a36Sopenharmony_ci cb->ucast_cipher = arsta->ucast_cipher; 393862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 393962306a36Sopenharmony_ci } 394062306a36Sopenharmony_ci} 394162306a36Sopenharmony_ci 394262306a36Sopenharmony_cibool ath10k_mac_tx_frm_has_freq(struct ath10k *ar) 394362306a36Sopenharmony_ci{ 394462306a36Sopenharmony_ci /* FIXME: Not really sure since when the behaviour changed. At some 394562306a36Sopenharmony_ci * point new firmware stopped requiring creation of peer entries for 394662306a36Sopenharmony_ci * offchannel tx (and actually creating them causes issues with wmi-htc 394762306a36Sopenharmony_ci * tx credit replenishment and reliability). Assuming it's at least 3.4 394862306a36Sopenharmony_ci * because that's when the `freq` was introduced to TX_FRM HTT command. 394962306a36Sopenharmony_ci */ 395062306a36Sopenharmony_ci return (ar->htt.target_version_major >= 3 && 395162306a36Sopenharmony_ci ar->htt.target_version_minor >= 4 && 395262306a36Sopenharmony_ci ar->running_fw->fw_file.htt_op_version == ATH10K_FW_HTT_OP_VERSION_TLV); 395362306a36Sopenharmony_ci} 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_cistatic int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb) 395662306a36Sopenharmony_ci{ 395762306a36Sopenharmony_ci struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue; 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci if (skb_queue_len_lockless(q) >= ATH10K_MAX_NUM_MGMT_PENDING) { 396062306a36Sopenharmony_ci ath10k_warn(ar, "wmi mgmt tx queue is full\n"); 396162306a36Sopenharmony_ci return -ENOSPC; 396262306a36Sopenharmony_ci } 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci skb_queue_tail(q, skb); 396562306a36Sopenharmony_ci ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); 396662306a36Sopenharmony_ci 396762306a36Sopenharmony_ci return 0; 396862306a36Sopenharmony_ci} 396962306a36Sopenharmony_ci 397062306a36Sopenharmony_cistatic enum ath10k_mac_tx_path 397162306a36Sopenharmony_ciath10k_mac_tx_h_get_txpath(struct ath10k *ar, 397262306a36Sopenharmony_ci struct sk_buff *skb, 397362306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode) 397462306a36Sopenharmony_ci{ 397562306a36Sopenharmony_ci switch (txmode) { 397662306a36Sopenharmony_ci case ATH10K_HW_TXRX_RAW: 397762306a36Sopenharmony_ci case ATH10K_HW_TXRX_NATIVE_WIFI: 397862306a36Sopenharmony_ci case ATH10K_HW_TXRX_ETHERNET: 397962306a36Sopenharmony_ci return ATH10K_MAC_TX_HTT; 398062306a36Sopenharmony_ci case ATH10K_HW_TXRX_MGMT: 398162306a36Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, 398262306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features) || 398362306a36Sopenharmony_ci test_bit(WMI_SERVICE_MGMT_TX_WMI, 398462306a36Sopenharmony_ci ar->wmi.svc_map)) 398562306a36Sopenharmony_ci return ATH10K_MAC_TX_WMI_MGMT; 398662306a36Sopenharmony_ci else if (ar->htt.target_version_major >= 3) 398762306a36Sopenharmony_ci return ATH10K_MAC_TX_HTT; 398862306a36Sopenharmony_ci else 398962306a36Sopenharmony_ci return ATH10K_MAC_TX_HTT_MGMT; 399062306a36Sopenharmony_ci } 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci return ATH10K_MAC_TX_UNKNOWN; 399362306a36Sopenharmony_ci} 399462306a36Sopenharmony_ci 399562306a36Sopenharmony_cistatic int ath10k_mac_tx_submit(struct ath10k *ar, 399662306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode, 399762306a36Sopenharmony_ci enum ath10k_mac_tx_path txpath, 399862306a36Sopenharmony_ci struct sk_buff *skb) 399962306a36Sopenharmony_ci{ 400062306a36Sopenharmony_ci struct ath10k_htt *htt = &ar->htt; 400162306a36Sopenharmony_ci int ret = -EINVAL; 400262306a36Sopenharmony_ci 400362306a36Sopenharmony_ci switch (txpath) { 400462306a36Sopenharmony_ci case ATH10K_MAC_TX_HTT: 400562306a36Sopenharmony_ci ret = ath10k_htt_tx(htt, txmode, skb); 400662306a36Sopenharmony_ci break; 400762306a36Sopenharmony_ci case ATH10K_MAC_TX_HTT_MGMT: 400862306a36Sopenharmony_ci ret = ath10k_htt_mgmt_tx(htt, skb); 400962306a36Sopenharmony_ci break; 401062306a36Sopenharmony_ci case ATH10K_MAC_TX_WMI_MGMT: 401162306a36Sopenharmony_ci ret = ath10k_mac_tx_wmi_mgmt(ar, skb); 401262306a36Sopenharmony_ci break; 401362306a36Sopenharmony_ci case ATH10K_MAC_TX_UNKNOWN: 401462306a36Sopenharmony_ci WARN_ON_ONCE(1); 401562306a36Sopenharmony_ci ret = -EINVAL; 401662306a36Sopenharmony_ci break; 401762306a36Sopenharmony_ci } 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_ci if (ret) { 402062306a36Sopenharmony_ci ath10k_warn(ar, "failed to transmit packet, dropping: %d\n", 402162306a36Sopenharmony_ci ret); 402262306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 402362306a36Sopenharmony_ci } 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci return ret; 402662306a36Sopenharmony_ci} 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci/* This function consumes the sk_buff regardless of return value as far as 402962306a36Sopenharmony_ci * caller is concerned so no freeing is necessary afterwards. 403062306a36Sopenharmony_ci */ 403162306a36Sopenharmony_cistatic int ath10k_mac_tx(struct ath10k *ar, 403262306a36Sopenharmony_ci struct ieee80211_vif *vif, 403362306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode, 403462306a36Sopenharmony_ci enum ath10k_mac_tx_path txpath, 403562306a36Sopenharmony_ci struct sk_buff *skb, bool noque_offchan) 403662306a36Sopenharmony_ci{ 403762306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 403862306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 403962306a36Sopenharmony_ci const struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb); 404062306a36Sopenharmony_ci int ret; 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci /* We should disable CCK RATE due to P2P */ 404362306a36Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE) 404462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n"); 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci switch (txmode) { 404762306a36Sopenharmony_ci case ATH10K_HW_TXRX_MGMT: 404862306a36Sopenharmony_ci case ATH10K_HW_TXRX_NATIVE_WIFI: 404962306a36Sopenharmony_ci ath10k_tx_h_nwifi(hw, skb); 405062306a36Sopenharmony_ci ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb); 405162306a36Sopenharmony_ci ath10k_tx_h_seq_no(vif, skb); 405262306a36Sopenharmony_ci break; 405362306a36Sopenharmony_ci case ATH10K_HW_TXRX_ETHERNET: 405462306a36Sopenharmony_ci /* Convert 802.11->802.3 header only if the frame was earlier 405562306a36Sopenharmony_ci * encapsulated to 802.11 by mac80211. Otherwise pass it as is. 405662306a36Sopenharmony_ci */ 405762306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) 405862306a36Sopenharmony_ci ath10k_tx_h_8023(skb); 405962306a36Sopenharmony_ci break; 406062306a36Sopenharmony_ci case ATH10K_HW_TXRX_RAW: 406162306a36Sopenharmony_ci if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags) && 406262306a36Sopenharmony_ci !(skb_cb->flags & ATH10K_SKB_F_RAW_TX)) { 406362306a36Sopenharmony_ci WARN_ON_ONCE(1); 406462306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 406562306a36Sopenharmony_ci return -ENOTSUPP; 406662306a36Sopenharmony_ci } 406762306a36Sopenharmony_ci } 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_ci if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 407062306a36Sopenharmony_ci if (!ath10k_mac_tx_frm_has_freq(ar)) { 407162306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n", 407262306a36Sopenharmony_ci skb, skb->len); 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ci skb_queue_tail(&ar->offchan_tx_queue, skb); 407562306a36Sopenharmony_ci ieee80211_queue_work(hw, &ar->offchan_tx_work); 407662306a36Sopenharmony_ci return 0; 407762306a36Sopenharmony_ci } 407862306a36Sopenharmony_ci } 407962306a36Sopenharmony_ci 408062306a36Sopenharmony_ci ret = ath10k_mac_tx_submit(ar, txmode, txpath, skb); 408162306a36Sopenharmony_ci if (ret) { 408262306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit frame: %d\n", ret); 408362306a36Sopenharmony_ci return ret; 408462306a36Sopenharmony_ci } 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_ci return 0; 408762306a36Sopenharmony_ci} 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_civoid ath10k_offchan_tx_purge(struct ath10k *ar) 409062306a36Sopenharmony_ci{ 409162306a36Sopenharmony_ci struct sk_buff *skb; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci for (;;) { 409462306a36Sopenharmony_ci skb = skb_dequeue(&ar->offchan_tx_queue); 409562306a36Sopenharmony_ci if (!skb) 409662306a36Sopenharmony_ci break; 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 409962306a36Sopenharmony_ci } 410062306a36Sopenharmony_ci} 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_civoid ath10k_offchan_tx_work(struct work_struct *work) 410362306a36Sopenharmony_ci{ 410462306a36Sopenharmony_ci struct ath10k *ar = container_of(work, struct ath10k, offchan_tx_work); 410562306a36Sopenharmony_ci struct ath10k_peer *peer; 410662306a36Sopenharmony_ci struct ath10k_vif *arvif; 410762306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode; 410862306a36Sopenharmony_ci enum ath10k_mac_tx_path txpath; 410962306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 411062306a36Sopenharmony_ci struct ieee80211_vif *vif; 411162306a36Sopenharmony_ci struct ieee80211_sta *sta; 411262306a36Sopenharmony_ci struct sk_buff *skb; 411362306a36Sopenharmony_ci const u8 *peer_addr; 411462306a36Sopenharmony_ci int vdev_id; 411562306a36Sopenharmony_ci int ret; 411662306a36Sopenharmony_ci unsigned long time_left; 411762306a36Sopenharmony_ci bool tmp_peer_created = false; 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci /* FW requirement: We must create a peer before FW will send out 412062306a36Sopenharmony_ci * an offchannel frame. Otherwise the frame will be stuck and 412162306a36Sopenharmony_ci * never transmitted. We delete the peer upon tx completion. 412262306a36Sopenharmony_ci * It is unlikely that a peer for offchannel tx will already be 412362306a36Sopenharmony_ci * present. However it may be in some rare cases so account for that. 412462306a36Sopenharmony_ci * Otherwise we might remove a legitimate peer and break stuff. 412562306a36Sopenharmony_ci */ 412662306a36Sopenharmony_ci 412762306a36Sopenharmony_ci for (;;) { 412862306a36Sopenharmony_ci skb = skb_dequeue(&ar->offchan_tx_queue); 412962306a36Sopenharmony_ci if (!skb) 413062306a36Sopenharmony_ci break; 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n", 413562306a36Sopenharmony_ci skb, skb->len); 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 413862306a36Sopenharmony_ci peer_addr = ieee80211_get_DA(hdr); 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 414162306a36Sopenharmony_ci vdev_id = ar->scan.vdev_id; 414262306a36Sopenharmony_ci peer = ath10k_peer_find(ar, vdev_id, peer_addr); 414362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci if (peer) { 414662306a36Sopenharmony_ci ath10k_warn(ar, "peer %pM on vdev %d already present\n", 414762306a36Sopenharmony_ci peer_addr, vdev_id); 414862306a36Sopenharmony_ci } else { 414962306a36Sopenharmony_ci ret = ath10k_peer_create(ar, NULL, NULL, vdev_id, 415062306a36Sopenharmony_ci peer_addr, 415162306a36Sopenharmony_ci WMI_PEER_TYPE_DEFAULT); 415262306a36Sopenharmony_ci if (ret) 415362306a36Sopenharmony_ci ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n", 415462306a36Sopenharmony_ci peer_addr, vdev_id, ret); 415562306a36Sopenharmony_ci tmp_peer_created = (ret == 0); 415662306a36Sopenharmony_ci } 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 415962306a36Sopenharmony_ci reinit_completion(&ar->offchan_tx_completed); 416062306a36Sopenharmony_ci ar->offchan_tx_skb = skb; 416162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci /* It's safe to access vif and sta - conf_mutex guarantees that 416462306a36Sopenharmony_ci * sta_state() and remove_interface() are locked exclusively 416562306a36Sopenharmony_ci * out wrt to this offchannel worker. 416662306a36Sopenharmony_ci */ 416762306a36Sopenharmony_ci arvif = ath10k_get_arvif(ar, vdev_id); 416862306a36Sopenharmony_ci if (arvif) { 416962306a36Sopenharmony_ci vif = arvif->vif; 417062306a36Sopenharmony_ci sta = ieee80211_find_sta(vif, peer_addr); 417162306a36Sopenharmony_ci } else { 417262306a36Sopenharmony_ci vif = NULL; 417362306a36Sopenharmony_ci sta = NULL; 417462306a36Sopenharmony_ci } 417562306a36Sopenharmony_ci 417662306a36Sopenharmony_ci txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); 417762306a36Sopenharmony_ci txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); 417862306a36Sopenharmony_ci 417962306a36Sopenharmony_ci ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true); 418062306a36Sopenharmony_ci if (ret) { 418162306a36Sopenharmony_ci ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", 418262306a36Sopenharmony_ci ret); 418362306a36Sopenharmony_ci /* not serious */ 418462306a36Sopenharmony_ci } 418562306a36Sopenharmony_ci 418662306a36Sopenharmony_ci time_left = 418762306a36Sopenharmony_ci wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); 418862306a36Sopenharmony_ci if (time_left == 0) 418962306a36Sopenharmony_ci ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n", 419062306a36Sopenharmony_ci skb, skb->len); 419162306a36Sopenharmony_ci 419262306a36Sopenharmony_ci if (!peer && tmp_peer_created) { 419362306a36Sopenharmony_ci ret = ath10k_peer_delete(ar, vdev_id, peer_addr); 419462306a36Sopenharmony_ci if (ret) 419562306a36Sopenharmony_ci ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n", 419662306a36Sopenharmony_ci peer_addr, vdev_id, ret); 419762306a36Sopenharmony_ci } 419862306a36Sopenharmony_ci 419962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 420062306a36Sopenharmony_ci } 420162306a36Sopenharmony_ci} 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_civoid ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar) 420462306a36Sopenharmony_ci{ 420562306a36Sopenharmony_ci struct sk_buff *skb; 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ci for (;;) { 420862306a36Sopenharmony_ci skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); 420962306a36Sopenharmony_ci if (!skb) 421062306a36Sopenharmony_ci break; 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 421362306a36Sopenharmony_ci } 421462306a36Sopenharmony_ci} 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_civoid ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) 421762306a36Sopenharmony_ci{ 421862306a36Sopenharmony_ci struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work); 421962306a36Sopenharmony_ci struct sk_buff *skb; 422062306a36Sopenharmony_ci dma_addr_t paddr; 422162306a36Sopenharmony_ci int ret; 422262306a36Sopenharmony_ci 422362306a36Sopenharmony_ci for (;;) { 422462306a36Sopenharmony_ci skb = skb_dequeue(&ar->wmi_mgmt_tx_queue); 422562306a36Sopenharmony_ci if (!skb) 422662306a36Sopenharmony_ci break; 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF, 422962306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 423062306a36Sopenharmony_ci paddr = dma_map_single(ar->dev, skb->data, 423162306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 423262306a36Sopenharmony_ci if (dma_mapping_error(ar->dev, paddr)) { 423362306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 423462306a36Sopenharmony_ci continue; 423562306a36Sopenharmony_ci } 423662306a36Sopenharmony_ci ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr); 423762306a36Sopenharmony_ci if (ret) { 423862306a36Sopenharmony_ci ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n", 423962306a36Sopenharmony_ci ret); 424062306a36Sopenharmony_ci /* remove this msdu from idr tracking */ 424162306a36Sopenharmony_ci ath10k_wmi_cleanup_mgmt_tx_send(ar, skb); 424262306a36Sopenharmony_ci 424362306a36Sopenharmony_ci dma_unmap_single(ar->dev, paddr, skb->len, 424462306a36Sopenharmony_ci DMA_TO_DEVICE); 424562306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 424662306a36Sopenharmony_ci } 424762306a36Sopenharmony_ci } else { 424862306a36Sopenharmony_ci ret = ath10k_wmi_mgmt_tx(ar, skb); 424962306a36Sopenharmony_ci if (ret) { 425062306a36Sopenharmony_ci ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", 425162306a36Sopenharmony_ci ret); 425262306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 425362306a36Sopenharmony_ci } 425462306a36Sopenharmony_ci } 425562306a36Sopenharmony_ci } 425662306a36Sopenharmony_ci} 425762306a36Sopenharmony_ci 425862306a36Sopenharmony_cistatic void ath10k_mac_txq_init(struct ieee80211_txq *txq) 425962306a36Sopenharmony_ci{ 426062306a36Sopenharmony_ci struct ath10k_txq *artxq; 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci if (!txq) 426362306a36Sopenharmony_ci return; 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_ci artxq = (void *)txq->drv_priv; 426662306a36Sopenharmony_ci INIT_LIST_HEAD(&artxq->list); 426762306a36Sopenharmony_ci} 426862306a36Sopenharmony_ci 426962306a36Sopenharmony_cistatic void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq) 427062306a36Sopenharmony_ci{ 427162306a36Sopenharmony_ci struct ath10k_skb_cb *cb; 427262306a36Sopenharmony_ci struct sk_buff *msdu; 427362306a36Sopenharmony_ci int msdu_id; 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_ci if (!txq) 427662306a36Sopenharmony_ci return; 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 427962306a36Sopenharmony_ci idr_for_each_entry(&ar->htt.pending_tx, msdu, msdu_id) { 428062306a36Sopenharmony_ci cb = ATH10K_SKB_CB(msdu); 428162306a36Sopenharmony_ci if (cb->txq == txq) 428262306a36Sopenharmony_ci cb->txq = NULL; 428362306a36Sopenharmony_ci } 428462306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 428562306a36Sopenharmony_ci} 428662306a36Sopenharmony_ci 428762306a36Sopenharmony_cistruct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar, 428862306a36Sopenharmony_ci u16 peer_id, 428962306a36Sopenharmony_ci u8 tid) 429062306a36Sopenharmony_ci{ 429162306a36Sopenharmony_ci struct ath10k_peer *peer; 429262306a36Sopenharmony_ci 429362306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci peer = ar->peer_map[peer_id]; 429662306a36Sopenharmony_ci if (!peer) 429762306a36Sopenharmony_ci return NULL; 429862306a36Sopenharmony_ci 429962306a36Sopenharmony_ci if (peer->removed) 430062306a36Sopenharmony_ci return NULL; 430162306a36Sopenharmony_ci 430262306a36Sopenharmony_ci if (peer->sta) 430362306a36Sopenharmony_ci return peer->sta->txq[tid]; 430462306a36Sopenharmony_ci else if (peer->vif) 430562306a36Sopenharmony_ci return peer->vif->txq; 430662306a36Sopenharmony_ci else 430762306a36Sopenharmony_ci return NULL; 430862306a36Sopenharmony_ci} 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_cistatic bool ath10k_mac_tx_can_push(struct ieee80211_hw *hw, 431162306a36Sopenharmony_ci struct ieee80211_txq *txq) 431262306a36Sopenharmony_ci{ 431362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 431462306a36Sopenharmony_ci struct ath10k_txq *artxq = (void *)txq->drv_priv; 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci /* No need to get locks */ 431762306a36Sopenharmony_ci if (ar->htt.tx_q_state.mode == HTT_TX_MODE_SWITCH_PUSH) 431862306a36Sopenharmony_ci return true; 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci if (ar->htt.num_pending_tx < ar->htt.tx_q_state.num_push_allowed) 432162306a36Sopenharmony_ci return true; 432262306a36Sopenharmony_ci 432362306a36Sopenharmony_ci if (artxq->num_fw_queued < artxq->num_push_allowed) 432462306a36Sopenharmony_ci return true; 432562306a36Sopenharmony_ci 432662306a36Sopenharmony_ci return false; 432762306a36Sopenharmony_ci} 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci/* Return estimated airtime in microsecond, which is calculated using last 433062306a36Sopenharmony_ci * reported TX rate. This is just a rough estimation because host driver has no 433162306a36Sopenharmony_ci * knowledge of the actual transmit rate, retries or aggregation. If actual 433262306a36Sopenharmony_ci * airtime can be reported by firmware, then delta between estimated and actual 433362306a36Sopenharmony_ci * airtime can be adjusted from deficit. 433462306a36Sopenharmony_ci */ 433562306a36Sopenharmony_ci#define IEEE80211_ATF_OVERHEAD 100 /* IFS + some slot time */ 433662306a36Sopenharmony_ci#define IEEE80211_ATF_OVERHEAD_IFS 16 /* IFS only */ 433762306a36Sopenharmony_cistatic u16 ath10k_mac_update_airtime(struct ath10k *ar, 433862306a36Sopenharmony_ci struct ieee80211_txq *txq, 433962306a36Sopenharmony_ci struct sk_buff *skb) 434062306a36Sopenharmony_ci{ 434162306a36Sopenharmony_ci struct ath10k_sta *arsta; 434262306a36Sopenharmony_ci u32 pktlen; 434362306a36Sopenharmony_ci u16 airtime = 0; 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci if (!txq || !txq->sta) 434662306a36Sopenharmony_ci return airtime; 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map)) 434962306a36Sopenharmony_ci return airtime; 435062306a36Sopenharmony_ci 435162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 435262306a36Sopenharmony_ci arsta = (struct ath10k_sta *)txq->sta->drv_priv; 435362306a36Sopenharmony_ci 435462306a36Sopenharmony_ci pktlen = skb->len + 38; /* Assume MAC header 30, SNAP 8 for most case */ 435562306a36Sopenharmony_ci if (arsta->last_tx_bitrate) { 435662306a36Sopenharmony_ci /* airtime in us, last_tx_bitrate in 100kbps */ 435762306a36Sopenharmony_ci airtime = (pktlen * 8 * (1000 / 100)) 435862306a36Sopenharmony_ci / arsta->last_tx_bitrate; 435962306a36Sopenharmony_ci /* overhead for media access time and IFS */ 436062306a36Sopenharmony_ci airtime += IEEE80211_ATF_OVERHEAD_IFS; 436162306a36Sopenharmony_ci } else { 436262306a36Sopenharmony_ci /* This is mostly for throttle excessive BC/MC frames, and the 436362306a36Sopenharmony_ci * airtime/rate doesn't need be exact. Airtime of BC/MC frames 436462306a36Sopenharmony_ci * in 2G get some discount, which helps prevent very low rate 436562306a36Sopenharmony_ci * frames from being blocked for too long. 436662306a36Sopenharmony_ci */ 436762306a36Sopenharmony_ci airtime = (pktlen * 8 * (1000 / 100)) / 60; /* 6M */ 436862306a36Sopenharmony_ci airtime += IEEE80211_ATF_OVERHEAD; 436962306a36Sopenharmony_ci } 437062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 437162306a36Sopenharmony_ci 437262306a36Sopenharmony_ci return airtime; 437362306a36Sopenharmony_ci} 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ciint ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, 437662306a36Sopenharmony_ci struct ieee80211_txq *txq) 437762306a36Sopenharmony_ci{ 437862306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 437962306a36Sopenharmony_ci struct ath10k_htt *htt = &ar->htt; 438062306a36Sopenharmony_ci struct ath10k_txq *artxq = (void *)txq->drv_priv; 438162306a36Sopenharmony_ci struct ieee80211_vif *vif = txq->vif; 438262306a36Sopenharmony_ci struct ieee80211_sta *sta = txq->sta; 438362306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode; 438462306a36Sopenharmony_ci enum ath10k_mac_tx_path txpath; 438562306a36Sopenharmony_ci struct sk_buff *skb; 438662306a36Sopenharmony_ci struct ieee80211_hdr *hdr; 438762306a36Sopenharmony_ci size_t skb_len; 438862306a36Sopenharmony_ci bool is_mgmt, is_presp; 438962306a36Sopenharmony_ci int ret; 439062306a36Sopenharmony_ci u16 airtime; 439162306a36Sopenharmony_ci 439262306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 439362306a36Sopenharmony_ci ret = ath10k_htt_tx_inc_pending(htt); 439462306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci if (ret) 439762306a36Sopenharmony_ci return ret; 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci skb = ieee80211_tx_dequeue_ni(hw, txq); 440062306a36Sopenharmony_ci if (!skb) { 440162306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 440262306a36Sopenharmony_ci ath10k_htt_tx_dec_pending(htt); 440362306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 440462306a36Sopenharmony_ci 440562306a36Sopenharmony_ci return -ENOENT; 440662306a36Sopenharmony_ci } 440762306a36Sopenharmony_ci 440862306a36Sopenharmony_ci airtime = ath10k_mac_update_airtime(ar, txq, skb); 440962306a36Sopenharmony_ci ath10k_mac_tx_h_fill_cb(ar, vif, txq, sta, skb, airtime); 441062306a36Sopenharmony_ci 441162306a36Sopenharmony_ci skb_len = skb->len; 441262306a36Sopenharmony_ci txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); 441362306a36Sopenharmony_ci txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); 441462306a36Sopenharmony_ci is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT); 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci if (is_mgmt) { 441762306a36Sopenharmony_ci hdr = (struct ieee80211_hdr *)skb->data; 441862306a36Sopenharmony_ci is_presp = ieee80211_is_probe_resp(hdr->frame_control); 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 442162306a36Sopenharmony_ci ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp); 442262306a36Sopenharmony_ci 442362306a36Sopenharmony_ci if (ret) { 442462306a36Sopenharmony_ci ath10k_htt_tx_dec_pending(htt); 442562306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 442662306a36Sopenharmony_ci return ret; 442762306a36Sopenharmony_ci } 442862306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 442962306a36Sopenharmony_ci } 443062306a36Sopenharmony_ci 443162306a36Sopenharmony_ci ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); 443262306a36Sopenharmony_ci if (unlikely(ret)) { 443362306a36Sopenharmony_ci ath10k_warn(ar, "failed to push frame: %d\n", ret); 443462306a36Sopenharmony_ci 443562306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 443662306a36Sopenharmony_ci ath10k_htt_tx_dec_pending(htt); 443762306a36Sopenharmony_ci if (is_mgmt) 443862306a36Sopenharmony_ci ath10k_htt_tx_mgmt_dec_pending(htt); 443962306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 444062306a36Sopenharmony_ci 444162306a36Sopenharmony_ci return ret; 444262306a36Sopenharmony_ci } 444362306a36Sopenharmony_ci 444462306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 444562306a36Sopenharmony_ci artxq->num_fw_queued++; 444662306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci return skb_len; 444962306a36Sopenharmony_ci} 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_cistatic int ath10k_mac_schedule_txq(struct ieee80211_hw *hw, u32 ac) 445262306a36Sopenharmony_ci{ 445362306a36Sopenharmony_ci struct ieee80211_txq *txq; 445462306a36Sopenharmony_ci int ret = 0; 445562306a36Sopenharmony_ci 445662306a36Sopenharmony_ci ieee80211_txq_schedule_start(hw, ac); 445762306a36Sopenharmony_ci while ((txq = ieee80211_next_txq(hw, ac))) { 445862306a36Sopenharmony_ci while (ath10k_mac_tx_can_push(hw, txq)) { 445962306a36Sopenharmony_ci ret = ath10k_mac_tx_push_txq(hw, txq); 446062306a36Sopenharmony_ci if (ret < 0) 446162306a36Sopenharmony_ci break; 446262306a36Sopenharmony_ci } 446362306a36Sopenharmony_ci ieee80211_return_txq(hw, txq, false); 446462306a36Sopenharmony_ci ath10k_htt_tx_txq_update(hw, txq); 446562306a36Sopenharmony_ci if (ret == -EBUSY) 446662306a36Sopenharmony_ci break; 446762306a36Sopenharmony_ci } 446862306a36Sopenharmony_ci ieee80211_txq_schedule_end(hw, ac); 446962306a36Sopenharmony_ci 447062306a36Sopenharmony_ci return ret; 447162306a36Sopenharmony_ci} 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_civoid ath10k_mac_tx_push_pending(struct ath10k *ar) 447462306a36Sopenharmony_ci{ 447562306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 447662306a36Sopenharmony_ci u32 ac; 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH) 447962306a36Sopenharmony_ci return; 448062306a36Sopenharmony_ci 448162306a36Sopenharmony_ci if (ar->htt.num_pending_tx >= (ar->htt.max_num_pending_tx / 2)) 448262306a36Sopenharmony_ci return; 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci rcu_read_lock(); 448562306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { 448662306a36Sopenharmony_ci if (ath10k_mac_schedule_txq(hw, ac) == -EBUSY) 448762306a36Sopenharmony_ci break; 448862306a36Sopenharmony_ci } 448962306a36Sopenharmony_ci rcu_read_unlock(); 449062306a36Sopenharmony_ci} 449162306a36Sopenharmony_ciEXPORT_SYMBOL(ath10k_mac_tx_push_pending); 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci/************/ 449462306a36Sopenharmony_ci/* Scanning */ 449562306a36Sopenharmony_ci/************/ 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_civoid __ath10k_scan_finish(struct ath10k *ar) 449862306a36Sopenharmony_ci{ 449962306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 450062306a36Sopenharmony_ci 450162306a36Sopenharmony_ci switch (ar->scan.state) { 450262306a36Sopenharmony_ci case ATH10K_SCAN_IDLE: 450362306a36Sopenharmony_ci break; 450462306a36Sopenharmony_ci case ATH10K_SCAN_RUNNING: 450562306a36Sopenharmony_ci case ATH10K_SCAN_ABORTING: 450662306a36Sopenharmony_ci if (!ar->scan.is_roc) { 450762306a36Sopenharmony_ci struct cfg80211_scan_info info = { 450862306a36Sopenharmony_ci .aborted = (ar->scan.state == 450962306a36Sopenharmony_ci ATH10K_SCAN_ABORTING), 451062306a36Sopenharmony_ci }; 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci ieee80211_scan_completed(ar->hw, &info); 451362306a36Sopenharmony_ci } else if (ar->scan.roc_notify) { 451462306a36Sopenharmony_ci ieee80211_remain_on_channel_expired(ar->hw); 451562306a36Sopenharmony_ci } 451662306a36Sopenharmony_ci fallthrough; 451762306a36Sopenharmony_ci case ATH10K_SCAN_STARTING: 451862306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_IDLE; 451962306a36Sopenharmony_ci ar->scan_channel = NULL; 452062306a36Sopenharmony_ci ar->scan.roc_freq = 0; 452162306a36Sopenharmony_ci ath10k_offchan_tx_purge(ar); 452262306a36Sopenharmony_ci cancel_delayed_work(&ar->scan.timeout); 452362306a36Sopenharmony_ci complete(&ar->scan.completed); 452462306a36Sopenharmony_ci break; 452562306a36Sopenharmony_ci } 452662306a36Sopenharmony_ci} 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_civoid ath10k_scan_finish(struct ath10k *ar) 452962306a36Sopenharmony_ci{ 453062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 453162306a36Sopenharmony_ci __ath10k_scan_finish(ar); 453262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 453362306a36Sopenharmony_ci} 453462306a36Sopenharmony_ci 453562306a36Sopenharmony_cistatic int ath10k_scan_stop(struct ath10k *ar) 453662306a36Sopenharmony_ci{ 453762306a36Sopenharmony_ci struct wmi_stop_scan_arg arg = { 453862306a36Sopenharmony_ci .req_id = 1, /* FIXME */ 453962306a36Sopenharmony_ci .req_type = WMI_SCAN_STOP_ONE, 454062306a36Sopenharmony_ci .u.scan_id = ATH10K_SCAN_ID, 454162306a36Sopenharmony_ci }; 454262306a36Sopenharmony_ci int ret; 454362306a36Sopenharmony_ci 454462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 454562306a36Sopenharmony_ci 454662306a36Sopenharmony_ci ret = ath10k_wmi_stop_scan(ar, &arg); 454762306a36Sopenharmony_ci if (ret) { 454862306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret); 454962306a36Sopenharmony_ci goto out; 455062306a36Sopenharmony_ci } 455162306a36Sopenharmony_ci 455262306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ); 455362306a36Sopenharmony_ci if (ret == 0) { 455462306a36Sopenharmony_ci ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n"); 455562306a36Sopenharmony_ci ret = -ETIMEDOUT; 455662306a36Sopenharmony_ci } else if (ret > 0) { 455762306a36Sopenharmony_ci ret = 0; 455862306a36Sopenharmony_ci } 455962306a36Sopenharmony_ci 456062306a36Sopenharmony_ciout: 456162306a36Sopenharmony_ci /* Scan state should be updated upon scan completion but in case 456262306a36Sopenharmony_ci * firmware fails to deliver the event (for whatever reason) it is 456362306a36Sopenharmony_ci * desired to clean up scan state anyway. Firmware may have just 456462306a36Sopenharmony_ci * dropped the scan completion event delivery due to transport pipe 456562306a36Sopenharmony_ci * being overflown with data and/or it can recover on its own before 456662306a36Sopenharmony_ci * next scan request is submitted. 456762306a36Sopenharmony_ci */ 456862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 456962306a36Sopenharmony_ci if (ar->scan.state != ATH10K_SCAN_IDLE) 457062306a36Sopenharmony_ci __ath10k_scan_finish(ar); 457162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 457262306a36Sopenharmony_ci 457362306a36Sopenharmony_ci return ret; 457462306a36Sopenharmony_ci} 457562306a36Sopenharmony_ci 457662306a36Sopenharmony_cistatic void ath10k_scan_abort(struct ath10k *ar) 457762306a36Sopenharmony_ci{ 457862306a36Sopenharmony_ci int ret; 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 458362306a36Sopenharmony_ci 458462306a36Sopenharmony_ci switch (ar->scan.state) { 458562306a36Sopenharmony_ci case ATH10K_SCAN_IDLE: 458662306a36Sopenharmony_ci /* This can happen if timeout worker kicked in and called 458762306a36Sopenharmony_ci * abortion while scan completion was being processed. 458862306a36Sopenharmony_ci */ 458962306a36Sopenharmony_ci break; 459062306a36Sopenharmony_ci case ATH10K_SCAN_STARTING: 459162306a36Sopenharmony_ci case ATH10K_SCAN_ABORTING: 459262306a36Sopenharmony_ci ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n", 459362306a36Sopenharmony_ci ath10k_scan_state_str(ar->scan.state), 459462306a36Sopenharmony_ci ar->scan.state); 459562306a36Sopenharmony_ci break; 459662306a36Sopenharmony_ci case ATH10K_SCAN_RUNNING: 459762306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_ABORTING; 459862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 459962306a36Sopenharmony_ci 460062306a36Sopenharmony_ci ret = ath10k_scan_stop(ar); 460162306a36Sopenharmony_ci if (ret) 460262306a36Sopenharmony_ci ath10k_warn(ar, "failed to abort scan: %d\n", ret); 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 460562306a36Sopenharmony_ci break; 460662306a36Sopenharmony_ci } 460762306a36Sopenharmony_ci 460862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 460962306a36Sopenharmony_ci} 461062306a36Sopenharmony_ci 461162306a36Sopenharmony_civoid ath10k_scan_timeout_work(struct work_struct *work) 461262306a36Sopenharmony_ci{ 461362306a36Sopenharmony_ci struct ath10k *ar = container_of(work, struct ath10k, 461462306a36Sopenharmony_ci scan.timeout.work); 461562306a36Sopenharmony_ci 461662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 461762306a36Sopenharmony_ci ath10k_scan_abort(ar); 461862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 461962306a36Sopenharmony_ci} 462062306a36Sopenharmony_ci 462162306a36Sopenharmony_cistatic int ath10k_start_scan(struct ath10k *ar, 462262306a36Sopenharmony_ci const struct wmi_start_scan_arg *arg) 462362306a36Sopenharmony_ci{ 462462306a36Sopenharmony_ci int ret; 462562306a36Sopenharmony_ci 462662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 462762306a36Sopenharmony_ci 462862306a36Sopenharmony_ci ret = ath10k_wmi_start_scan(ar, arg); 462962306a36Sopenharmony_ci if (ret) 463062306a36Sopenharmony_ci return ret; 463162306a36Sopenharmony_ci 463262306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); 463362306a36Sopenharmony_ci if (ret == 0) { 463462306a36Sopenharmony_ci ret = ath10k_scan_stop(ar); 463562306a36Sopenharmony_ci if (ret) 463662306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop scan: %d\n", ret); 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci return -ETIMEDOUT; 463962306a36Sopenharmony_ci } 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci /* If we failed to start the scan, return error code at 464262306a36Sopenharmony_ci * this point. This is probably due to some issue in the 464362306a36Sopenharmony_ci * firmware, but no need to wedge the driver due to that... 464462306a36Sopenharmony_ci */ 464562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 464662306a36Sopenharmony_ci if (ar->scan.state == ATH10K_SCAN_IDLE) { 464762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 464862306a36Sopenharmony_ci return -EINVAL; 464962306a36Sopenharmony_ci } 465062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_ci return 0; 465362306a36Sopenharmony_ci} 465462306a36Sopenharmony_ci 465562306a36Sopenharmony_ci/**********************/ 465662306a36Sopenharmony_ci/* mac80211 callbacks */ 465762306a36Sopenharmony_ci/**********************/ 465862306a36Sopenharmony_ci 465962306a36Sopenharmony_cistatic void ath10k_mac_op_tx(struct ieee80211_hw *hw, 466062306a36Sopenharmony_ci struct ieee80211_tx_control *control, 466162306a36Sopenharmony_ci struct sk_buff *skb) 466262306a36Sopenharmony_ci{ 466362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 466462306a36Sopenharmony_ci struct ath10k_htt *htt = &ar->htt; 466562306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 466662306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 466762306a36Sopenharmony_ci struct ieee80211_sta *sta = control->sta; 466862306a36Sopenharmony_ci struct ieee80211_txq *txq = NULL; 466962306a36Sopenharmony_ci enum ath10k_hw_txrx_mode txmode; 467062306a36Sopenharmony_ci enum ath10k_mac_tx_path txpath; 467162306a36Sopenharmony_ci bool is_htt; 467262306a36Sopenharmony_ci bool is_mgmt; 467362306a36Sopenharmony_ci int ret; 467462306a36Sopenharmony_ci u16 airtime; 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci airtime = ath10k_mac_update_airtime(ar, txq, skb); 467762306a36Sopenharmony_ci ath10k_mac_tx_h_fill_cb(ar, vif, txq, sta, skb, airtime); 467862306a36Sopenharmony_ci 467962306a36Sopenharmony_ci txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); 468062306a36Sopenharmony_ci txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); 468162306a36Sopenharmony_ci is_htt = (txpath == ATH10K_MAC_TX_HTT || 468262306a36Sopenharmony_ci txpath == ATH10K_MAC_TX_HTT_MGMT); 468362306a36Sopenharmony_ci is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT); 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (is_htt) { 468662306a36Sopenharmony_ci bool is_presp = false; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 468962306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) { 469062306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 469162306a36Sopenharmony_ci 469262306a36Sopenharmony_ci is_presp = ieee80211_is_probe_resp(hdr->frame_control); 469362306a36Sopenharmony_ci } 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci ret = ath10k_htt_tx_inc_pending(htt); 469662306a36Sopenharmony_ci if (ret) { 469762306a36Sopenharmony_ci ath10k_warn(ar, "failed to increase tx pending count: %d, dropping\n", 469862306a36Sopenharmony_ci ret); 469962306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 470062306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 470162306a36Sopenharmony_ci return; 470262306a36Sopenharmony_ci } 470362306a36Sopenharmony_ci 470462306a36Sopenharmony_ci ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp); 470562306a36Sopenharmony_ci if (ret) { 470662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "failed to increase tx mgmt pending count: %d, dropping\n", 470762306a36Sopenharmony_ci ret); 470862306a36Sopenharmony_ci ath10k_htt_tx_dec_pending(htt); 470962306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 471062306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 471162306a36Sopenharmony_ci return; 471262306a36Sopenharmony_ci } 471362306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 471462306a36Sopenharmony_ci } 471562306a36Sopenharmony_ci 471662306a36Sopenharmony_ci ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); 471762306a36Sopenharmony_ci if (ret) { 471862306a36Sopenharmony_ci ath10k_warn(ar, "failed to transmit frame: %d\n", ret); 471962306a36Sopenharmony_ci if (is_htt) { 472062306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 472162306a36Sopenharmony_ci ath10k_htt_tx_dec_pending(htt); 472262306a36Sopenharmony_ci if (is_mgmt) 472362306a36Sopenharmony_ci ath10k_htt_tx_mgmt_dec_pending(htt); 472462306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 472562306a36Sopenharmony_ci } 472662306a36Sopenharmony_ci return; 472762306a36Sopenharmony_ci } 472862306a36Sopenharmony_ci} 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_cistatic void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, 473162306a36Sopenharmony_ci struct ieee80211_txq *txq) 473262306a36Sopenharmony_ci{ 473362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 473462306a36Sopenharmony_ci int ret; 473562306a36Sopenharmony_ci u8 ac = txq->ac; 473662306a36Sopenharmony_ci 473762306a36Sopenharmony_ci ath10k_htt_tx_txq_update(hw, txq); 473862306a36Sopenharmony_ci if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH) 473962306a36Sopenharmony_ci return; 474062306a36Sopenharmony_ci 474162306a36Sopenharmony_ci spin_lock_bh(&ar->queue_lock[ac]); 474262306a36Sopenharmony_ci 474362306a36Sopenharmony_ci ieee80211_txq_schedule_start(hw, ac); 474462306a36Sopenharmony_ci txq = ieee80211_next_txq(hw, ac); 474562306a36Sopenharmony_ci if (!txq) 474662306a36Sopenharmony_ci goto out; 474762306a36Sopenharmony_ci 474862306a36Sopenharmony_ci while (ath10k_mac_tx_can_push(hw, txq)) { 474962306a36Sopenharmony_ci ret = ath10k_mac_tx_push_txq(hw, txq); 475062306a36Sopenharmony_ci if (ret < 0) 475162306a36Sopenharmony_ci break; 475262306a36Sopenharmony_ci } 475362306a36Sopenharmony_ci ieee80211_return_txq(hw, txq, false); 475462306a36Sopenharmony_ci ath10k_htt_tx_txq_update(hw, txq); 475562306a36Sopenharmony_ciout: 475662306a36Sopenharmony_ci ieee80211_txq_schedule_end(hw, ac); 475762306a36Sopenharmony_ci spin_unlock_bh(&ar->queue_lock[ac]); 475862306a36Sopenharmony_ci} 475962306a36Sopenharmony_ci 476062306a36Sopenharmony_ci/* Must not be called with conf_mutex held as workers can use that also. */ 476162306a36Sopenharmony_civoid ath10k_drain_tx(struct ath10k *ar) 476262306a36Sopenharmony_ci{ 476362306a36Sopenharmony_ci lockdep_assert_not_held(&ar->conf_mutex); 476462306a36Sopenharmony_ci 476562306a36Sopenharmony_ci /* make sure rcu-protected mac80211 tx path itself is drained */ 476662306a36Sopenharmony_ci synchronize_net(); 476762306a36Sopenharmony_ci 476862306a36Sopenharmony_ci ath10k_offchan_tx_purge(ar); 476962306a36Sopenharmony_ci ath10k_mgmt_over_wmi_tx_purge(ar); 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci cancel_work_sync(&ar->offchan_tx_work); 477262306a36Sopenharmony_ci cancel_work_sync(&ar->wmi_mgmt_tx_work); 477362306a36Sopenharmony_ci} 477462306a36Sopenharmony_ci 477562306a36Sopenharmony_civoid ath10k_halt(struct ath10k *ar) 477662306a36Sopenharmony_ci{ 477762306a36Sopenharmony_ci struct ath10k_vif *arvif; 477862306a36Sopenharmony_ci 477962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags); 478262306a36Sopenharmony_ci ar->filter_flags = 0; 478362306a36Sopenharmony_ci ar->monitor = false; 478462306a36Sopenharmony_ci ar->monitor_arvif = NULL; 478562306a36Sopenharmony_ci 478662306a36Sopenharmony_ci if (ar->monitor_started) 478762306a36Sopenharmony_ci ath10k_monitor_stop(ar); 478862306a36Sopenharmony_ci 478962306a36Sopenharmony_ci ar->monitor_started = false; 479062306a36Sopenharmony_ci ar->tx_paused = 0; 479162306a36Sopenharmony_ci 479262306a36Sopenharmony_ci ath10k_scan_finish(ar); 479362306a36Sopenharmony_ci ath10k_peer_cleanup_all(ar); 479462306a36Sopenharmony_ci ath10k_stop_radar_confirmation(ar); 479562306a36Sopenharmony_ci ath10k_core_stop(ar); 479662306a36Sopenharmony_ci ath10k_hif_power_down(ar); 479762306a36Sopenharmony_ci 479862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 479962306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) 480062306a36Sopenharmony_ci ath10k_mac_vif_beacon_cleanup(arvif); 480162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 480262306a36Sopenharmony_ci} 480362306a36Sopenharmony_ci 480462306a36Sopenharmony_cistatic int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 480562306a36Sopenharmony_ci{ 480662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 480762306a36Sopenharmony_ci 480862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 480962306a36Sopenharmony_ci 481062306a36Sopenharmony_ci *tx_ant = ar->cfg_tx_chainmask; 481162306a36Sopenharmony_ci *rx_ant = ar->cfg_rx_chainmask; 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 481462306a36Sopenharmony_ci 481562306a36Sopenharmony_ci return 0; 481662306a36Sopenharmony_ci} 481762306a36Sopenharmony_ci 481862306a36Sopenharmony_cistatic bool ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg) 481962306a36Sopenharmony_ci{ 482062306a36Sopenharmony_ci /* It is not clear that allowing gaps in chainmask 482162306a36Sopenharmony_ci * is helpful. Probably it will not do what user 482262306a36Sopenharmony_ci * is hoping for, so warn in that case. 482362306a36Sopenharmony_ci */ 482462306a36Sopenharmony_ci if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0) 482562306a36Sopenharmony_ci return true; 482662306a36Sopenharmony_ci 482762306a36Sopenharmony_ci ath10k_warn(ar, "mac %s antenna chainmask is invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n", 482862306a36Sopenharmony_ci dbg, cm); 482962306a36Sopenharmony_ci return false; 483062306a36Sopenharmony_ci} 483162306a36Sopenharmony_ci 483262306a36Sopenharmony_cistatic int ath10k_mac_get_vht_cap_bf_sts(struct ath10k *ar) 483362306a36Sopenharmony_ci{ 483462306a36Sopenharmony_ci int nsts = ar->vht_cap_info; 483562306a36Sopenharmony_ci 483662306a36Sopenharmony_ci nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; 483762306a36Sopenharmony_ci nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; 483862306a36Sopenharmony_ci 483962306a36Sopenharmony_ci /* If firmware does not deliver to host number of space-time 484062306a36Sopenharmony_ci * streams supported, assume it support up to 4 BF STS and return 484162306a36Sopenharmony_ci * the value for VHT CAP: nsts-1) 484262306a36Sopenharmony_ci */ 484362306a36Sopenharmony_ci if (nsts == 0) 484462306a36Sopenharmony_ci return 3; 484562306a36Sopenharmony_ci 484662306a36Sopenharmony_ci return nsts; 484762306a36Sopenharmony_ci} 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_cistatic int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) 485062306a36Sopenharmony_ci{ 485162306a36Sopenharmony_ci int sound_dim = ar->vht_cap_info; 485262306a36Sopenharmony_ci 485362306a36Sopenharmony_ci sound_dim &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; 485462306a36Sopenharmony_ci sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci /* If the sounding dimension is not advertised by the firmware, 485762306a36Sopenharmony_ci * let's use a default value of 1 485862306a36Sopenharmony_ci */ 485962306a36Sopenharmony_ci if (sound_dim == 0) 486062306a36Sopenharmony_ci return 1; 486162306a36Sopenharmony_ci 486262306a36Sopenharmony_ci return sound_dim; 486362306a36Sopenharmony_ci} 486462306a36Sopenharmony_ci 486562306a36Sopenharmony_cistatic struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) 486662306a36Sopenharmony_ci{ 486762306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap = {0}; 486862306a36Sopenharmony_ci struct ath10k_hw_params *hw = &ar->hw_params; 486962306a36Sopenharmony_ci u16 mcs_map; 487062306a36Sopenharmony_ci u32 val; 487162306a36Sopenharmony_ci int i; 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_ci vht_cap.vht_supported = 1; 487462306a36Sopenharmony_ci vht_cap.cap = ar->vht_cap_info; 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 487762306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) { 487862306a36Sopenharmony_ci val = ath10k_mac_get_vht_cap_bf_sts(ar); 487962306a36Sopenharmony_ci val <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; 488062306a36Sopenharmony_ci val &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; 488162306a36Sopenharmony_ci 488262306a36Sopenharmony_ci vht_cap.cap |= val; 488362306a36Sopenharmony_ci } 488462306a36Sopenharmony_ci 488562306a36Sopenharmony_ci if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 488662306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { 488762306a36Sopenharmony_ci val = ath10k_mac_get_vht_cap_bf_sound_dim(ar); 488862306a36Sopenharmony_ci val <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; 488962306a36Sopenharmony_ci val &= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; 489062306a36Sopenharmony_ci 489162306a36Sopenharmony_ci vht_cap.cap |= val; 489262306a36Sopenharmony_ci } 489362306a36Sopenharmony_ci 489462306a36Sopenharmony_ci mcs_map = 0; 489562306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 489662306a36Sopenharmony_ci if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i))) 489762306a36Sopenharmony_ci mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); 489862306a36Sopenharmony_ci else 489962306a36Sopenharmony_ci mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); 490062306a36Sopenharmony_ci } 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci if (ar->cfg_tx_chainmask <= 1) 490362306a36Sopenharmony_ci vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC; 490462306a36Sopenharmony_ci 490562306a36Sopenharmony_ci vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 490662306a36Sopenharmony_ci vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 490762306a36Sopenharmony_ci 490862306a36Sopenharmony_ci /* If we are supporting 160Mhz or 80+80, then the NIC may be able to do 490962306a36Sopenharmony_ci * a restricted NSS for 160 or 80+80 vs what it can do for 80Mhz. Give 491062306a36Sopenharmony_ci * user-space a clue if that is the case. 491162306a36Sopenharmony_ci */ 491262306a36Sopenharmony_ci if ((vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) && 491362306a36Sopenharmony_ci (hw->vht160_mcs_rx_highest != 0 || 491462306a36Sopenharmony_ci hw->vht160_mcs_tx_highest != 0)) { 491562306a36Sopenharmony_ci vht_cap.vht_mcs.rx_highest = cpu_to_le16(hw->vht160_mcs_rx_highest); 491662306a36Sopenharmony_ci vht_cap.vht_mcs.tx_highest = cpu_to_le16(hw->vht160_mcs_tx_highest); 491762306a36Sopenharmony_ci } 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_ci return vht_cap; 492062306a36Sopenharmony_ci} 492162306a36Sopenharmony_ci 492262306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) 492362306a36Sopenharmony_ci{ 492462306a36Sopenharmony_ci int i; 492562306a36Sopenharmony_ci struct ieee80211_sta_ht_cap ht_cap = {0}; 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_ci if (!(ar->ht_cap_info & WMI_HT_CAP_ENABLED)) 492862306a36Sopenharmony_ci return ht_cap; 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci ht_cap.ht_supported = 1; 493162306a36Sopenharmony_ci ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 493262306a36Sopenharmony_ci ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8; 493362306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 493462306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; 493562306a36Sopenharmony_ci ht_cap.cap |= 493662306a36Sopenharmony_ci WLAN_HT_CAP_SM_PS_DISABLED << IEEE80211_HT_CAP_SM_PS_SHIFT; 493762306a36Sopenharmony_ci 493862306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI) 493962306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; 494062306a36Sopenharmony_ci 494162306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_HT40_SGI) 494262306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) { 494562306a36Sopenharmony_ci u32 smps; 494662306a36Sopenharmony_ci 494762306a36Sopenharmony_ci smps = WLAN_HT_CAP_SM_PS_DYNAMIC; 494862306a36Sopenharmony_ci smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci ht_cap.cap |= smps; 495162306a36Sopenharmony_ci } 495262306a36Sopenharmony_ci 495362306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC && (ar->cfg_tx_chainmask > 1)) 495462306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; 495562306a36Sopenharmony_ci 495662306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_RX_STBC) { 495762306a36Sopenharmony_ci u32 stbc; 495862306a36Sopenharmony_ci 495962306a36Sopenharmony_ci stbc = ar->ht_cap_info; 496062306a36Sopenharmony_ci stbc &= WMI_HT_CAP_RX_STBC; 496162306a36Sopenharmony_ci stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT; 496262306a36Sopenharmony_ci stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT; 496362306a36Sopenharmony_ci stbc &= IEEE80211_HT_CAP_RX_STBC; 496462306a36Sopenharmony_ci 496562306a36Sopenharmony_ci ht_cap.cap |= stbc; 496662306a36Sopenharmony_ci } 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_LDPC || (ar->ht_cap_info & 496962306a36Sopenharmony_ci WMI_HT_CAP_RX_LDPC && (ar->ht_cap_info & WMI_HT_CAP_TX_LDPC))) 497062306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_L_SIG_TXOP_PROT) 497362306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT; 497462306a36Sopenharmony_ci 497562306a36Sopenharmony_ci /* max AMSDU is implicitly taken from vht_cap_info */ 497662306a36Sopenharmony_ci if (ar->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_MASK) 497762306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; 497862306a36Sopenharmony_ci 497962306a36Sopenharmony_ci for (i = 0; i < ar->num_rf_chains; i++) { 498062306a36Sopenharmony_ci if (ar->cfg_rx_chainmask & BIT(i)) 498162306a36Sopenharmony_ci ht_cap.mcs.rx_mask[i] = 0xFF; 498262306a36Sopenharmony_ci } 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci return ht_cap; 498762306a36Sopenharmony_ci} 498862306a36Sopenharmony_ci 498962306a36Sopenharmony_cistatic void ath10k_mac_setup_ht_vht_cap(struct ath10k *ar) 499062306a36Sopenharmony_ci{ 499162306a36Sopenharmony_ci struct ieee80211_supported_band *band; 499262306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap; 499362306a36Sopenharmony_ci struct ieee80211_sta_ht_cap ht_cap; 499462306a36Sopenharmony_ci 499562306a36Sopenharmony_ci ht_cap = ath10k_get_ht_cap(ar); 499662306a36Sopenharmony_ci vht_cap = ath10k_create_vht_cap(ar); 499762306a36Sopenharmony_ci 499862306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) { 499962306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_2GHZ]; 500062306a36Sopenharmony_ci band->ht_cap = ht_cap; 500162306a36Sopenharmony_ci } 500262306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) { 500362306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_5GHZ]; 500462306a36Sopenharmony_ci band->ht_cap = ht_cap; 500562306a36Sopenharmony_ci band->vht_cap = vht_cap; 500662306a36Sopenharmony_ci } 500762306a36Sopenharmony_ci} 500862306a36Sopenharmony_ci 500962306a36Sopenharmony_cistatic int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) 501062306a36Sopenharmony_ci{ 501162306a36Sopenharmony_ci int ret; 501262306a36Sopenharmony_ci bool is_valid_tx_chain_mask, is_valid_rx_chain_mask; 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 501562306a36Sopenharmony_ci 501662306a36Sopenharmony_ci is_valid_tx_chain_mask = ath10k_check_chain_mask(ar, tx_ant, "tx"); 501762306a36Sopenharmony_ci is_valid_rx_chain_mask = ath10k_check_chain_mask(ar, rx_ant, "rx"); 501862306a36Sopenharmony_ci 501962306a36Sopenharmony_ci if (!is_valid_tx_chain_mask || !is_valid_rx_chain_mask) 502062306a36Sopenharmony_ci return -EINVAL; 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci ar->cfg_tx_chainmask = tx_ant; 502362306a36Sopenharmony_ci ar->cfg_rx_chainmask = rx_ant; 502462306a36Sopenharmony_ci 502562306a36Sopenharmony_ci if ((ar->state != ATH10K_STATE_ON) && 502662306a36Sopenharmony_ci (ar->state != ATH10K_STATE_RESTARTED)) 502762306a36Sopenharmony_ci return 0; 502862306a36Sopenharmony_ci 502962306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask, 503062306a36Sopenharmony_ci tx_ant); 503162306a36Sopenharmony_ci if (ret) { 503262306a36Sopenharmony_ci ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n", 503362306a36Sopenharmony_ci ret, tx_ant); 503462306a36Sopenharmony_ci return ret; 503562306a36Sopenharmony_ci } 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask, 503862306a36Sopenharmony_ci rx_ant); 503962306a36Sopenharmony_ci if (ret) { 504062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n", 504162306a36Sopenharmony_ci ret, rx_ant); 504262306a36Sopenharmony_ci return ret; 504362306a36Sopenharmony_ci } 504462306a36Sopenharmony_ci 504562306a36Sopenharmony_ci /* Reload HT/VHT capability */ 504662306a36Sopenharmony_ci ath10k_mac_setup_ht_vht_cap(ar); 504762306a36Sopenharmony_ci 504862306a36Sopenharmony_ci return 0; 504962306a36Sopenharmony_ci} 505062306a36Sopenharmony_ci 505162306a36Sopenharmony_cistatic int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 505262306a36Sopenharmony_ci{ 505362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 505462306a36Sopenharmony_ci int ret; 505562306a36Sopenharmony_ci 505662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 505762306a36Sopenharmony_ci ret = __ath10k_set_antenna(ar, tx_ant, rx_ant); 505862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 505962306a36Sopenharmony_ci return ret; 506062306a36Sopenharmony_ci} 506162306a36Sopenharmony_ci 506262306a36Sopenharmony_cistatic int __ath10k_fetch_bb_timing_dt(struct ath10k *ar, 506362306a36Sopenharmony_ci struct wmi_bb_timing_cfg_arg *bb_timing) 506462306a36Sopenharmony_ci{ 506562306a36Sopenharmony_ci struct device_node *node; 506662306a36Sopenharmony_ci const char *fem_name; 506762306a36Sopenharmony_ci int ret; 506862306a36Sopenharmony_ci 506962306a36Sopenharmony_ci node = ar->dev->of_node; 507062306a36Sopenharmony_ci if (!node) 507162306a36Sopenharmony_ci return -ENOENT; 507262306a36Sopenharmony_ci 507362306a36Sopenharmony_ci ret = of_property_read_string_index(node, "ext-fem-name", 0, &fem_name); 507462306a36Sopenharmony_ci if (ret) 507562306a36Sopenharmony_ci return -ENOENT; 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ci /* 507862306a36Sopenharmony_ci * If external Front End module used in hardware, then default base band timing 507962306a36Sopenharmony_ci * parameter cannot be used since they were fine tuned for reference hardware, 508062306a36Sopenharmony_ci * so choosing different value suitable for that external FEM. 508162306a36Sopenharmony_ci */ 508262306a36Sopenharmony_ci if (!strcmp("microsemi-lx5586", fem_name)) { 508362306a36Sopenharmony_ci bb_timing->bb_tx_timing = 0x00; 508462306a36Sopenharmony_ci bb_timing->bb_xpa_timing = 0x0101; 508562306a36Sopenharmony_ci } else { 508662306a36Sopenharmony_ci return -ENOENT; 508762306a36Sopenharmony_ci } 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot bb_tx_timing 0x%x bb_xpa_timing 0x%x\n", 509062306a36Sopenharmony_ci bb_timing->bb_tx_timing, bb_timing->bb_xpa_timing); 509162306a36Sopenharmony_ci return 0; 509262306a36Sopenharmony_ci} 509362306a36Sopenharmony_ci 509462306a36Sopenharmony_cistatic int ath10k_mac_rfkill_config(struct ath10k *ar) 509562306a36Sopenharmony_ci{ 509662306a36Sopenharmony_ci u32 param; 509762306a36Sopenharmony_ci int ret; 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci if (ar->hw_values->rfkill_pin == 0) { 510062306a36Sopenharmony_ci ath10k_warn(ar, "ath10k does not support hardware rfkill with this device\n"); 510162306a36Sopenharmony_ci return -EOPNOTSUPP; 510262306a36Sopenharmony_ci } 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 510562306a36Sopenharmony_ci "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", 510662306a36Sopenharmony_ci ar->hw_values->rfkill_pin, ar->hw_values->rfkill_cfg, 510762306a36Sopenharmony_ci ar->hw_values->rfkill_on_level); 510862306a36Sopenharmony_ci 510962306a36Sopenharmony_ci param = FIELD_PREP(WMI_TLV_RFKILL_CFG_RADIO_LEVEL, 511062306a36Sopenharmony_ci ar->hw_values->rfkill_on_level) | 511162306a36Sopenharmony_ci FIELD_PREP(WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM, 511262306a36Sopenharmony_ci ar->hw_values->rfkill_pin) | 511362306a36Sopenharmony_ci FIELD_PREP(WMI_TLV_RFKILL_CFG_PIN_AS_GPIO, 511462306a36Sopenharmony_ci ar->hw_values->rfkill_cfg); 511562306a36Sopenharmony_ci 511662306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, 511762306a36Sopenharmony_ci ar->wmi.pdev_param->rfkill_config, 511862306a36Sopenharmony_ci param); 511962306a36Sopenharmony_ci if (ret) { 512062306a36Sopenharmony_ci ath10k_warn(ar, 512162306a36Sopenharmony_ci "failed to set rfkill config 0x%x: %d\n", 512262306a36Sopenharmony_ci param, ret); 512362306a36Sopenharmony_ci return ret; 512462306a36Sopenharmony_ci } 512562306a36Sopenharmony_ci return 0; 512662306a36Sopenharmony_ci} 512762306a36Sopenharmony_ci 512862306a36Sopenharmony_ciint ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable) 512962306a36Sopenharmony_ci{ 513062306a36Sopenharmony_ci enum wmi_tlv_rfkill_enable_radio param; 513162306a36Sopenharmony_ci int ret; 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci if (enable) 513462306a36Sopenharmony_ci param = WMI_TLV_RFKILL_ENABLE_RADIO_ON; 513562306a36Sopenharmony_ci else 513662306a36Sopenharmony_ci param = WMI_TLV_RFKILL_ENABLE_RADIO_OFF; 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac rfkill enable %d", param); 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rfkill_enable, 514162306a36Sopenharmony_ci param); 514262306a36Sopenharmony_ci if (ret) { 514362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set rfkill enable param %d: %d\n", 514462306a36Sopenharmony_ci param, ret); 514562306a36Sopenharmony_ci return ret; 514662306a36Sopenharmony_ci } 514762306a36Sopenharmony_ci 514862306a36Sopenharmony_ci return 0; 514962306a36Sopenharmony_ci} 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_cistatic int ath10k_start(struct ieee80211_hw *hw) 515262306a36Sopenharmony_ci{ 515362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 515462306a36Sopenharmony_ci u32 param; 515562306a36Sopenharmony_ci int ret = 0; 515662306a36Sopenharmony_ci struct wmi_bb_timing_cfg_arg bb_timing = {0}; 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci /* 515962306a36Sopenharmony_ci * This makes sense only when restarting hw. It is harmless to call 516062306a36Sopenharmony_ci * unconditionally. This is necessary to make sure no HTT/WMI tx 516162306a36Sopenharmony_ci * commands will be submitted while restarting. 516262306a36Sopenharmony_ci */ 516362306a36Sopenharmony_ci ath10k_drain_tx(ar); 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 516662306a36Sopenharmony_ci 516762306a36Sopenharmony_ci switch (ar->state) { 516862306a36Sopenharmony_ci case ATH10K_STATE_OFF: 516962306a36Sopenharmony_ci ar->state = ATH10K_STATE_ON; 517062306a36Sopenharmony_ci break; 517162306a36Sopenharmony_ci case ATH10K_STATE_RESTARTING: 517262306a36Sopenharmony_ci ar->state = ATH10K_STATE_RESTARTED; 517362306a36Sopenharmony_ci break; 517462306a36Sopenharmony_ci case ATH10K_STATE_ON: 517562306a36Sopenharmony_ci case ATH10K_STATE_RESTARTED: 517662306a36Sopenharmony_ci case ATH10K_STATE_WEDGED: 517762306a36Sopenharmony_ci WARN_ON(1); 517862306a36Sopenharmony_ci ret = -EINVAL; 517962306a36Sopenharmony_ci goto err; 518062306a36Sopenharmony_ci case ATH10K_STATE_UTF: 518162306a36Sopenharmony_ci ret = -EBUSY; 518262306a36Sopenharmony_ci goto err; 518362306a36Sopenharmony_ci } 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci if (ar->hw_rfkill_on) { 518862306a36Sopenharmony_ci ar->hw_rfkill_on = false; 518962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 519062306a36Sopenharmony_ci goto err; 519162306a36Sopenharmony_ci } 519262306a36Sopenharmony_ci 519362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 519462306a36Sopenharmony_ci 519562306a36Sopenharmony_ci ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL); 519662306a36Sopenharmony_ci if (ret) { 519762306a36Sopenharmony_ci ath10k_err(ar, "Could not init hif: %d\n", ret); 519862306a36Sopenharmony_ci goto err_off; 519962306a36Sopenharmony_ci } 520062306a36Sopenharmony_ci 520162306a36Sopenharmony_ci ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL, 520262306a36Sopenharmony_ci &ar->normal_mode_fw); 520362306a36Sopenharmony_ci if (ret) { 520462306a36Sopenharmony_ci ath10k_err(ar, "Could not init core: %d\n", ret); 520562306a36Sopenharmony_ci goto err_power_down; 520662306a36Sopenharmony_ci } 520762306a36Sopenharmony_ci 520862306a36Sopenharmony_ci if (ar->sys_cap_info & WMI_TLV_SYS_CAP_INFO_RFKILL) { 520962306a36Sopenharmony_ci ret = ath10k_mac_rfkill_config(ar); 521062306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 521162306a36Sopenharmony_ci ath10k_warn(ar, "failed to configure rfkill: %d", ret); 521262306a36Sopenharmony_ci goto err_core_stop; 521362306a36Sopenharmony_ci } 521462306a36Sopenharmony_ci } 521562306a36Sopenharmony_ci 521662306a36Sopenharmony_ci param = ar->wmi.pdev_param->pmf_qos; 521762306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 1); 521862306a36Sopenharmony_ci if (ret) { 521962306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret); 522062306a36Sopenharmony_ci goto err_core_stop; 522162306a36Sopenharmony_ci } 522262306a36Sopenharmony_ci 522362306a36Sopenharmony_ci param = ar->wmi.pdev_param->dynamic_bw; 522462306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 1); 522562306a36Sopenharmony_ci if (ret) { 522662306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret); 522762306a36Sopenharmony_ci goto err_core_stop; 522862306a36Sopenharmony_ci } 522962306a36Sopenharmony_ci 523062306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { 523162306a36Sopenharmony_ci ret = ath10k_wmi_scan_prob_req_oui(ar, ar->mac_addr); 523262306a36Sopenharmony_ci if (ret) { 523362306a36Sopenharmony_ci ath10k_err(ar, "failed to set prob req oui: %i\n", ret); 523462306a36Sopenharmony_ci goto err_core_stop; 523562306a36Sopenharmony_ci } 523662306a36Sopenharmony_ci } 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { 523962306a36Sopenharmony_ci ret = ath10k_wmi_adaptive_qcs(ar, true); 524062306a36Sopenharmony_ci if (ret) { 524162306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable adaptive qcs: %d\n", 524262306a36Sopenharmony_ci ret); 524362306a36Sopenharmony_ci goto err_core_stop; 524462306a36Sopenharmony_ci } 524562306a36Sopenharmony_ci } 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) { 524862306a36Sopenharmony_ci param = ar->wmi.pdev_param->burst_enable; 524962306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 0); 525062306a36Sopenharmony_ci if (ret) { 525162306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable burst: %d\n", ret); 525262306a36Sopenharmony_ci goto err_core_stop; 525362306a36Sopenharmony_ci } 525462306a36Sopenharmony_ci } 525562306a36Sopenharmony_ci 525662306a36Sopenharmony_ci param = ar->wmi.pdev_param->idle_ps_config; 525762306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 1); 525862306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 525962306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret); 526062306a36Sopenharmony_ci goto err_core_stop; 526162306a36Sopenharmony_ci } 526262306a36Sopenharmony_ci 526362306a36Sopenharmony_ci __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask); 526462306a36Sopenharmony_ci 526562306a36Sopenharmony_ci /* 526662306a36Sopenharmony_ci * By default FW set ARP frames ac to voice (6). In that case ARP 526762306a36Sopenharmony_ci * exchange is not working properly for UAPSD enabled AP. ARP requests 526862306a36Sopenharmony_ci * which arrives with access category 0 are processed by network stack 526962306a36Sopenharmony_ci * and send back with access category 0, but FW changes access category 527062306a36Sopenharmony_ci * to 6. Set ARP frames access category to best effort (0) solves 527162306a36Sopenharmony_ci * this problem. 527262306a36Sopenharmony_ci */ 527362306a36Sopenharmony_ci 527462306a36Sopenharmony_ci param = ar->wmi.pdev_param->arp_ac_override; 527562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 0); 527662306a36Sopenharmony_ci if (ret) { 527762306a36Sopenharmony_ci ath10k_warn(ar, "failed to set arp ac override parameter: %d\n", 527862306a36Sopenharmony_ci ret); 527962306a36Sopenharmony_ci goto err_core_stop; 528062306a36Sopenharmony_ci } 528162306a36Sopenharmony_ci 528262306a36Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA, 528362306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 528462306a36Sopenharmony_ci ret = ath10k_wmi_pdev_enable_adaptive_cca(ar, 1, 528562306a36Sopenharmony_ci WMI_CCA_DETECT_LEVEL_AUTO, 528662306a36Sopenharmony_ci WMI_CCA_DETECT_MARGIN_AUTO); 528762306a36Sopenharmony_ci if (ret) { 528862306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable adaptive cca: %d\n", 528962306a36Sopenharmony_ci ret); 529062306a36Sopenharmony_ci goto err_core_stop; 529162306a36Sopenharmony_ci } 529262306a36Sopenharmony_ci } 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci param = ar->wmi.pdev_param->ani_enable; 529562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 1); 529662306a36Sopenharmony_ci if (ret) { 529762306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable ani by default: %d\n", 529862306a36Sopenharmony_ci ret); 529962306a36Sopenharmony_ci goto err_core_stop; 530062306a36Sopenharmony_ci } 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_ci ar->ani_enabled = true; 530362306a36Sopenharmony_ci 530462306a36Sopenharmony_ci if (ath10k_peer_stats_enabled(ar)) { 530562306a36Sopenharmony_ci param = ar->wmi.pdev_param->peer_stats_update_period; 530662306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 530762306a36Sopenharmony_ci PEER_DEFAULT_STATS_UPDATE_PERIOD); 530862306a36Sopenharmony_ci if (ret) { 530962306a36Sopenharmony_ci ath10k_warn(ar, 531062306a36Sopenharmony_ci "failed to set peer stats period : %d\n", 531162306a36Sopenharmony_ci ret); 531262306a36Sopenharmony_ci goto err_core_stop; 531362306a36Sopenharmony_ci } 531462306a36Sopenharmony_ci } 531562306a36Sopenharmony_ci 531662306a36Sopenharmony_ci param = ar->wmi.pdev_param->enable_btcoex; 531762306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) && 531862306a36Sopenharmony_ci test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, 531962306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features) && 532062306a36Sopenharmony_ci ar->coex_support) { 532162306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, param, 0); 532262306a36Sopenharmony_ci if (ret) { 532362306a36Sopenharmony_ci ath10k_warn(ar, 532462306a36Sopenharmony_ci "failed to set btcoex param: %d\n", ret); 532562306a36Sopenharmony_ci goto err_core_stop; 532662306a36Sopenharmony_ci } 532762306a36Sopenharmony_ci clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags); 532862306a36Sopenharmony_ci } 532962306a36Sopenharmony_ci 533062306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_BB_TIMING_CONFIG_SUPPORT, ar->wmi.svc_map)) { 533162306a36Sopenharmony_ci ret = __ath10k_fetch_bb_timing_dt(ar, &bb_timing); 533262306a36Sopenharmony_ci if (!ret) { 533362306a36Sopenharmony_ci ret = ath10k_wmi_pdev_bb_timing(ar, &bb_timing); 533462306a36Sopenharmony_ci if (ret) { 533562306a36Sopenharmony_ci ath10k_warn(ar, 533662306a36Sopenharmony_ci "failed to set bb timings: %d\n", 533762306a36Sopenharmony_ci ret); 533862306a36Sopenharmony_ci goto err_core_stop; 533962306a36Sopenharmony_ci } 534062306a36Sopenharmony_ci } 534162306a36Sopenharmony_ci } 534262306a36Sopenharmony_ci 534362306a36Sopenharmony_ci ar->num_started_vdevs = 0; 534462306a36Sopenharmony_ci ath10k_regd_update(ar); 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci ath10k_spectral_start(ar); 534762306a36Sopenharmony_ci ath10k_thermal_set_throttling(ar); 534862306a36Sopenharmony_ci 534962306a36Sopenharmony_ci ar->radar_conf_state = ATH10K_RADAR_CONFIRMATION_IDLE; 535062306a36Sopenharmony_ci 535162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 535262306a36Sopenharmony_ci return 0; 535362306a36Sopenharmony_ci 535462306a36Sopenharmony_cierr_core_stop: 535562306a36Sopenharmony_ci ath10k_core_stop(ar); 535662306a36Sopenharmony_ci 535762306a36Sopenharmony_cierr_power_down: 535862306a36Sopenharmony_ci ath10k_hif_power_down(ar); 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_cierr_off: 536162306a36Sopenharmony_ci ar->state = ATH10K_STATE_OFF; 536262306a36Sopenharmony_ci 536362306a36Sopenharmony_cierr: 536462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 536562306a36Sopenharmony_ci return ret; 536662306a36Sopenharmony_ci} 536762306a36Sopenharmony_ci 536862306a36Sopenharmony_cistatic void ath10k_stop(struct ieee80211_hw *hw) 536962306a36Sopenharmony_ci{ 537062306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 537162306a36Sopenharmony_ci u32 opt; 537262306a36Sopenharmony_ci 537362306a36Sopenharmony_ci ath10k_drain_tx(ar); 537462306a36Sopenharmony_ci 537562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 537662306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_OFF) { 537762306a36Sopenharmony_ci if (!ar->hw_rfkill_on) { 537862306a36Sopenharmony_ci /* If the current driver state is RESTARTING but not yet 537962306a36Sopenharmony_ci * fully RESTARTED because of incoming suspend event, 538062306a36Sopenharmony_ci * then ath10k_halt() is already called via 538162306a36Sopenharmony_ci * ath10k_core_restart() and should not be called here. 538262306a36Sopenharmony_ci */ 538362306a36Sopenharmony_ci if (ar->state != ATH10K_STATE_RESTARTING) { 538462306a36Sopenharmony_ci ath10k_halt(ar); 538562306a36Sopenharmony_ci } else { 538662306a36Sopenharmony_ci /* Suspending here, because when in RESTARTING 538762306a36Sopenharmony_ci * state, ath10k_core_stop() skips 538862306a36Sopenharmony_ci * ath10k_wait_for_suspend(). 538962306a36Sopenharmony_ci */ 539062306a36Sopenharmony_ci opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR; 539162306a36Sopenharmony_ci ath10k_wait_for_suspend(ar, opt); 539262306a36Sopenharmony_ci } 539362306a36Sopenharmony_ci } 539462306a36Sopenharmony_ci ar->state = ATH10K_STATE_OFF; 539562306a36Sopenharmony_ci } 539662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 539762306a36Sopenharmony_ci 539862306a36Sopenharmony_ci cancel_work_sync(&ar->set_coverage_class_work); 539962306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->scan.timeout); 540062306a36Sopenharmony_ci cancel_work_sync(&ar->restart_work); 540162306a36Sopenharmony_ci} 540262306a36Sopenharmony_ci 540362306a36Sopenharmony_cistatic int ath10k_config_ps(struct ath10k *ar) 540462306a36Sopenharmony_ci{ 540562306a36Sopenharmony_ci struct ath10k_vif *arvif; 540662306a36Sopenharmony_ci int ret = 0; 540762306a36Sopenharmony_ci 540862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 540962306a36Sopenharmony_ci 541062306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 541162306a36Sopenharmony_ci ret = ath10k_mac_vif_setup_ps(arvif); 541262306a36Sopenharmony_ci if (ret) { 541362306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup powersave: %d\n", ret); 541462306a36Sopenharmony_ci break; 541562306a36Sopenharmony_ci } 541662306a36Sopenharmony_ci } 541762306a36Sopenharmony_ci 541862306a36Sopenharmony_ci return ret; 541962306a36Sopenharmony_ci} 542062306a36Sopenharmony_ci 542162306a36Sopenharmony_cistatic int ath10k_config(struct ieee80211_hw *hw, u32 changed) 542262306a36Sopenharmony_ci{ 542362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 542462306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 542562306a36Sopenharmony_ci int ret = 0; 542662306a36Sopenharmony_ci 542762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 542862306a36Sopenharmony_ci 542962306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_PS) 543062306a36Sopenharmony_ci ath10k_config_ps(ar); 543162306a36Sopenharmony_ci 543262306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 543362306a36Sopenharmony_ci ar->monitor = conf->flags & IEEE80211_CONF_MONITOR; 543462306a36Sopenharmony_ci ret = ath10k_monitor_recalc(ar); 543562306a36Sopenharmony_ci if (ret) 543662306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc monitor: %d\n", ret); 543762306a36Sopenharmony_ci } 543862306a36Sopenharmony_ci 543962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 544062306a36Sopenharmony_ci return ret; 544162306a36Sopenharmony_ci} 544262306a36Sopenharmony_ci 544362306a36Sopenharmony_cistatic u32 get_nss_from_chainmask(u16 chain_mask) 544462306a36Sopenharmony_ci{ 544562306a36Sopenharmony_ci if ((chain_mask & 0xf) == 0xf) 544662306a36Sopenharmony_ci return 4; 544762306a36Sopenharmony_ci else if ((chain_mask & 0x7) == 0x7) 544862306a36Sopenharmony_ci return 3; 544962306a36Sopenharmony_ci else if ((chain_mask & 0x3) == 0x3) 545062306a36Sopenharmony_ci return 2; 545162306a36Sopenharmony_ci return 1; 545262306a36Sopenharmony_ci} 545362306a36Sopenharmony_ci 545462306a36Sopenharmony_cistatic int ath10k_mac_set_txbf_conf(struct ath10k_vif *arvif) 545562306a36Sopenharmony_ci{ 545662306a36Sopenharmony_ci u32 value = 0; 545762306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 545862306a36Sopenharmony_ci int nsts; 545962306a36Sopenharmony_ci int sound_dim; 546062306a36Sopenharmony_ci 546162306a36Sopenharmony_ci if (ath10k_wmi_get_txbf_conf_scheme(ar) != WMI_TXBF_CONF_BEFORE_ASSOC) 546262306a36Sopenharmony_ci return 0; 546362306a36Sopenharmony_ci 546462306a36Sopenharmony_ci nsts = ath10k_mac_get_vht_cap_bf_sts(ar); 546562306a36Sopenharmony_ci if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | 546662306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) 546762306a36Sopenharmony_ci value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET); 546862306a36Sopenharmony_ci 546962306a36Sopenharmony_ci sound_dim = ath10k_mac_get_vht_cap_bf_sound_dim(ar); 547062306a36Sopenharmony_ci if (ar->vht_cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | 547162306a36Sopenharmony_ci IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) 547262306a36Sopenharmony_ci value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET); 547362306a36Sopenharmony_ci 547462306a36Sopenharmony_ci if (!value) 547562306a36Sopenharmony_ci return 0; 547662306a36Sopenharmony_ci 547762306a36Sopenharmony_ci if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) 547862306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; 547962306a36Sopenharmony_ci 548062306a36Sopenharmony_ci if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) 548162306a36Sopenharmony_ci value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFER | 548262306a36Sopenharmony_ci WMI_VDEV_PARAM_TXBF_SU_TX_BFER); 548362306a36Sopenharmony_ci 548462306a36Sopenharmony_ci if (ar->vht_cap_info & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) 548562306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; 548662306a36Sopenharmony_ci 548762306a36Sopenharmony_ci if (ar->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) 548862306a36Sopenharmony_ci value |= (WMI_VDEV_PARAM_TXBF_MU_TX_BFEE | 548962306a36Sopenharmony_ci WMI_VDEV_PARAM_TXBF_SU_TX_BFEE); 549062306a36Sopenharmony_ci 549162306a36Sopenharmony_ci return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, 549262306a36Sopenharmony_ci ar->wmi.vdev_param->txbf, value); 549362306a36Sopenharmony_ci} 549462306a36Sopenharmony_ci 549562306a36Sopenharmony_cistatic void ath10k_update_vif_offload(struct ieee80211_hw *hw, 549662306a36Sopenharmony_ci struct ieee80211_vif *vif) 549762306a36Sopenharmony_ci{ 549862306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 549962306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 550062306a36Sopenharmony_ci u32 vdev_param; 550162306a36Sopenharmony_ci int ret; 550262306a36Sopenharmony_ci 550362306a36Sopenharmony_ci if (ath10k_frame_mode != ATH10K_HW_TXRX_ETHERNET || 550462306a36Sopenharmony_ci ar->wmi.vdev_param->tx_encap_type == WMI_VDEV_PARAM_UNSUPPORTED || 550562306a36Sopenharmony_ci (vif->type != NL80211_IFTYPE_STATION && 550662306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_AP)) 550762306a36Sopenharmony_ci vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; 550862306a36Sopenharmony_ci 550962306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->tx_encap_type; 551062306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 551162306a36Sopenharmony_ci ATH10K_HW_TXRX_NATIVE_WIFI); 551262306a36Sopenharmony_ci /* 10.X firmware does not support this VDEV parameter. Do not warn */ 551362306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 551462306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n", 551562306a36Sopenharmony_ci arvif->vdev_id, ret); 551662306a36Sopenharmony_ci } 551762306a36Sopenharmony_ci} 551862306a36Sopenharmony_ci 551962306a36Sopenharmony_ci/* 552062306a36Sopenharmony_ci * TODO: 552162306a36Sopenharmony_ci * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE, 552262306a36Sopenharmony_ci * because we will send mgmt frames without CCK. This requirement 552362306a36Sopenharmony_ci * for P2P_FIND/GO_NEG should be handled by checking CCK flag 552462306a36Sopenharmony_ci * in the TX packet. 552562306a36Sopenharmony_ci */ 552662306a36Sopenharmony_cistatic int ath10k_add_interface(struct ieee80211_hw *hw, 552762306a36Sopenharmony_ci struct ieee80211_vif *vif) 552862306a36Sopenharmony_ci{ 552962306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 553062306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 553162306a36Sopenharmony_ci struct ath10k_peer *peer; 553262306a36Sopenharmony_ci enum wmi_sta_powersave_param param; 553362306a36Sopenharmony_ci int ret = 0; 553462306a36Sopenharmony_ci u32 value; 553562306a36Sopenharmony_ci int bit; 553662306a36Sopenharmony_ci int i; 553762306a36Sopenharmony_ci u32 vdev_param; 553862306a36Sopenharmony_ci 553962306a36Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; 554062306a36Sopenharmony_ci 554162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci memset(arvif, 0, sizeof(*arvif)); 554462306a36Sopenharmony_ci ath10k_mac_txq_init(vif->txq); 554562306a36Sopenharmony_ci 554662306a36Sopenharmony_ci arvif->ar = ar; 554762306a36Sopenharmony_ci arvif->vif = vif; 554862306a36Sopenharmony_ci 554962306a36Sopenharmony_ci INIT_LIST_HEAD(&arvif->list); 555062306a36Sopenharmony_ci INIT_WORK(&arvif->ap_csa_work, ath10k_mac_vif_ap_csa_work); 555162306a36Sopenharmony_ci INIT_DELAYED_WORK(&arvif->connection_loss_work, 555262306a36Sopenharmony_ci ath10k_mac_vif_sta_connection_loss_work); 555362306a36Sopenharmony_ci 555462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { 555562306a36Sopenharmony_ci arvif->bitrate_mask.control[i].legacy = 0xffffffff; 555662306a36Sopenharmony_ci memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, 555762306a36Sopenharmony_ci sizeof(arvif->bitrate_mask.control[i].ht_mcs)); 555862306a36Sopenharmony_ci memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, 555962306a36Sopenharmony_ci sizeof(arvif->bitrate_mask.control[i].vht_mcs)); 556062306a36Sopenharmony_ci } 556162306a36Sopenharmony_ci 556262306a36Sopenharmony_ci if (ar->num_peers >= ar->max_num_peers) { 556362306a36Sopenharmony_ci ath10k_warn(ar, "refusing vdev creation due to insufficient peer entry resources in firmware\n"); 556462306a36Sopenharmony_ci ret = -ENOBUFS; 556562306a36Sopenharmony_ci goto err; 556662306a36Sopenharmony_ci } 556762306a36Sopenharmony_ci 556862306a36Sopenharmony_ci if (ar->free_vdev_map == 0) { 556962306a36Sopenharmony_ci ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n"); 557062306a36Sopenharmony_ci ret = -EBUSY; 557162306a36Sopenharmony_ci goto err; 557262306a36Sopenharmony_ci } 557362306a36Sopenharmony_ci bit = __ffs64(ar->free_vdev_map); 557462306a36Sopenharmony_ci 557562306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n", 557662306a36Sopenharmony_ci bit, ar->free_vdev_map); 557762306a36Sopenharmony_ci 557862306a36Sopenharmony_ci arvif->vdev_id = bit; 557962306a36Sopenharmony_ci arvif->vdev_subtype = 558062306a36Sopenharmony_ci ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE); 558162306a36Sopenharmony_ci 558262306a36Sopenharmony_ci switch (vif->type) { 558362306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_DEVICE: 558462306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_STA; 558562306a36Sopenharmony_ci arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype 558662306a36Sopenharmony_ci (ar, WMI_VDEV_SUBTYPE_P2P_DEVICE); 558762306a36Sopenharmony_ci break; 558862306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 558962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 559062306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_STA; 559162306a36Sopenharmony_ci if (vif->p2p) 559262306a36Sopenharmony_ci arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype 559362306a36Sopenharmony_ci (ar, WMI_VDEV_SUBTYPE_P2P_CLIENT); 559462306a36Sopenharmony_ci break; 559562306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 559662306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_IBSS; 559762306a36Sopenharmony_ci break; 559862306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 559962306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) { 560062306a36Sopenharmony_ci arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype 560162306a36Sopenharmony_ci (ar, WMI_VDEV_SUBTYPE_MESH_11S); 560262306a36Sopenharmony_ci } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { 560362306a36Sopenharmony_ci ret = -EINVAL; 560462306a36Sopenharmony_ci ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n"); 560562306a36Sopenharmony_ci goto err; 560662306a36Sopenharmony_ci } 560762306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_AP; 560862306a36Sopenharmony_ci break; 560962306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 561062306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_AP; 561162306a36Sopenharmony_ci 561262306a36Sopenharmony_ci if (vif->p2p) 561362306a36Sopenharmony_ci arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype 561462306a36Sopenharmony_ci (ar, WMI_VDEV_SUBTYPE_P2P_GO); 561562306a36Sopenharmony_ci break; 561662306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 561762306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; 561862306a36Sopenharmony_ci break; 561962306a36Sopenharmony_ci default: 562062306a36Sopenharmony_ci WARN_ON(1); 562162306a36Sopenharmony_ci break; 562262306a36Sopenharmony_ci } 562362306a36Sopenharmony_ci 562462306a36Sopenharmony_ci /* Using vdev_id as queue number will make it very easy to do per-vif 562562306a36Sopenharmony_ci * tx queue locking. This shouldn't wrap due to interface combinations 562662306a36Sopenharmony_ci * but do a modulo for correctness sake and prevent using offchannel tx 562762306a36Sopenharmony_ci * queues for regular vif tx. 562862306a36Sopenharmony_ci */ 562962306a36Sopenharmony_ci vif->cab_queue = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1); 563062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) 563162306a36Sopenharmony_ci vif->hw_queue[i] = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1); 563262306a36Sopenharmony_ci 563362306a36Sopenharmony_ci /* Some firmware revisions don't wait for beacon tx completion before 563462306a36Sopenharmony_ci * sending another SWBA event. This could lead to hardware using old 563562306a36Sopenharmony_ci * (freed) beacon data in some cases, e.g. tx credit starvation 563662306a36Sopenharmony_ci * combined with missed TBTT. This is very rare. 563762306a36Sopenharmony_ci * 563862306a36Sopenharmony_ci * On non-IOMMU-enabled hosts this could be a possible security issue 563962306a36Sopenharmony_ci * because hw could beacon some random data on the air. On 564062306a36Sopenharmony_ci * IOMMU-enabled hosts DMAR faults would occur in most cases and target 564162306a36Sopenharmony_ci * device would crash. 564262306a36Sopenharmony_ci * 564362306a36Sopenharmony_ci * Since there are no beacon tx completions (implicit nor explicit) 564462306a36Sopenharmony_ci * propagated to host the only workaround for this is to allocate a 564562306a36Sopenharmony_ci * DMA-coherent buffer for a lifetime of a vif and use it for all 564662306a36Sopenharmony_ci * beacon tx commands. Worst case for this approach is some beacons may 564762306a36Sopenharmony_ci * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap. 564862306a36Sopenharmony_ci */ 564962306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_ADHOC || 565062306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT || 565162306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_AP) { 565262306a36Sopenharmony_ci if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) { 565362306a36Sopenharmony_ci arvif->beacon_buf = kmalloc(IEEE80211_MAX_FRAME_LEN, 565462306a36Sopenharmony_ci GFP_KERNEL); 565562306a36Sopenharmony_ci 565662306a36Sopenharmony_ci /* Using a kernel pointer in place of a dma_addr_t 565762306a36Sopenharmony_ci * token can lead to undefined behavior if that 565862306a36Sopenharmony_ci * makes it into cache management functions. Use a 565962306a36Sopenharmony_ci * known-invalid address token instead, which 566062306a36Sopenharmony_ci * avoids the warning and makes it easier to catch 566162306a36Sopenharmony_ci * bugs if it does end up getting used. 566262306a36Sopenharmony_ci */ 566362306a36Sopenharmony_ci arvif->beacon_paddr = DMA_MAPPING_ERROR; 566462306a36Sopenharmony_ci } else { 566562306a36Sopenharmony_ci arvif->beacon_buf = 566662306a36Sopenharmony_ci dma_alloc_coherent(ar->dev, 566762306a36Sopenharmony_ci IEEE80211_MAX_FRAME_LEN, 566862306a36Sopenharmony_ci &arvif->beacon_paddr, 566962306a36Sopenharmony_ci GFP_ATOMIC); 567062306a36Sopenharmony_ci } 567162306a36Sopenharmony_ci if (!arvif->beacon_buf) { 567262306a36Sopenharmony_ci ret = -ENOMEM; 567362306a36Sopenharmony_ci ath10k_warn(ar, "failed to allocate beacon buffer: %d\n", 567462306a36Sopenharmony_ci ret); 567562306a36Sopenharmony_ci goto err; 567662306a36Sopenharmony_ci } 567762306a36Sopenharmony_ci } 567862306a36Sopenharmony_ci if (test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)) 567962306a36Sopenharmony_ci arvif->nohwcrypt = true; 568062306a36Sopenharmony_ci 568162306a36Sopenharmony_ci if (arvif->nohwcrypt && 568262306a36Sopenharmony_ci !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { 568362306a36Sopenharmony_ci ret = -EINVAL; 568462306a36Sopenharmony_ci ath10k_warn(ar, "cryptmode module param needed for sw crypto\n"); 568562306a36Sopenharmony_ci goto err; 568662306a36Sopenharmony_ci } 568762306a36Sopenharmony_ci 568862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n", 568962306a36Sopenharmony_ci arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, 569062306a36Sopenharmony_ci arvif->beacon_buf ? "single-buf" : "per-skb"); 569162306a36Sopenharmony_ci 569262306a36Sopenharmony_ci ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, 569362306a36Sopenharmony_ci arvif->vdev_subtype, vif->addr); 569462306a36Sopenharmony_ci if (ret) { 569562306a36Sopenharmony_ci ath10k_warn(ar, "failed to create WMI vdev %i: %d\n", 569662306a36Sopenharmony_ci arvif->vdev_id, ret); 569762306a36Sopenharmony_ci goto err; 569862306a36Sopenharmony_ci } 569962306a36Sopenharmony_ci 570062306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_VDEV_DISABLE_4_ADDR_SRC_LRN_SUPPORT, 570162306a36Sopenharmony_ci ar->wmi.svc_map)) { 570262306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->disable_4addr_src_lrn; 570362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 570462306a36Sopenharmony_ci WMI_VDEV_DISABLE_4_ADDR_SRC_LRN); 570562306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 570662306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable 4addr src lrn vdev %i: %d\n", 570762306a36Sopenharmony_ci arvif->vdev_id, ret); 570862306a36Sopenharmony_ci } 570962306a36Sopenharmony_ci } 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_ci ar->free_vdev_map &= ~(1LL << arvif->vdev_id); 571262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 571362306a36Sopenharmony_ci list_add(&arvif->list, &ar->arvifs); 571462306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 571562306a36Sopenharmony_ci 571662306a36Sopenharmony_ci /* It makes no sense to have firmware do keepalives. mac80211 already 571762306a36Sopenharmony_ci * takes care of this with idle connection polling. 571862306a36Sopenharmony_ci */ 571962306a36Sopenharmony_ci ret = ath10k_mac_vif_disable_keepalive(arvif); 572062306a36Sopenharmony_ci if (ret) { 572162306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n", 572262306a36Sopenharmony_ci arvif->vdev_id, ret); 572362306a36Sopenharmony_ci goto err_vdev_delete; 572462306a36Sopenharmony_ci } 572562306a36Sopenharmony_ci 572662306a36Sopenharmony_ci arvif->def_wep_key_idx = -1; 572762306a36Sopenharmony_ci 572862306a36Sopenharmony_ci ath10k_update_vif_offload(hw, vif); 572962306a36Sopenharmony_ci 573062306a36Sopenharmony_ci /* Configuring number of spatial stream for monitor interface is causing 573162306a36Sopenharmony_ci * target assert in qca9888 and qca6174. 573262306a36Sopenharmony_ci */ 573362306a36Sopenharmony_ci if (ar->cfg_tx_chainmask && (vif->type != NL80211_IFTYPE_MONITOR)) { 573462306a36Sopenharmony_ci u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask); 573562306a36Sopenharmony_ci 573662306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->nss; 573762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 573862306a36Sopenharmony_ci nss); 573962306a36Sopenharmony_ci if (ret) { 574062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n", 574162306a36Sopenharmony_ci arvif->vdev_id, ar->cfg_tx_chainmask, nss, 574262306a36Sopenharmony_ci ret); 574362306a36Sopenharmony_ci goto err_vdev_delete; 574462306a36Sopenharmony_ci } 574562306a36Sopenharmony_ci } 574662306a36Sopenharmony_ci 574762306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP || 574862306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { 574962306a36Sopenharmony_ci ret = ath10k_peer_create(ar, vif, NULL, arvif->vdev_id, 575062306a36Sopenharmony_ci vif->addr, WMI_PEER_TYPE_DEFAULT); 575162306a36Sopenharmony_ci if (ret) { 575262306a36Sopenharmony_ci ath10k_warn(ar, "failed to create vdev %i peer for AP/IBSS: %d\n", 575362306a36Sopenharmony_ci arvif->vdev_id, ret); 575462306a36Sopenharmony_ci goto err_vdev_delete; 575562306a36Sopenharmony_ci } 575662306a36Sopenharmony_ci 575762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 575862306a36Sopenharmony_ci 575962306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, vif->addr); 576062306a36Sopenharmony_ci if (!peer) { 576162306a36Sopenharmony_ci ath10k_warn(ar, "failed to lookup peer %pM on vdev %i\n", 576262306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 576362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 576462306a36Sopenharmony_ci ret = -ENOENT; 576562306a36Sopenharmony_ci goto err_peer_delete; 576662306a36Sopenharmony_ci } 576762306a36Sopenharmony_ci 576862306a36Sopenharmony_ci arvif->peer_id = find_first_bit(peer->peer_ids, 576962306a36Sopenharmony_ci ATH10K_MAX_NUM_PEER_IDS); 577062306a36Sopenharmony_ci 577162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 577262306a36Sopenharmony_ci } else { 577362306a36Sopenharmony_ci arvif->peer_id = HTT_INVALID_PEERID; 577462306a36Sopenharmony_ci } 577562306a36Sopenharmony_ci 577662306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { 577762306a36Sopenharmony_ci ret = ath10k_mac_set_kickout(arvif); 577862306a36Sopenharmony_ci if (ret) { 577962306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n", 578062306a36Sopenharmony_ci arvif->vdev_id, ret); 578162306a36Sopenharmony_ci goto err_peer_delete; 578262306a36Sopenharmony_ci } 578362306a36Sopenharmony_ci } 578462306a36Sopenharmony_ci 578562306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { 578662306a36Sopenharmony_ci param = WMI_STA_PS_PARAM_RX_WAKE_POLICY; 578762306a36Sopenharmony_ci value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; 578862306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 578962306a36Sopenharmony_ci param, value); 579062306a36Sopenharmony_ci if (ret) { 579162306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n", 579262306a36Sopenharmony_ci arvif->vdev_id, ret); 579362306a36Sopenharmony_ci goto err_peer_delete; 579462306a36Sopenharmony_ci } 579562306a36Sopenharmony_ci 579662306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); 579762306a36Sopenharmony_ci if (ret) { 579862306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", 579962306a36Sopenharmony_ci arvif->vdev_id, ret); 580062306a36Sopenharmony_ci goto err_peer_delete; 580162306a36Sopenharmony_ci } 580262306a36Sopenharmony_ci 580362306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); 580462306a36Sopenharmony_ci if (ret) { 580562306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", 580662306a36Sopenharmony_ci arvif->vdev_id, ret); 580762306a36Sopenharmony_ci goto err_peer_delete; 580862306a36Sopenharmony_ci } 580962306a36Sopenharmony_ci } 581062306a36Sopenharmony_ci 581162306a36Sopenharmony_ci ret = ath10k_mac_set_txbf_conf(arvif); 581262306a36Sopenharmony_ci if (ret) { 581362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set txbf for vdev %d: %d\n", 581462306a36Sopenharmony_ci arvif->vdev_id, ret); 581562306a36Sopenharmony_ci goto err_peer_delete; 581662306a36Sopenharmony_ci } 581762306a36Sopenharmony_ci 581862306a36Sopenharmony_ci ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold); 581962306a36Sopenharmony_ci if (ret) { 582062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", 582162306a36Sopenharmony_ci arvif->vdev_id, ret); 582262306a36Sopenharmony_ci goto err_peer_delete; 582362306a36Sopenharmony_ci } 582462306a36Sopenharmony_ci 582562306a36Sopenharmony_ci arvif->txpower = vif->bss_conf.txpower; 582662306a36Sopenharmony_ci ret = ath10k_mac_txpower_recalc(ar); 582762306a36Sopenharmony_ci if (ret) { 582862306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); 582962306a36Sopenharmony_ci goto err_peer_delete; 583062306a36Sopenharmony_ci } 583162306a36Sopenharmony_ci 583262306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_RTT_RESPONDER_ROLE, ar->wmi.svc_map)) { 583362306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->rtt_responder_role; 583462306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 583562306a36Sopenharmony_ci arvif->ftm_responder); 583662306a36Sopenharmony_ci 583762306a36Sopenharmony_ci /* It is harmless to not set FTM role. Do not warn */ 583862306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) 583962306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i FTM Responder: %d\n", 584062306a36Sopenharmony_ci arvif->vdev_id, ret); 584162306a36Sopenharmony_ci } 584262306a36Sopenharmony_ci 584362306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR) { 584462306a36Sopenharmony_ci ar->monitor_arvif = arvif; 584562306a36Sopenharmony_ci ret = ath10k_monitor_recalc(ar); 584662306a36Sopenharmony_ci if (ret) { 584762306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc monitor: %d\n", ret); 584862306a36Sopenharmony_ci goto err_peer_delete; 584962306a36Sopenharmony_ci } 585062306a36Sopenharmony_ci } 585162306a36Sopenharmony_ci 585262306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 585362306a36Sopenharmony_ci if (!ar->tx_paused) 585462306a36Sopenharmony_ci ieee80211_wake_queue(ar->hw, arvif->vdev_id); 585562306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 585662306a36Sopenharmony_ci 585762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 585862306a36Sopenharmony_ci return 0; 585962306a36Sopenharmony_ci 586062306a36Sopenharmony_cierr_peer_delete: 586162306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP || 586262306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { 586362306a36Sopenharmony_ci ath10k_wmi_peer_delete(ar, arvif->vdev_id, vif->addr); 586462306a36Sopenharmony_ci ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id, 586562306a36Sopenharmony_ci vif->addr); 586662306a36Sopenharmony_ci } 586762306a36Sopenharmony_ci 586862306a36Sopenharmony_cierr_vdev_delete: 586962306a36Sopenharmony_ci ath10k_wmi_vdev_delete(ar, arvif->vdev_id); 587062306a36Sopenharmony_ci ar->free_vdev_map |= 1LL << arvif->vdev_id; 587162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 587262306a36Sopenharmony_ci list_del(&arvif->list); 587362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 587462306a36Sopenharmony_ci 587562306a36Sopenharmony_cierr: 587662306a36Sopenharmony_ci if (arvif->beacon_buf) { 587762306a36Sopenharmony_ci if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) 587862306a36Sopenharmony_ci kfree(arvif->beacon_buf); 587962306a36Sopenharmony_ci else 588062306a36Sopenharmony_ci dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, 588162306a36Sopenharmony_ci arvif->beacon_buf, 588262306a36Sopenharmony_ci arvif->beacon_paddr); 588362306a36Sopenharmony_ci arvif->beacon_buf = NULL; 588462306a36Sopenharmony_ci } 588562306a36Sopenharmony_ci 588662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 588762306a36Sopenharmony_ci 588862306a36Sopenharmony_ci return ret; 588962306a36Sopenharmony_ci} 589062306a36Sopenharmony_ci 589162306a36Sopenharmony_cistatic void ath10k_mac_vif_tx_unlock_all(struct ath10k_vif *arvif) 589262306a36Sopenharmony_ci{ 589362306a36Sopenharmony_ci int i; 589462306a36Sopenharmony_ci 589562306a36Sopenharmony_ci for (i = 0; i < BITS_PER_LONG; i++) 589662306a36Sopenharmony_ci ath10k_mac_vif_tx_unlock(arvif, i); 589762306a36Sopenharmony_ci} 589862306a36Sopenharmony_ci 589962306a36Sopenharmony_cistatic void ath10k_remove_interface(struct ieee80211_hw *hw, 590062306a36Sopenharmony_ci struct ieee80211_vif *vif) 590162306a36Sopenharmony_ci{ 590262306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 590362306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 590462306a36Sopenharmony_ci struct ath10k_peer *peer; 590562306a36Sopenharmony_ci unsigned long time_left; 590662306a36Sopenharmony_ci int ret; 590762306a36Sopenharmony_ci int i; 590862306a36Sopenharmony_ci 590962306a36Sopenharmony_ci cancel_work_sync(&arvif->ap_csa_work); 591062306a36Sopenharmony_ci cancel_delayed_work_sync(&arvif->connection_loss_work); 591162306a36Sopenharmony_ci 591262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 591362306a36Sopenharmony_ci 591462306a36Sopenharmony_ci ret = ath10k_spectral_vif_stop(arvif); 591562306a36Sopenharmony_ci if (ret) 591662306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n", 591762306a36Sopenharmony_ci arvif->vdev_id, ret); 591862306a36Sopenharmony_ci 591962306a36Sopenharmony_ci ar->free_vdev_map |= 1LL << arvif->vdev_id; 592062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 592162306a36Sopenharmony_ci list_del(&arvif->list); 592262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 592362306a36Sopenharmony_ci 592462306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP || 592562306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { 592662306a36Sopenharmony_ci ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id, 592762306a36Sopenharmony_ci vif->addr); 592862306a36Sopenharmony_ci if (ret) 592962306a36Sopenharmony_ci ath10k_warn(ar, "failed to submit AP/IBSS self-peer removal on vdev %i: %d\n", 593062306a36Sopenharmony_ci arvif->vdev_id, ret); 593162306a36Sopenharmony_ci 593262306a36Sopenharmony_ci ath10k_wait_for_peer_delete_done(ar, arvif->vdev_id, 593362306a36Sopenharmony_ci vif->addr); 593462306a36Sopenharmony_ci kfree(arvif->u.ap.noa_data); 593562306a36Sopenharmony_ci } 593662306a36Sopenharmony_ci 593762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n", 593862306a36Sopenharmony_ci arvif->vdev_id); 593962306a36Sopenharmony_ci 594062306a36Sopenharmony_ci ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id); 594162306a36Sopenharmony_ci if (ret) 594262306a36Sopenharmony_ci ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", 594362306a36Sopenharmony_ci arvif->vdev_id, ret); 594462306a36Sopenharmony_ci 594562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_SYNC_DELETE_CMDS, ar->wmi.svc_map)) { 594662306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->vdev_delete_done, 594762306a36Sopenharmony_ci ATH10K_VDEV_DELETE_TIMEOUT_HZ); 594862306a36Sopenharmony_ci if (time_left == 0) { 594962306a36Sopenharmony_ci ath10k_warn(ar, "Timeout in receiving vdev delete response\n"); 595062306a36Sopenharmony_ci goto out; 595162306a36Sopenharmony_ci } 595262306a36Sopenharmony_ci } 595362306a36Sopenharmony_ci 595462306a36Sopenharmony_ci /* Some firmware revisions don't notify host about self-peer removal 595562306a36Sopenharmony_ci * until after associated vdev is deleted. 595662306a36Sopenharmony_ci */ 595762306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP || 595862306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { 595962306a36Sopenharmony_ci ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id, 596062306a36Sopenharmony_ci vif->addr); 596162306a36Sopenharmony_ci if (ret) 596262306a36Sopenharmony_ci ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n", 596362306a36Sopenharmony_ci arvif->vdev_id, ret); 596462306a36Sopenharmony_ci 596562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 596662306a36Sopenharmony_ci ar->num_peers--; 596762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 596862306a36Sopenharmony_ci } 596962306a36Sopenharmony_ci 597062306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 597162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) { 597262306a36Sopenharmony_ci peer = ar->peer_map[i]; 597362306a36Sopenharmony_ci if (!peer) 597462306a36Sopenharmony_ci continue; 597562306a36Sopenharmony_ci 597662306a36Sopenharmony_ci if (peer->vif == vif) { 597762306a36Sopenharmony_ci ath10k_warn(ar, "found vif peer %pM entry on vdev %i after it was supposedly removed\n", 597862306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 597962306a36Sopenharmony_ci peer->vif = NULL; 598062306a36Sopenharmony_ci } 598162306a36Sopenharmony_ci } 598262306a36Sopenharmony_ci 598362306a36Sopenharmony_ci /* Clean this up late, less opportunity for firmware to access 598462306a36Sopenharmony_ci * DMA memory we have deleted. 598562306a36Sopenharmony_ci */ 598662306a36Sopenharmony_ci ath10k_mac_vif_beacon_cleanup(arvif); 598762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 598862306a36Sopenharmony_ci 598962306a36Sopenharmony_ci ath10k_peer_cleanup(ar, arvif->vdev_id); 599062306a36Sopenharmony_ci ath10k_mac_txq_unref(ar, vif->txq); 599162306a36Sopenharmony_ci 599262306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR) { 599362306a36Sopenharmony_ci ar->monitor_arvif = NULL; 599462306a36Sopenharmony_ci ret = ath10k_monitor_recalc(ar); 599562306a36Sopenharmony_ci if (ret) 599662306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc monitor: %d\n", ret); 599762306a36Sopenharmony_ci } 599862306a36Sopenharmony_ci 599962306a36Sopenharmony_ci ret = ath10k_mac_txpower_recalc(ar); 600062306a36Sopenharmony_ci if (ret) 600162306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); 600262306a36Sopenharmony_ci 600362306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 600462306a36Sopenharmony_ci ath10k_mac_vif_tx_unlock_all(arvif); 600562306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 600662306a36Sopenharmony_ci 600762306a36Sopenharmony_ci ath10k_mac_txq_unref(ar, vif->txq); 600862306a36Sopenharmony_ci 600962306a36Sopenharmony_ciout: 601062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 601162306a36Sopenharmony_ci} 601262306a36Sopenharmony_ci 601362306a36Sopenharmony_ci/* 601462306a36Sopenharmony_ci * FIXME: Has to be verified. 601562306a36Sopenharmony_ci */ 601662306a36Sopenharmony_ci#define SUPPORTED_FILTERS \ 601762306a36Sopenharmony_ci (FIF_ALLMULTI | \ 601862306a36Sopenharmony_ci FIF_CONTROL | \ 601962306a36Sopenharmony_ci FIF_PSPOLL | \ 602062306a36Sopenharmony_ci FIF_OTHER_BSS | \ 602162306a36Sopenharmony_ci FIF_BCN_PRBRESP_PROMISC | \ 602262306a36Sopenharmony_ci FIF_PROBE_REQ | \ 602362306a36Sopenharmony_ci FIF_FCSFAIL) 602462306a36Sopenharmony_ci 602562306a36Sopenharmony_cistatic void ath10k_configure_filter(struct ieee80211_hw *hw, 602662306a36Sopenharmony_ci unsigned int changed_flags, 602762306a36Sopenharmony_ci unsigned int *total_flags, 602862306a36Sopenharmony_ci u64 multicast) 602962306a36Sopenharmony_ci{ 603062306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 603162306a36Sopenharmony_ci int ret; 603262306a36Sopenharmony_ci 603362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 603462306a36Sopenharmony_ci 603562306a36Sopenharmony_ci *total_flags &= SUPPORTED_FILTERS; 603662306a36Sopenharmony_ci ar->filter_flags = *total_flags; 603762306a36Sopenharmony_ci 603862306a36Sopenharmony_ci ret = ath10k_monitor_recalc(ar); 603962306a36Sopenharmony_ci if (ret) 604062306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc monitor: %d\n", ret); 604162306a36Sopenharmony_ci 604262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 604362306a36Sopenharmony_ci} 604462306a36Sopenharmony_ci 604562306a36Sopenharmony_cistatic void ath10k_recalculate_mgmt_rate(struct ath10k *ar, 604662306a36Sopenharmony_ci struct ieee80211_vif *vif, 604762306a36Sopenharmony_ci struct cfg80211_chan_def *def) 604862306a36Sopenharmony_ci{ 604962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 605062306a36Sopenharmony_ci const struct ieee80211_supported_band *sband; 605162306a36Sopenharmony_ci u8 basic_rate_idx; 605262306a36Sopenharmony_ci int hw_rate_code; 605362306a36Sopenharmony_ci u32 vdev_param; 605462306a36Sopenharmony_ci u16 bitrate; 605562306a36Sopenharmony_ci int ret; 605662306a36Sopenharmony_ci 605762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 605862306a36Sopenharmony_ci 605962306a36Sopenharmony_ci sband = ar->hw->wiphy->bands[def->chan->band]; 606062306a36Sopenharmony_ci basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; 606162306a36Sopenharmony_ci bitrate = sband->bitrates[basic_rate_idx].bitrate; 606262306a36Sopenharmony_ci 606362306a36Sopenharmony_ci hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); 606462306a36Sopenharmony_ci if (hw_rate_code < 0) { 606562306a36Sopenharmony_ci ath10k_warn(ar, "bitrate not supported %d\n", bitrate); 606662306a36Sopenharmony_ci return; 606762306a36Sopenharmony_ci } 606862306a36Sopenharmony_ci 606962306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->mgmt_rate; 607062306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 607162306a36Sopenharmony_ci hw_rate_code); 607262306a36Sopenharmony_ci if (ret) 607362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); 607462306a36Sopenharmony_ci} 607562306a36Sopenharmony_ci 607662306a36Sopenharmony_cistatic void ath10k_bss_info_changed(struct ieee80211_hw *hw, 607762306a36Sopenharmony_ci struct ieee80211_vif *vif, 607862306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 607962306a36Sopenharmony_ci u64 changed) 608062306a36Sopenharmony_ci{ 608162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 608262306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 608362306a36Sopenharmony_ci struct cfg80211_chan_def def; 608462306a36Sopenharmony_ci u32 vdev_param, pdev_param, slottime, preamble; 608562306a36Sopenharmony_ci u16 bitrate, hw_value; 608662306a36Sopenharmony_ci u8 rate, rateidx; 608762306a36Sopenharmony_ci int ret = 0, mcast_rate; 608862306a36Sopenharmony_ci enum nl80211_band band; 608962306a36Sopenharmony_ci 609062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 609162306a36Sopenharmony_ci 609262306a36Sopenharmony_ci if (changed & BSS_CHANGED_IBSS) 609362306a36Sopenharmony_ci ath10k_control_ibss(arvif, vif); 609462306a36Sopenharmony_ci 609562306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 609662306a36Sopenharmony_ci arvif->beacon_interval = info->beacon_int; 609762306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->beacon_interval; 609862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 609962306a36Sopenharmony_ci arvif->beacon_interval); 610062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 610162306a36Sopenharmony_ci "mac vdev %d beacon_interval %d\n", 610262306a36Sopenharmony_ci arvif->vdev_id, arvif->beacon_interval); 610362306a36Sopenharmony_ci 610462306a36Sopenharmony_ci if (ret) 610562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n", 610662306a36Sopenharmony_ci arvif->vdev_id, ret); 610762306a36Sopenharmony_ci } 610862306a36Sopenharmony_ci 610962306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON) { 611062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 611162306a36Sopenharmony_ci "vdev %d set beacon tx mode to staggered\n", 611262306a36Sopenharmony_ci arvif->vdev_id); 611362306a36Sopenharmony_ci 611462306a36Sopenharmony_ci pdev_param = ar->wmi.pdev_param->beacon_tx_mode; 611562306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_param(ar, pdev_param, 611662306a36Sopenharmony_ci WMI_BEACON_STAGGERED_MODE); 611762306a36Sopenharmony_ci if (ret) 611862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n", 611962306a36Sopenharmony_ci arvif->vdev_id, ret); 612062306a36Sopenharmony_ci 612162306a36Sopenharmony_ci ret = ath10k_mac_setup_bcn_tmpl(arvif); 612262306a36Sopenharmony_ci if (ret) 612362306a36Sopenharmony_ci ath10k_warn(ar, "failed to update beacon template: %d\n", 612462306a36Sopenharmony_ci ret); 612562306a36Sopenharmony_ci 612662306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(vif)) { 612762306a36Sopenharmony_ci /* mesh doesn't use SSID but firmware needs it */ 612862306a36Sopenharmony_ci strncpy(arvif->u.ap.ssid, "mesh", 612962306a36Sopenharmony_ci sizeof(arvif->u.ap.ssid)); 613062306a36Sopenharmony_ci arvif->u.ap.ssid_len = 4; 613162306a36Sopenharmony_ci } 613262306a36Sopenharmony_ci } 613362306a36Sopenharmony_ci 613462306a36Sopenharmony_ci if (changed & BSS_CHANGED_AP_PROBE_RESP) { 613562306a36Sopenharmony_ci ret = ath10k_mac_setup_prb_tmpl(arvif); 613662306a36Sopenharmony_ci if (ret) 613762306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n", 613862306a36Sopenharmony_ci arvif->vdev_id, ret); 613962306a36Sopenharmony_ci } 614062306a36Sopenharmony_ci 614162306a36Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { 614262306a36Sopenharmony_ci arvif->dtim_period = info->dtim_period; 614362306a36Sopenharmony_ci 614462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 614562306a36Sopenharmony_ci "mac vdev %d dtim_period %d\n", 614662306a36Sopenharmony_ci arvif->vdev_id, arvif->dtim_period); 614762306a36Sopenharmony_ci 614862306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->dtim_period; 614962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 615062306a36Sopenharmony_ci arvif->dtim_period); 615162306a36Sopenharmony_ci if (ret) 615262306a36Sopenharmony_ci ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n", 615362306a36Sopenharmony_ci arvif->vdev_id, ret); 615462306a36Sopenharmony_ci } 615562306a36Sopenharmony_ci 615662306a36Sopenharmony_ci if (changed & BSS_CHANGED_SSID && 615762306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_AP) { 615862306a36Sopenharmony_ci arvif->u.ap.ssid_len = vif->cfg.ssid_len; 615962306a36Sopenharmony_ci if (vif->cfg.ssid_len) 616062306a36Sopenharmony_ci memcpy(arvif->u.ap.ssid, vif->cfg.ssid, 616162306a36Sopenharmony_ci vif->cfg.ssid_len); 616262306a36Sopenharmony_ci arvif->u.ap.hidden_ssid = info->hidden_ssid; 616362306a36Sopenharmony_ci } 616462306a36Sopenharmony_ci 616562306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) 616662306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, info->bssid); 616762306a36Sopenharmony_ci 616862306a36Sopenharmony_ci if (changed & BSS_CHANGED_FTM_RESPONDER && 616962306a36Sopenharmony_ci arvif->ftm_responder != info->ftm_responder && 617062306a36Sopenharmony_ci test_bit(WMI_SERVICE_RTT_RESPONDER_ROLE, ar->wmi.svc_map)) { 617162306a36Sopenharmony_ci arvif->ftm_responder = info->ftm_responder; 617262306a36Sopenharmony_ci 617362306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->rtt_responder_role; 617462306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 617562306a36Sopenharmony_ci arvif->ftm_responder); 617662306a36Sopenharmony_ci 617762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 617862306a36Sopenharmony_ci "mac vdev %d ftm_responder %d:ret %d\n", 617962306a36Sopenharmony_ci arvif->vdev_id, arvif->ftm_responder, ret); 618062306a36Sopenharmony_ci } 618162306a36Sopenharmony_ci 618262306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED) 618362306a36Sopenharmony_ci ath10k_control_beaconing(arvif, info); 618462306a36Sopenharmony_ci 618562306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_CTS_PROT) { 618662306a36Sopenharmony_ci arvif->use_cts_prot = info->use_cts_prot; 618762306a36Sopenharmony_ci 618862306a36Sopenharmony_ci ret = ath10k_recalc_rtscts_prot(arvif); 618962306a36Sopenharmony_ci if (ret) 619062306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", 619162306a36Sopenharmony_ci arvif->vdev_id, ret); 619262306a36Sopenharmony_ci 619362306a36Sopenharmony_ci if (ath10k_mac_can_set_cts_prot(arvif)) { 619462306a36Sopenharmony_ci ret = ath10k_mac_set_cts_prot(arvif); 619562306a36Sopenharmony_ci if (ret) 619662306a36Sopenharmony_ci ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n", 619762306a36Sopenharmony_ci arvif->vdev_id, ret); 619862306a36Sopenharmony_ci } 619962306a36Sopenharmony_ci } 620062306a36Sopenharmony_ci 620162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 620262306a36Sopenharmony_ci if (info->use_short_slot) 620362306a36Sopenharmony_ci slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */ 620462306a36Sopenharmony_ci 620562306a36Sopenharmony_ci else 620662306a36Sopenharmony_ci slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */ 620762306a36Sopenharmony_ci 620862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n", 620962306a36Sopenharmony_ci arvif->vdev_id, slottime); 621062306a36Sopenharmony_ci 621162306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->slot_time; 621262306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 621362306a36Sopenharmony_ci slottime); 621462306a36Sopenharmony_ci if (ret) 621562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n", 621662306a36Sopenharmony_ci arvif->vdev_id, ret); 621762306a36Sopenharmony_ci } 621862306a36Sopenharmony_ci 621962306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 622062306a36Sopenharmony_ci if (info->use_short_preamble) 622162306a36Sopenharmony_ci preamble = WMI_VDEV_PREAMBLE_SHORT; 622262306a36Sopenharmony_ci else 622362306a36Sopenharmony_ci preamble = WMI_VDEV_PREAMBLE_LONG; 622462306a36Sopenharmony_ci 622562306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 622662306a36Sopenharmony_ci "mac vdev %d preamble %dn", 622762306a36Sopenharmony_ci arvif->vdev_id, preamble); 622862306a36Sopenharmony_ci 622962306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->preamble; 623062306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 623162306a36Sopenharmony_ci preamble); 623262306a36Sopenharmony_ci if (ret) 623362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n", 623462306a36Sopenharmony_ci arvif->vdev_id, ret); 623562306a36Sopenharmony_ci } 623662306a36Sopenharmony_ci 623762306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 623862306a36Sopenharmony_ci if (vif->cfg.assoc) { 623962306a36Sopenharmony_ci /* Workaround: Make sure monitor vdev is not running 624062306a36Sopenharmony_ci * when associating to prevent some firmware revisions 624162306a36Sopenharmony_ci * (e.g. 10.1 and 10.2) from crashing. 624262306a36Sopenharmony_ci */ 624362306a36Sopenharmony_ci if (ar->monitor_started) 624462306a36Sopenharmony_ci ath10k_monitor_stop(ar); 624562306a36Sopenharmony_ci ath10k_bss_assoc(hw, vif, info); 624662306a36Sopenharmony_ci ath10k_monitor_recalc(ar); 624762306a36Sopenharmony_ci } else { 624862306a36Sopenharmony_ci ath10k_bss_disassoc(hw, vif); 624962306a36Sopenharmony_ci } 625062306a36Sopenharmony_ci } 625162306a36Sopenharmony_ci 625262306a36Sopenharmony_ci if (changed & BSS_CHANGED_TXPOWER) { 625362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n", 625462306a36Sopenharmony_ci arvif->vdev_id, info->txpower); 625562306a36Sopenharmony_ci 625662306a36Sopenharmony_ci arvif->txpower = info->txpower; 625762306a36Sopenharmony_ci ret = ath10k_mac_txpower_recalc(ar); 625862306a36Sopenharmony_ci if (ret) 625962306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); 626062306a36Sopenharmony_ci } 626162306a36Sopenharmony_ci 626262306a36Sopenharmony_ci if (changed & BSS_CHANGED_PS) { 626362306a36Sopenharmony_ci arvif->ps = vif->cfg.ps; 626462306a36Sopenharmony_ci 626562306a36Sopenharmony_ci ret = ath10k_config_ps(ar); 626662306a36Sopenharmony_ci if (ret) 626762306a36Sopenharmony_ci ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", 626862306a36Sopenharmony_ci arvif->vdev_id, ret); 626962306a36Sopenharmony_ci } 627062306a36Sopenharmony_ci 627162306a36Sopenharmony_ci if (changed & BSS_CHANGED_MCAST_RATE && 627262306a36Sopenharmony_ci !ath10k_mac_vif_chan(arvif->vif, &def)) { 627362306a36Sopenharmony_ci band = def.chan->band; 627462306a36Sopenharmony_ci mcast_rate = vif->bss_conf.mcast_rate[band]; 627562306a36Sopenharmony_ci if (mcast_rate > 0) 627662306a36Sopenharmony_ci rateidx = mcast_rate - 1; 627762306a36Sopenharmony_ci else 627862306a36Sopenharmony_ci rateidx = ffs(vif->bss_conf.basic_rates) - 1; 627962306a36Sopenharmony_ci 628062306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) 628162306a36Sopenharmony_ci rateidx += ATH10K_MAC_FIRST_OFDM_RATE_IDX; 628262306a36Sopenharmony_ci 628362306a36Sopenharmony_ci bitrate = ath10k_wmi_legacy_rates[rateidx].bitrate; 628462306a36Sopenharmony_ci hw_value = ath10k_wmi_legacy_rates[rateidx].hw_value; 628562306a36Sopenharmony_ci if (ath10k_mac_bitrate_is_cck(bitrate)) 628662306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_CCK; 628762306a36Sopenharmony_ci else 628862306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_OFDM; 628962306a36Sopenharmony_ci 629062306a36Sopenharmony_ci rate = ATH10K_HW_RATECODE(hw_value, 0, preamble); 629162306a36Sopenharmony_ci 629262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 629362306a36Sopenharmony_ci "mac vdev %d mcast_rate %x\n", 629462306a36Sopenharmony_ci arvif->vdev_id, rate); 629562306a36Sopenharmony_ci 629662306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->mcast_data_rate; 629762306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, 629862306a36Sopenharmony_ci vdev_param, rate); 629962306a36Sopenharmony_ci if (ret) 630062306a36Sopenharmony_ci ath10k_warn(ar, 630162306a36Sopenharmony_ci "failed to set mcast rate on vdev %i: %d\n", 630262306a36Sopenharmony_ci arvif->vdev_id, ret); 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->bcast_data_rate; 630562306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, 630662306a36Sopenharmony_ci vdev_param, rate); 630762306a36Sopenharmony_ci if (ret) 630862306a36Sopenharmony_ci ath10k_warn(ar, 630962306a36Sopenharmony_ci "failed to set bcast rate on vdev %i: %d\n", 631062306a36Sopenharmony_ci arvif->vdev_id, ret); 631162306a36Sopenharmony_ci } 631262306a36Sopenharmony_ci 631362306a36Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES && 631462306a36Sopenharmony_ci !ath10k_mac_vif_chan(arvif->vif, &def)) 631562306a36Sopenharmony_ci ath10k_recalculate_mgmt_rate(ar, vif, &def); 631662306a36Sopenharmony_ci 631762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 631862306a36Sopenharmony_ci} 631962306a36Sopenharmony_ci 632062306a36Sopenharmony_cistatic void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, s16 value) 632162306a36Sopenharmony_ci{ 632262306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 632362306a36Sopenharmony_ci 632462306a36Sopenharmony_ci /* This function should never be called if setting the coverage class 632562306a36Sopenharmony_ci * is not supported on this hardware. 632662306a36Sopenharmony_ci */ 632762306a36Sopenharmony_ci if (!ar->hw_params.hw_ops->set_coverage_class) { 632862306a36Sopenharmony_ci WARN_ON_ONCE(1); 632962306a36Sopenharmony_ci return; 633062306a36Sopenharmony_ci } 633162306a36Sopenharmony_ci ar->hw_params.hw_ops->set_coverage_class(ar, value); 633262306a36Sopenharmony_ci} 633362306a36Sopenharmony_ci 633462306a36Sopenharmony_cistruct ath10k_mac_tdls_iter_data { 633562306a36Sopenharmony_ci u32 num_tdls_stations; 633662306a36Sopenharmony_ci struct ieee80211_vif *curr_vif; 633762306a36Sopenharmony_ci}; 633862306a36Sopenharmony_ci 633962306a36Sopenharmony_cistatic void ath10k_mac_tdls_vif_stations_count_iter(void *data, 634062306a36Sopenharmony_ci struct ieee80211_sta *sta) 634162306a36Sopenharmony_ci{ 634262306a36Sopenharmony_ci struct ath10k_mac_tdls_iter_data *iter_data = data; 634362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 634462306a36Sopenharmony_ci struct ieee80211_vif *sta_vif = arsta->arvif->vif; 634562306a36Sopenharmony_ci 634662306a36Sopenharmony_ci if (sta->tdls && sta_vif == iter_data->curr_vif) 634762306a36Sopenharmony_ci iter_data->num_tdls_stations++; 634862306a36Sopenharmony_ci} 634962306a36Sopenharmony_ci 635062306a36Sopenharmony_cistatic int ath10k_mac_tdls_vif_stations_count(struct ieee80211_hw *hw, 635162306a36Sopenharmony_ci struct ieee80211_vif *vif) 635262306a36Sopenharmony_ci{ 635362306a36Sopenharmony_ci struct ath10k_mac_tdls_iter_data data = {}; 635462306a36Sopenharmony_ci 635562306a36Sopenharmony_ci data.curr_vif = vif; 635662306a36Sopenharmony_ci 635762306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, 635862306a36Sopenharmony_ci ath10k_mac_tdls_vif_stations_count_iter, 635962306a36Sopenharmony_ci &data); 636062306a36Sopenharmony_ci return data.num_tdls_stations; 636162306a36Sopenharmony_ci} 636262306a36Sopenharmony_ci 636362306a36Sopenharmony_cistatic int ath10k_hw_scan(struct ieee80211_hw *hw, 636462306a36Sopenharmony_ci struct ieee80211_vif *vif, 636562306a36Sopenharmony_ci struct ieee80211_scan_request *hw_req) 636662306a36Sopenharmony_ci{ 636762306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 636862306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 636962306a36Sopenharmony_ci struct cfg80211_scan_request *req = &hw_req->req; 637062306a36Sopenharmony_ci struct wmi_start_scan_arg arg; 637162306a36Sopenharmony_ci int ret = 0; 637262306a36Sopenharmony_ci int i; 637362306a36Sopenharmony_ci u32 scan_timeout; 637462306a36Sopenharmony_ci 637562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 637662306a36Sopenharmony_ci 637762306a36Sopenharmony_ci if (ath10k_mac_tdls_vif_stations_count(hw, vif) > 0) { 637862306a36Sopenharmony_ci ret = -EBUSY; 637962306a36Sopenharmony_ci goto exit; 638062306a36Sopenharmony_ci } 638162306a36Sopenharmony_ci 638262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 638362306a36Sopenharmony_ci switch (ar->scan.state) { 638462306a36Sopenharmony_ci case ATH10K_SCAN_IDLE: 638562306a36Sopenharmony_ci reinit_completion(&ar->scan.started); 638662306a36Sopenharmony_ci reinit_completion(&ar->scan.completed); 638762306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_STARTING; 638862306a36Sopenharmony_ci ar->scan.is_roc = false; 638962306a36Sopenharmony_ci ar->scan.vdev_id = arvif->vdev_id; 639062306a36Sopenharmony_ci ret = 0; 639162306a36Sopenharmony_ci break; 639262306a36Sopenharmony_ci case ATH10K_SCAN_STARTING: 639362306a36Sopenharmony_ci case ATH10K_SCAN_RUNNING: 639462306a36Sopenharmony_ci case ATH10K_SCAN_ABORTING: 639562306a36Sopenharmony_ci ret = -EBUSY; 639662306a36Sopenharmony_ci break; 639762306a36Sopenharmony_ci } 639862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 639962306a36Sopenharmony_ci 640062306a36Sopenharmony_ci if (ret) 640162306a36Sopenharmony_ci goto exit; 640262306a36Sopenharmony_ci 640362306a36Sopenharmony_ci memset(&arg, 0, sizeof(arg)); 640462306a36Sopenharmony_ci ath10k_wmi_start_scan_init(ar, &arg); 640562306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 640662306a36Sopenharmony_ci arg.scan_id = ATH10K_SCAN_ID; 640762306a36Sopenharmony_ci 640862306a36Sopenharmony_ci if (req->ie_len) { 640962306a36Sopenharmony_ci arg.ie_len = req->ie_len; 641062306a36Sopenharmony_ci memcpy(arg.ie, req->ie, arg.ie_len); 641162306a36Sopenharmony_ci } 641262306a36Sopenharmony_ci 641362306a36Sopenharmony_ci if (req->n_ssids) { 641462306a36Sopenharmony_ci arg.n_ssids = req->n_ssids; 641562306a36Sopenharmony_ci for (i = 0; i < arg.n_ssids; i++) { 641662306a36Sopenharmony_ci arg.ssids[i].len = req->ssids[i].ssid_len; 641762306a36Sopenharmony_ci arg.ssids[i].ssid = req->ssids[i].ssid; 641862306a36Sopenharmony_ci } 641962306a36Sopenharmony_ci } else { 642062306a36Sopenharmony_ci arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; 642162306a36Sopenharmony_ci } 642262306a36Sopenharmony_ci 642362306a36Sopenharmony_ci if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { 642462306a36Sopenharmony_ci arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; 642562306a36Sopenharmony_ci ether_addr_copy(arg.mac_addr.addr, req->mac_addr); 642662306a36Sopenharmony_ci ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); 642762306a36Sopenharmony_ci } 642862306a36Sopenharmony_ci 642962306a36Sopenharmony_ci if (req->n_channels) { 643062306a36Sopenharmony_ci arg.n_channels = req->n_channels; 643162306a36Sopenharmony_ci for (i = 0; i < arg.n_channels; i++) 643262306a36Sopenharmony_ci arg.channels[i] = req->channels[i]->center_freq; 643362306a36Sopenharmony_ci } 643462306a36Sopenharmony_ci 643562306a36Sopenharmony_ci /* if duration is set, default dwell times will be overwritten */ 643662306a36Sopenharmony_ci if (req->duration) { 643762306a36Sopenharmony_ci arg.dwell_time_active = req->duration; 643862306a36Sopenharmony_ci arg.dwell_time_passive = req->duration; 643962306a36Sopenharmony_ci arg.burst_duration_ms = req->duration; 644062306a36Sopenharmony_ci 644162306a36Sopenharmony_ci scan_timeout = min_t(u32, arg.max_rest_time * 644262306a36Sopenharmony_ci (arg.n_channels - 1) + (req->duration + 644362306a36Sopenharmony_ci ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * 644462306a36Sopenharmony_ci arg.n_channels, arg.max_scan_time); 644562306a36Sopenharmony_ci } else { 644662306a36Sopenharmony_ci scan_timeout = arg.max_scan_time; 644762306a36Sopenharmony_ci } 644862306a36Sopenharmony_ci 644962306a36Sopenharmony_ci /* Add a 200ms margin to account for event/command processing */ 645062306a36Sopenharmony_ci scan_timeout += 200; 645162306a36Sopenharmony_ci 645262306a36Sopenharmony_ci ret = ath10k_start_scan(ar, &arg); 645362306a36Sopenharmony_ci if (ret) { 645462306a36Sopenharmony_ci ath10k_warn(ar, "failed to start hw scan: %d\n", ret); 645562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 645662306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_IDLE; 645762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 645862306a36Sopenharmony_ci } 645962306a36Sopenharmony_ci 646062306a36Sopenharmony_ci ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, 646162306a36Sopenharmony_ci msecs_to_jiffies(scan_timeout)); 646262306a36Sopenharmony_ci 646362306a36Sopenharmony_ciexit: 646462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 646562306a36Sopenharmony_ci return ret; 646662306a36Sopenharmony_ci} 646762306a36Sopenharmony_ci 646862306a36Sopenharmony_cistatic void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, 646962306a36Sopenharmony_ci struct ieee80211_vif *vif) 647062306a36Sopenharmony_ci{ 647162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 647262306a36Sopenharmony_ci 647362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 647462306a36Sopenharmony_ci ath10k_scan_abort(ar); 647562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 647662306a36Sopenharmony_ci 647762306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->scan.timeout); 647862306a36Sopenharmony_ci} 647962306a36Sopenharmony_ci 648062306a36Sopenharmony_cistatic void ath10k_set_key_h_def_keyidx(struct ath10k *ar, 648162306a36Sopenharmony_ci struct ath10k_vif *arvif, 648262306a36Sopenharmony_ci enum set_key_cmd cmd, 648362306a36Sopenharmony_ci struct ieee80211_key_conf *key) 648462306a36Sopenharmony_ci{ 648562306a36Sopenharmony_ci u32 vdev_param = arvif->ar->wmi.vdev_param->def_keyid; 648662306a36Sopenharmony_ci int ret; 648762306a36Sopenharmony_ci 648862306a36Sopenharmony_ci /* 10.1 firmware branch requires default key index to be set to group 648962306a36Sopenharmony_ci * key index after installing it. Otherwise FW/HW Txes corrupted 649062306a36Sopenharmony_ci * frames with multi-vif APs. This is not required for main firmware 649162306a36Sopenharmony_ci * branch (e.g. 636). 649262306a36Sopenharmony_ci * 649362306a36Sopenharmony_ci * This is also needed for 636 fw for IBSS-RSN to work more reliably. 649462306a36Sopenharmony_ci * 649562306a36Sopenharmony_ci * FIXME: It remains unknown if this is required for multi-vif STA 649662306a36Sopenharmony_ci * interfaces on 10.1. 649762306a36Sopenharmony_ci */ 649862306a36Sopenharmony_ci 649962306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_AP && 650062306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_IBSS) 650162306a36Sopenharmony_ci return; 650262306a36Sopenharmony_ci 650362306a36Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_WEP40) 650462306a36Sopenharmony_ci return; 650562306a36Sopenharmony_ci 650662306a36Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_WEP104) 650762306a36Sopenharmony_ci return; 650862306a36Sopenharmony_ci 650962306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 651062306a36Sopenharmony_ci return; 651162306a36Sopenharmony_ci 651262306a36Sopenharmony_ci if (cmd != SET_KEY) 651362306a36Sopenharmony_ci return; 651462306a36Sopenharmony_ci 651562306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, 651662306a36Sopenharmony_ci key->keyidx); 651762306a36Sopenharmony_ci if (ret) 651862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n", 651962306a36Sopenharmony_ci arvif->vdev_id, ret); 652062306a36Sopenharmony_ci} 652162306a36Sopenharmony_ci 652262306a36Sopenharmony_cistatic int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 652362306a36Sopenharmony_ci struct ieee80211_vif *vif, struct ieee80211_sta *sta, 652462306a36Sopenharmony_ci struct ieee80211_key_conf *key) 652562306a36Sopenharmony_ci{ 652662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 652762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 652862306a36Sopenharmony_ci struct ath10k_sta *arsta; 652962306a36Sopenharmony_ci struct ath10k_peer *peer; 653062306a36Sopenharmony_ci const u8 *peer_addr; 653162306a36Sopenharmony_ci bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 || 653262306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_WEP104; 653362306a36Sopenharmony_ci int ret = 0; 653462306a36Sopenharmony_ci int ret2; 653562306a36Sopenharmony_ci u32 flags = 0; 653662306a36Sopenharmony_ci u32 flags2; 653762306a36Sopenharmony_ci 653862306a36Sopenharmony_ci /* this one needs to be done in software */ 653962306a36Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || 654062306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || 654162306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || 654262306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) 654362306a36Sopenharmony_ci return 1; 654462306a36Sopenharmony_ci 654562306a36Sopenharmony_ci if (arvif->nohwcrypt) 654662306a36Sopenharmony_ci return 1; 654762306a36Sopenharmony_ci 654862306a36Sopenharmony_ci if (key->keyidx > WMI_MAX_KEY_INDEX) 654962306a36Sopenharmony_ci return -ENOSPC; 655062306a36Sopenharmony_ci 655162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 655262306a36Sopenharmony_ci 655362306a36Sopenharmony_ci if (sta) { 655462306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 655562306a36Sopenharmony_ci peer_addr = sta->addr; 655662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 655762306a36Sopenharmony_ci arsta->ucast_cipher = key->cipher; 655862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 655962306a36Sopenharmony_ci } else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { 656062306a36Sopenharmony_ci peer_addr = vif->bss_conf.bssid; 656162306a36Sopenharmony_ci } else { 656262306a36Sopenharmony_ci peer_addr = vif->addr; 656362306a36Sopenharmony_ci } 656462306a36Sopenharmony_ci 656562306a36Sopenharmony_ci key->hw_key_idx = key->keyidx; 656662306a36Sopenharmony_ci 656762306a36Sopenharmony_ci if (is_wep) { 656862306a36Sopenharmony_ci if (cmd == SET_KEY) 656962306a36Sopenharmony_ci arvif->wep_keys[key->keyidx] = key; 657062306a36Sopenharmony_ci else 657162306a36Sopenharmony_ci arvif->wep_keys[key->keyidx] = NULL; 657262306a36Sopenharmony_ci } 657362306a36Sopenharmony_ci 657462306a36Sopenharmony_ci /* the peer should not disappear in mid-way (unless FW goes awry) since 657562306a36Sopenharmony_ci * we already hold conf_mutex. we just make sure its there now. 657662306a36Sopenharmony_ci */ 657762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 657862306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr); 657962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 658062306a36Sopenharmony_ci 658162306a36Sopenharmony_ci if (!peer) { 658262306a36Sopenharmony_ci if (cmd == SET_KEY) { 658362306a36Sopenharmony_ci ath10k_warn(ar, "failed to install key for non-existent peer %pM\n", 658462306a36Sopenharmony_ci peer_addr); 658562306a36Sopenharmony_ci ret = -EOPNOTSUPP; 658662306a36Sopenharmony_ci goto exit; 658762306a36Sopenharmony_ci } else { 658862306a36Sopenharmony_ci /* if the peer doesn't exist there is no key to disable anymore */ 658962306a36Sopenharmony_ci goto exit; 659062306a36Sopenharmony_ci } 659162306a36Sopenharmony_ci } 659262306a36Sopenharmony_ci 659362306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 659462306a36Sopenharmony_ci flags |= WMI_KEY_PAIRWISE; 659562306a36Sopenharmony_ci else 659662306a36Sopenharmony_ci flags |= WMI_KEY_GROUP; 659762306a36Sopenharmony_ci 659862306a36Sopenharmony_ci if (is_wep) { 659962306a36Sopenharmony_ci if (cmd == DISABLE_KEY) 660062306a36Sopenharmony_ci ath10k_clear_vdev_key(arvif, key); 660162306a36Sopenharmony_ci 660262306a36Sopenharmony_ci /* When WEP keys are uploaded it's possible that there are 660362306a36Sopenharmony_ci * stations associated already (e.g. when merging) without any 660462306a36Sopenharmony_ci * keys. Static WEP needs an explicit per-peer key upload. 660562306a36Sopenharmony_ci */ 660662306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_ADHOC && 660762306a36Sopenharmony_ci cmd == SET_KEY) 660862306a36Sopenharmony_ci ath10k_mac_vif_update_wep_key(arvif, key); 660962306a36Sopenharmony_ci 661062306a36Sopenharmony_ci /* 802.1x never sets the def_wep_key_idx so each set_key() 661162306a36Sopenharmony_ci * call changes default tx key. 661262306a36Sopenharmony_ci * 661362306a36Sopenharmony_ci * Static WEP sets def_wep_key_idx via .set_default_unicast_key 661462306a36Sopenharmony_ci * after first set_key(). 661562306a36Sopenharmony_ci */ 661662306a36Sopenharmony_ci if (cmd == SET_KEY && arvif->def_wep_key_idx == -1) 661762306a36Sopenharmony_ci flags |= WMI_KEY_TX_USAGE; 661862306a36Sopenharmony_ci } 661962306a36Sopenharmony_ci 662062306a36Sopenharmony_ci ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags); 662162306a36Sopenharmony_ci if (ret) { 662262306a36Sopenharmony_ci WARN_ON(ret > 0); 662362306a36Sopenharmony_ci ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", 662462306a36Sopenharmony_ci arvif->vdev_id, peer_addr, ret); 662562306a36Sopenharmony_ci goto exit; 662662306a36Sopenharmony_ci } 662762306a36Sopenharmony_ci 662862306a36Sopenharmony_ci /* mac80211 sets static WEP keys as groupwise while firmware requires 662962306a36Sopenharmony_ci * them to be installed twice as both pairwise and groupwise. 663062306a36Sopenharmony_ci */ 663162306a36Sopenharmony_ci if (is_wep && !sta && vif->type == NL80211_IFTYPE_STATION) { 663262306a36Sopenharmony_ci flags2 = flags; 663362306a36Sopenharmony_ci flags2 &= ~WMI_KEY_GROUP; 663462306a36Sopenharmony_ci flags2 |= WMI_KEY_PAIRWISE; 663562306a36Sopenharmony_ci 663662306a36Sopenharmony_ci ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2); 663762306a36Sopenharmony_ci if (ret) { 663862306a36Sopenharmony_ci WARN_ON(ret > 0); 663962306a36Sopenharmony_ci ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n", 664062306a36Sopenharmony_ci arvif->vdev_id, peer_addr, ret); 664162306a36Sopenharmony_ci ret2 = ath10k_install_key(arvif, key, DISABLE_KEY, 664262306a36Sopenharmony_ci peer_addr, flags); 664362306a36Sopenharmony_ci if (ret2) { 664462306a36Sopenharmony_ci WARN_ON(ret2 > 0); 664562306a36Sopenharmony_ci ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n", 664662306a36Sopenharmony_ci arvif->vdev_id, peer_addr, ret2); 664762306a36Sopenharmony_ci } 664862306a36Sopenharmony_ci goto exit; 664962306a36Sopenharmony_ci } 665062306a36Sopenharmony_ci } 665162306a36Sopenharmony_ci 665262306a36Sopenharmony_ci ath10k_set_key_h_def_keyidx(ar, arvif, cmd, key); 665362306a36Sopenharmony_ci 665462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 665562306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, peer_addr); 665662306a36Sopenharmony_ci if (peer && cmd == SET_KEY) 665762306a36Sopenharmony_ci peer->keys[key->keyidx] = key; 665862306a36Sopenharmony_ci else if (peer && cmd == DISABLE_KEY) 665962306a36Sopenharmony_ci peer->keys[key->keyidx] = NULL; 666062306a36Sopenharmony_ci else if (peer == NULL) 666162306a36Sopenharmony_ci /* impossible unless FW goes crazy */ 666262306a36Sopenharmony_ci ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr); 666362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 666462306a36Sopenharmony_ci 666562306a36Sopenharmony_ci if (sta && sta->tdls) 666662306a36Sopenharmony_ci ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 666762306a36Sopenharmony_ci ar->wmi.peer_param->authorize, 1); 666862306a36Sopenharmony_ci else if (sta && cmd == SET_KEY && (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 666962306a36Sopenharmony_ci ath10k_wmi_peer_set_param(ar, arvif->vdev_id, peer_addr, 667062306a36Sopenharmony_ci ar->wmi.peer_param->authorize, 1); 667162306a36Sopenharmony_ci 667262306a36Sopenharmony_ciexit: 667362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 667462306a36Sopenharmony_ci return ret; 667562306a36Sopenharmony_ci} 667662306a36Sopenharmony_ci 667762306a36Sopenharmony_cistatic void ath10k_set_default_unicast_key(struct ieee80211_hw *hw, 667862306a36Sopenharmony_ci struct ieee80211_vif *vif, 667962306a36Sopenharmony_ci int keyidx) 668062306a36Sopenharmony_ci{ 668162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 668262306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 668362306a36Sopenharmony_ci int ret; 668462306a36Sopenharmony_ci 668562306a36Sopenharmony_ci mutex_lock(&arvif->ar->conf_mutex); 668662306a36Sopenharmony_ci 668762306a36Sopenharmony_ci if (arvif->ar->state != ATH10K_STATE_ON) 668862306a36Sopenharmony_ci goto unlock; 668962306a36Sopenharmony_ci 669062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n", 669162306a36Sopenharmony_ci arvif->vdev_id, keyidx); 669262306a36Sopenharmony_ci 669362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(arvif->ar, 669462306a36Sopenharmony_ci arvif->vdev_id, 669562306a36Sopenharmony_ci arvif->ar->wmi.vdev_param->def_keyid, 669662306a36Sopenharmony_ci keyidx); 669762306a36Sopenharmony_ci 669862306a36Sopenharmony_ci if (ret) { 669962306a36Sopenharmony_ci ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n", 670062306a36Sopenharmony_ci arvif->vdev_id, 670162306a36Sopenharmony_ci ret); 670262306a36Sopenharmony_ci goto unlock; 670362306a36Sopenharmony_ci } 670462306a36Sopenharmony_ci 670562306a36Sopenharmony_ci arvif->def_wep_key_idx = keyidx; 670662306a36Sopenharmony_ci 670762306a36Sopenharmony_ciunlock: 670862306a36Sopenharmony_ci mutex_unlock(&arvif->ar->conf_mutex); 670962306a36Sopenharmony_ci} 671062306a36Sopenharmony_ci 671162306a36Sopenharmony_cistatic void ath10k_sta_rc_update_wk(struct work_struct *wk) 671262306a36Sopenharmony_ci{ 671362306a36Sopenharmony_ci struct ath10k *ar; 671462306a36Sopenharmony_ci struct ath10k_vif *arvif; 671562306a36Sopenharmony_ci struct ath10k_sta *arsta; 671662306a36Sopenharmony_ci struct ieee80211_sta *sta; 671762306a36Sopenharmony_ci struct cfg80211_chan_def def; 671862306a36Sopenharmony_ci enum nl80211_band band; 671962306a36Sopenharmony_ci const u8 *ht_mcs_mask; 672062306a36Sopenharmony_ci const u16 *vht_mcs_mask; 672162306a36Sopenharmony_ci u32 changed, bw, nss, smps; 672262306a36Sopenharmony_ci int err; 672362306a36Sopenharmony_ci 672462306a36Sopenharmony_ci arsta = container_of(wk, struct ath10k_sta, update_wk); 672562306a36Sopenharmony_ci sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); 672662306a36Sopenharmony_ci arvif = arsta->arvif; 672762306a36Sopenharmony_ci ar = arvif->ar; 672862306a36Sopenharmony_ci 672962306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) 673062306a36Sopenharmony_ci return; 673162306a36Sopenharmony_ci 673262306a36Sopenharmony_ci band = def.chan->band; 673362306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 673462306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 673562306a36Sopenharmony_ci 673662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 673762306a36Sopenharmony_ci 673862306a36Sopenharmony_ci changed = arsta->changed; 673962306a36Sopenharmony_ci arsta->changed = 0; 674062306a36Sopenharmony_ci 674162306a36Sopenharmony_ci bw = arsta->bw; 674262306a36Sopenharmony_ci nss = arsta->nss; 674362306a36Sopenharmony_ci smps = arsta->smps; 674462306a36Sopenharmony_ci 674562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 674662306a36Sopenharmony_ci 674762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 674862306a36Sopenharmony_ci 674962306a36Sopenharmony_ci nss = max_t(u32, 1, nss); 675062306a36Sopenharmony_ci nss = min(nss, max(ath10k_mac_max_ht_nss(ht_mcs_mask), 675162306a36Sopenharmony_ci ath10k_mac_max_vht_nss(vht_mcs_mask))); 675262306a36Sopenharmony_ci 675362306a36Sopenharmony_ci if (changed & IEEE80211_RC_BW_CHANGED) { 675462306a36Sopenharmony_ci enum wmi_phy_mode mode; 675562306a36Sopenharmony_ci 675662306a36Sopenharmony_ci mode = chan_to_phymode(&def); 675762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac update sta %pM peer bw %d phymode %d\n", 675862306a36Sopenharmony_ci sta->addr, bw, mode); 675962306a36Sopenharmony_ci 676062306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 676162306a36Sopenharmony_ci ar->wmi.peer_param->phymode, mode); 676262306a36Sopenharmony_ci if (err) { 676362306a36Sopenharmony_ci ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n", 676462306a36Sopenharmony_ci sta->addr, mode, err); 676562306a36Sopenharmony_ci goto exit; 676662306a36Sopenharmony_ci } 676762306a36Sopenharmony_ci 676862306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 676962306a36Sopenharmony_ci ar->wmi.peer_param->chan_width, bw); 677062306a36Sopenharmony_ci if (err) 677162306a36Sopenharmony_ci ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", 677262306a36Sopenharmony_ci sta->addr, bw, err); 677362306a36Sopenharmony_ci } 677462306a36Sopenharmony_ci 677562306a36Sopenharmony_ci if (changed & IEEE80211_RC_NSS_CHANGED) { 677662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac update sta %pM nss %d\n", 677762306a36Sopenharmony_ci sta->addr, nss); 677862306a36Sopenharmony_ci 677962306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 678062306a36Sopenharmony_ci ar->wmi.peer_param->nss, nss); 678162306a36Sopenharmony_ci if (err) 678262306a36Sopenharmony_ci ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", 678362306a36Sopenharmony_ci sta->addr, nss, err); 678462306a36Sopenharmony_ci } 678562306a36Sopenharmony_ci 678662306a36Sopenharmony_ci if (changed & IEEE80211_RC_SMPS_CHANGED) { 678762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac update sta %pM smps %d\n", 678862306a36Sopenharmony_ci sta->addr, smps); 678962306a36Sopenharmony_ci 679062306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 679162306a36Sopenharmony_ci ar->wmi.peer_param->smps_state, smps); 679262306a36Sopenharmony_ci if (err) 679362306a36Sopenharmony_ci ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", 679462306a36Sopenharmony_ci sta->addr, smps, err); 679562306a36Sopenharmony_ci } 679662306a36Sopenharmony_ci 679762306a36Sopenharmony_ci if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { 679862306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac update sta %pM supp rates\n", 679962306a36Sopenharmony_ci sta->addr); 680062306a36Sopenharmony_ci 680162306a36Sopenharmony_ci err = ath10k_station_assoc(ar, arvif->vif, sta, true); 680262306a36Sopenharmony_ci if (err) 680362306a36Sopenharmony_ci ath10k_warn(ar, "failed to reassociate station: %pM\n", 680462306a36Sopenharmony_ci sta->addr); 680562306a36Sopenharmony_ci } 680662306a36Sopenharmony_ci 680762306a36Sopenharmony_ciexit: 680862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 680962306a36Sopenharmony_ci} 681062306a36Sopenharmony_ci 681162306a36Sopenharmony_cistatic int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif, 681262306a36Sopenharmony_ci struct ieee80211_sta *sta) 681362306a36Sopenharmony_ci{ 681462306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 681562306a36Sopenharmony_ci 681662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 681762306a36Sopenharmony_ci 681862306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) 681962306a36Sopenharmony_ci return 0; 682062306a36Sopenharmony_ci 682162306a36Sopenharmony_ci if (ar->num_stations >= ar->max_num_stations) 682262306a36Sopenharmony_ci return -ENOBUFS; 682362306a36Sopenharmony_ci 682462306a36Sopenharmony_ci ar->num_stations++; 682562306a36Sopenharmony_ci 682662306a36Sopenharmony_ci return 0; 682762306a36Sopenharmony_ci} 682862306a36Sopenharmony_ci 682962306a36Sopenharmony_cistatic void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif, 683062306a36Sopenharmony_ci struct ieee80211_sta *sta) 683162306a36Sopenharmony_ci{ 683262306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 683362306a36Sopenharmony_ci 683462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 683562306a36Sopenharmony_ci 683662306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) 683762306a36Sopenharmony_ci return; 683862306a36Sopenharmony_ci 683962306a36Sopenharmony_ci ar->num_stations--; 684062306a36Sopenharmony_ci} 684162306a36Sopenharmony_ci 684262306a36Sopenharmony_cistatic int ath10k_sta_set_txpwr(struct ieee80211_hw *hw, 684362306a36Sopenharmony_ci struct ieee80211_vif *vif, 684462306a36Sopenharmony_ci struct ieee80211_sta *sta) 684562306a36Sopenharmony_ci{ 684662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 684762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 684862306a36Sopenharmony_ci int ret = 0; 684962306a36Sopenharmony_ci s16 txpwr; 685062306a36Sopenharmony_ci 685162306a36Sopenharmony_ci if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) { 685262306a36Sopenharmony_ci txpwr = 0; 685362306a36Sopenharmony_ci } else { 685462306a36Sopenharmony_ci txpwr = sta->deflink.txpwr.power; 685562306a36Sopenharmony_ci if (!txpwr) 685662306a36Sopenharmony_ci return -EINVAL; 685762306a36Sopenharmony_ci } 685862306a36Sopenharmony_ci 685962306a36Sopenharmony_ci if (txpwr > ATH10K_TX_POWER_MAX_VAL || txpwr < ATH10K_TX_POWER_MIN_VAL) 686062306a36Sopenharmony_ci return -EINVAL; 686162306a36Sopenharmony_ci 686262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 686362306a36Sopenharmony_ci 686462306a36Sopenharmony_ci ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 686562306a36Sopenharmony_ci ar->wmi.peer_param->use_fixed_power, txpwr); 686662306a36Sopenharmony_ci if (ret) { 686762306a36Sopenharmony_ci ath10k_warn(ar, "failed to set tx power for station ret: %d\n", 686862306a36Sopenharmony_ci ret); 686962306a36Sopenharmony_ci goto out; 687062306a36Sopenharmony_ci } 687162306a36Sopenharmony_ci 687262306a36Sopenharmony_ciout: 687362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 687462306a36Sopenharmony_ci return ret; 687562306a36Sopenharmony_ci} 687662306a36Sopenharmony_ci 687762306a36Sopenharmony_cistruct ath10k_mac_iter_tid_conf_data { 687862306a36Sopenharmony_ci struct ieee80211_vif *curr_vif; 687962306a36Sopenharmony_ci struct ath10k *ar; 688062306a36Sopenharmony_ci bool reset_config; 688162306a36Sopenharmony_ci}; 688262306a36Sopenharmony_ci 688362306a36Sopenharmony_cistatic bool 688462306a36Sopenharmony_ciath10k_mac_bitrate_mask_has_single_rate(struct ath10k *ar, 688562306a36Sopenharmony_ci enum nl80211_band band, 688662306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 688762306a36Sopenharmony_ci int *vht_num_rates) 688862306a36Sopenharmony_ci{ 688962306a36Sopenharmony_ci int num_rates = 0; 689062306a36Sopenharmony_ci int i, tmp; 689162306a36Sopenharmony_ci 689262306a36Sopenharmony_ci num_rates += hweight32(mask->control[band].legacy); 689362306a36Sopenharmony_ci 689462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) 689562306a36Sopenharmony_ci num_rates += hweight8(mask->control[band].ht_mcs[i]); 689662306a36Sopenharmony_ci 689762306a36Sopenharmony_ci *vht_num_rates = 0; 689862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { 689962306a36Sopenharmony_ci tmp = hweight16(mask->control[band].vht_mcs[i]); 690062306a36Sopenharmony_ci num_rates += tmp; 690162306a36Sopenharmony_ci *vht_num_rates += tmp; 690262306a36Sopenharmony_ci } 690362306a36Sopenharmony_ci 690462306a36Sopenharmony_ci return num_rates == 1; 690562306a36Sopenharmony_ci} 690662306a36Sopenharmony_ci 690762306a36Sopenharmony_cistatic int 690862306a36Sopenharmony_ciath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar, 690962306a36Sopenharmony_ci enum nl80211_band band, 691062306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 691162306a36Sopenharmony_ci u8 *rate, u8 *nss, bool vht_only) 691262306a36Sopenharmony_ci{ 691362306a36Sopenharmony_ci int rate_idx; 691462306a36Sopenharmony_ci int i; 691562306a36Sopenharmony_ci u16 bitrate; 691662306a36Sopenharmony_ci u8 preamble; 691762306a36Sopenharmony_ci u8 hw_rate; 691862306a36Sopenharmony_ci 691962306a36Sopenharmony_ci if (vht_only) 692062306a36Sopenharmony_ci goto next; 692162306a36Sopenharmony_ci 692262306a36Sopenharmony_ci if (hweight32(mask->control[band].legacy) == 1) { 692362306a36Sopenharmony_ci rate_idx = ffs(mask->control[band].legacy) - 1; 692462306a36Sopenharmony_ci 692562306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) 692662306a36Sopenharmony_ci rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX; 692762306a36Sopenharmony_ci 692862306a36Sopenharmony_ci hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value; 692962306a36Sopenharmony_ci bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate; 693062306a36Sopenharmony_ci 693162306a36Sopenharmony_ci if (ath10k_mac_bitrate_is_cck(bitrate)) 693262306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_CCK; 693362306a36Sopenharmony_ci else 693462306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_OFDM; 693562306a36Sopenharmony_ci 693662306a36Sopenharmony_ci *nss = 1; 693762306a36Sopenharmony_ci *rate = preamble << 6 | 693862306a36Sopenharmony_ci (*nss - 1) << 4 | 693962306a36Sopenharmony_ci hw_rate << 0; 694062306a36Sopenharmony_ci 694162306a36Sopenharmony_ci return 0; 694262306a36Sopenharmony_ci } 694362306a36Sopenharmony_ci 694462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { 694562306a36Sopenharmony_ci if (hweight8(mask->control[band].ht_mcs[i]) == 1) { 694662306a36Sopenharmony_ci *nss = i + 1; 694762306a36Sopenharmony_ci *rate = WMI_RATE_PREAMBLE_HT << 6 | 694862306a36Sopenharmony_ci (*nss - 1) << 4 | 694962306a36Sopenharmony_ci (ffs(mask->control[band].ht_mcs[i]) - 1); 695062306a36Sopenharmony_ci 695162306a36Sopenharmony_ci return 0; 695262306a36Sopenharmony_ci } 695362306a36Sopenharmony_ci } 695462306a36Sopenharmony_ci 695562306a36Sopenharmony_cinext: 695662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { 695762306a36Sopenharmony_ci if (hweight16(mask->control[band].vht_mcs[i]) == 1) { 695862306a36Sopenharmony_ci *nss = i + 1; 695962306a36Sopenharmony_ci *rate = WMI_RATE_PREAMBLE_VHT << 6 | 696062306a36Sopenharmony_ci (*nss - 1) << 4 | 696162306a36Sopenharmony_ci (ffs(mask->control[band].vht_mcs[i]) - 1); 696262306a36Sopenharmony_ci 696362306a36Sopenharmony_ci return 0; 696462306a36Sopenharmony_ci } 696562306a36Sopenharmony_ci } 696662306a36Sopenharmony_ci 696762306a36Sopenharmony_ci return -EINVAL; 696862306a36Sopenharmony_ci} 696962306a36Sopenharmony_ci 697062306a36Sopenharmony_cistatic int ath10k_mac_validate_rate_mask(struct ath10k *ar, 697162306a36Sopenharmony_ci struct ieee80211_sta *sta, 697262306a36Sopenharmony_ci u32 rate_ctrl_flag, u8 nss) 697362306a36Sopenharmony_ci{ 697462306a36Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; 697562306a36Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; 697662306a36Sopenharmony_ci 697762306a36Sopenharmony_ci if (nss > sta->deflink.rx_nss) { 697862306a36Sopenharmony_ci ath10k_warn(ar, "Invalid nss field, configured %u limit %u\n", 697962306a36Sopenharmony_ci nss, sta->deflink.rx_nss); 698062306a36Sopenharmony_ci return -EINVAL; 698162306a36Sopenharmony_ci } 698262306a36Sopenharmony_ci 698362306a36Sopenharmony_ci if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_VHT) { 698462306a36Sopenharmony_ci if (!vht_cap->vht_supported) { 698562306a36Sopenharmony_ci ath10k_warn(ar, "Invalid VHT rate for sta %pM\n", 698662306a36Sopenharmony_ci sta->addr); 698762306a36Sopenharmony_ci return -EINVAL; 698862306a36Sopenharmony_ci } 698962306a36Sopenharmony_ci } else if (ATH10K_HW_PREAMBLE(rate_ctrl_flag) == WMI_RATE_PREAMBLE_HT) { 699062306a36Sopenharmony_ci if (!ht_cap->ht_supported || vht_cap->vht_supported) { 699162306a36Sopenharmony_ci ath10k_warn(ar, "Invalid HT rate for sta %pM\n", 699262306a36Sopenharmony_ci sta->addr); 699362306a36Sopenharmony_ci return -EINVAL; 699462306a36Sopenharmony_ci } 699562306a36Sopenharmony_ci } else { 699662306a36Sopenharmony_ci if (ht_cap->ht_supported || vht_cap->vht_supported) 699762306a36Sopenharmony_ci return -EINVAL; 699862306a36Sopenharmony_ci } 699962306a36Sopenharmony_ci 700062306a36Sopenharmony_ci return 0; 700162306a36Sopenharmony_ci} 700262306a36Sopenharmony_ci 700362306a36Sopenharmony_cistatic int 700462306a36Sopenharmony_ciath10k_mac_tid_bitrate_config(struct ath10k *ar, 700562306a36Sopenharmony_ci struct ieee80211_vif *vif, 700662306a36Sopenharmony_ci struct ieee80211_sta *sta, 700762306a36Sopenharmony_ci u32 *rate_ctrl_flag, u8 *rate_ctrl, 700862306a36Sopenharmony_ci enum nl80211_tx_rate_setting txrate_type, 700962306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 701062306a36Sopenharmony_ci{ 701162306a36Sopenharmony_ci struct cfg80211_chan_def def; 701262306a36Sopenharmony_ci enum nl80211_band band; 701362306a36Sopenharmony_ci u8 nss, rate; 701462306a36Sopenharmony_ci int vht_num_rates, ret; 701562306a36Sopenharmony_ci 701662306a36Sopenharmony_ci if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) 701762306a36Sopenharmony_ci return -EINVAL; 701862306a36Sopenharmony_ci 701962306a36Sopenharmony_ci if (txrate_type == NL80211_TX_RATE_AUTOMATIC) { 702062306a36Sopenharmony_ci *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO; 702162306a36Sopenharmony_ci *rate_ctrl_flag = 0; 702262306a36Sopenharmony_ci return 0; 702362306a36Sopenharmony_ci } 702462306a36Sopenharmony_ci 702562306a36Sopenharmony_ci band = def.chan->band; 702662306a36Sopenharmony_ci 702762306a36Sopenharmony_ci if (!ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask, 702862306a36Sopenharmony_ci &vht_num_rates)) { 702962306a36Sopenharmony_ci return -EINVAL; 703062306a36Sopenharmony_ci } 703162306a36Sopenharmony_ci 703262306a36Sopenharmony_ci ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask, 703362306a36Sopenharmony_ci &rate, &nss, false); 703462306a36Sopenharmony_ci if (ret) { 703562306a36Sopenharmony_ci ath10k_warn(ar, "failed to get single rate: %d\n", 703662306a36Sopenharmony_ci ret); 703762306a36Sopenharmony_ci return ret; 703862306a36Sopenharmony_ci } 703962306a36Sopenharmony_ci 704062306a36Sopenharmony_ci *rate_ctrl_flag = rate; 704162306a36Sopenharmony_ci 704262306a36Sopenharmony_ci if (sta && ath10k_mac_validate_rate_mask(ar, sta, *rate_ctrl_flag, nss)) 704362306a36Sopenharmony_ci return -EINVAL; 704462306a36Sopenharmony_ci 704562306a36Sopenharmony_ci if (txrate_type == NL80211_TX_RATE_FIXED) 704662306a36Sopenharmony_ci *rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_FIXED_RATE; 704762306a36Sopenharmony_ci else if (txrate_type == NL80211_TX_RATE_LIMITED && 704862306a36Sopenharmony_ci (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, 704962306a36Sopenharmony_ci ar->wmi.svc_map))) 705062306a36Sopenharmony_ci *rate_ctrl = WMI_PEER_TID_CONFIG_RATE_UPPER_CAP; 705162306a36Sopenharmony_ci else 705262306a36Sopenharmony_ci return -EOPNOTSUPP; 705362306a36Sopenharmony_ci 705462306a36Sopenharmony_ci return 0; 705562306a36Sopenharmony_ci} 705662306a36Sopenharmony_ci 705762306a36Sopenharmony_cistatic int ath10k_mac_set_tid_config(struct ath10k *ar, struct ieee80211_sta *sta, 705862306a36Sopenharmony_ci struct ieee80211_vif *vif, u32 changed, 705962306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg *arg) 706062306a36Sopenharmony_ci{ 706162306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 706262306a36Sopenharmony_ci struct ath10k_sta *arsta; 706362306a36Sopenharmony_ci int ret; 706462306a36Sopenharmony_ci 706562306a36Sopenharmony_ci if (sta) { 706662306a36Sopenharmony_ci if (!sta->wme) 706762306a36Sopenharmony_ci return -ENOTSUPP; 706862306a36Sopenharmony_ci 706962306a36Sopenharmony_ci arsta = (struct ath10k_sta *)sta->drv_priv; 707062306a36Sopenharmony_ci 707162306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { 707262306a36Sopenharmony_ci if ((arsta->retry_long[arg->tid] > 0 || 707362306a36Sopenharmony_ci arsta->rate_code[arg->tid] > 0 || 707462306a36Sopenharmony_ci arsta->ampdu[arg->tid] == 707562306a36Sopenharmony_ci WMI_TID_CONFIG_AGGR_CONTROL_ENABLE) && 707662306a36Sopenharmony_ci arg->ack_policy == WMI_PEER_TID_CONFIG_NOACK) { 707762306a36Sopenharmony_ci changed &= ~BIT(NL80211_TID_CONFIG_ATTR_NOACK); 707862306a36Sopenharmony_ci arg->ack_policy = 0; 707962306a36Sopenharmony_ci arg->aggr_control = 0; 708062306a36Sopenharmony_ci arg->rate_ctrl = 0; 708162306a36Sopenharmony_ci arg->rcode_flags = 0; 708262306a36Sopenharmony_ci } 708362306a36Sopenharmony_ci } 708462306a36Sopenharmony_ci 708562306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { 708662306a36Sopenharmony_ci if (arsta->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK || 708762306a36Sopenharmony_ci arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { 708862306a36Sopenharmony_ci arg->aggr_control = 0; 708962306a36Sopenharmony_ci changed &= ~BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG); 709062306a36Sopenharmony_ci } 709162306a36Sopenharmony_ci } 709262306a36Sopenharmony_ci 709362306a36Sopenharmony_ci if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 709462306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { 709562306a36Sopenharmony_ci if (arsta->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK || 709662306a36Sopenharmony_ci arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { 709762306a36Sopenharmony_ci arg->rate_ctrl = 0; 709862306a36Sopenharmony_ci arg->rcode_flags = 0; 709962306a36Sopenharmony_ci } 710062306a36Sopenharmony_ci } 710162306a36Sopenharmony_ci 710262306a36Sopenharmony_ci ether_addr_copy(arg->peer_macaddr.addr, sta->addr); 710362306a36Sopenharmony_ci 710462306a36Sopenharmony_ci ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, arg); 710562306a36Sopenharmony_ci if (ret) 710662306a36Sopenharmony_ci return ret; 710762306a36Sopenharmony_ci 710862306a36Sopenharmony_ci /* Store the configured parameters in success case */ 710962306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { 711062306a36Sopenharmony_ci arsta->noack[arg->tid] = arg->ack_policy; 711162306a36Sopenharmony_ci arg->ack_policy = 0; 711262306a36Sopenharmony_ci arg->aggr_control = 0; 711362306a36Sopenharmony_ci arg->rate_ctrl = 0; 711462306a36Sopenharmony_ci arg->rcode_flags = 0; 711562306a36Sopenharmony_ci } 711662306a36Sopenharmony_ci 711762306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { 711862306a36Sopenharmony_ci arsta->retry_long[arg->tid] = arg->retry_count; 711962306a36Sopenharmony_ci arg->retry_count = 0; 712062306a36Sopenharmony_ci } 712162306a36Sopenharmony_ci 712262306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { 712362306a36Sopenharmony_ci arsta->ampdu[arg->tid] = arg->aggr_control; 712462306a36Sopenharmony_ci arg->aggr_control = 0; 712562306a36Sopenharmony_ci } 712662306a36Sopenharmony_ci 712762306a36Sopenharmony_ci if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 712862306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { 712962306a36Sopenharmony_ci arsta->rate_ctrl[arg->tid] = arg->rate_ctrl; 713062306a36Sopenharmony_ci arg->rate_ctrl = 0; 713162306a36Sopenharmony_ci arg->rcode_flags = 0; 713262306a36Sopenharmony_ci } 713362306a36Sopenharmony_ci 713462306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { 713562306a36Sopenharmony_ci arsta->rtscts[arg->tid] = arg->rtscts_ctrl; 713662306a36Sopenharmony_ci arg->ext_tid_cfg_bitmap = 0; 713762306a36Sopenharmony_ci } 713862306a36Sopenharmony_ci } else { 713962306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { 714062306a36Sopenharmony_ci if ((arvif->retry_long[arg->tid] || 714162306a36Sopenharmony_ci arvif->rate_code[arg->tid] || 714262306a36Sopenharmony_ci arvif->ampdu[arg->tid] == 714362306a36Sopenharmony_ci WMI_TID_CONFIG_AGGR_CONTROL_ENABLE) && 714462306a36Sopenharmony_ci arg->ack_policy == WMI_PEER_TID_CONFIG_NOACK) { 714562306a36Sopenharmony_ci changed &= ~BIT(NL80211_TID_CONFIG_ATTR_NOACK); 714662306a36Sopenharmony_ci } else { 714762306a36Sopenharmony_ci arvif->noack[arg->tid] = arg->ack_policy; 714862306a36Sopenharmony_ci arvif->ampdu[arg->tid] = arg->aggr_control; 714962306a36Sopenharmony_ci arvif->rate_ctrl[arg->tid] = arg->rate_ctrl; 715062306a36Sopenharmony_ci } 715162306a36Sopenharmony_ci } 715262306a36Sopenharmony_ci 715362306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { 715462306a36Sopenharmony_ci if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) 715562306a36Sopenharmony_ci changed &= ~BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG); 715662306a36Sopenharmony_ci else 715762306a36Sopenharmony_ci arvif->retry_long[arg->tid] = arg->retry_count; 715862306a36Sopenharmony_ci } 715962306a36Sopenharmony_ci 716062306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { 716162306a36Sopenharmony_ci if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) 716262306a36Sopenharmony_ci changed &= ~BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); 716362306a36Sopenharmony_ci else 716462306a36Sopenharmony_ci arvif->ampdu[arg->tid] = arg->aggr_control; 716562306a36Sopenharmony_ci } 716662306a36Sopenharmony_ci 716762306a36Sopenharmony_ci if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 716862306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { 716962306a36Sopenharmony_ci if (arvif->noack[arg->tid] == WMI_PEER_TID_CONFIG_NOACK) { 717062306a36Sopenharmony_ci changed &= ~(BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 717162306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE)); 717262306a36Sopenharmony_ci } else { 717362306a36Sopenharmony_ci arvif->rate_ctrl[arg->tid] = arg->rate_ctrl; 717462306a36Sopenharmony_ci arvif->rate_code[arg->tid] = arg->rcode_flags; 717562306a36Sopenharmony_ci } 717662306a36Sopenharmony_ci } 717762306a36Sopenharmony_ci 717862306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { 717962306a36Sopenharmony_ci arvif->rtscts[arg->tid] = arg->rtscts_ctrl; 718062306a36Sopenharmony_ci arg->ext_tid_cfg_bitmap = 0; 718162306a36Sopenharmony_ci } 718262306a36Sopenharmony_ci 718362306a36Sopenharmony_ci if (changed) 718462306a36Sopenharmony_ci arvif->tid_conf_changed[arg->tid] |= changed; 718562306a36Sopenharmony_ci } 718662306a36Sopenharmony_ci 718762306a36Sopenharmony_ci return 0; 718862306a36Sopenharmony_ci} 718962306a36Sopenharmony_ci 719062306a36Sopenharmony_cistatic int 719162306a36Sopenharmony_ciath10k_mac_parse_tid_config(struct ath10k *ar, 719262306a36Sopenharmony_ci struct ieee80211_sta *sta, 719362306a36Sopenharmony_ci struct ieee80211_vif *vif, 719462306a36Sopenharmony_ci struct cfg80211_tid_cfg *tid_conf, 719562306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg *arg) 719662306a36Sopenharmony_ci{ 719762306a36Sopenharmony_ci u32 changed = tid_conf->mask; 719862306a36Sopenharmony_ci int ret = 0, i = 0; 719962306a36Sopenharmony_ci 720062306a36Sopenharmony_ci if (!changed) 720162306a36Sopenharmony_ci return -EINVAL; 720262306a36Sopenharmony_ci 720362306a36Sopenharmony_ci while (i < ATH10K_TID_MAX) { 720462306a36Sopenharmony_ci if (!(tid_conf->tids & BIT(i))) { 720562306a36Sopenharmony_ci i++; 720662306a36Sopenharmony_ci continue; 720762306a36Sopenharmony_ci } 720862306a36Sopenharmony_ci 720962306a36Sopenharmony_ci arg->tid = i; 721062306a36Sopenharmony_ci 721162306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { 721262306a36Sopenharmony_ci if (tid_conf->noack == NL80211_TID_CONFIG_ENABLE) { 721362306a36Sopenharmony_ci arg->ack_policy = WMI_PEER_TID_CONFIG_NOACK; 721462306a36Sopenharmony_ci arg->rate_ctrl = 721562306a36Sopenharmony_ci WMI_TID_CONFIG_RATE_CONTROL_DEFAULT_LOWEST_RATE; 721662306a36Sopenharmony_ci arg->aggr_control = 721762306a36Sopenharmony_ci WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; 721862306a36Sopenharmony_ci } else { 721962306a36Sopenharmony_ci arg->ack_policy = 722062306a36Sopenharmony_ci WMI_PEER_TID_CONFIG_ACK; 722162306a36Sopenharmony_ci arg->rate_ctrl = 722262306a36Sopenharmony_ci WMI_TID_CONFIG_RATE_CONTROL_AUTO; 722362306a36Sopenharmony_ci arg->aggr_control = 722462306a36Sopenharmony_ci WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; 722562306a36Sopenharmony_ci } 722662306a36Sopenharmony_ci } 722762306a36Sopenharmony_ci 722862306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) 722962306a36Sopenharmony_ci arg->retry_count = tid_conf->retry_long; 723062306a36Sopenharmony_ci 723162306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { 723262306a36Sopenharmony_ci if (tid_conf->noack == NL80211_TID_CONFIG_ENABLE) 723362306a36Sopenharmony_ci arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; 723462306a36Sopenharmony_ci else 723562306a36Sopenharmony_ci arg->aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_DISABLE; 723662306a36Sopenharmony_ci } 723762306a36Sopenharmony_ci 723862306a36Sopenharmony_ci if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 723962306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { 724062306a36Sopenharmony_ci ret = ath10k_mac_tid_bitrate_config(ar, vif, sta, 724162306a36Sopenharmony_ci &arg->rcode_flags, 724262306a36Sopenharmony_ci &arg->rate_ctrl, 724362306a36Sopenharmony_ci tid_conf->txrate_type, 724462306a36Sopenharmony_ci &tid_conf->txrate_mask); 724562306a36Sopenharmony_ci if (ret) { 724662306a36Sopenharmony_ci ath10k_warn(ar, "failed to configure bitrate mask %d\n", 724762306a36Sopenharmony_ci ret); 724862306a36Sopenharmony_ci arg->rcode_flags = 0; 724962306a36Sopenharmony_ci arg->rate_ctrl = 0; 725062306a36Sopenharmony_ci } 725162306a36Sopenharmony_ci } 725262306a36Sopenharmony_ci 725362306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { 725462306a36Sopenharmony_ci if (tid_conf->rtscts) 725562306a36Sopenharmony_ci arg->rtscts_ctrl = tid_conf->rtscts; 725662306a36Sopenharmony_ci 725762306a36Sopenharmony_ci arg->ext_tid_cfg_bitmap = WMI_EXT_TID_RTS_CTS_CONFIG; 725862306a36Sopenharmony_ci } 725962306a36Sopenharmony_ci 726062306a36Sopenharmony_ci ret = ath10k_mac_set_tid_config(ar, sta, vif, changed, arg); 726162306a36Sopenharmony_ci if (ret) 726262306a36Sopenharmony_ci return ret; 726362306a36Sopenharmony_ci i++; 726462306a36Sopenharmony_ci } 726562306a36Sopenharmony_ci 726662306a36Sopenharmony_ci return ret; 726762306a36Sopenharmony_ci} 726862306a36Sopenharmony_ci 726962306a36Sopenharmony_cistatic int ath10k_mac_reset_tid_config(struct ath10k *ar, 727062306a36Sopenharmony_ci struct ieee80211_sta *sta, 727162306a36Sopenharmony_ci struct ath10k_vif *arvif, 727262306a36Sopenharmony_ci u8 tids) 727362306a36Sopenharmony_ci{ 727462306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 727562306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg arg; 727662306a36Sopenharmony_ci int ret = 0, i = 0; 727762306a36Sopenharmony_ci 727862306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 727962306a36Sopenharmony_ci while (i < ATH10K_TID_MAX) { 728062306a36Sopenharmony_ci if (!(tids & BIT(i))) { 728162306a36Sopenharmony_ci i++; 728262306a36Sopenharmony_ci continue; 728362306a36Sopenharmony_ci } 728462306a36Sopenharmony_ci 728562306a36Sopenharmony_ci arg.tid = i; 728662306a36Sopenharmony_ci arg.ack_policy = WMI_PEER_TID_CONFIG_ACK; 728762306a36Sopenharmony_ci arg.retry_count = ATH10K_MAX_RETRY_COUNT; 728862306a36Sopenharmony_ci arg.rate_ctrl = WMI_TID_CONFIG_RATE_CONTROL_AUTO; 728962306a36Sopenharmony_ci arg.aggr_control = WMI_TID_CONFIG_AGGR_CONTROL_ENABLE; 729062306a36Sopenharmony_ci arg.rtscts_ctrl = WMI_TID_CONFIG_RTSCTS_CONTROL_ENABLE; 729162306a36Sopenharmony_ci arg.ext_tid_cfg_bitmap = WMI_EXT_TID_RTS_CTS_CONFIG; 729262306a36Sopenharmony_ci 729362306a36Sopenharmony_ci ether_addr_copy(arg.peer_macaddr.addr, sta->addr); 729462306a36Sopenharmony_ci 729562306a36Sopenharmony_ci ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); 729662306a36Sopenharmony_ci if (ret) 729762306a36Sopenharmony_ci return ret; 729862306a36Sopenharmony_ci 729962306a36Sopenharmony_ci if (!arvif->tids_rst) { 730062306a36Sopenharmony_ci arsta->retry_long[i] = -1; 730162306a36Sopenharmony_ci arsta->noack[i] = -1; 730262306a36Sopenharmony_ci arsta->ampdu[i] = -1; 730362306a36Sopenharmony_ci arsta->rate_code[i] = -1; 730462306a36Sopenharmony_ci arsta->rate_ctrl[i] = 0; 730562306a36Sopenharmony_ci arsta->rtscts[i] = -1; 730662306a36Sopenharmony_ci } else { 730762306a36Sopenharmony_ci arvif->retry_long[i] = 0; 730862306a36Sopenharmony_ci arvif->noack[i] = 0; 730962306a36Sopenharmony_ci arvif->ampdu[i] = 0; 731062306a36Sopenharmony_ci arvif->rate_code[i] = 0; 731162306a36Sopenharmony_ci arvif->rate_ctrl[i] = 0; 731262306a36Sopenharmony_ci arvif->rtscts[i] = 0; 731362306a36Sopenharmony_ci } 731462306a36Sopenharmony_ci 731562306a36Sopenharmony_ci i++; 731662306a36Sopenharmony_ci } 731762306a36Sopenharmony_ci 731862306a36Sopenharmony_ci return ret; 731962306a36Sopenharmony_ci} 732062306a36Sopenharmony_ci 732162306a36Sopenharmony_cistatic void ath10k_sta_tid_cfg_wk(struct work_struct *wk) 732262306a36Sopenharmony_ci{ 732362306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg arg = {}; 732462306a36Sopenharmony_ci struct ieee80211_sta *sta; 732562306a36Sopenharmony_ci struct ath10k_sta *arsta; 732662306a36Sopenharmony_ci struct ath10k_vif *arvif; 732762306a36Sopenharmony_ci struct ath10k *ar; 732862306a36Sopenharmony_ci bool config_apply; 732962306a36Sopenharmony_ci int ret, i; 733062306a36Sopenharmony_ci u32 changed; 733162306a36Sopenharmony_ci u8 nss; 733262306a36Sopenharmony_ci 733362306a36Sopenharmony_ci arsta = container_of(wk, struct ath10k_sta, tid_config_wk); 733462306a36Sopenharmony_ci sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); 733562306a36Sopenharmony_ci arvif = arsta->arvif; 733662306a36Sopenharmony_ci ar = arvif->ar; 733762306a36Sopenharmony_ci 733862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 733962306a36Sopenharmony_ci 734062306a36Sopenharmony_ci if (arvif->tids_rst) { 734162306a36Sopenharmony_ci ret = ath10k_mac_reset_tid_config(ar, sta, arvif, 734262306a36Sopenharmony_ci arvif->tids_rst); 734362306a36Sopenharmony_ci goto exit; 734462306a36Sopenharmony_ci } 734562306a36Sopenharmony_ci 734662306a36Sopenharmony_ci ether_addr_copy(arg.peer_macaddr.addr, sta->addr); 734762306a36Sopenharmony_ci 734862306a36Sopenharmony_ci for (i = 0; i < ATH10K_TID_MAX; i++) { 734962306a36Sopenharmony_ci config_apply = false; 735062306a36Sopenharmony_ci changed = arvif->tid_conf_changed[i]; 735162306a36Sopenharmony_ci 735262306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_NOACK)) { 735362306a36Sopenharmony_ci if (arsta->noack[i] != -1) { 735462306a36Sopenharmony_ci arg.ack_policy = 0; 735562306a36Sopenharmony_ci } else { 735662306a36Sopenharmony_ci config_apply = true; 735762306a36Sopenharmony_ci arg.ack_policy = arvif->noack[i]; 735862306a36Sopenharmony_ci arg.aggr_control = arvif->ampdu[i]; 735962306a36Sopenharmony_ci arg.rate_ctrl = arvif->rate_ctrl[i]; 736062306a36Sopenharmony_ci } 736162306a36Sopenharmony_ci } 736262306a36Sopenharmony_ci 736362306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG)) { 736462306a36Sopenharmony_ci if (arsta->retry_long[i] != -1 || 736562306a36Sopenharmony_ci arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || 736662306a36Sopenharmony_ci arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { 736762306a36Sopenharmony_ci arg.retry_count = 0; 736862306a36Sopenharmony_ci } else { 736962306a36Sopenharmony_ci arg.retry_count = arvif->retry_long[i]; 737062306a36Sopenharmony_ci config_apply = true; 737162306a36Sopenharmony_ci } 737262306a36Sopenharmony_ci } 737362306a36Sopenharmony_ci 737462306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) { 737562306a36Sopenharmony_ci if (arsta->ampdu[i] != -1 || 737662306a36Sopenharmony_ci arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || 737762306a36Sopenharmony_ci arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { 737862306a36Sopenharmony_ci arg.aggr_control = 0; 737962306a36Sopenharmony_ci } else { 738062306a36Sopenharmony_ci arg.aggr_control = arvif->ampdu[i]; 738162306a36Sopenharmony_ci config_apply = true; 738262306a36Sopenharmony_ci } 738362306a36Sopenharmony_ci } 738462306a36Sopenharmony_ci 738562306a36Sopenharmony_ci if (changed & (BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 738662306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE))) { 738762306a36Sopenharmony_ci nss = ATH10K_HW_NSS(arvif->rate_code[i]); 738862306a36Sopenharmony_ci ret = ath10k_mac_validate_rate_mask(ar, sta, 738962306a36Sopenharmony_ci arvif->rate_code[i], 739062306a36Sopenharmony_ci nss); 739162306a36Sopenharmony_ci if (ret && 739262306a36Sopenharmony_ci arvif->rate_ctrl[i] > WMI_TID_CONFIG_RATE_CONTROL_AUTO) { 739362306a36Sopenharmony_ci arg.rate_ctrl = 0; 739462306a36Sopenharmony_ci arg.rcode_flags = 0; 739562306a36Sopenharmony_ci } 739662306a36Sopenharmony_ci 739762306a36Sopenharmony_ci if (arsta->rate_ctrl[i] > 739862306a36Sopenharmony_ci WMI_TID_CONFIG_RATE_CONTROL_AUTO || 739962306a36Sopenharmony_ci arsta->noack[i] == WMI_PEER_TID_CONFIG_NOACK || 740062306a36Sopenharmony_ci arvif->noack[i] == WMI_PEER_TID_CONFIG_NOACK) { 740162306a36Sopenharmony_ci arg.rate_ctrl = 0; 740262306a36Sopenharmony_ci arg.rcode_flags = 0; 740362306a36Sopenharmony_ci } else { 740462306a36Sopenharmony_ci arg.rate_ctrl = arvif->rate_ctrl[i]; 740562306a36Sopenharmony_ci arg.rcode_flags = arvif->rate_code[i]; 740662306a36Sopenharmony_ci config_apply = true; 740762306a36Sopenharmony_ci } 740862306a36Sopenharmony_ci } 740962306a36Sopenharmony_ci 741062306a36Sopenharmony_ci if (changed & BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL)) { 741162306a36Sopenharmony_ci if (arsta->rtscts[i]) { 741262306a36Sopenharmony_ci arg.rtscts_ctrl = 0; 741362306a36Sopenharmony_ci arg.ext_tid_cfg_bitmap = 0; 741462306a36Sopenharmony_ci } else { 741562306a36Sopenharmony_ci arg.rtscts_ctrl = arvif->rtscts[i] - 1; 741662306a36Sopenharmony_ci arg.ext_tid_cfg_bitmap = 741762306a36Sopenharmony_ci WMI_EXT_TID_RTS_CTS_CONFIG; 741862306a36Sopenharmony_ci config_apply = true; 741962306a36Sopenharmony_ci } 742062306a36Sopenharmony_ci } 742162306a36Sopenharmony_ci 742262306a36Sopenharmony_ci arg.tid = i; 742362306a36Sopenharmony_ci 742462306a36Sopenharmony_ci if (config_apply) { 742562306a36Sopenharmony_ci ret = ath10k_wmi_set_per_peer_per_tid_cfg(ar, &arg); 742662306a36Sopenharmony_ci if (ret) 742762306a36Sopenharmony_ci ath10k_warn(ar, "failed to set per tid config for sta %pM: %d\n", 742862306a36Sopenharmony_ci sta->addr, ret); 742962306a36Sopenharmony_ci } 743062306a36Sopenharmony_ci 743162306a36Sopenharmony_ci arg.ack_policy = 0; 743262306a36Sopenharmony_ci arg.retry_count = 0; 743362306a36Sopenharmony_ci arg.aggr_control = 0; 743462306a36Sopenharmony_ci arg.rate_ctrl = 0; 743562306a36Sopenharmony_ci arg.rcode_flags = 0; 743662306a36Sopenharmony_ci } 743762306a36Sopenharmony_ci 743862306a36Sopenharmony_ciexit: 743962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 744062306a36Sopenharmony_ci} 744162306a36Sopenharmony_ci 744262306a36Sopenharmony_cistatic void ath10k_mac_vif_stations_tid_conf(void *data, 744362306a36Sopenharmony_ci struct ieee80211_sta *sta) 744462306a36Sopenharmony_ci{ 744562306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 744662306a36Sopenharmony_ci struct ath10k_mac_iter_tid_conf_data *iter_data = data; 744762306a36Sopenharmony_ci struct ieee80211_vif *sta_vif = arsta->arvif->vif; 744862306a36Sopenharmony_ci 744962306a36Sopenharmony_ci if (sta_vif != iter_data->curr_vif || !sta->wme) 745062306a36Sopenharmony_ci return; 745162306a36Sopenharmony_ci 745262306a36Sopenharmony_ci ieee80211_queue_work(iter_data->ar->hw, &arsta->tid_config_wk); 745362306a36Sopenharmony_ci} 745462306a36Sopenharmony_ci 745562306a36Sopenharmony_cistatic int ath10k_sta_state(struct ieee80211_hw *hw, 745662306a36Sopenharmony_ci struct ieee80211_vif *vif, 745762306a36Sopenharmony_ci struct ieee80211_sta *sta, 745862306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 745962306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 746062306a36Sopenharmony_ci{ 746162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 746262306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 746362306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 746462306a36Sopenharmony_ci struct ath10k_peer *peer; 746562306a36Sopenharmony_ci int ret = 0; 746662306a36Sopenharmony_ci int i; 746762306a36Sopenharmony_ci 746862306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 746962306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) { 747062306a36Sopenharmony_ci memset(arsta, 0, sizeof(*arsta)); 747162306a36Sopenharmony_ci arsta->arvif = arvif; 747262306a36Sopenharmony_ci arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED; 747362306a36Sopenharmony_ci INIT_WORK(&arsta->update_wk, ath10k_sta_rc_update_wk); 747462306a36Sopenharmony_ci INIT_WORK(&arsta->tid_config_wk, ath10k_sta_tid_cfg_wk); 747562306a36Sopenharmony_ci 747662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 747762306a36Sopenharmony_ci ath10k_mac_txq_init(sta->txq[i]); 747862306a36Sopenharmony_ci } 747962306a36Sopenharmony_ci 748062306a36Sopenharmony_ci /* cancel must be done outside the mutex to avoid deadlock */ 748162306a36Sopenharmony_ci if ((old_state == IEEE80211_STA_NONE && 748262306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST)) { 748362306a36Sopenharmony_ci cancel_work_sync(&arsta->update_wk); 748462306a36Sopenharmony_ci cancel_work_sync(&arsta->tid_config_wk); 748562306a36Sopenharmony_ci } 748662306a36Sopenharmony_ci 748762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 748862306a36Sopenharmony_ci 748962306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 749062306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) { 749162306a36Sopenharmony_ci /* 749262306a36Sopenharmony_ci * New station addition. 749362306a36Sopenharmony_ci */ 749462306a36Sopenharmony_ci enum wmi_peer_type peer_type = WMI_PEER_TYPE_DEFAULT; 749562306a36Sopenharmony_ci u32 num_tdls_stations; 749662306a36Sopenharmony_ci 749762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, 749862306a36Sopenharmony_ci "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n", 749962306a36Sopenharmony_ci arvif->vdev_id, sta->addr, 750062306a36Sopenharmony_ci ar->num_stations + 1, ar->max_num_stations, 750162306a36Sopenharmony_ci ar->num_peers + 1, ar->max_num_peers); 750262306a36Sopenharmony_ci 750362306a36Sopenharmony_ci num_tdls_stations = ath10k_mac_tdls_vif_stations_count(hw, vif); 750462306a36Sopenharmony_ci 750562306a36Sopenharmony_ci if (sta->tdls) { 750662306a36Sopenharmony_ci if (num_tdls_stations >= ar->max_num_tdls_vdevs) { 750762306a36Sopenharmony_ci ath10k_warn(ar, "vdev %i exceeded maximum number of tdls vdevs %i\n", 750862306a36Sopenharmony_ci arvif->vdev_id, 750962306a36Sopenharmony_ci ar->max_num_tdls_vdevs); 751062306a36Sopenharmony_ci ret = -ELNRNG; 751162306a36Sopenharmony_ci goto exit; 751262306a36Sopenharmony_ci } 751362306a36Sopenharmony_ci peer_type = WMI_PEER_TYPE_TDLS; 751462306a36Sopenharmony_ci } 751562306a36Sopenharmony_ci 751662306a36Sopenharmony_ci ret = ath10k_mac_inc_num_stations(arvif, sta); 751762306a36Sopenharmony_ci if (ret) { 751862306a36Sopenharmony_ci ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n", 751962306a36Sopenharmony_ci ar->max_num_stations); 752062306a36Sopenharmony_ci goto exit; 752162306a36Sopenharmony_ci } 752262306a36Sopenharmony_ci 752362306a36Sopenharmony_ci if (ath10k_debug_is_extd_tx_stats_enabled(ar)) { 752462306a36Sopenharmony_ci arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), 752562306a36Sopenharmony_ci GFP_KERNEL); 752662306a36Sopenharmony_ci if (!arsta->tx_stats) { 752762306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 752862306a36Sopenharmony_ci ret = -ENOMEM; 752962306a36Sopenharmony_ci goto exit; 753062306a36Sopenharmony_ci } 753162306a36Sopenharmony_ci } 753262306a36Sopenharmony_ci 753362306a36Sopenharmony_ci ret = ath10k_peer_create(ar, vif, sta, arvif->vdev_id, 753462306a36Sopenharmony_ci sta->addr, peer_type); 753562306a36Sopenharmony_ci if (ret) { 753662306a36Sopenharmony_ci ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", 753762306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 753862306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 753962306a36Sopenharmony_ci kfree(arsta->tx_stats); 754062306a36Sopenharmony_ci goto exit; 754162306a36Sopenharmony_ci } 754262306a36Sopenharmony_ci 754362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 754462306a36Sopenharmony_ci 754562306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); 754662306a36Sopenharmony_ci if (!peer) { 754762306a36Sopenharmony_ci ath10k_warn(ar, "failed to lookup peer %pM on vdev %i\n", 754862306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 754962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 755062306a36Sopenharmony_ci ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); 755162306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 755262306a36Sopenharmony_ci kfree(arsta->tx_stats); 755362306a36Sopenharmony_ci ret = -ENOENT; 755462306a36Sopenharmony_ci goto exit; 755562306a36Sopenharmony_ci } 755662306a36Sopenharmony_ci 755762306a36Sopenharmony_ci arsta->peer_id = find_first_bit(peer->peer_ids, 755862306a36Sopenharmony_ci ATH10K_MAX_NUM_PEER_IDS); 755962306a36Sopenharmony_ci 756062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 756162306a36Sopenharmony_ci 756262306a36Sopenharmony_ci if (!sta->tdls) 756362306a36Sopenharmony_ci goto exit; 756462306a36Sopenharmony_ci 756562306a36Sopenharmony_ci ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, 756662306a36Sopenharmony_ci WMI_TDLS_ENABLE_ACTIVE); 756762306a36Sopenharmony_ci if (ret) { 756862306a36Sopenharmony_ci ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", 756962306a36Sopenharmony_ci arvif->vdev_id, ret); 757062306a36Sopenharmony_ci ath10k_peer_delete(ar, arvif->vdev_id, 757162306a36Sopenharmony_ci sta->addr); 757262306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 757362306a36Sopenharmony_ci kfree(arsta->tx_stats); 757462306a36Sopenharmony_ci goto exit; 757562306a36Sopenharmony_ci } 757662306a36Sopenharmony_ci 757762306a36Sopenharmony_ci ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta, 757862306a36Sopenharmony_ci WMI_TDLS_PEER_STATE_PEERING); 757962306a36Sopenharmony_ci if (ret) { 758062306a36Sopenharmony_ci ath10k_warn(ar, 758162306a36Sopenharmony_ci "failed to update tdls peer %pM for vdev %d when adding a new sta: %i\n", 758262306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 758362306a36Sopenharmony_ci ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); 758462306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 758562306a36Sopenharmony_ci kfree(arsta->tx_stats); 758662306a36Sopenharmony_ci 758762306a36Sopenharmony_ci if (num_tdls_stations != 0) 758862306a36Sopenharmony_ci goto exit; 758962306a36Sopenharmony_ci ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, 759062306a36Sopenharmony_ci WMI_TDLS_DISABLE); 759162306a36Sopenharmony_ci } 759262306a36Sopenharmony_ci } else if ((old_state == IEEE80211_STA_NONE && 759362306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST)) { 759462306a36Sopenharmony_ci /* 759562306a36Sopenharmony_ci * Existing station deletion. 759662306a36Sopenharmony_ci */ 759762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, 759862306a36Sopenharmony_ci "mac vdev %d peer delete %pM sta %pK (sta gone)\n", 759962306a36Sopenharmony_ci arvif->vdev_id, sta->addr, sta); 760062306a36Sopenharmony_ci 760162306a36Sopenharmony_ci if (sta->tdls) { 760262306a36Sopenharmony_ci ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, 760362306a36Sopenharmony_ci sta, 760462306a36Sopenharmony_ci WMI_TDLS_PEER_STATE_TEARDOWN); 760562306a36Sopenharmony_ci if (ret) 760662306a36Sopenharmony_ci ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n", 760762306a36Sopenharmony_ci sta->addr, 760862306a36Sopenharmony_ci WMI_TDLS_PEER_STATE_TEARDOWN, ret); 760962306a36Sopenharmony_ci } 761062306a36Sopenharmony_ci 761162306a36Sopenharmony_ci ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); 761262306a36Sopenharmony_ci if (ret) 761362306a36Sopenharmony_ci ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", 761462306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 761562306a36Sopenharmony_ci 761662306a36Sopenharmony_ci ath10k_mac_dec_num_stations(arvif, sta); 761762306a36Sopenharmony_ci 761862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 761962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ar->peer_map); i++) { 762062306a36Sopenharmony_ci peer = ar->peer_map[i]; 762162306a36Sopenharmony_ci if (!peer) 762262306a36Sopenharmony_ci continue; 762362306a36Sopenharmony_ci 762462306a36Sopenharmony_ci if (peer->sta == sta) { 762562306a36Sopenharmony_ci ath10k_warn(ar, "found sta peer %pM (ptr %pK id %d) entry on vdev %i after it was supposedly removed\n", 762662306a36Sopenharmony_ci sta->addr, peer, i, arvif->vdev_id); 762762306a36Sopenharmony_ci peer->sta = NULL; 762862306a36Sopenharmony_ci 762962306a36Sopenharmony_ci /* Clean up the peer object as well since we 763062306a36Sopenharmony_ci * must have failed to do this above. 763162306a36Sopenharmony_ci */ 763262306a36Sopenharmony_ci ath10k_peer_map_cleanup(ar, peer); 763362306a36Sopenharmony_ci } 763462306a36Sopenharmony_ci } 763562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 763662306a36Sopenharmony_ci 763762306a36Sopenharmony_ci if (ath10k_debug_is_extd_tx_stats_enabled(ar)) { 763862306a36Sopenharmony_ci kfree(arsta->tx_stats); 763962306a36Sopenharmony_ci arsta->tx_stats = NULL; 764062306a36Sopenharmony_ci } 764162306a36Sopenharmony_ci 764262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->txq); i++) 764362306a36Sopenharmony_ci ath10k_mac_txq_unref(ar, sta->txq[i]); 764462306a36Sopenharmony_ci 764562306a36Sopenharmony_ci if (!sta->tdls) 764662306a36Sopenharmony_ci goto exit; 764762306a36Sopenharmony_ci 764862306a36Sopenharmony_ci if (ath10k_mac_tdls_vif_stations_count(hw, vif)) 764962306a36Sopenharmony_ci goto exit; 765062306a36Sopenharmony_ci 765162306a36Sopenharmony_ci /* This was the last tdls peer in current vif */ 765262306a36Sopenharmony_ci ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, 765362306a36Sopenharmony_ci WMI_TDLS_DISABLE); 765462306a36Sopenharmony_ci if (ret) { 765562306a36Sopenharmony_ci ath10k_warn(ar, "failed to update fw tdls state on vdev %i: %i\n", 765662306a36Sopenharmony_ci arvif->vdev_id, ret); 765762306a36Sopenharmony_ci } 765862306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_AUTH && 765962306a36Sopenharmony_ci new_state == IEEE80211_STA_ASSOC && 766062306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP || 766162306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT || 766262306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_ADHOC)) { 766362306a36Sopenharmony_ci /* 766462306a36Sopenharmony_ci * New association. 766562306a36Sopenharmony_ci */ 766662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac sta %pM associated\n", 766762306a36Sopenharmony_ci sta->addr); 766862306a36Sopenharmony_ci 766962306a36Sopenharmony_ci ret = ath10k_station_assoc(ar, vif, sta, false); 767062306a36Sopenharmony_ci if (ret) 767162306a36Sopenharmony_ci ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n", 767262306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 767362306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_ASSOC && 767462306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTHORIZED && 767562306a36Sopenharmony_ci sta->tdls) { 767662306a36Sopenharmony_ci /* 767762306a36Sopenharmony_ci * Tdls station authorized. 767862306a36Sopenharmony_ci */ 767962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac tdls sta %pM authorized\n", 768062306a36Sopenharmony_ci sta->addr); 768162306a36Sopenharmony_ci 768262306a36Sopenharmony_ci ret = ath10k_station_assoc(ar, vif, sta, false); 768362306a36Sopenharmony_ci if (ret) { 768462306a36Sopenharmony_ci ath10k_warn(ar, "failed to associate tdls station %pM for vdev %i: %i\n", 768562306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 768662306a36Sopenharmony_ci goto exit; 768762306a36Sopenharmony_ci } 768862306a36Sopenharmony_ci 768962306a36Sopenharmony_ci ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, sta, 769062306a36Sopenharmony_ci WMI_TDLS_PEER_STATE_CONNECTED); 769162306a36Sopenharmony_ci if (ret) 769262306a36Sopenharmony_ci ath10k_warn(ar, "failed to update tdls peer %pM for vdev %i: %i\n", 769362306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 769462306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_ASSOC && 769562306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTH && 769662306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP || 769762306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT || 769862306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_ADHOC)) { 769962306a36Sopenharmony_ci /* 770062306a36Sopenharmony_ci * Disassociation. 770162306a36Sopenharmony_ci */ 770262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, "mac sta %pM disassociated\n", 770362306a36Sopenharmony_ci sta->addr); 770462306a36Sopenharmony_ci 770562306a36Sopenharmony_ci ret = ath10k_station_disassoc(ar, vif, sta); 770662306a36Sopenharmony_ci if (ret) 770762306a36Sopenharmony_ci ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n", 770862306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 770962306a36Sopenharmony_ci } 771062306a36Sopenharmony_ciexit: 771162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 771262306a36Sopenharmony_ci return ret; 771362306a36Sopenharmony_ci} 771462306a36Sopenharmony_ci 771562306a36Sopenharmony_cistatic int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif, 771662306a36Sopenharmony_ci u16 ac, bool enable) 771762306a36Sopenharmony_ci{ 771862306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 771962306a36Sopenharmony_ci struct wmi_sta_uapsd_auto_trig_arg arg = {}; 772062306a36Sopenharmony_ci u32 prio = 0, acc = 0; 772162306a36Sopenharmony_ci u32 value = 0; 772262306a36Sopenharmony_ci int ret = 0; 772362306a36Sopenharmony_ci 772462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 772562306a36Sopenharmony_ci 772662306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_STA) 772762306a36Sopenharmony_ci return 0; 772862306a36Sopenharmony_ci 772962306a36Sopenharmony_ci switch (ac) { 773062306a36Sopenharmony_ci case IEEE80211_AC_VO: 773162306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | 773262306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; 773362306a36Sopenharmony_ci prio = 7; 773462306a36Sopenharmony_ci acc = 3; 773562306a36Sopenharmony_ci break; 773662306a36Sopenharmony_ci case IEEE80211_AC_VI: 773762306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | 773862306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; 773962306a36Sopenharmony_ci prio = 5; 774062306a36Sopenharmony_ci acc = 2; 774162306a36Sopenharmony_ci break; 774262306a36Sopenharmony_ci case IEEE80211_AC_BE: 774362306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | 774462306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; 774562306a36Sopenharmony_ci prio = 2; 774662306a36Sopenharmony_ci acc = 1; 774762306a36Sopenharmony_ci break; 774862306a36Sopenharmony_ci case IEEE80211_AC_BK: 774962306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | 775062306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; 775162306a36Sopenharmony_ci prio = 0; 775262306a36Sopenharmony_ci acc = 0; 775362306a36Sopenharmony_ci break; 775462306a36Sopenharmony_ci } 775562306a36Sopenharmony_ci 775662306a36Sopenharmony_ci if (enable) 775762306a36Sopenharmony_ci arvif->u.sta.uapsd |= value; 775862306a36Sopenharmony_ci else 775962306a36Sopenharmony_ci arvif->u.sta.uapsd &= ~value; 776062306a36Sopenharmony_ci 776162306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 776262306a36Sopenharmony_ci WMI_STA_PS_PARAM_UAPSD, 776362306a36Sopenharmony_ci arvif->u.sta.uapsd); 776462306a36Sopenharmony_ci if (ret) { 776562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set uapsd params: %d\n", ret); 776662306a36Sopenharmony_ci goto exit; 776762306a36Sopenharmony_ci } 776862306a36Sopenharmony_ci 776962306a36Sopenharmony_ci if (arvif->u.sta.uapsd) 777062306a36Sopenharmony_ci value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; 777162306a36Sopenharmony_ci else 777262306a36Sopenharmony_ci value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; 777362306a36Sopenharmony_ci 777462306a36Sopenharmony_ci ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 777562306a36Sopenharmony_ci WMI_STA_PS_PARAM_RX_WAKE_POLICY, 777662306a36Sopenharmony_ci value); 777762306a36Sopenharmony_ci if (ret) 777862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set rx wake param: %d\n", ret); 777962306a36Sopenharmony_ci 778062306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif); 778162306a36Sopenharmony_ci if (ret) { 778262306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n", 778362306a36Sopenharmony_ci arvif->vdev_id, ret); 778462306a36Sopenharmony_ci return ret; 778562306a36Sopenharmony_ci } 778662306a36Sopenharmony_ci 778762306a36Sopenharmony_ci ret = ath10k_mac_vif_recalc_ps_poll_count(arvif); 778862306a36Sopenharmony_ci if (ret) { 778962306a36Sopenharmony_ci ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n", 779062306a36Sopenharmony_ci arvif->vdev_id, ret); 779162306a36Sopenharmony_ci return ret; 779262306a36Sopenharmony_ci } 779362306a36Sopenharmony_ci 779462306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) || 779562306a36Sopenharmony_ci test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) { 779662306a36Sopenharmony_ci /* Only userspace can make an educated decision when to send 779762306a36Sopenharmony_ci * trigger frame. The following effectively disables u-UAPSD 779862306a36Sopenharmony_ci * autotrigger in firmware (which is enabled by default 779962306a36Sopenharmony_ci * provided the autotrigger service is available). 780062306a36Sopenharmony_ci */ 780162306a36Sopenharmony_ci 780262306a36Sopenharmony_ci arg.wmm_ac = acc; 780362306a36Sopenharmony_ci arg.user_priority = prio; 780462306a36Sopenharmony_ci arg.service_interval = 0; 780562306a36Sopenharmony_ci arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; 780662306a36Sopenharmony_ci arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC; 780762306a36Sopenharmony_ci 780862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id, 780962306a36Sopenharmony_ci arvif->bssid, &arg, 1); 781062306a36Sopenharmony_ci if (ret) { 781162306a36Sopenharmony_ci ath10k_warn(ar, "failed to set uapsd auto trigger %d\n", 781262306a36Sopenharmony_ci ret); 781362306a36Sopenharmony_ci return ret; 781462306a36Sopenharmony_ci } 781562306a36Sopenharmony_ci } 781662306a36Sopenharmony_ci 781762306a36Sopenharmony_ciexit: 781862306a36Sopenharmony_ci return ret; 781962306a36Sopenharmony_ci} 782062306a36Sopenharmony_ci 782162306a36Sopenharmony_cistatic int ath10k_conf_tx(struct ieee80211_hw *hw, 782262306a36Sopenharmony_ci struct ieee80211_vif *vif, 782362306a36Sopenharmony_ci unsigned int link_id, u16 ac, 782462306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 782562306a36Sopenharmony_ci{ 782662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 782762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 782862306a36Sopenharmony_ci struct wmi_wmm_params_arg *p = NULL; 782962306a36Sopenharmony_ci int ret; 783062306a36Sopenharmony_ci 783162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 783262306a36Sopenharmony_ci 783362306a36Sopenharmony_ci switch (ac) { 783462306a36Sopenharmony_ci case IEEE80211_AC_VO: 783562306a36Sopenharmony_ci p = &arvif->wmm_params.ac_vo; 783662306a36Sopenharmony_ci break; 783762306a36Sopenharmony_ci case IEEE80211_AC_VI: 783862306a36Sopenharmony_ci p = &arvif->wmm_params.ac_vi; 783962306a36Sopenharmony_ci break; 784062306a36Sopenharmony_ci case IEEE80211_AC_BE: 784162306a36Sopenharmony_ci p = &arvif->wmm_params.ac_be; 784262306a36Sopenharmony_ci break; 784362306a36Sopenharmony_ci case IEEE80211_AC_BK: 784462306a36Sopenharmony_ci p = &arvif->wmm_params.ac_bk; 784562306a36Sopenharmony_ci break; 784662306a36Sopenharmony_ci } 784762306a36Sopenharmony_ci 784862306a36Sopenharmony_ci if (WARN_ON(!p)) { 784962306a36Sopenharmony_ci ret = -EINVAL; 785062306a36Sopenharmony_ci goto exit; 785162306a36Sopenharmony_ci } 785262306a36Sopenharmony_ci 785362306a36Sopenharmony_ci p->cwmin = params->cw_min; 785462306a36Sopenharmony_ci p->cwmax = params->cw_max; 785562306a36Sopenharmony_ci p->aifs = params->aifs; 785662306a36Sopenharmony_ci 785762306a36Sopenharmony_ci /* 785862306a36Sopenharmony_ci * The channel time duration programmed in the HW is in absolute 785962306a36Sopenharmony_ci * microseconds, while mac80211 gives the txop in units of 786062306a36Sopenharmony_ci * 32 microseconds. 786162306a36Sopenharmony_ci */ 786262306a36Sopenharmony_ci p->txop = params->txop * 32; 786362306a36Sopenharmony_ci 786462306a36Sopenharmony_ci if (ar->wmi.ops->gen_vdev_wmm_conf) { 786562306a36Sopenharmony_ci ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id, 786662306a36Sopenharmony_ci &arvif->wmm_params); 786762306a36Sopenharmony_ci if (ret) { 786862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n", 786962306a36Sopenharmony_ci arvif->vdev_id, ret); 787062306a36Sopenharmony_ci goto exit; 787162306a36Sopenharmony_ci } 787262306a36Sopenharmony_ci } else { 787362306a36Sopenharmony_ci /* This won't work well with multi-interface cases but it's 787462306a36Sopenharmony_ci * better than nothing. 787562306a36Sopenharmony_ci */ 787662306a36Sopenharmony_ci ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params); 787762306a36Sopenharmony_ci if (ret) { 787862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set wmm params: %d\n", ret); 787962306a36Sopenharmony_ci goto exit; 788062306a36Sopenharmony_ci } 788162306a36Sopenharmony_ci } 788262306a36Sopenharmony_ci 788362306a36Sopenharmony_ci ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd); 788462306a36Sopenharmony_ci if (ret) 788562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret); 788662306a36Sopenharmony_ci 788762306a36Sopenharmony_ciexit: 788862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 788962306a36Sopenharmony_ci return ret; 789062306a36Sopenharmony_ci} 789162306a36Sopenharmony_ci 789262306a36Sopenharmony_cistatic int ath10k_remain_on_channel(struct ieee80211_hw *hw, 789362306a36Sopenharmony_ci struct ieee80211_vif *vif, 789462306a36Sopenharmony_ci struct ieee80211_channel *chan, 789562306a36Sopenharmony_ci int duration, 789662306a36Sopenharmony_ci enum ieee80211_roc_type type) 789762306a36Sopenharmony_ci{ 789862306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 789962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 790062306a36Sopenharmony_ci struct wmi_start_scan_arg arg; 790162306a36Sopenharmony_ci int ret = 0; 790262306a36Sopenharmony_ci u32 scan_time_msec; 790362306a36Sopenharmony_ci 790462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 790562306a36Sopenharmony_ci 790662306a36Sopenharmony_ci if (ath10k_mac_tdls_vif_stations_count(hw, vif) > 0) { 790762306a36Sopenharmony_ci ret = -EBUSY; 790862306a36Sopenharmony_ci goto exit; 790962306a36Sopenharmony_ci } 791062306a36Sopenharmony_ci 791162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 791262306a36Sopenharmony_ci switch (ar->scan.state) { 791362306a36Sopenharmony_ci case ATH10K_SCAN_IDLE: 791462306a36Sopenharmony_ci reinit_completion(&ar->scan.started); 791562306a36Sopenharmony_ci reinit_completion(&ar->scan.completed); 791662306a36Sopenharmony_ci reinit_completion(&ar->scan.on_channel); 791762306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_STARTING; 791862306a36Sopenharmony_ci ar->scan.is_roc = true; 791962306a36Sopenharmony_ci ar->scan.vdev_id = arvif->vdev_id; 792062306a36Sopenharmony_ci ar->scan.roc_freq = chan->center_freq; 792162306a36Sopenharmony_ci ar->scan.roc_notify = true; 792262306a36Sopenharmony_ci ret = 0; 792362306a36Sopenharmony_ci break; 792462306a36Sopenharmony_ci case ATH10K_SCAN_STARTING: 792562306a36Sopenharmony_ci case ATH10K_SCAN_RUNNING: 792662306a36Sopenharmony_ci case ATH10K_SCAN_ABORTING: 792762306a36Sopenharmony_ci ret = -EBUSY; 792862306a36Sopenharmony_ci break; 792962306a36Sopenharmony_ci } 793062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 793162306a36Sopenharmony_ci 793262306a36Sopenharmony_ci if (ret) 793362306a36Sopenharmony_ci goto exit; 793462306a36Sopenharmony_ci 793562306a36Sopenharmony_ci scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2; 793662306a36Sopenharmony_ci 793762306a36Sopenharmony_ci memset(&arg, 0, sizeof(arg)); 793862306a36Sopenharmony_ci ath10k_wmi_start_scan_init(ar, &arg); 793962306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 794062306a36Sopenharmony_ci arg.scan_id = ATH10K_SCAN_ID; 794162306a36Sopenharmony_ci arg.n_channels = 1; 794262306a36Sopenharmony_ci arg.channels[0] = chan->center_freq; 794362306a36Sopenharmony_ci arg.dwell_time_active = scan_time_msec; 794462306a36Sopenharmony_ci arg.dwell_time_passive = scan_time_msec; 794562306a36Sopenharmony_ci arg.max_scan_time = scan_time_msec; 794662306a36Sopenharmony_ci arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; 794762306a36Sopenharmony_ci arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; 794862306a36Sopenharmony_ci arg.burst_duration_ms = duration; 794962306a36Sopenharmony_ci 795062306a36Sopenharmony_ci ret = ath10k_start_scan(ar, &arg); 795162306a36Sopenharmony_ci if (ret) { 795262306a36Sopenharmony_ci ath10k_warn(ar, "failed to start roc scan: %d\n", ret); 795362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 795462306a36Sopenharmony_ci ar->scan.state = ATH10K_SCAN_IDLE; 795562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 795662306a36Sopenharmony_ci goto exit; 795762306a36Sopenharmony_ci } 795862306a36Sopenharmony_ci 795962306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); 796062306a36Sopenharmony_ci if (ret == 0) { 796162306a36Sopenharmony_ci ath10k_warn(ar, "failed to switch to channel for roc scan\n"); 796262306a36Sopenharmony_ci 796362306a36Sopenharmony_ci ret = ath10k_scan_stop(ar); 796462306a36Sopenharmony_ci if (ret) 796562306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop scan: %d\n", ret); 796662306a36Sopenharmony_ci 796762306a36Sopenharmony_ci ret = -ETIMEDOUT; 796862306a36Sopenharmony_ci goto exit; 796962306a36Sopenharmony_ci } 797062306a36Sopenharmony_ci 797162306a36Sopenharmony_ci ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, 797262306a36Sopenharmony_ci msecs_to_jiffies(duration)); 797362306a36Sopenharmony_ci 797462306a36Sopenharmony_ci ret = 0; 797562306a36Sopenharmony_ciexit: 797662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 797762306a36Sopenharmony_ci return ret; 797862306a36Sopenharmony_ci} 797962306a36Sopenharmony_ci 798062306a36Sopenharmony_cistatic int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw, 798162306a36Sopenharmony_ci struct ieee80211_vif *vif) 798262306a36Sopenharmony_ci{ 798362306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 798462306a36Sopenharmony_ci 798562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 798662306a36Sopenharmony_ci 798762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 798862306a36Sopenharmony_ci ar->scan.roc_notify = false; 798962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 799062306a36Sopenharmony_ci 799162306a36Sopenharmony_ci ath10k_scan_abort(ar); 799262306a36Sopenharmony_ci 799362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 799462306a36Sopenharmony_ci 799562306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->scan.timeout); 799662306a36Sopenharmony_ci 799762306a36Sopenharmony_ci return 0; 799862306a36Sopenharmony_ci} 799962306a36Sopenharmony_ci 800062306a36Sopenharmony_ci/* 800162306a36Sopenharmony_ci * Both RTS and Fragmentation threshold are interface-specific 800262306a36Sopenharmony_ci * in ath10k, but device-specific in mac80211. 800362306a36Sopenharmony_ci */ 800462306a36Sopenharmony_ci 800562306a36Sopenharmony_cistatic int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 800662306a36Sopenharmony_ci{ 800762306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 800862306a36Sopenharmony_ci struct ath10k_vif *arvif; 800962306a36Sopenharmony_ci int ret = 0; 801062306a36Sopenharmony_ci 801162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 801262306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 801362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n", 801462306a36Sopenharmony_ci arvif->vdev_id, value); 801562306a36Sopenharmony_ci 801662306a36Sopenharmony_ci ret = ath10k_mac_set_rts(arvif, value); 801762306a36Sopenharmony_ci if (ret) { 801862306a36Sopenharmony_ci ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n", 801962306a36Sopenharmony_ci arvif->vdev_id, ret); 802062306a36Sopenharmony_ci break; 802162306a36Sopenharmony_ci } 802262306a36Sopenharmony_ci } 802362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 802462306a36Sopenharmony_ci 802562306a36Sopenharmony_ci return ret; 802662306a36Sopenharmony_ci} 802762306a36Sopenharmony_ci 802862306a36Sopenharmony_cistatic int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) 802962306a36Sopenharmony_ci{ 803062306a36Sopenharmony_ci /* Even though there's a WMI enum for fragmentation threshold no known 803162306a36Sopenharmony_ci * firmware actually implements it. Moreover it is not possible to rely 803262306a36Sopenharmony_ci * frame fragmentation to mac80211 because firmware clears the "more 803362306a36Sopenharmony_ci * fragments" bit in frame control making it impossible for remote 803462306a36Sopenharmony_ci * devices to reassemble frames. 803562306a36Sopenharmony_ci * 803662306a36Sopenharmony_ci * Hence implement a dummy callback just to say fragmentation isn't 803762306a36Sopenharmony_ci * supported. This effectively prevents mac80211 from doing frame 803862306a36Sopenharmony_ci * fragmentation in software. 803962306a36Sopenharmony_ci */ 804062306a36Sopenharmony_ci return -EOPNOTSUPP; 804162306a36Sopenharmony_ci} 804262306a36Sopenharmony_ci 804362306a36Sopenharmony_civoid ath10k_mac_wait_tx_complete(struct ath10k *ar) 804462306a36Sopenharmony_ci{ 804562306a36Sopenharmony_ci bool skip; 804662306a36Sopenharmony_ci long time_left; 804762306a36Sopenharmony_ci 804862306a36Sopenharmony_ci /* mac80211 doesn't care if we really xmit queued frames or not 804962306a36Sopenharmony_ci * we'll collect those frames either way if we stop/delete vdevs 805062306a36Sopenharmony_ci */ 805162306a36Sopenharmony_ci 805262306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_WEDGED) 805362306a36Sopenharmony_ci return; 805462306a36Sopenharmony_ci 805562306a36Sopenharmony_ci time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({ 805662306a36Sopenharmony_ci bool empty; 805762306a36Sopenharmony_ci 805862306a36Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 805962306a36Sopenharmony_ci empty = (ar->htt.num_pending_tx == 0); 806062306a36Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 806162306a36Sopenharmony_ci 806262306a36Sopenharmony_ci skip = (ar->state == ATH10K_STATE_WEDGED) || 806362306a36Sopenharmony_ci test_bit(ATH10K_FLAG_CRASH_FLUSH, 806462306a36Sopenharmony_ci &ar->dev_flags); 806562306a36Sopenharmony_ci 806662306a36Sopenharmony_ci (empty || skip); 806762306a36Sopenharmony_ci }), ATH10K_FLUSH_TIMEOUT_HZ); 806862306a36Sopenharmony_ci 806962306a36Sopenharmony_ci if (time_left == 0 || skip) 807062306a36Sopenharmony_ci ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", 807162306a36Sopenharmony_ci skip, ar->state, time_left); 807262306a36Sopenharmony_ci} 807362306a36Sopenharmony_ci 807462306a36Sopenharmony_cistatic void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 807562306a36Sopenharmony_ci u32 queues, bool drop) 807662306a36Sopenharmony_ci{ 807762306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 807862306a36Sopenharmony_ci struct ath10k_vif *arvif; 807962306a36Sopenharmony_ci u32 bitmap; 808062306a36Sopenharmony_ci 808162306a36Sopenharmony_ci if (drop) { 808262306a36Sopenharmony_ci if (vif && vif->type == NL80211_IFTYPE_STATION) { 808362306a36Sopenharmony_ci bitmap = ~(1 << WMI_MGMT_TID); 808462306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 808562306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA) 808662306a36Sopenharmony_ci ath10k_wmi_peer_flush(ar, arvif->vdev_id, 808762306a36Sopenharmony_ci arvif->bssid, bitmap); 808862306a36Sopenharmony_ci } 808962306a36Sopenharmony_ci ath10k_htt_flush_tx(&ar->htt); 809062306a36Sopenharmony_ci } 809162306a36Sopenharmony_ci return; 809262306a36Sopenharmony_ci } 809362306a36Sopenharmony_ci 809462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 809562306a36Sopenharmony_ci ath10k_mac_wait_tx_complete(ar); 809662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 809762306a36Sopenharmony_ci} 809862306a36Sopenharmony_ci 809962306a36Sopenharmony_ci/* TODO: Implement this function properly 810062306a36Sopenharmony_ci * For now it is needed to reply to Probe Requests in IBSS mode. 810162306a36Sopenharmony_ci * Probably we need this information from FW. 810262306a36Sopenharmony_ci */ 810362306a36Sopenharmony_cistatic int ath10k_tx_last_beacon(struct ieee80211_hw *hw) 810462306a36Sopenharmony_ci{ 810562306a36Sopenharmony_ci return 1; 810662306a36Sopenharmony_ci} 810762306a36Sopenharmony_ci 810862306a36Sopenharmony_cistatic void ath10k_reconfig_complete(struct ieee80211_hw *hw, 810962306a36Sopenharmony_ci enum ieee80211_reconfig_type reconfig_type) 811062306a36Sopenharmony_ci{ 811162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 811262306a36Sopenharmony_ci struct ath10k_vif *arvif; 811362306a36Sopenharmony_ci 811462306a36Sopenharmony_ci if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) 811562306a36Sopenharmony_ci return; 811662306a36Sopenharmony_ci 811762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 811862306a36Sopenharmony_ci 811962306a36Sopenharmony_ci /* If device failed to restart it will be in a different state, e.g. 812062306a36Sopenharmony_ci * ATH10K_STATE_WEDGED 812162306a36Sopenharmony_ci */ 812262306a36Sopenharmony_ci if (ar->state == ATH10K_STATE_RESTARTED) { 812362306a36Sopenharmony_ci ath10k_info(ar, "device successfully recovered\n"); 812462306a36Sopenharmony_ci ar->state = ATH10K_STATE_ON; 812562306a36Sopenharmony_ci ieee80211_wake_queues(ar->hw); 812662306a36Sopenharmony_ci clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags); 812762306a36Sopenharmony_ci if (ar->hw_params.hw_restart_disconnect) { 812862306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 812962306a36Sopenharmony_ci if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) 813062306a36Sopenharmony_ci ieee80211_hw_restart_disconnect(arvif->vif); 813162306a36Sopenharmony_ci } 813262306a36Sopenharmony_ci } 813362306a36Sopenharmony_ci } 813462306a36Sopenharmony_ci 813562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 813662306a36Sopenharmony_ci} 813762306a36Sopenharmony_ci 813862306a36Sopenharmony_cistatic void 813962306a36Sopenharmony_ciath10k_mac_update_bss_chan_survey(struct ath10k *ar, 814062306a36Sopenharmony_ci struct ieee80211_channel *channel) 814162306a36Sopenharmony_ci{ 814262306a36Sopenharmony_ci int ret; 814362306a36Sopenharmony_ci enum wmi_bss_survey_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; 814462306a36Sopenharmony_ci 814562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 814662306a36Sopenharmony_ci 814762306a36Sopenharmony_ci if (!test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map) || 814862306a36Sopenharmony_ci (ar->rx_channel != channel)) 814962306a36Sopenharmony_ci return; 815062306a36Sopenharmony_ci 815162306a36Sopenharmony_ci if (ar->scan.state != ATH10K_SCAN_IDLE) { 815262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "ignoring bss chan info request while scanning..\n"); 815362306a36Sopenharmony_ci return; 815462306a36Sopenharmony_ci } 815562306a36Sopenharmony_ci 815662306a36Sopenharmony_ci reinit_completion(&ar->bss_survey_done); 815762306a36Sopenharmony_ci 815862306a36Sopenharmony_ci ret = ath10k_wmi_pdev_bss_chan_info_request(ar, type); 815962306a36Sopenharmony_ci if (ret) { 816062306a36Sopenharmony_ci ath10k_warn(ar, "failed to send pdev bss chan info request\n"); 816162306a36Sopenharmony_ci return; 816262306a36Sopenharmony_ci } 816362306a36Sopenharmony_ci 816462306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ); 816562306a36Sopenharmony_ci if (!ret) { 816662306a36Sopenharmony_ci ath10k_warn(ar, "bss channel survey timed out\n"); 816762306a36Sopenharmony_ci return; 816862306a36Sopenharmony_ci } 816962306a36Sopenharmony_ci} 817062306a36Sopenharmony_ci 817162306a36Sopenharmony_cistatic int ath10k_get_survey(struct ieee80211_hw *hw, int idx, 817262306a36Sopenharmony_ci struct survey_info *survey) 817362306a36Sopenharmony_ci{ 817462306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 817562306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 817662306a36Sopenharmony_ci struct survey_info *ar_survey = &ar->survey[idx]; 817762306a36Sopenharmony_ci int ret = 0; 817862306a36Sopenharmony_ci 817962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 818062306a36Sopenharmony_ci 818162306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; 818262306a36Sopenharmony_ci if (sband && idx >= sband->n_channels) { 818362306a36Sopenharmony_ci idx -= sband->n_channels; 818462306a36Sopenharmony_ci sband = NULL; 818562306a36Sopenharmony_ci } 818662306a36Sopenharmony_ci 818762306a36Sopenharmony_ci if (!sband) 818862306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; 818962306a36Sopenharmony_ci 819062306a36Sopenharmony_ci if (!sband || idx >= sband->n_channels) { 819162306a36Sopenharmony_ci ret = -ENOENT; 819262306a36Sopenharmony_ci goto exit; 819362306a36Sopenharmony_ci } 819462306a36Sopenharmony_ci 819562306a36Sopenharmony_ci ath10k_mac_update_bss_chan_survey(ar, &sband->channels[idx]); 819662306a36Sopenharmony_ci 819762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 819862306a36Sopenharmony_ci memcpy(survey, ar_survey, sizeof(*survey)); 819962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 820062306a36Sopenharmony_ci 820162306a36Sopenharmony_ci survey->channel = &sband->channels[idx]; 820262306a36Sopenharmony_ci 820362306a36Sopenharmony_ci if (ar->rx_channel == survey->channel) 820462306a36Sopenharmony_ci survey->filled |= SURVEY_INFO_IN_USE; 820562306a36Sopenharmony_ci 820662306a36Sopenharmony_ciexit: 820762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 820862306a36Sopenharmony_ci return ret; 820962306a36Sopenharmony_ci} 821062306a36Sopenharmony_ci 821162306a36Sopenharmony_cistatic bool 821262306a36Sopenharmony_ciath10k_mac_bitrate_mask_get_single_nss(struct ath10k *ar, 821362306a36Sopenharmony_ci enum nl80211_band band, 821462306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 821562306a36Sopenharmony_ci int *nss) 821662306a36Sopenharmony_ci{ 821762306a36Sopenharmony_ci struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; 821862306a36Sopenharmony_ci u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); 821962306a36Sopenharmony_ci u8 ht_nss_mask = 0; 822062306a36Sopenharmony_ci u8 vht_nss_mask = 0; 822162306a36Sopenharmony_ci int i; 822262306a36Sopenharmony_ci 822362306a36Sopenharmony_ci if (mask->control[band].legacy) 822462306a36Sopenharmony_ci return false; 822562306a36Sopenharmony_ci 822662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { 822762306a36Sopenharmony_ci if (mask->control[band].ht_mcs[i] == 0) 822862306a36Sopenharmony_ci continue; 822962306a36Sopenharmony_ci else if (mask->control[band].ht_mcs[i] == 823062306a36Sopenharmony_ci sband->ht_cap.mcs.rx_mask[i]) 823162306a36Sopenharmony_ci ht_nss_mask |= BIT(i); 823262306a36Sopenharmony_ci else 823362306a36Sopenharmony_ci return false; 823462306a36Sopenharmony_ci } 823562306a36Sopenharmony_ci 823662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { 823762306a36Sopenharmony_ci if (mask->control[band].vht_mcs[i] == 0) 823862306a36Sopenharmony_ci continue; 823962306a36Sopenharmony_ci else if (mask->control[band].vht_mcs[i] == 824062306a36Sopenharmony_ci ath10k_mac_get_max_vht_mcs_map(vht_mcs_map, i)) 824162306a36Sopenharmony_ci vht_nss_mask |= BIT(i); 824262306a36Sopenharmony_ci else 824362306a36Sopenharmony_ci return false; 824462306a36Sopenharmony_ci } 824562306a36Sopenharmony_ci 824662306a36Sopenharmony_ci if (ht_nss_mask != vht_nss_mask) 824762306a36Sopenharmony_ci return false; 824862306a36Sopenharmony_ci 824962306a36Sopenharmony_ci if (ht_nss_mask == 0) 825062306a36Sopenharmony_ci return false; 825162306a36Sopenharmony_ci 825262306a36Sopenharmony_ci if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask) 825362306a36Sopenharmony_ci return false; 825462306a36Sopenharmony_ci 825562306a36Sopenharmony_ci *nss = fls(ht_nss_mask); 825662306a36Sopenharmony_ci 825762306a36Sopenharmony_ci return true; 825862306a36Sopenharmony_ci} 825962306a36Sopenharmony_ci 826062306a36Sopenharmony_cistatic int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif, 826162306a36Sopenharmony_ci u8 rate, u8 nss, u8 sgi, u8 ldpc) 826262306a36Sopenharmony_ci{ 826362306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 826462306a36Sopenharmony_ci u32 vdev_param; 826562306a36Sopenharmony_ci int ret; 826662306a36Sopenharmony_ci 826762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 826862306a36Sopenharmony_ci 826962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", 827062306a36Sopenharmony_ci arvif->vdev_id, rate, nss, sgi); 827162306a36Sopenharmony_ci 827262306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->fixed_rate; 827362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate); 827462306a36Sopenharmony_ci if (ret) { 827562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n", 827662306a36Sopenharmony_ci rate, ret); 827762306a36Sopenharmony_ci return ret; 827862306a36Sopenharmony_ci } 827962306a36Sopenharmony_ci 828062306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->nss; 828162306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss); 828262306a36Sopenharmony_ci if (ret) { 828362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set nss param %d: %d\n", nss, ret); 828462306a36Sopenharmony_ci return ret; 828562306a36Sopenharmony_ci } 828662306a36Sopenharmony_ci 828762306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->sgi; 828862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, sgi); 828962306a36Sopenharmony_ci if (ret) { 829062306a36Sopenharmony_ci ath10k_warn(ar, "failed to set sgi param %d: %d\n", sgi, ret); 829162306a36Sopenharmony_ci return ret; 829262306a36Sopenharmony_ci } 829362306a36Sopenharmony_ci 829462306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->ldpc; 829562306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, ldpc); 829662306a36Sopenharmony_ci if (ret) { 829762306a36Sopenharmony_ci ath10k_warn(ar, "failed to set ldpc param %d: %d\n", ldpc, ret); 829862306a36Sopenharmony_ci return ret; 829962306a36Sopenharmony_ci } 830062306a36Sopenharmony_ci 830162306a36Sopenharmony_ci return 0; 830262306a36Sopenharmony_ci} 830362306a36Sopenharmony_ci 830462306a36Sopenharmony_cistatic bool 830562306a36Sopenharmony_ciath10k_mac_can_set_bitrate_mask(struct ath10k *ar, 830662306a36Sopenharmony_ci enum nl80211_band band, 830762306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 830862306a36Sopenharmony_ci bool allow_pfr) 830962306a36Sopenharmony_ci{ 831062306a36Sopenharmony_ci int i; 831162306a36Sopenharmony_ci u16 vht_mcs; 831262306a36Sopenharmony_ci 831362306a36Sopenharmony_ci /* Due to firmware limitation in WMI_PEER_ASSOC_CMDID it is impossible 831462306a36Sopenharmony_ci * to express all VHT MCS rate masks. Effectively only the following 831562306a36Sopenharmony_ci * ranges can be used: none, 0-7, 0-8 and 0-9. 831662306a36Sopenharmony_ci */ 831762306a36Sopenharmony_ci for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { 831862306a36Sopenharmony_ci vht_mcs = mask->control[band].vht_mcs[i]; 831962306a36Sopenharmony_ci 832062306a36Sopenharmony_ci switch (vht_mcs) { 832162306a36Sopenharmony_ci case 0: 832262306a36Sopenharmony_ci case BIT(8) - 1: 832362306a36Sopenharmony_ci case BIT(9) - 1: 832462306a36Sopenharmony_ci case BIT(10) - 1: 832562306a36Sopenharmony_ci break; 832662306a36Sopenharmony_ci default: 832762306a36Sopenharmony_ci if (!allow_pfr) 832862306a36Sopenharmony_ci ath10k_warn(ar, "refusing bitrate mask with missing 0-7 VHT MCS rates\n"); 832962306a36Sopenharmony_ci return false; 833062306a36Sopenharmony_ci } 833162306a36Sopenharmony_ci } 833262306a36Sopenharmony_ci 833362306a36Sopenharmony_ci return true; 833462306a36Sopenharmony_ci} 833562306a36Sopenharmony_ci 833662306a36Sopenharmony_cistatic bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar, 833762306a36Sopenharmony_ci struct ath10k_vif *arvif, 833862306a36Sopenharmony_ci struct ieee80211_sta *sta) 833962306a36Sopenharmony_ci{ 834062306a36Sopenharmony_ci int err; 834162306a36Sopenharmony_ci u8 rate = arvif->vht_pfr; 834262306a36Sopenharmony_ci 834362306a36Sopenharmony_ci /* skip non vht and multiple rate peers */ 834462306a36Sopenharmony_ci if (!sta->deflink.vht_cap.vht_supported || arvif->vht_num_rates != 1) 834562306a36Sopenharmony_ci return false; 834662306a36Sopenharmony_ci 834762306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 834862306a36Sopenharmony_ci WMI_PEER_PARAM_FIXED_RATE, rate); 834962306a36Sopenharmony_ci if (err) 835062306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable STA %pM peer fixed rate: %d\n", 835162306a36Sopenharmony_ci sta->addr, err); 835262306a36Sopenharmony_ci 835362306a36Sopenharmony_ci return true; 835462306a36Sopenharmony_ci} 835562306a36Sopenharmony_ci 835662306a36Sopenharmony_cistatic void ath10k_mac_set_bitrate_mask_iter(void *data, 835762306a36Sopenharmony_ci struct ieee80211_sta *sta) 835862306a36Sopenharmony_ci{ 835962306a36Sopenharmony_ci struct ath10k_vif *arvif = data; 836062306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 836162306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 836262306a36Sopenharmony_ci 836362306a36Sopenharmony_ci if (arsta->arvif != arvif) 836462306a36Sopenharmony_ci return; 836562306a36Sopenharmony_ci 836662306a36Sopenharmony_ci if (ath10k_mac_set_vht_bitrate_mask_fixup(ar, arvif, sta)) 836762306a36Sopenharmony_ci return; 836862306a36Sopenharmony_ci 836962306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 837062306a36Sopenharmony_ci arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; 837162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 837262306a36Sopenharmony_ci 837362306a36Sopenharmony_ci ieee80211_queue_work(ar->hw, &arsta->update_wk); 837462306a36Sopenharmony_ci} 837562306a36Sopenharmony_ci 837662306a36Sopenharmony_cistatic void ath10k_mac_clr_bitrate_mask_iter(void *data, 837762306a36Sopenharmony_ci struct ieee80211_sta *sta) 837862306a36Sopenharmony_ci{ 837962306a36Sopenharmony_ci struct ath10k_vif *arvif = data; 838062306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 838162306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 838262306a36Sopenharmony_ci int err; 838362306a36Sopenharmony_ci 838462306a36Sopenharmony_ci /* clear vht peers only */ 838562306a36Sopenharmony_ci if (arsta->arvif != arvif || !sta->deflink.vht_cap.vht_supported) 838662306a36Sopenharmony_ci return; 838762306a36Sopenharmony_ci 838862306a36Sopenharmony_ci err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, 838962306a36Sopenharmony_ci WMI_PEER_PARAM_FIXED_RATE, 839062306a36Sopenharmony_ci WMI_FIXED_RATE_NONE); 839162306a36Sopenharmony_ci if (err) 839262306a36Sopenharmony_ci ath10k_warn(ar, "failed to clear STA %pM peer fixed rate: %d\n", 839362306a36Sopenharmony_ci sta->addr, err); 839462306a36Sopenharmony_ci} 839562306a36Sopenharmony_ci 839662306a36Sopenharmony_cistatic int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, 839762306a36Sopenharmony_ci struct ieee80211_vif *vif, 839862306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 839962306a36Sopenharmony_ci{ 840062306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 840162306a36Sopenharmony_ci struct cfg80211_chan_def def; 840262306a36Sopenharmony_ci struct ath10k *ar = arvif->ar; 840362306a36Sopenharmony_ci enum nl80211_band band; 840462306a36Sopenharmony_ci const u8 *ht_mcs_mask; 840562306a36Sopenharmony_ci const u16 *vht_mcs_mask; 840662306a36Sopenharmony_ci u8 rate; 840762306a36Sopenharmony_ci u8 nss; 840862306a36Sopenharmony_ci u8 sgi; 840962306a36Sopenharmony_ci u8 ldpc; 841062306a36Sopenharmony_ci int single_nss; 841162306a36Sopenharmony_ci int ret; 841262306a36Sopenharmony_ci int vht_num_rates, allow_pfr; 841362306a36Sopenharmony_ci u8 vht_pfr; 841462306a36Sopenharmony_ci bool update_bitrate_mask = true; 841562306a36Sopenharmony_ci 841662306a36Sopenharmony_ci if (ath10k_mac_vif_chan(vif, &def)) 841762306a36Sopenharmony_ci return -EPERM; 841862306a36Sopenharmony_ci 841962306a36Sopenharmony_ci band = def.chan->band; 842062306a36Sopenharmony_ci ht_mcs_mask = mask->control[band].ht_mcs; 842162306a36Sopenharmony_ci vht_mcs_mask = mask->control[band].vht_mcs; 842262306a36Sopenharmony_ci ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); 842362306a36Sopenharmony_ci 842462306a36Sopenharmony_ci sgi = mask->control[band].gi; 842562306a36Sopenharmony_ci if (sgi == NL80211_TXRATE_FORCE_LGI) 842662306a36Sopenharmony_ci return -EINVAL; 842762306a36Sopenharmony_ci 842862306a36Sopenharmony_ci allow_pfr = test_bit(ATH10K_FW_FEATURE_PEER_FIXED_RATE, 842962306a36Sopenharmony_ci ar->normal_mode_fw.fw_file.fw_features); 843062306a36Sopenharmony_ci if (allow_pfr) { 843162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 843262306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 843362306a36Sopenharmony_ci ath10k_mac_clr_bitrate_mask_iter, 843462306a36Sopenharmony_ci arvif); 843562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 843662306a36Sopenharmony_ci } 843762306a36Sopenharmony_ci 843862306a36Sopenharmony_ci if (ath10k_mac_bitrate_mask_has_single_rate(ar, band, mask, 843962306a36Sopenharmony_ci &vht_num_rates)) { 844062306a36Sopenharmony_ci ret = ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask, 844162306a36Sopenharmony_ci &rate, &nss, 844262306a36Sopenharmony_ci false); 844362306a36Sopenharmony_ci if (ret) { 844462306a36Sopenharmony_ci ath10k_warn(ar, "failed to get single rate for vdev %i: %d\n", 844562306a36Sopenharmony_ci arvif->vdev_id, ret); 844662306a36Sopenharmony_ci return ret; 844762306a36Sopenharmony_ci } 844862306a36Sopenharmony_ci } else if (ath10k_mac_bitrate_mask_get_single_nss(ar, band, mask, 844962306a36Sopenharmony_ci &single_nss)) { 845062306a36Sopenharmony_ci rate = WMI_FIXED_RATE_NONE; 845162306a36Sopenharmony_ci nss = single_nss; 845262306a36Sopenharmony_ci } else { 845362306a36Sopenharmony_ci rate = WMI_FIXED_RATE_NONE; 845462306a36Sopenharmony_ci nss = min(ar->num_rf_chains, 845562306a36Sopenharmony_ci max(ath10k_mac_max_ht_nss(ht_mcs_mask), 845662306a36Sopenharmony_ci ath10k_mac_max_vht_nss(vht_mcs_mask))); 845762306a36Sopenharmony_ci 845862306a36Sopenharmony_ci if (!ath10k_mac_can_set_bitrate_mask(ar, band, mask, 845962306a36Sopenharmony_ci allow_pfr)) { 846062306a36Sopenharmony_ci u8 vht_nss; 846162306a36Sopenharmony_ci 846262306a36Sopenharmony_ci if (!allow_pfr || vht_num_rates != 1) 846362306a36Sopenharmony_ci return -EINVAL; 846462306a36Sopenharmony_ci 846562306a36Sopenharmony_ci /* Reach here, firmware supports peer fixed rate and has 846662306a36Sopenharmony_ci * single vht rate, and don't update vif birate_mask, as 846762306a36Sopenharmony_ci * the rate only for specific peer. 846862306a36Sopenharmony_ci */ 846962306a36Sopenharmony_ci ath10k_mac_bitrate_mask_get_single_rate(ar, band, mask, 847062306a36Sopenharmony_ci &vht_pfr, 847162306a36Sopenharmony_ci &vht_nss, 847262306a36Sopenharmony_ci true); 847362306a36Sopenharmony_ci update_bitrate_mask = false; 847462306a36Sopenharmony_ci } else { 847562306a36Sopenharmony_ci vht_pfr = 0; 847662306a36Sopenharmony_ci } 847762306a36Sopenharmony_ci 847862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 847962306a36Sopenharmony_ci 848062306a36Sopenharmony_ci if (update_bitrate_mask) 848162306a36Sopenharmony_ci arvif->bitrate_mask = *mask; 848262306a36Sopenharmony_ci arvif->vht_num_rates = vht_num_rates; 848362306a36Sopenharmony_ci arvif->vht_pfr = vht_pfr; 848462306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 848562306a36Sopenharmony_ci ath10k_mac_set_bitrate_mask_iter, 848662306a36Sopenharmony_ci arvif); 848762306a36Sopenharmony_ci 848862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 848962306a36Sopenharmony_ci } 849062306a36Sopenharmony_ci 849162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 849262306a36Sopenharmony_ci 849362306a36Sopenharmony_ci ret = ath10k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); 849462306a36Sopenharmony_ci if (ret) { 849562306a36Sopenharmony_ci ath10k_warn(ar, "failed to set fixed rate params on vdev %i: %d\n", 849662306a36Sopenharmony_ci arvif->vdev_id, ret); 849762306a36Sopenharmony_ci goto exit; 849862306a36Sopenharmony_ci } 849962306a36Sopenharmony_ci 850062306a36Sopenharmony_ciexit: 850162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 850262306a36Sopenharmony_ci 850362306a36Sopenharmony_ci return ret; 850462306a36Sopenharmony_ci} 850562306a36Sopenharmony_ci 850662306a36Sopenharmony_cistatic void ath10k_sta_rc_update(struct ieee80211_hw *hw, 850762306a36Sopenharmony_ci struct ieee80211_vif *vif, 850862306a36Sopenharmony_ci struct ieee80211_sta *sta, 850962306a36Sopenharmony_ci u32 changed) 851062306a36Sopenharmony_ci{ 851162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 851262306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 851362306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 851462306a36Sopenharmony_ci struct ath10k_peer *peer; 851562306a36Sopenharmony_ci u32 bw, smps; 851662306a36Sopenharmony_ci 851762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 851862306a36Sopenharmony_ci 851962306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); 852062306a36Sopenharmony_ci if (!peer) { 852162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 852262306a36Sopenharmony_ci ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", 852362306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 852462306a36Sopenharmony_ci return; 852562306a36Sopenharmony_ci } 852662306a36Sopenharmony_ci 852762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_STA, 852862306a36Sopenharmony_ci "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", 852962306a36Sopenharmony_ci sta->addr, changed, sta->deflink.bandwidth, 853062306a36Sopenharmony_ci sta->deflink.rx_nss, 853162306a36Sopenharmony_ci sta->deflink.smps_mode); 853262306a36Sopenharmony_ci 853362306a36Sopenharmony_ci if (changed & IEEE80211_RC_BW_CHANGED) { 853462306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_20MHZ; 853562306a36Sopenharmony_ci 853662306a36Sopenharmony_ci switch (sta->deflink.bandwidth) { 853762306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_20: 853862306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_20MHZ; 853962306a36Sopenharmony_ci break; 854062306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 854162306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_40MHZ; 854262306a36Sopenharmony_ci break; 854362306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 854462306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_80MHZ; 854562306a36Sopenharmony_ci break; 854662306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 854762306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_160MHZ; 854862306a36Sopenharmony_ci break; 854962306a36Sopenharmony_ci default: 855062306a36Sopenharmony_ci ath10k_warn(ar, "Invalid bandwidth %d in rc update for %pM\n", 855162306a36Sopenharmony_ci sta->deflink.bandwidth, sta->addr); 855262306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_20MHZ; 855362306a36Sopenharmony_ci break; 855462306a36Sopenharmony_ci } 855562306a36Sopenharmony_ci 855662306a36Sopenharmony_ci arsta->bw = bw; 855762306a36Sopenharmony_ci } 855862306a36Sopenharmony_ci 855962306a36Sopenharmony_ci if (changed & IEEE80211_RC_NSS_CHANGED) 856062306a36Sopenharmony_ci arsta->nss = sta->deflink.rx_nss; 856162306a36Sopenharmony_ci 856262306a36Sopenharmony_ci if (changed & IEEE80211_RC_SMPS_CHANGED) { 856362306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 856462306a36Sopenharmony_ci 856562306a36Sopenharmony_ci switch (sta->deflink.smps_mode) { 856662306a36Sopenharmony_ci case IEEE80211_SMPS_AUTOMATIC: 856762306a36Sopenharmony_ci case IEEE80211_SMPS_OFF: 856862306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 856962306a36Sopenharmony_ci break; 857062306a36Sopenharmony_ci case IEEE80211_SMPS_STATIC: 857162306a36Sopenharmony_ci smps = WMI_PEER_SMPS_STATIC; 857262306a36Sopenharmony_ci break; 857362306a36Sopenharmony_ci case IEEE80211_SMPS_DYNAMIC: 857462306a36Sopenharmony_ci smps = WMI_PEER_SMPS_DYNAMIC; 857562306a36Sopenharmony_ci break; 857662306a36Sopenharmony_ci case IEEE80211_SMPS_NUM_MODES: 857762306a36Sopenharmony_ci ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n", 857862306a36Sopenharmony_ci sta->deflink.smps_mode, sta->addr); 857962306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 858062306a36Sopenharmony_ci break; 858162306a36Sopenharmony_ci } 858262306a36Sopenharmony_ci 858362306a36Sopenharmony_ci arsta->smps = smps; 858462306a36Sopenharmony_ci } 858562306a36Sopenharmony_ci 858662306a36Sopenharmony_ci arsta->changed |= changed; 858762306a36Sopenharmony_ci 858862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 858962306a36Sopenharmony_ci 859062306a36Sopenharmony_ci ieee80211_queue_work(hw, &arsta->update_wk); 859162306a36Sopenharmony_ci} 859262306a36Sopenharmony_ci 859362306a36Sopenharmony_cistatic void ath10k_offset_tsf(struct ieee80211_hw *hw, 859462306a36Sopenharmony_ci struct ieee80211_vif *vif, s64 tsf_offset) 859562306a36Sopenharmony_ci{ 859662306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 859762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 859862306a36Sopenharmony_ci u32 offset, vdev_param; 859962306a36Sopenharmony_ci int ret; 860062306a36Sopenharmony_ci 860162306a36Sopenharmony_ci if (tsf_offset < 0) { 860262306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->dec_tsf; 860362306a36Sopenharmony_ci offset = -tsf_offset; 860462306a36Sopenharmony_ci } else { 860562306a36Sopenharmony_ci vdev_param = ar->wmi.vdev_param->inc_tsf; 860662306a36Sopenharmony_ci offset = tsf_offset; 860762306a36Sopenharmony_ci } 860862306a36Sopenharmony_ci 860962306a36Sopenharmony_ci ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, 861062306a36Sopenharmony_ci vdev_param, offset); 861162306a36Sopenharmony_ci 861262306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) 861362306a36Sopenharmony_ci ath10k_warn(ar, "failed to set tsf offset %d cmd %d: %d\n", 861462306a36Sopenharmony_ci offset, vdev_param, ret); 861562306a36Sopenharmony_ci} 861662306a36Sopenharmony_ci 861762306a36Sopenharmony_cistatic int ath10k_ampdu_action(struct ieee80211_hw *hw, 861862306a36Sopenharmony_ci struct ieee80211_vif *vif, 861962306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 862062306a36Sopenharmony_ci{ 862162306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 862262306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 862362306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 862462306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 862562306a36Sopenharmony_ci u16 tid = params->tid; 862662306a36Sopenharmony_ci 862762306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %u action %d\n", 862862306a36Sopenharmony_ci arvif->vdev_id, sta->addr, tid, action); 862962306a36Sopenharmony_ci 863062306a36Sopenharmony_ci switch (action) { 863162306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 863262306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 863362306a36Sopenharmony_ci /* HTT AddBa/DelBa events trigger mac80211 Rx BA session 863462306a36Sopenharmony_ci * creation/removal. Do we need to verify this? 863562306a36Sopenharmony_ci */ 863662306a36Sopenharmony_ci return 0; 863762306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 863862306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 863962306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 864062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 864162306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 864262306a36Sopenharmony_ci /* Firmware offloads Tx aggregation entirely so deny mac80211 864362306a36Sopenharmony_ci * Tx aggregation requests. 864462306a36Sopenharmony_ci */ 864562306a36Sopenharmony_ci return -EOPNOTSUPP; 864662306a36Sopenharmony_ci } 864762306a36Sopenharmony_ci 864862306a36Sopenharmony_ci return -EINVAL; 864962306a36Sopenharmony_ci} 865062306a36Sopenharmony_ci 865162306a36Sopenharmony_cistatic void 865262306a36Sopenharmony_ciath10k_mac_update_rx_channel(struct ath10k *ar, 865362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 865462306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 865562306a36Sopenharmony_ci int n_vifs) 865662306a36Sopenharmony_ci{ 865762306a36Sopenharmony_ci struct cfg80211_chan_def *def = NULL; 865862306a36Sopenharmony_ci 865962306a36Sopenharmony_ci /* Both locks are required because ar->rx_channel is modified. This 866062306a36Sopenharmony_ci * allows readers to hold either lock. 866162306a36Sopenharmony_ci */ 866262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 866362306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 866462306a36Sopenharmony_ci 866562306a36Sopenharmony_ci WARN_ON(ctx && vifs); 866662306a36Sopenharmony_ci WARN_ON(vifs && !n_vifs); 866762306a36Sopenharmony_ci 866862306a36Sopenharmony_ci /* FIXME: Sort of an optimization and a workaround. Peers and vifs are 866962306a36Sopenharmony_ci * on a linked list now. Doing a lookup peer -> vif -> chanctx for each 867062306a36Sopenharmony_ci * ppdu on Rx may reduce performance on low-end systems. It should be 867162306a36Sopenharmony_ci * possible to make tables/hashmaps to speed the lookup up (be vary of 867262306a36Sopenharmony_ci * cpu data cache lines though regarding sizes) but to keep the initial 867362306a36Sopenharmony_ci * implementation simple and less intrusive fallback to the slow lookup 867462306a36Sopenharmony_ci * only for multi-channel cases. Single-channel cases will remain to 867562306a36Sopenharmony_ci * use the old channel derival and thus performance should not be 867662306a36Sopenharmony_ci * affected much. 867762306a36Sopenharmony_ci */ 867862306a36Sopenharmony_ci rcu_read_lock(); 867962306a36Sopenharmony_ci if (!ctx && ath10k_mac_num_chanctxs(ar) == 1) { 868062306a36Sopenharmony_ci ieee80211_iter_chan_contexts_atomic(ar->hw, 868162306a36Sopenharmony_ci ath10k_mac_get_any_chandef_iter, 868262306a36Sopenharmony_ci &def); 868362306a36Sopenharmony_ci 868462306a36Sopenharmony_ci if (vifs) 868562306a36Sopenharmony_ci def = &vifs[0].new_ctx->def; 868662306a36Sopenharmony_ci 868762306a36Sopenharmony_ci ar->rx_channel = def->chan; 868862306a36Sopenharmony_ci } else if ((ctx && ath10k_mac_num_chanctxs(ar) == 0) || 868962306a36Sopenharmony_ci (ctx && (ar->state == ATH10K_STATE_RESTARTED))) { 869062306a36Sopenharmony_ci /* During driver restart due to firmware assert, since mac80211 869162306a36Sopenharmony_ci * already has valid channel context for given radio, channel 869262306a36Sopenharmony_ci * context iteration return num_chanctx > 0. So fix rx_channel 869362306a36Sopenharmony_ci * when restart is in progress. 869462306a36Sopenharmony_ci */ 869562306a36Sopenharmony_ci ar->rx_channel = ctx->def.chan; 869662306a36Sopenharmony_ci } else { 869762306a36Sopenharmony_ci ar->rx_channel = NULL; 869862306a36Sopenharmony_ci } 869962306a36Sopenharmony_ci rcu_read_unlock(); 870062306a36Sopenharmony_ci} 870162306a36Sopenharmony_ci 870262306a36Sopenharmony_cistatic void 870362306a36Sopenharmony_ciath10k_mac_update_vif_chan(struct ath10k *ar, 870462306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 870562306a36Sopenharmony_ci int n_vifs) 870662306a36Sopenharmony_ci{ 870762306a36Sopenharmony_ci struct ath10k_vif *arvif; 870862306a36Sopenharmony_ci int ret; 870962306a36Sopenharmony_ci int i; 871062306a36Sopenharmony_ci 871162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 871262306a36Sopenharmony_ci 871362306a36Sopenharmony_ci /* First stop monitor interface. Some FW versions crash if there's a 871462306a36Sopenharmony_ci * lone monitor interface. 871562306a36Sopenharmony_ci */ 871662306a36Sopenharmony_ci if (ar->monitor_started) 871762306a36Sopenharmony_ci ath10k_monitor_stop(ar); 871862306a36Sopenharmony_ci 871962306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 872062306a36Sopenharmony_ci arvif = (void *)vifs[i].vif->drv_priv; 872162306a36Sopenharmony_ci 872262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 872362306a36Sopenharmony_ci "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", 872462306a36Sopenharmony_ci arvif->vdev_id, 872562306a36Sopenharmony_ci vifs[i].old_ctx->def.chan->center_freq, 872662306a36Sopenharmony_ci vifs[i].new_ctx->def.chan->center_freq, 872762306a36Sopenharmony_ci vifs[i].old_ctx->def.width, 872862306a36Sopenharmony_ci vifs[i].new_ctx->def.width); 872962306a36Sopenharmony_ci 873062306a36Sopenharmony_ci if (WARN_ON(!arvif->is_started)) 873162306a36Sopenharmony_ci continue; 873262306a36Sopenharmony_ci 873362306a36Sopenharmony_ci if (WARN_ON(!arvif->is_up)) 873462306a36Sopenharmony_ci continue; 873562306a36Sopenharmony_ci 873662306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 873762306a36Sopenharmony_ci if (ret) { 873862306a36Sopenharmony_ci ath10k_warn(ar, "failed to down vdev %d: %d\n", 873962306a36Sopenharmony_ci arvif->vdev_id, ret); 874062306a36Sopenharmony_ci continue; 874162306a36Sopenharmony_ci } 874262306a36Sopenharmony_ci } 874362306a36Sopenharmony_ci 874462306a36Sopenharmony_ci /* All relevant vdevs are downed and associated channel resources 874562306a36Sopenharmony_ci * should be available for the channel switch now. 874662306a36Sopenharmony_ci */ 874762306a36Sopenharmony_ci 874862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 874962306a36Sopenharmony_ci ath10k_mac_update_rx_channel(ar, NULL, vifs, n_vifs); 875062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 875162306a36Sopenharmony_ci 875262306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 875362306a36Sopenharmony_ci arvif = (void *)vifs[i].vif->drv_priv; 875462306a36Sopenharmony_ci 875562306a36Sopenharmony_ci if (WARN_ON(!arvif->is_started)) 875662306a36Sopenharmony_ci continue; 875762306a36Sopenharmony_ci 875862306a36Sopenharmony_ci if (WARN_ON(!arvif->is_up)) 875962306a36Sopenharmony_ci continue; 876062306a36Sopenharmony_ci 876162306a36Sopenharmony_ci ret = ath10k_mac_setup_bcn_tmpl(arvif); 876262306a36Sopenharmony_ci if (ret) 876362306a36Sopenharmony_ci ath10k_warn(ar, "failed to update bcn tmpl during csa: %d\n", 876462306a36Sopenharmony_ci ret); 876562306a36Sopenharmony_ci 876662306a36Sopenharmony_ci ret = ath10k_mac_setup_prb_tmpl(arvif); 876762306a36Sopenharmony_ci if (ret) 876862306a36Sopenharmony_ci ath10k_warn(ar, "failed to update prb tmpl during csa: %d\n", 876962306a36Sopenharmony_ci ret); 877062306a36Sopenharmony_ci 877162306a36Sopenharmony_ci ret = ath10k_vdev_restart(arvif, &vifs[i].new_ctx->def); 877262306a36Sopenharmony_ci if (ret) { 877362306a36Sopenharmony_ci ath10k_warn(ar, "failed to restart vdev %d: %d\n", 877462306a36Sopenharmony_ci arvif->vdev_id, ret); 877562306a36Sopenharmony_ci continue; 877662306a36Sopenharmony_ci } 877762306a36Sopenharmony_ci 877862306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, 877962306a36Sopenharmony_ci arvif->bssid); 878062306a36Sopenharmony_ci if (ret) { 878162306a36Sopenharmony_ci ath10k_warn(ar, "failed to bring vdev up %d: %d\n", 878262306a36Sopenharmony_ci arvif->vdev_id, ret); 878362306a36Sopenharmony_ci continue; 878462306a36Sopenharmony_ci } 878562306a36Sopenharmony_ci } 878662306a36Sopenharmony_ci 878762306a36Sopenharmony_ci ath10k_monitor_recalc(ar); 878862306a36Sopenharmony_ci} 878962306a36Sopenharmony_ci 879062306a36Sopenharmony_cistatic int 879162306a36Sopenharmony_ciath10k_mac_op_add_chanctx(struct ieee80211_hw *hw, 879262306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 879362306a36Sopenharmony_ci{ 879462306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 879562306a36Sopenharmony_ci 879662306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 879762306a36Sopenharmony_ci "mac chanctx add freq %u width %d ptr %pK\n", 879862306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx); 879962306a36Sopenharmony_ci 880062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 880162306a36Sopenharmony_ci 880262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 880362306a36Sopenharmony_ci ath10k_mac_update_rx_channel(ar, ctx, NULL, 0); 880462306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 880562306a36Sopenharmony_ci 880662306a36Sopenharmony_ci ath10k_recalc_radar_detection(ar); 880762306a36Sopenharmony_ci ath10k_monitor_recalc(ar); 880862306a36Sopenharmony_ci 880962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 881062306a36Sopenharmony_ci 881162306a36Sopenharmony_ci return 0; 881262306a36Sopenharmony_ci} 881362306a36Sopenharmony_ci 881462306a36Sopenharmony_cistatic void 881562306a36Sopenharmony_ciath10k_mac_op_remove_chanctx(struct ieee80211_hw *hw, 881662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 881762306a36Sopenharmony_ci{ 881862306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 881962306a36Sopenharmony_ci 882062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 882162306a36Sopenharmony_ci "mac chanctx remove freq %u width %d ptr %pK\n", 882262306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx); 882362306a36Sopenharmony_ci 882462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 882562306a36Sopenharmony_ci 882662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 882762306a36Sopenharmony_ci ath10k_mac_update_rx_channel(ar, NULL, NULL, 0); 882862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 882962306a36Sopenharmony_ci 883062306a36Sopenharmony_ci ath10k_recalc_radar_detection(ar); 883162306a36Sopenharmony_ci ath10k_monitor_recalc(ar); 883262306a36Sopenharmony_ci 883362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 883462306a36Sopenharmony_ci} 883562306a36Sopenharmony_ci 883662306a36Sopenharmony_cistruct ath10k_mac_change_chanctx_arg { 883762306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx; 883862306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs; 883962306a36Sopenharmony_ci int n_vifs; 884062306a36Sopenharmony_ci int next_vif; 884162306a36Sopenharmony_ci}; 884262306a36Sopenharmony_ci 884362306a36Sopenharmony_cistatic void 884462306a36Sopenharmony_ciath10k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, 884562306a36Sopenharmony_ci struct ieee80211_vif *vif) 884662306a36Sopenharmony_ci{ 884762306a36Sopenharmony_ci struct ath10k_mac_change_chanctx_arg *arg = data; 884862306a36Sopenharmony_ci 884962306a36Sopenharmony_ci if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) 885062306a36Sopenharmony_ci return; 885162306a36Sopenharmony_ci 885262306a36Sopenharmony_ci arg->n_vifs++; 885362306a36Sopenharmony_ci} 885462306a36Sopenharmony_ci 885562306a36Sopenharmony_cistatic void 885662306a36Sopenharmony_ciath10k_mac_change_chanctx_fill_iter(void *data, u8 *mac, 885762306a36Sopenharmony_ci struct ieee80211_vif *vif) 885862306a36Sopenharmony_ci{ 885962306a36Sopenharmony_ci struct ath10k_mac_change_chanctx_arg *arg = data; 886062306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx; 886162306a36Sopenharmony_ci 886262306a36Sopenharmony_ci ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); 886362306a36Sopenharmony_ci if (ctx != arg->ctx) 886462306a36Sopenharmony_ci return; 886562306a36Sopenharmony_ci 886662306a36Sopenharmony_ci if (WARN_ON(arg->next_vif == arg->n_vifs)) 886762306a36Sopenharmony_ci return; 886862306a36Sopenharmony_ci 886962306a36Sopenharmony_ci arg->vifs[arg->next_vif].vif = vif; 887062306a36Sopenharmony_ci arg->vifs[arg->next_vif].old_ctx = ctx; 887162306a36Sopenharmony_ci arg->vifs[arg->next_vif].new_ctx = ctx; 887262306a36Sopenharmony_ci arg->next_vif++; 887362306a36Sopenharmony_ci} 887462306a36Sopenharmony_ci 887562306a36Sopenharmony_cistatic void 887662306a36Sopenharmony_ciath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, 887762306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 887862306a36Sopenharmony_ci u32 changed) 887962306a36Sopenharmony_ci{ 888062306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 888162306a36Sopenharmony_ci struct ath10k_mac_change_chanctx_arg arg = { .ctx = ctx }; 888262306a36Sopenharmony_ci 888362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 888462306a36Sopenharmony_ci 888562306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 888662306a36Sopenharmony_ci "mac chanctx change freq %u width %d ptr %pK changed %x\n", 888762306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx, changed); 888862306a36Sopenharmony_ci 888962306a36Sopenharmony_ci /* This shouldn't really happen because channel switching should use 889062306a36Sopenharmony_ci * switch_vif_chanctx(). 889162306a36Sopenharmony_ci */ 889262306a36Sopenharmony_ci if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) 889362306a36Sopenharmony_ci goto unlock; 889462306a36Sopenharmony_ci 889562306a36Sopenharmony_ci if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) { 889662306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 889762306a36Sopenharmony_ci hw, 889862306a36Sopenharmony_ci ATH10K_ITER_NORMAL_FLAGS, 889962306a36Sopenharmony_ci ath10k_mac_change_chanctx_cnt_iter, 890062306a36Sopenharmony_ci &arg); 890162306a36Sopenharmony_ci if (arg.n_vifs == 0) 890262306a36Sopenharmony_ci goto radar; 890362306a36Sopenharmony_ci 890462306a36Sopenharmony_ci arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]), 890562306a36Sopenharmony_ci GFP_KERNEL); 890662306a36Sopenharmony_ci if (!arg.vifs) 890762306a36Sopenharmony_ci goto radar; 890862306a36Sopenharmony_ci 890962306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 891062306a36Sopenharmony_ci hw, 891162306a36Sopenharmony_ci ATH10K_ITER_NORMAL_FLAGS, 891262306a36Sopenharmony_ci ath10k_mac_change_chanctx_fill_iter, 891362306a36Sopenharmony_ci &arg); 891462306a36Sopenharmony_ci ath10k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs); 891562306a36Sopenharmony_ci kfree(arg.vifs); 891662306a36Sopenharmony_ci } 891762306a36Sopenharmony_ci 891862306a36Sopenharmony_ciradar: 891962306a36Sopenharmony_ci ath10k_recalc_radar_detection(ar); 892062306a36Sopenharmony_ci 892162306a36Sopenharmony_ci /* FIXME: How to configure Rx chains properly? */ 892262306a36Sopenharmony_ci 892362306a36Sopenharmony_ci /* No other actions are actually necessary. Firmware maintains channel 892462306a36Sopenharmony_ci * definitions per vdev internally and there's no host-side channel 892562306a36Sopenharmony_ci * context abstraction to configure, e.g. channel width. 892662306a36Sopenharmony_ci */ 892762306a36Sopenharmony_ci 892862306a36Sopenharmony_ciunlock: 892962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 893062306a36Sopenharmony_ci} 893162306a36Sopenharmony_ci 893262306a36Sopenharmony_cistatic int 893362306a36Sopenharmony_ciath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, 893462306a36Sopenharmony_ci struct ieee80211_vif *vif, 893562306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 893662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 893762306a36Sopenharmony_ci{ 893862306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 893962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 894062306a36Sopenharmony_ci int ret; 894162306a36Sopenharmony_ci 894262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 894362306a36Sopenharmony_ci 894462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 894562306a36Sopenharmony_ci "mac chanctx assign ptr %pK vdev_id %i\n", 894662306a36Sopenharmony_ci ctx, arvif->vdev_id); 894762306a36Sopenharmony_ci 894862306a36Sopenharmony_ci if (WARN_ON(arvif->is_started)) { 894962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 895062306a36Sopenharmony_ci return -EBUSY; 895162306a36Sopenharmony_ci } 895262306a36Sopenharmony_ci 895362306a36Sopenharmony_ci ret = ath10k_vdev_start(arvif, &ctx->def); 895462306a36Sopenharmony_ci if (ret) { 895562306a36Sopenharmony_ci ath10k_warn(ar, "failed to start vdev %i addr %pM on freq %d: %d\n", 895662306a36Sopenharmony_ci arvif->vdev_id, vif->addr, 895762306a36Sopenharmony_ci ctx->def.chan->center_freq, ret); 895862306a36Sopenharmony_ci goto err; 895962306a36Sopenharmony_ci } 896062306a36Sopenharmony_ci 896162306a36Sopenharmony_ci arvif->is_started = true; 896262306a36Sopenharmony_ci 896362306a36Sopenharmony_ci ret = ath10k_mac_vif_setup_ps(arvif); 896462306a36Sopenharmony_ci if (ret) { 896562306a36Sopenharmony_ci ath10k_warn(ar, "failed to update vdev %i ps: %d\n", 896662306a36Sopenharmony_ci arvif->vdev_id, ret); 896762306a36Sopenharmony_ci goto err_stop; 896862306a36Sopenharmony_ci } 896962306a36Sopenharmony_ci 897062306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR) { 897162306a36Sopenharmony_ci ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr); 897262306a36Sopenharmony_ci if (ret) { 897362306a36Sopenharmony_ci ath10k_warn(ar, "failed to up monitor vdev %i: %d\n", 897462306a36Sopenharmony_ci arvif->vdev_id, ret); 897562306a36Sopenharmony_ci goto err_stop; 897662306a36Sopenharmony_ci } 897762306a36Sopenharmony_ci 897862306a36Sopenharmony_ci arvif->is_up = true; 897962306a36Sopenharmony_ci } 898062306a36Sopenharmony_ci 898162306a36Sopenharmony_ci if (ath10k_mac_can_set_cts_prot(arvif)) { 898262306a36Sopenharmony_ci ret = ath10k_mac_set_cts_prot(arvif); 898362306a36Sopenharmony_ci if (ret) 898462306a36Sopenharmony_ci ath10k_warn(ar, "failed to set cts protection for vdev %d: %d\n", 898562306a36Sopenharmony_ci arvif->vdev_id, ret); 898662306a36Sopenharmony_ci } 898762306a36Sopenharmony_ci 898862306a36Sopenharmony_ci if (ath10k_peer_stats_enabled(ar) && 898962306a36Sopenharmony_ci ar->hw_params.tx_stats_over_pktlog) { 899062306a36Sopenharmony_ci ar->pktlog_filter |= ATH10K_PKTLOG_PEER_STATS; 899162306a36Sopenharmony_ci ret = ath10k_wmi_pdev_pktlog_enable(ar, 899262306a36Sopenharmony_ci ar->pktlog_filter); 899362306a36Sopenharmony_ci if (ret) { 899462306a36Sopenharmony_ci ath10k_warn(ar, "failed to enable pktlog %d\n", ret); 899562306a36Sopenharmony_ci goto err_stop; 899662306a36Sopenharmony_ci } 899762306a36Sopenharmony_ci } 899862306a36Sopenharmony_ci 899962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 900062306a36Sopenharmony_ci return 0; 900162306a36Sopenharmony_ci 900262306a36Sopenharmony_cierr_stop: 900362306a36Sopenharmony_ci ath10k_vdev_stop(arvif); 900462306a36Sopenharmony_ci arvif->is_started = false; 900562306a36Sopenharmony_ci ath10k_mac_vif_setup_ps(arvif); 900662306a36Sopenharmony_ci 900762306a36Sopenharmony_cierr: 900862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 900962306a36Sopenharmony_ci return ret; 901062306a36Sopenharmony_ci} 901162306a36Sopenharmony_ci 901262306a36Sopenharmony_cistatic void 901362306a36Sopenharmony_ciath10k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, 901462306a36Sopenharmony_ci struct ieee80211_vif *vif, 901562306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 901662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 901762306a36Sopenharmony_ci{ 901862306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 901962306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 902062306a36Sopenharmony_ci int ret; 902162306a36Sopenharmony_ci 902262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 902362306a36Sopenharmony_ci 902462306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 902562306a36Sopenharmony_ci "mac chanctx unassign ptr %pK vdev_id %i\n", 902662306a36Sopenharmony_ci ctx, arvif->vdev_id); 902762306a36Sopenharmony_ci 902862306a36Sopenharmony_ci WARN_ON(!arvif->is_started); 902962306a36Sopenharmony_ci 903062306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR) { 903162306a36Sopenharmony_ci WARN_ON(!arvif->is_up); 903262306a36Sopenharmony_ci 903362306a36Sopenharmony_ci ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); 903462306a36Sopenharmony_ci if (ret) 903562306a36Sopenharmony_ci ath10k_warn(ar, "failed to down monitor vdev %i: %d\n", 903662306a36Sopenharmony_ci arvif->vdev_id, ret); 903762306a36Sopenharmony_ci 903862306a36Sopenharmony_ci arvif->is_up = false; 903962306a36Sopenharmony_ci } 904062306a36Sopenharmony_ci 904162306a36Sopenharmony_ci ret = ath10k_vdev_stop(arvif); 904262306a36Sopenharmony_ci if (ret) 904362306a36Sopenharmony_ci ath10k_warn(ar, "failed to stop vdev %i: %d\n", 904462306a36Sopenharmony_ci arvif->vdev_id, ret); 904562306a36Sopenharmony_ci 904662306a36Sopenharmony_ci arvif->is_started = false; 904762306a36Sopenharmony_ci 904862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 904962306a36Sopenharmony_ci} 905062306a36Sopenharmony_ci 905162306a36Sopenharmony_cistatic int 905262306a36Sopenharmony_ciath10k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, 905362306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 905462306a36Sopenharmony_ci int n_vifs, 905562306a36Sopenharmony_ci enum ieee80211_chanctx_switch_mode mode) 905662306a36Sopenharmony_ci{ 905762306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 905862306a36Sopenharmony_ci 905962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 906062306a36Sopenharmony_ci 906162306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 906262306a36Sopenharmony_ci "mac chanctx switch n_vifs %d mode %d\n", 906362306a36Sopenharmony_ci n_vifs, mode); 906462306a36Sopenharmony_ci ath10k_mac_update_vif_chan(ar, vifs, n_vifs); 906562306a36Sopenharmony_ci 906662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 906762306a36Sopenharmony_ci return 0; 906862306a36Sopenharmony_ci} 906962306a36Sopenharmony_ci 907062306a36Sopenharmony_cistatic void ath10k_mac_op_sta_pre_rcu_remove(struct ieee80211_hw *hw, 907162306a36Sopenharmony_ci struct ieee80211_vif *vif, 907262306a36Sopenharmony_ci struct ieee80211_sta *sta) 907362306a36Sopenharmony_ci{ 907462306a36Sopenharmony_ci struct ath10k *ar; 907562306a36Sopenharmony_ci struct ath10k_peer *peer; 907662306a36Sopenharmony_ci 907762306a36Sopenharmony_ci ar = hw->priv; 907862306a36Sopenharmony_ci 907962306a36Sopenharmony_ci list_for_each_entry(peer, &ar->peers, list) 908062306a36Sopenharmony_ci if (peer->sta == sta) 908162306a36Sopenharmony_ci peer->removed = true; 908262306a36Sopenharmony_ci} 908362306a36Sopenharmony_ci 908462306a36Sopenharmony_ci/* HT MCS parameters with Nss = 1 */ 908562306a36Sopenharmony_cistatic const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss1[] = { 908662306a36Sopenharmony_ci /* MCS L20 L40 S20 S40 */ 908762306a36Sopenharmony_ci {0, { 65, 135, 72, 150} }, 908862306a36Sopenharmony_ci {1, { 130, 270, 144, 300} }, 908962306a36Sopenharmony_ci {2, { 195, 405, 217, 450} }, 909062306a36Sopenharmony_ci {3, { 260, 540, 289, 600} }, 909162306a36Sopenharmony_ci {4, { 390, 810, 433, 900} }, 909262306a36Sopenharmony_ci {5, { 520, 1080, 578, 1200} }, 909362306a36Sopenharmony_ci {6, { 585, 1215, 650, 1350} }, 909462306a36Sopenharmony_ci {7, { 650, 1350, 722, 1500} } 909562306a36Sopenharmony_ci}; 909662306a36Sopenharmony_ci 909762306a36Sopenharmony_ci/* HT MCS parameters with Nss = 2 */ 909862306a36Sopenharmony_cistatic const struct ath10k_index_ht_data_rate_type supported_ht_mcs_rate_nss2[] = { 909962306a36Sopenharmony_ci /* MCS L20 L40 S20 S40 */ 910062306a36Sopenharmony_ci {0, {130, 270, 144, 300} }, 910162306a36Sopenharmony_ci {1, {260, 540, 289, 600} }, 910262306a36Sopenharmony_ci {2, {390, 810, 433, 900} }, 910362306a36Sopenharmony_ci {3, {520, 1080, 578, 1200} }, 910462306a36Sopenharmony_ci {4, {780, 1620, 867, 1800} }, 910562306a36Sopenharmony_ci {5, {1040, 2160, 1156, 2400} }, 910662306a36Sopenharmony_ci {6, {1170, 2430, 1300, 2700} }, 910762306a36Sopenharmony_ci {7, {1300, 2700, 1444, 3000} } 910862306a36Sopenharmony_ci}; 910962306a36Sopenharmony_ci 911062306a36Sopenharmony_ci/* MCS parameters with Nss = 1 */ 911162306a36Sopenharmony_cistatic const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { 911262306a36Sopenharmony_ci /* MCS L80 S80 L40 S40 L20 S20 */ 911362306a36Sopenharmony_ci {0, {293, 325}, {135, 150}, {65, 72} }, 911462306a36Sopenharmony_ci {1, {585, 650}, {270, 300}, {130, 144} }, 911562306a36Sopenharmony_ci {2, {878, 975}, {405, 450}, {195, 217} }, 911662306a36Sopenharmony_ci {3, {1170, 1300}, {540, 600}, {260, 289} }, 911762306a36Sopenharmony_ci {4, {1755, 1950}, {810, 900}, {390, 433} }, 911862306a36Sopenharmony_ci {5, {2340, 2600}, {1080, 1200}, {520, 578} }, 911962306a36Sopenharmony_ci {6, {2633, 2925}, {1215, 1350}, {585, 650} }, 912062306a36Sopenharmony_ci {7, {2925, 3250}, {1350, 1500}, {650, 722} }, 912162306a36Sopenharmony_ci {8, {3510, 3900}, {1620, 1800}, {780, 867} }, 912262306a36Sopenharmony_ci {9, {3900, 4333}, {1800, 2000}, {780, 867} } 912362306a36Sopenharmony_ci}; 912462306a36Sopenharmony_ci 912562306a36Sopenharmony_ci/*MCS parameters with Nss = 2 */ 912662306a36Sopenharmony_cistatic const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { 912762306a36Sopenharmony_ci /* MCS L80 S80 L40 S40 L20 S20 */ 912862306a36Sopenharmony_ci {0, {585, 650}, {270, 300}, {130, 144} }, 912962306a36Sopenharmony_ci {1, {1170, 1300}, {540, 600}, {260, 289} }, 913062306a36Sopenharmony_ci {2, {1755, 1950}, {810, 900}, {390, 433} }, 913162306a36Sopenharmony_ci {3, {2340, 2600}, {1080, 1200}, {520, 578} }, 913262306a36Sopenharmony_ci {4, {3510, 3900}, {1620, 1800}, {780, 867} }, 913362306a36Sopenharmony_ci {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, 913462306a36Sopenharmony_ci {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, 913562306a36Sopenharmony_ci {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, 913662306a36Sopenharmony_ci {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, 913762306a36Sopenharmony_ci {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } 913862306a36Sopenharmony_ci}; 913962306a36Sopenharmony_ci 914062306a36Sopenharmony_cistatic void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs, 914162306a36Sopenharmony_ci u8 *flags, u8 *bw) 914262306a36Sopenharmony_ci{ 914362306a36Sopenharmony_ci struct ath10k_index_ht_data_rate_type *mcs_rate; 914462306a36Sopenharmony_ci u8 index; 914562306a36Sopenharmony_ci size_t len_nss1 = ARRAY_SIZE(supported_ht_mcs_rate_nss1); 914662306a36Sopenharmony_ci size_t len_nss2 = ARRAY_SIZE(supported_ht_mcs_rate_nss2); 914762306a36Sopenharmony_ci 914862306a36Sopenharmony_ci if (mcs >= (len_nss1 + len_nss2)) { 914962306a36Sopenharmony_ci ath10k_warn(ar, "not supported mcs %d in current rate table", mcs); 915062306a36Sopenharmony_ci return; 915162306a36Sopenharmony_ci } 915262306a36Sopenharmony_ci 915362306a36Sopenharmony_ci mcs_rate = (struct ath10k_index_ht_data_rate_type *) 915462306a36Sopenharmony_ci ((nss == 1) ? &supported_ht_mcs_rate_nss1 : 915562306a36Sopenharmony_ci &supported_ht_mcs_rate_nss2); 915662306a36Sopenharmony_ci 915762306a36Sopenharmony_ci if (mcs >= len_nss1) 915862306a36Sopenharmony_ci index = mcs - len_nss1; 915962306a36Sopenharmony_ci else 916062306a36Sopenharmony_ci index = mcs; 916162306a36Sopenharmony_ci 916262306a36Sopenharmony_ci if (rate == mcs_rate[index].supported_rate[0]) { 916362306a36Sopenharmony_ci *bw = RATE_INFO_BW_20; 916462306a36Sopenharmony_ci } else if (rate == mcs_rate[index].supported_rate[1]) { 916562306a36Sopenharmony_ci *bw |= RATE_INFO_BW_40; 916662306a36Sopenharmony_ci } else if (rate == mcs_rate[index].supported_rate[2]) { 916762306a36Sopenharmony_ci *bw |= RATE_INFO_BW_20; 916862306a36Sopenharmony_ci *flags |= RATE_INFO_FLAGS_SHORT_GI; 916962306a36Sopenharmony_ci } else if (rate == mcs_rate[index].supported_rate[3]) { 917062306a36Sopenharmony_ci *bw |= RATE_INFO_BW_40; 917162306a36Sopenharmony_ci *flags |= RATE_INFO_FLAGS_SHORT_GI; 917262306a36Sopenharmony_ci } else { 917362306a36Sopenharmony_ci ath10k_warn(ar, "invalid ht params rate %d 100kbps nss %d mcs %d", 917462306a36Sopenharmony_ci rate, nss, mcs); 917562306a36Sopenharmony_ci } 917662306a36Sopenharmony_ci} 917762306a36Sopenharmony_ci 917862306a36Sopenharmony_cistatic void ath10k_mac_get_rate_flags_vht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs, 917962306a36Sopenharmony_ci u8 *flags, u8 *bw) 918062306a36Sopenharmony_ci{ 918162306a36Sopenharmony_ci struct ath10k_index_vht_data_rate_type *mcs_rate; 918262306a36Sopenharmony_ci 918362306a36Sopenharmony_ci mcs_rate = (struct ath10k_index_vht_data_rate_type *) 918462306a36Sopenharmony_ci ((nss == 1) ? &supported_vht_mcs_rate_nss1 : 918562306a36Sopenharmony_ci &supported_vht_mcs_rate_nss2); 918662306a36Sopenharmony_ci 918762306a36Sopenharmony_ci if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) { 918862306a36Sopenharmony_ci *bw = RATE_INFO_BW_80; 918962306a36Sopenharmony_ci } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) { 919062306a36Sopenharmony_ci *bw = RATE_INFO_BW_80; 919162306a36Sopenharmony_ci *flags |= RATE_INFO_FLAGS_SHORT_GI; 919262306a36Sopenharmony_ci } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) { 919362306a36Sopenharmony_ci *bw = RATE_INFO_BW_40; 919462306a36Sopenharmony_ci } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) { 919562306a36Sopenharmony_ci *bw = RATE_INFO_BW_40; 919662306a36Sopenharmony_ci *flags |= RATE_INFO_FLAGS_SHORT_GI; 919762306a36Sopenharmony_ci } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) { 919862306a36Sopenharmony_ci *bw = RATE_INFO_BW_20; 919962306a36Sopenharmony_ci } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) { 920062306a36Sopenharmony_ci *bw = RATE_INFO_BW_20; 920162306a36Sopenharmony_ci *flags |= RATE_INFO_FLAGS_SHORT_GI; 920262306a36Sopenharmony_ci } else { 920362306a36Sopenharmony_ci ath10k_warn(ar, "invalid vht params rate %d 100kbps nss %d mcs %d", 920462306a36Sopenharmony_ci rate, nss, mcs); 920562306a36Sopenharmony_ci } 920662306a36Sopenharmony_ci} 920762306a36Sopenharmony_ci 920862306a36Sopenharmony_cistatic void ath10k_mac_get_rate_flags(struct ath10k *ar, u32 rate, 920962306a36Sopenharmony_ci enum ath10k_phy_mode mode, u8 nss, u8 mcs, 921062306a36Sopenharmony_ci u8 *flags, u8 *bw) 921162306a36Sopenharmony_ci{ 921262306a36Sopenharmony_ci if (mode == ATH10K_PHY_MODE_HT) { 921362306a36Sopenharmony_ci *flags = RATE_INFO_FLAGS_MCS; 921462306a36Sopenharmony_ci ath10k_mac_get_rate_flags_ht(ar, rate, nss, mcs, flags, bw); 921562306a36Sopenharmony_ci } else if (mode == ATH10K_PHY_MODE_VHT) { 921662306a36Sopenharmony_ci *flags = RATE_INFO_FLAGS_VHT_MCS; 921762306a36Sopenharmony_ci ath10k_mac_get_rate_flags_vht(ar, rate, nss, mcs, flags, bw); 921862306a36Sopenharmony_ci } 921962306a36Sopenharmony_ci} 922062306a36Sopenharmony_ci 922162306a36Sopenharmony_cistatic void ath10k_mac_parse_bitrate(struct ath10k *ar, u32 rate_code, 922262306a36Sopenharmony_ci u32 bitrate_kbps, struct rate_info *rate) 922362306a36Sopenharmony_ci{ 922462306a36Sopenharmony_ci enum ath10k_phy_mode mode = ATH10K_PHY_MODE_LEGACY; 922562306a36Sopenharmony_ci enum wmi_rate_preamble preamble = WMI_TLV_GET_HW_RC_PREAM_V1(rate_code); 922662306a36Sopenharmony_ci u8 nss = WMI_TLV_GET_HW_RC_NSS_V1(rate_code) + 1; 922762306a36Sopenharmony_ci u8 mcs = WMI_TLV_GET_HW_RC_RATE_V1(rate_code); 922862306a36Sopenharmony_ci u8 flags = 0, bw = 0; 922962306a36Sopenharmony_ci 923062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, "mac parse rate code 0x%x bitrate %d kbps\n", 923162306a36Sopenharmony_ci rate_code, bitrate_kbps); 923262306a36Sopenharmony_ci 923362306a36Sopenharmony_ci if (preamble == WMI_RATE_PREAMBLE_HT) 923462306a36Sopenharmony_ci mode = ATH10K_PHY_MODE_HT; 923562306a36Sopenharmony_ci else if (preamble == WMI_RATE_PREAMBLE_VHT) 923662306a36Sopenharmony_ci mode = ATH10K_PHY_MODE_VHT; 923762306a36Sopenharmony_ci 923862306a36Sopenharmony_ci ath10k_mac_get_rate_flags(ar, bitrate_kbps / 100, mode, nss, mcs, &flags, &bw); 923962306a36Sopenharmony_ci 924062306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_MAC, 924162306a36Sopenharmony_ci "mac parse bitrate preamble %d mode %d nss %d mcs %d flags %x bw %d\n", 924262306a36Sopenharmony_ci preamble, mode, nss, mcs, flags, bw); 924362306a36Sopenharmony_ci 924462306a36Sopenharmony_ci rate->flags = flags; 924562306a36Sopenharmony_ci rate->bw = bw; 924662306a36Sopenharmony_ci rate->legacy = bitrate_kbps / 100; 924762306a36Sopenharmony_ci rate->nss = nss; 924862306a36Sopenharmony_ci rate->mcs = mcs; 924962306a36Sopenharmony_ci} 925062306a36Sopenharmony_ci 925162306a36Sopenharmony_cistatic void ath10k_mac_sta_get_peer_stats_info(struct ath10k *ar, 925262306a36Sopenharmony_ci struct ieee80211_sta *sta, 925362306a36Sopenharmony_ci struct station_info *sinfo) 925462306a36Sopenharmony_ci{ 925562306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 925662306a36Sopenharmony_ci struct ath10k_peer *peer; 925762306a36Sopenharmony_ci unsigned long time_left; 925862306a36Sopenharmony_ci int ret; 925962306a36Sopenharmony_ci 926062306a36Sopenharmony_ci if (!(ar->hw_params.supports_peer_stats_info && 926162306a36Sopenharmony_ci arsta->arvif->vdev_type == WMI_VDEV_TYPE_STA)) 926262306a36Sopenharmony_ci return; 926362306a36Sopenharmony_ci 926462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 926562306a36Sopenharmony_ci peer = ath10k_peer_find(ar, arsta->arvif->vdev_id, sta->addr); 926662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 926762306a36Sopenharmony_ci if (!peer) 926862306a36Sopenharmony_ci return; 926962306a36Sopenharmony_ci 927062306a36Sopenharmony_ci reinit_completion(&ar->peer_stats_info_complete); 927162306a36Sopenharmony_ci 927262306a36Sopenharmony_ci ret = ath10k_wmi_request_peer_stats_info(ar, 927362306a36Sopenharmony_ci arsta->arvif->vdev_id, 927462306a36Sopenharmony_ci WMI_REQUEST_ONE_PEER_STATS_INFO, 927562306a36Sopenharmony_ci arsta->arvif->bssid, 927662306a36Sopenharmony_ci 0); 927762306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 927862306a36Sopenharmony_ci ath10k_warn(ar, "could not request peer stats info: %d\n", ret); 927962306a36Sopenharmony_ci return; 928062306a36Sopenharmony_ci } 928162306a36Sopenharmony_ci 928262306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->peer_stats_info_complete, 3 * HZ); 928362306a36Sopenharmony_ci if (time_left == 0) { 928462306a36Sopenharmony_ci ath10k_warn(ar, "timed out waiting peer stats info\n"); 928562306a36Sopenharmony_ci return; 928662306a36Sopenharmony_ci } 928762306a36Sopenharmony_ci 928862306a36Sopenharmony_ci if (arsta->rx_rate_code != 0 && arsta->rx_bitrate_kbps != 0) { 928962306a36Sopenharmony_ci ath10k_mac_parse_bitrate(ar, arsta->rx_rate_code, 929062306a36Sopenharmony_ci arsta->rx_bitrate_kbps, 929162306a36Sopenharmony_ci &sinfo->rxrate); 929262306a36Sopenharmony_ci 929362306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); 929462306a36Sopenharmony_ci arsta->rx_rate_code = 0; 929562306a36Sopenharmony_ci arsta->rx_bitrate_kbps = 0; 929662306a36Sopenharmony_ci } 929762306a36Sopenharmony_ci 929862306a36Sopenharmony_ci if (arsta->tx_rate_code != 0 && arsta->tx_bitrate_kbps != 0) { 929962306a36Sopenharmony_ci ath10k_mac_parse_bitrate(ar, arsta->tx_rate_code, 930062306a36Sopenharmony_ci arsta->tx_bitrate_kbps, 930162306a36Sopenharmony_ci &sinfo->txrate); 930262306a36Sopenharmony_ci 930362306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 930462306a36Sopenharmony_ci arsta->tx_rate_code = 0; 930562306a36Sopenharmony_ci arsta->tx_bitrate_kbps = 0; 930662306a36Sopenharmony_ci } 930762306a36Sopenharmony_ci} 930862306a36Sopenharmony_ci 930962306a36Sopenharmony_cistatic void ath10k_sta_statistics(struct ieee80211_hw *hw, 931062306a36Sopenharmony_ci struct ieee80211_vif *vif, 931162306a36Sopenharmony_ci struct ieee80211_sta *sta, 931262306a36Sopenharmony_ci struct station_info *sinfo) 931362306a36Sopenharmony_ci{ 931462306a36Sopenharmony_ci struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; 931562306a36Sopenharmony_ci struct ath10k *ar = arsta->arvif->ar; 931662306a36Sopenharmony_ci 931762306a36Sopenharmony_ci if (!ath10k_peer_stats_enabled(ar)) 931862306a36Sopenharmony_ci return; 931962306a36Sopenharmony_ci 932062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 932162306a36Sopenharmony_ci ath10k_debug_fw_stats_request(ar); 932262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 932362306a36Sopenharmony_ci 932462306a36Sopenharmony_ci sinfo->rx_duration = arsta->rx_duration; 932562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); 932662306a36Sopenharmony_ci 932762306a36Sopenharmony_ci if (arsta->txrate.legacy || arsta->txrate.nss) { 932862306a36Sopenharmony_ci if (arsta->txrate.legacy) { 932962306a36Sopenharmony_ci sinfo->txrate.legacy = arsta->txrate.legacy; 933062306a36Sopenharmony_ci } else { 933162306a36Sopenharmony_ci sinfo->txrate.mcs = arsta->txrate.mcs; 933262306a36Sopenharmony_ci sinfo->txrate.nss = arsta->txrate.nss; 933362306a36Sopenharmony_ci sinfo->txrate.bw = arsta->txrate.bw; 933462306a36Sopenharmony_ci } 933562306a36Sopenharmony_ci sinfo->txrate.flags = arsta->txrate.flags; 933662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 933762306a36Sopenharmony_ci } 933862306a36Sopenharmony_ci 933962306a36Sopenharmony_ci if (ar->htt.disable_tx_comp) { 934062306a36Sopenharmony_ci sinfo->tx_failed = arsta->tx_failed; 934162306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 934262306a36Sopenharmony_ci } 934362306a36Sopenharmony_ci 934462306a36Sopenharmony_ci sinfo->tx_retries = arsta->tx_retries; 934562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); 934662306a36Sopenharmony_ci 934762306a36Sopenharmony_ci ath10k_mac_sta_get_peer_stats_info(ar, sta, sinfo); 934862306a36Sopenharmony_ci} 934962306a36Sopenharmony_ci 935062306a36Sopenharmony_cistatic int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw, 935162306a36Sopenharmony_ci struct ieee80211_vif *vif, 935262306a36Sopenharmony_ci struct ieee80211_sta *sta, 935362306a36Sopenharmony_ci struct cfg80211_tid_config *tid_config) 935462306a36Sopenharmony_ci{ 935562306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 935662306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 935762306a36Sopenharmony_ci struct ath10k_mac_iter_tid_conf_data data = {}; 935862306a36Sopenharmony_ci struct wmi_per_peer_per_tid_cfg_arg arg = {}; 935962306a36Sopenharmony_ci int ret, i; 936062306a36Sopenharmony_ci 936162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 936262306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 936362306a36Sopenharmony_ci 936462306a36Sopenharmony_ci arvif->tids_rst = 0; 936562306a36Sopenharmony_ci memset(arvif->tid_conf_changed, 0, sizeof(arvif->tid_conf_changed)); 936662306a36Sopenharmony_ci 936762306a36Sopenharmony_ci for (i = 0; i < tid_config->n_tid_conf; i++) { 936862306a36Sopenharmony_ci ret = ath10k_mac_parse_tid_config(ar, sta, vif, 936962306a36Sopenharmony_ci &tid_config->tid_conf[i], 937062306a36Sopenharmony_ci &arg); 937162306a36Sopenharmony_ci if (ret) 937262306a36Sopenharmony_ci goto exit; 937362306a36Sopenharmony_ci } 937462306a36Sopenharmony_ci 937562306a36Sopenharmony_ci ret = 0; 937662306a36Sopenharmony_ci 937762306a36Sopenharmony_ci if (sta) 937862306a36Sopenharmony_ci goto exit; 937962306a36Sopenharmony_ci 938062306a36Sopenharmony_ci arvif->tids_rst = 0; 938162306a36Sopenharmony_ci data.curr_vif = vif; 938262306a36Sopenharmony_ci data.ar = ar; 938362306a36Sopenharmony_ci 938462306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf, 938562306a36Sopenharmony_ci &data); 938662306a36Sopenharmony_ci 938762306a36Sopenharmony_ciexit: 938862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 938962306a36Sopenharmony_ci return ret; 939062306a36Sopenharmony_ci} 939162306a36Sopenharmony_ci 939262306a36Sopenharmony_cistatic int ath10k_mac_op_reset_tid_config(struct ieee80211_hw *hw, 939362306a36Sopenharmony_ci struct ieee80211_vif *vif, 939462306a36Sopenharmony_ci struct ieee80211_sta *sta, 939562306a36Sopenharmony_ci u8 tids) 939662306a36Sopenharmony_ci{ 939762306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 939862306a36Sopenharmony_ci struct ath10k_mac_iter_tid_conf_data data = {}; 939962306a36Sopenharmony_ci struct ath10k *ar = hw->priv; 940062306a36Sopenharmony_ci int ret = 0; 940162306a36Sopenharmony_ci 940262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 940362306a36Sopenharmony_ci 940462306a36Sopenharmony_ci if (sta) { 940562306a36Sopenharmony_ci arvif->tids_rst = 0; 940662306a36Sopenharmony_ci ret = ath10k_mac_reset_tid_config(ar, sta, arvif, tids); 940762306a36Sopenharmony_ci goto exit; 940862306a36Sopenharmony_ci } 940962306a36Sopenharmony_ci 941062306a36Sopenharmony_ci arvif->tids_rst = tids; 941162306a36Sopenharmony_ci data.curr_vif = vif; 941262306a36Sopenharmony_ci data.ar = ar; 941362306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, ath10k_mac_vif_stations_tid_conf, 941462306a36Sopenharmony_ci &data); 941562306a36Sopenharmony_ci 941662306a36Sopenharmony_ciexit: 941762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 941862306a36Sopenharmony_ci return ret; 941962306a36Sopenharmony_ci} 942062306a36Sopenharmony_ci 942162306a36Sopenharmony_cistatic const struct ieee80211_ops ath10k_ops = { 942262306a36Sopenharmony_ci .tx = ath10k_mac_op_tx, 942362306a36Sopenharmony_ci .wake_tx_queue = ath10k_mac_op_wake_tx_queue, 942462306a36Sopenharmony_ci .start = ath10k_start, 942562306a36Sopenharmony_ci .stop = ath10k_stop, 942662306a36Sopenharmony_ci .config = ath10k_config, 942762306a36Sopenharmony_ci .add_interface = ath10k_add_interface, 942862306a36Sopenharmony_ci .update_vif_offload = ath10k_update_vif_offload, 942962306a36Sopenharmony_ci .remove_interface = ath10k_remove_interface, 943062306a36Sopenharmony_ci .configure_filter = ath10k_configure_filter, 943162306a36Sopenharmony_ci .bss_info_changed = ath10k_bss_info_changed, 943262306a36Sopenharmony_ci .set_coverage_class = ath10k_mac_op_set_coverage_class, 943362306a36Sopenharmony_ci .hw_scan = ath10k_hw_scan, 943462306a36Sopenharmony_ci .cancel_hw_scan = ath10k_cancel_hw_scan, 943562306a36Sopenharmony_ci .set_key = ath10k_set_key, 943662306a36Sopenharmony_ci .set_default_unicast_key = ath10k_set_default_unicast_key, 943762306a36Sopenharmony_ci .sta_state = ath10k_sta_state, 943862306a36Sopenharmony_ci .sta_set_txpwr = ath10k_sta_set_txpwr, 943962306a36Sopenharmony_ci .conf_tx = ath10k_conf_tx, 944062306a36Sopenharmony_ci .remain_on_channel = ath10k_remain_on_channel, 944162306a36Sopenharmony_ci .cancel_remain_on_channel = ath10k_cancel_remain_on_channel, 944262306a36Sopenharmony_ci .set_rts_threshold = ath10k_set_rts_threshold, 944362306a36Sopenharmony_ci .set_frag_threshold = ath10k_mac_op_set_frag_threshold, 944462306a36Sopenharmony_ci .flush = ath10k_flush, 944562306a36Sopenharmony_ci .tx_last_beacon = ath10k_tx_last_beacon, 944662306a36Sopenharmony_ci .set_antenna = ath10k_set_antenna, 944762306a36Sopenharmony_ci .get_antenna = ath10k_get_antenna, 944862306a36Sopenharmony_ci .reconfig_complete = ath10k_reconfig_complete, 944962306a36Sopenharmony_ci .get_survey = ath10k_get_survey, 945062306a36Sopenharmony_ci .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask, 945162306a36Sopenharmony_ci .sta_rc_update = ath10k_sta_rc_update, 945262306a36Sopenharmony_ci .offset_tsf = ath10k_offset_tsf, 945362306a36Sopenharmony_ci .ampdu_action = ath10k_ampdu_action, 945462306a36Sopenharmony_ci .get_et_sset_count = ath10k_debug_get_et_sset_count, 945562306a36Sopenharmony_ci .get_et_stats = ath10k_debug_get_et_stats, 945662306a36Sopenharmony_ci .get_et_strings = ath10k_debug_get_et_strings, 945762306a36Sopenharmony_ci .add_chanctx = ath10k_mac_op_add_chanctx, 945862306a36Sopenharmony_ci .remove_chanctx = ath10k_mac_op_remove_chanctx, 945962306a36Sopenharmony_ci .change_chanctx = ath10k_mac_op_change_chanctx, 946062306a36Sopenharmony_ci .assign_vif_chanctx = ath10k_mac_op_assign_vif_chanctx, 946162306a36Sopenharmony_ci .unassign_vif_chanctx = ath10k_mac_op_unassign_vif_chanctx, 946262306a36Sopenharmony_ci .switch_vif_chanctx = ath10k_mac_op_switch_vif_chanctx, 946362306a36Sopenharmony_ci .sta_pre_rcu_remove = ath10k_mac_op_sta_pre_rcu_remove, 946462306a36Sopenharmony_ci .sta_statistics = ath10k_sta_statistics, 946562306a36Sopenharmony_ci .set_tid_config = ath10k_mac_op_set_tid_config, 946662306a36Sopenharmony_ci .reset_tid_config = ath10k_mac_op_reset_tid_config, 946762306a36Sopenharmony_ci 946862306a36Sopenharmony_ci CFG80211_TESTMODE_CMD(ath10k_tm_cmd) 946962306a36Sopenharmony_ci 947062306a36Sopenharmony_ci#ifdef CONFIG_PM 947162306a36Sopenharmony_ci .suspend = ath10k_wow_op_suspend, 947262306a36Sopenharmony_ci .resume = ath10k_wow_op_resume, 947362306a36Sopenharmony_ci .set_wakeup = ath10k_wow_op_set_wakeup, 947462306a36Sopenharmony_ci#endif 947562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS 947662306a36Sopenharmony_ci .sta_add_debugfs = ath10k_sta_add_debugfs, 947762306a36Sopenharmony_ci#endif 947862306a36Sopenharmony_ci .set_sar_specs = ath10k_mac_set_sar_specs, 947962306a36Sopenharmony_ci}; 948062306a36Sopenharmony_ci 948162306a36Sopenharmony_ci#define CHAN2G(_channel, _freq, _flags) { \ 948262306a36Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 948362306a36Sopenharmony_ci .hw_value = (_channel), \ 948462306a36Sopenharmony_ci .center_freq = (_freq), \ 948562306a36Sopenharmony_ci .flags = (_flags), \ 948662306a36Sopenharmony_ci .max_antenna_gain = 0, \ 948762306a36Sopenharmony_ci .max_power = 30, \ 948862306a36Sopenharmony_ci} 948962306a36Sopenharmony_ci 949062306a36Sopenharmony_ci#define CHAN5G(_channel, _freq, _flags) { \ 949162306a36Sopenharmony_ci .band = NL80211_BAND_5GHZ, \ 949262306a36Sopenharmony_ci .hw_value = (_channel), \ 949362306a36Sopenharmony_ci .center_freq = (_freq), \ 949462306a36Sopenharmony_ci .flags = (_flags), \ 949562306a36Sopenharmony_ci .max_antenna_gain = 0, \ 949662306a36Sopenharmony_ci .max_power = 30, \ 949762306a36Sopenharmony_ci} 949862306a36Sopenharmony_ci 949962306a36Sopenharmony_cistatic const struct ieee80211_channel ath10k_2ghz_channels[] = { 950062306a36Sopenharmony_ci CHAN2G(1, 2412, 0), 950162306a36Sopenharmony_ci CHAN2G(2, 2417, 0), 950262306a36Sopenharmony_ci CHAN2G(3, 2422, 0), 950362306a36Sopenharmony_ci CHAN2G(4, 2427, 0), 950462306a36Sopenharmony_ci CHAN2G(5, 2432, 0), 950562306a36Sopenharmony_ci CHAN2G(6, 2437, 0), 950662306a36Sopenharmony_ci CHAN2G(7, 2442, 0), 950762306a36Sopenharmony_ci CHAN2G(8, 2447, 0), 950862306a36Sopenharmony_ci CHAN2G(9, 2452, 0), 950962306a36Sopenharmony_ci CHAN2G(10, 2457, 0), 951062306a36Sopenharmony_ci CHAN2G(11, 2462, 0), 951162306a36Sopenharmony_ci CHAN2G(12, 2467, 0), 951262306a36Sopenharmony_ci CHAN2G(13, 2472, 0), 951362306a36Sopenharmony_ci CHAN2G(14, 2484, 0), 951462306a36Sopenharmony_ci}; 951562306a36Sopenharmony_ci 951662306a36Sopenharmony_cistatic const struct ieee80211_channel ath10k_5ghz_channels[] = { 951762306a36Sopenharmony_ci CHAN5G(36, 5180, 0), 951862306a36Sopenharmony_ci CHAN5G(40, 5200, 0), 951962306a36Sopenharmony_ci CHAN5G(44, 5220, 0), 952062306a36Sopenharmony_ci CHAN5G(48, 5240, 0), 952162306a36Sopenharmony_ci CHAN5G(52, 5260, 0), 952262306a36Sopenharmony_ci CHAN5G(56, 5280, 0), 952362306a36Sopenharmony_ci CHAN5G(60, 5300, 0), 952462306a36Sopenharmony_ci CHAN5G(64, 5320, 0), 952562306a36Sopenharmony_ci CHAN5G(100, 5500, 0), 952662306a36Sopenharmony_ci CHAN5G(104, 5520, 0), 952762306a36Sopenharmony_ci CHAN5G(108, 5540, 0), 952862306a36Sopenharmony_ci CHAN5G(112, 5560, 0), 952962306a36Sopenharmony_ci CHAN5G(116, 5580, 0), 953062306a36Sopenharmony_ci CHAN5G(120, 5600, 0), 953162306a36Sopenharmony_ci CHAN5G(124, 5620, 0), 953262306a36Sopenharmony_ci CHAN5G(128, 5640, 0), 953362306a36Sopenharmony_ci CHAN5G(132, 5660, 0), 953462306a36Sopenharmony_ci CHAN5G(136, 5680, 0), 953562306a36Sopenharmony_ci CHAN5G(140, 5700, 0), 953662306a36Sopenharmony_ci CHAN5G(144, 5720, 0), 953762306a36Sopenharmony_ci CHAN5G(149, 5745, 0), 953862306a36Sopenharmony_ci CHAN5G(153, 5765, 0), 953962306a36Sopenharmony_ci CHAN5G(157, 5785, 0), 954062306a36Sopenharmony_ci CHAN5G(161, 5805, 0), 954162306a36Sopenharmony_ci CHAN5G(165, 5825, 0), 954262306a36Sopenharmony_ci CHAN5G(169, 5845, 0), 954362306a36Sopenharmony_ci CHAN5G(173, 5865, 0), 954462306a36Sopenharmony_ci /* If you add more, you may need to change ATH10K_MAX_5G_CHAN */ 954562306a36Sopenharmony_ci /* And you will definitely need to change ATH10K_NUM_CHANS in core.h */ 954662306a36Sopenharmony_ci}; 954762306a36Sopenharmony_ci 954862306a36Sopenharmony_cistruct ath10k *ath10k_mac_create(size_t priv_size) 954962306a36Sopenharmony_ci{ 955062306a36Sopenharmony_ci struct ieee80211_hw *hw; 955162306a36Sopenharmony_ci struct ieee80211_ops *ops; 955262306a36Sopenharmony_ci struct ath10k *ar; 955362306a36Sopenharmony_ci 955462306a36Sopenharmony_ci ops = kmemdup(&ath10k_ops, sizeof(ath10k_ops), GFP_KERNEL); 955562306a36Sopenharmony_ci if (!ops) 955662306a36Sopenharmony_ci return NULL; 955762306a36Sopenharmony_ci 955862306a36Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, ops); 955962306a36Sopenharmony_ci if (!hw) { 956062306a36Sopenharmony_ci kfree(ops); 956162306a36Sopenharmony_ci return NULL; 956262306a36Sopenharmony_ci } 956362306a36Sopenharmony_ci 956462306a36Sopenharmony_ci ar = hw->priv; 956562306a36Sopenharmony_ci ar->hw = hw; 956662306a36Sopenharmony_ci ar->ops = ops; 956762306a36Sopenharmony_ci 956862306a36Sopenharmony_ci return ar; 956962306a36Sopenharmony_ci} 957062306a36Sopenharmony_ci 957162306a36Sopenharmony_civoid ath10k_mac_destroy(struct ath10k *ar) 957262306a36Sopenharmony_ci{ 957362306a36Sopenharmony_ci struct ieee80211_ops *ops = ar->ops; 957462306a36Sopenharmony_ci 957562306a36Sopenharmony_ci ieee80211_free_hw(ar->hw); 957662306a36Sopenharmony_ci kfree(ops); 957762306a36Sopenharmony_ci} 957862306a36Sopenharmony_ci 957962306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_if_limits[] = { 958062306a36Sopenharmony_ci { 958162306a36Sopenharmony_ci .max = 8, 958262306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION) 958362306a36Sopenharmony_ci | BIT(NL80211_IFTYPE_P2P_CLIENT) 958462306a36Sopenharmony_ci }, 958562306a36Sopenharmony_ci { 958662306a36Sopenharmony_ci .max = 3, 958762306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_GO) 958862306a36Sopenharmony_ci }, 958962306a36Sopenharmony_ci { 959062306a36Sopenharmony_ci .max = 1, 959162306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_DEVICE) 959262306a36Sopenharmony_ci }, 959362306a36Sopenharmony_ci { 959462306a36Sopenharmony_ci .max = 7, 959562306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) 959662306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 959762306a36Sopenharmony_ci | BIT(NL80211_IFTYPE_MESH_POINT) 959862306a36Sopenharmony_ci#endif 959962306a36Sopenharmony_ci }, 960062306a36Sopenharmony_ci}; 960162306a36Sopenharmony_ci 960262306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { 960362306a36Sopenharmony_ci { 960462306a36Sopenharmony_ci .max = 8, 960562306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) 960662306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 960762306a36Sopenharmony_ci | BIT(NL80211_IFTYPE_MESH_POINT) 960862306a36Sopenharmony_ci#endif 960962306a36Sopenharmony_ci }, 961062306a36Sopenharmony_ci { 961162306a36Sopenharmony_ci .max = 1, 961262306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION) 961362306a36Sopenharmony_ci }, 961462306a36Sopenharmony_ci}; 961562306a36Sopenharmony_ci 961662306a36Sopenharmony_cistatic const struct ieee80211_iface_combination ath10k_if_comb[] = { 961762306a36Sopenharmony_ci { 961862306a36Sopenharmony_ci .limits = ath10k_if_limits, 961962306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_if_limits), 962062306a36Sopenharmony_ci .max_interfaces = 8, 962162306a36Sopenharmony_ci .num_different_channels = 1, 962262306a36Sopenharmony_ci .beacon_int_infra_match = true, 962362306a36Sopenharmony_ci }, 962462306a36Sopenharmony_ci}; 962562306a36Sopenharmony_ci 962662306a36Sopenharmony_cistatic const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { 962762306a36Sopenharmony_ci { 962862306a36Sopenharmony_ci .limits = ath10k_10x_if_limits, 962962306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_10x_if_limits), 963062306a36Sopenharmony_ci .max_interfaces = 8, 963162306a36Sopenharmony_ci .num_different_channels = 1, 963262306a36Sopenharmony_ci .beacon_int_infra_match = true, 963362306a36Sopenharmony_ci .beacon_int_min_gcd = 1, 963462306a36Sopenharmony_ci#ifdef CONFIG_ATH10K_DFS_CERTIFIED 963562306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 963662306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 963762306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 963862306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80), 963962306a36Sopenharmony_ci#endif 964062306a36Sopenharmony_ci }, 964162306a36Sopenharmony_ci}; 964262306a36Sopenharmony_ci 964362306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { 964462306a36Sopenharmony_ci { 964562306a36Sopenharmony_ci .max = 2, 964662306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 964762306a36Sopenharmony_ci }, 964862306a36Sopenharmony_ci { 964962306a36Sopenharmony_ci .max = 2, 965062306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) | 965162306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 965262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 965362306a36Sopenharmony_ci#endif 965462306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 965562306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO), 965662306a36Sopenharmony_ci }, 965762306a36Sopenharmony_ci { 965862306a36Sopenharmony_ci .max = 1, 965962306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_DEVICE), 966062306a36Sopenharmony_ci }, 966162306a36Sopenharmony_ci}; 966262306a36Sopenharmony_ci 966362306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = { 966462306a36Sopenharmony_ci { 966562306a36Sopenharmony_ci .max = 2, 966662306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 966762306a36Sopenharmony_ci }, 966862306a36Sopenharmony_ci { 966962306a36Sopenharmony_ci .max = 2, 967062306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_CLIENT), 967162306a36Sopenharmony_ci }, 967262306a36Sopenharmony_ci { 967362306a36Sopenharmony_ci .max = 1, 967462306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) | 967562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 967662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 967762306a36Sopenharmony_ci#endif 967862306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO), 967962306a36Sopenharmony_ci }, 968062306a36Sopenharmony_ci { 968162306a36Sopenharmony_ci .max = 1, 968262306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_P2P_DEVICE), 968362306a36Sopenharmony_ci }, 968462306a36Sopenharmony_ci}; 968562306a36Sopenharmony_ci 968662306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = { 968762306a36Sopenharmony_ci { 968862306a36Sopenharmony_ci .max = 1, 968962306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 969062306a36Sopenharmony_ci }, 969162306a36Sopenharmony_ci { 969262306a36Sopenharmony_ci .max = 1, 969362306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_ADHOC), 969462306a36Sopenharmony_ci }, 969562306a36Sopenharmony_ci}; 969662306a36Sopenharmony_ci 969762306a36Sopenharmony_ci/* FIXME: This is not thoroughly tested. These combinations may over- or 969862306a36Sopenharmony_ci * underestimate hw/fw capabilities. 969962306a36Sopenharmony_ci */ 970062306a36Sopenharmony_cistatic struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { 970162306a36Sopenharmony_ci { 970262306a36Sopenharmony_ci .limits = ath10k_tlv_if_limit, 970362306a36Sopenharmony_ci .num_different_channels = 1, 970462306a36Sopenharmony_ci .max_interfaces = 4, 970562306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), 970662306a36Sopenharmony_ci }, 970762306a36Sopenharmony_ci { 970862306a36Sopenharmony_ci .limits = ath10k_tlv_if_limit_ibss, 970962306a36Sopenharmony_ci .num_different_channels = 1, 971062306a36Sopenharmony_ci .max_interfaces = 2, 971162306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss), 971262306a36Sopenharmony_ci }, 971362306a36Sopenharmony_ci}; 971462306a36Sopenharmony_ci 971562306a36Sopenharmony_cistatic struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { 971662306a36Sopenharmony_ci { 971762306a36Sopenharmony_ci .limits = ath10k_tlv_if_limit, 971862306a36Sopenharmony_ci .num_different_channels = 1, 971962306a36Sopenharmony_ci .max_interfaces = 4, 972062306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), 972162306a36Sopenharmony_ci }, 972262306a36Sopenharmony_ci { 972362306a36Sopenharmony_ci .limits = ath10k_tlv_qcs_if_limit, 972462306a36Sopenharmony_ci .num_different_channels = 2, 972562306a36Sopenharmony_ci .max_interfaces = 4, 972662306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_tlv_qcs_if_limit), 972762306a36Sopenharmony_ci }, 972862306a36Sopenharmony_ci { 972962306a36Sopenharmony_ci .limits = ath10k_tlv_if_limit_ibss, 973062306a36Sopenharmony_ci .num_different_channels = 1, 973162306a36Sopenharmony_ci .max_interfaces = 2, 973262306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit_ibss), 973362306a36Sopenharmony_ci }, 973462306a36Sopenharmony_ci}; 973562306a36Sopenharmony_ci 973662306a36Sopenharmony_cistatic const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { 973762306a36Sopenharmony_ci { 973862306a36Sopenharmony_ci .max = 1, 973962306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_STATION), 974062306a36Sopenharmony_ci }, 974162306a36Sopenharmony_ci { 974262306a36Sopenharmony_ci .max = 16, 974362306a36Sopenharmony_ci .types = BIT(NL80211_IFTYPE_AP) 974462306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 974562306a36Sopenharmony_ci | BIT(NL80211_IFTYPE_MESH_POINT) 974662306a36Sopenharmony_ci#endif 974762306a36Sopenharmony_ci }, 974862306a36Sopenharmony_ci}; 974962306a36Sopenharmony_ci 975062306a36Sopenharmony_cistatic const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { 975162306a36Sopenharmony_ci { 975262306a36Sopenharmony_ci .limits = ath10k_10_4_if_limits, 975362306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), 975462306a36Sopenharmony_ci .max_interfaces = 16, 975562306a36Sopenharmony_ci .num_different_channels = 1, 975662306a36Sopenharmony_ci .beacon_int_infra_match = true, 975762306a36Sopenharmony_ci .beacon_int_min_gcd = 1, 975862306a36Sopenharmony_ci#ifdef CONFIG_ATH10K_DFS_CERTIFIED 975962306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 976062306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 976162306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 976262306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80) | 976362306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80P80) | 976462306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_160), 976562306a36Sopenharmony_ci#endif 976662306a36Sopenharmony_ci }, 976762306a36Sopenharmony_ci}; 976862306a36Sopenharmony_ci 976962306a36Sopenharmony_cistatic const struct 977062306a36Sopenharmony_ciieee80211_iface_combination ath10k_10_4_bcn_int_if_comb[] = { 977162306a36Sopenharmony_ci { 977262306a36Sopenharmony_ci .limits = ath10k_10_4_if_limits, 977362306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), 977462306a36Sopenharmony_ci .max_interfaces = 16, 977562306a36Sopenharmony_ci .num_different_channels = 1, 977662306a36Sopenharmony_ci .beacon_int_infra_match = true, 977762306a36Sopenharmony_ci .beacon_int_min_gcd = 100, 977862306a36Sopenharmony_ci#ifdef CONFIG_ATH10K_DFS_CERTIFIED 977962306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 978062306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 978162306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 978262306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80) | 978362306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80P80) | 978462306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_160), 978562306a36Sopenharmony_ci#endif 978662306a36Sopenharmony_ci }, 978762306a36Sopenharmony_ci}; 978862306a36Sopenharmony_ci 978962306a36Sopenharmony_cistatic void ath10k_get_arvif_iter(void *data, u8 *mac, 979062306a36Sopenharmony_ci struct ieee80211_vif *vif) 979162306a36Sopenharmony_ci{ 979262306a36Sopenharmony_ci struct ath10k_vif_iter *arvif_iter = data; 979362306a36Sopenharmony_ci struct ath10k_vif *arvif = (void *)vif->drv_priv; 979462306a36Sopenharmony_ci 979562306a36Sopenharmony_ci if (arvif->vdev_id == arvif_iter->vdev_id) 979662306a36Sopenharmony_ci arvif_iter->arvif = arvif; 979762306a36Sopenharmony_ci} 979862306a36Sopenharmony_ci 979962306a36Sopenharmony_cistruct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) 980062306a36Sopenharmony_ci{ 980162306a36Sopenharmony_ci struct ath10k_vif_iter arvif_iter; 980262306a36Sopenharmony_ci 980362306a36Sopenharmony_ci memset(&arvif_iter, 0, sizeof(struct ath10k_vif_iter)); 980462306a36Sopenharmony_ci arvif_iter.vdev_id = vdev_id; 980562306a36Sopenharmony_ci 980662306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 980762306a36Sopenharmony_ci ATH10K_ITER_RESUME_FLAGS, 980862306a36Sopenharmony_ci ath10k_get_arvif_iter, 980962306a36Sopenharmony_ci &arvif_iter); 981062306a36Sopenharmony_ci if (!arvif_iter.arvif) { 981162306a36Sopenharmony_ci ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id); 981262306a36Sopenharmony_ci return NULL; 981362306a36Sopenharmony_ci } 981462306a36Sopenharmony_ci 981562306a36Sopenharmony_ci return arvif_iter.arvif; 981662306a36Sopenharmony_ci} 981762306a36Sopenharmony_ci 981862306a36Sopenharmony_ci#define WRD_METHOD "WRDD" 981962306a36Sopenharmony_ci#define WRDD_WIFI (0x07) 982062306a36Sopenharmony_ci 982162306a36Sopenharmony_cistatic u32 ath10k_mac_wrdd_get_mcc(struct ath10k *ar, union acpi_object *wrdd) 982262306a36Sopenharmony_ci{ 982362306a36Sopenharmony_ci union acpi_object *mcc_pkg; 982462306a36Sopenharmony_ci union acpi_object *domain_type; 982562306a36Sopenharmony_ci union acpi_object *mcc_value; 982662306a36Sopenharmony_ci u32 i; 982762306a36Sopenharmony_ci 982862306a36Sopenharmony_ci if (wrdd->type != ACPI_TYPE_PACKAGE || 982962306a36Sopenharmony_ci wrdd->package.count < 2 || 983062306a36Sopenharmony_ci wrdd->package.elements[0].type != ACPI_TYPE_INTEGER || 983162306a36Sopenharmony_ci wrdd->package.elements[0].integer.value != 0) { 983262306a36Sopenharmony_ci ath10k_warn(ar, "ignoring malformed/unsupported wrdd structure\n"); 983362306a36Sopenharmony_ci return 0; 983462306a36Sopenharmony_ci } 983562306a36Sopenharmony_ci 983662306a36Sopenharmony_ci for (i = 1; i < wrdd->package.count; ++i) { 983762306a36Sopenharmony_ci mcc_pkg = &wrdd->package.elements[i]; 983862306a36Sopenharmony_ci 983962306a36Sopenharmony_ci if (mcc_pkg->type != ACPI_TYPE_PACKAGE) 984062306a36Sopenharmony_ci continue; 984162306a36Sopenharmony_ci if (mcc_pkg->package.count < 2) 984262306a36Sopenharmony_ci continue; 984362306a36Sopenharmony_ci if (mcc_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || 984462306a36Sopenharmony_ci mcc_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) 984562306a36Sopenharmony_ci continue; 984662306a36Sopenharmony_ci 984762306a36Sopenharmony_ci domain_type = &mcc_pkg->package.elements[0]; 984862306a36Sopenharmony_ci if (domain_type->integer.value != WRDD_WIFI) 984962306a36Sopenharmony_ci continue; 985062306a36Sopenharmony_ci 985162306a36Sopenharmony_ci mcc_value = &mcc_pkg->package.elements[1]; 985262306a36Sopenharmony_ci return mcc_value->integer.value; 985362306a36Sopenharmony_ci } 985462306a36Sopenharmony_ci return 0; 985562306a36Sopenharmony_ci} 985662306a36Sopenharmony_ci 985762306a36Sopenharmony_cistatic int ath10k_mac_get_wrdd_regulatory(struct ath10k *ar, u16 *rd) 985862306a36Sopenharmony_ci{ 985962306a36Sopenharmony_ci acpi_handle root_handle; 986062306a36Sopenharmony_ci acpi_handle handle; 986162306a36Sopenharmony_ci struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL}; 986262306a36Sopenharmony_ci acpi_status status; 986362306a36Sopenharmony_ci u32 alpha2_code; 986462306a36Sopenharmony_ci char alpha2[3]; 986562306a36Sopenharmony_ci 986662306a36Sopenharmony_ci root_handle = ACPI_HANDLE(ar->dev); 986762306a36Sopenharmony_ci if (!root_handle) 986862306a36Sopenharmony_ci return -EOPNOTSUPP; 986962306a36Sopenharmony_ci 987062306a36Sopenharmony_ci status = acpi_get_handle(root_handle, (acpi_string)WRD_METHOD, &handle); 987162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 987262306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, 987362306a36Sopenharmony_ci "failed to get wrd method %d\n", status); 987462306a36Sopenharmony_ci return -EIO; 987562306a36Sopenharmony_ci } 987662306a36Sopenharmony_ci 987762306a36Sopenharmony_ci status = acpi_evaluate_object(handle, NULL, NULL, &wrdd); 987862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 987962306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, 988062306a36Sopenharmony_ci "failed to call wrdc %d\n", status); 988162306a36Sopenharmony_ci return -EIO; 988262306a36Sopenharmony_ci } 988362306a36Sopenharmony_ci 988462306a36Sopenharmony_ci alpha2_code = ath10k_mac_wrdd_get_mcc(ar, wrdd.pointer); 988562306a36Sopenharmony_ci kfree(wrdd.pointer); 988662306a36Sopenharmony_ci if (!alpha2_code) 988762306a36Sopenharmony_ci return -EIO; 988862306a36Sopenharmony_ci 988962306a36Sopenharmony_ci alpha2[0] = (alpha2_code >> 8) & 0xff; 989062306a36Sopenharmony_ci alpha2[1] = (alpha2_code >> 0) & 0xff; 989162306a36Sopenharmony_ci alpha2[2] = '\0'; 989262306a36Sopenharmony_ci 989362306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, 989462306a36Sopenharmony_ci "regulatory hint from WRDD (alpha2-code): %s\n", alpha2); 989562306a36Sopenharmony_ci 989662306a36Sopenharmony_ci *rd = ath_regd_find_country_by_name(alpha2); 989762306a36Sopenharmony_ci if (*rd == 0xffff) 989862306a36Sopenharmony_ci return -EIO; 989962306a36Sopenharmony_ci 990062306a36Sopenharmony_ci *rd |= COUNTRY_ERD_FLAG; 990162306a36Sopenharmony_ci return 0; 990262306a36Sopenharmony_ci} 990362306a36Sopenharmony_ci 990462306a36Sopenharmony_cistatic int ath10k_mac_init_rd(struct ath10k *ar) 990562306a36Sopenharmony_ci{ 990662306a36Sopenharmony_ci int ret; 990762306a36Sopenharmony_ci u16 rd; 990862306a36Sopenharmony_ci 990962306a36Sopenharmony_ci ret = ath10k_mac_get_wrdd_regulatory(ar, &rd); 991062306a36Sopenharmony_ci if (ret) { 991162306a36Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, 991262306a36Sopenharmony_ci "fallback to eeprom programmed regulatory settings\n"); 991362306a36Sopenharmony_ci rd = ar->hw_eeprom_rd; 991462306a36Sopenharmony_ci } 991562306a36Sopenharmony_ci 991662306a36Sopenharmony_ci ar->ath_common.regulatory.current_rd = rd; 991762306a36Sopenharmony_ci return 0; 991862306a36Sopenharmony_ci} 991962306a36Sopenharmony_ci 992062306a36Sopenharmony_ciint ath10k_mac_register(struct ath10k *ar) 992162306a36Sopenharmony_ci{ 992262306a36Sopenharmony_ci static const u32 cipher_suites[] = { 992362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP40, 992462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_WEP104, 992562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_TKIP, 992662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP, 992762306a36Sopenharmony_ci 992862306a36Sopenharmony_ci /* Do not add hardware supported ciphers before this line. 992962306a36Sopenharmony_ci * Allow software encryption for all chips. Don't forget to 993062306a36Sopenharmony_ci * update n_cipher_suites below. 993162306a36Sopenharmony_ci */ 993262306a36Sopenharmony_ci WLAN_CIPHER_SUITE_AES_CMAC, 993362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_CMAC_256, 993462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_128, 993562306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_256, 993662306a36Sopenharmony_ci 993762306a36Sopenharmony_ci /* Only QCA99x0 and QCA4019 variants support GCMP-128, GCMP-256 993862306a36Sopenharmony_ci * and CCMP-256 in hardware. 993962306a36Sopenharmony_ci */ 994062306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP, 994162306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP_256, 994262306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP_256, 994362306a36Sopenharmony_ci }; 994462306a36Sopenharmony_ci struct ieee80211_supported_band *band; 994562306a36Sopenharmony_ci void *channels; 994662306a36Sopenharmony_ci int ret; 994762306a36Sopenharmony_ci 994862306a36Sopenharmony_ci if (!is_valid_ether_addr(ar->mac_addr)) { 994962306a36Sopenharmony_ci ath10k_warn(ar, "invalid MAC address; choosing random\n"); 995062306a36Sopenharmony_ci eth_random_addr(ar->mac_addr); 995162306a36Sopenharmony_ci } 995262306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); 995362306a36Sopenharmony_ci 995462306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, ar->dev); 995562306a36Sopenharmony_ci 995662306a36Sopenharmony_ci BUILD_BUG_ON((ARRAY_SIZE(ath10k_2ghz_channels) + 995762306a36Sopenharmony_ci ARRAY_SIZE(ath10k_5ghz_channels)) != 995862306a36Sopenharmony_ci ATH10K_NUM_CHANS); 995962306a36Sopenharmony_ci 996062306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11G_CAPABILITY) { 996162306a36Sopenharmony_ci channels = kmemdup(ath10k_2ghz_channels, 996262306a36Sopenharmony_ci sizeof(ath10k_2ghz_channels), 996362306a36Sopenharmony_ci GFP_KERNEL); 996462306a36Sopenharmony_ci if (!channels) { 996562306a36Sopenharmony_ci ret = -ENOMEM; 996662306a36Sopenharmony_ci goto err_free; 996762306a36Sopenharmony_ci } 996862306a36Sopenharmony_ci 996962306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_2GHZ]; 997062306a36Sopenharmony_ci band->n_channels = ARRAY_SIZE(ath10k_2ghz_channels); 997162306a36Sopenharmony_ci band->channels = channels; 997262306a36Sopenharmony_ci 997362306a36Sopenharmony_ci if (ar->hw_params.cck_rate_map_rev2) { 997462306a36Sopenharmony_ci band->n_bitrates = ath10k_g_rates_rev2_size; 997562306a36Sopenharmony_ci band->bitrates = ath10k_g_rates_rev2; 997662306a36Sopenharmony_ci } else { 997762306a36Sopenharmony_ci band->n_bitrates = ath10k_g_rates_size; 997862306a36Sopenharmony_ci band->bitrates = ath10k_g_rates; 997962306a36Sopenharmony_ci } 998062306a36Sopenharmony_ci 998162306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; 998262306a36Sopenharmony_ci } 998362306a36Sopenharmony_ci 998462306a36Sopenharmony_ci if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY) { 998562306a36Sopenharmony_ci channels = kmemdup(ath10k_5ghz_channels, 998662306a36Sopenharmony_ci sizeof(ath10k_5ghz_channels), 998762306a36Sopenharmony_ci GFP_KERNEL); 998862306a36Sopenharmony_ci if (!channels) { 998962306a36Sopenharmony_ci ret = -ENOMEM; 999062306a36Sopenharmony_ci goto err_free; 999162306a36Sopenharmony_ci } 999262306a36Sopenharmony_ci 999362306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_5GHZ]; 999462306a36Sopenharmony_ci band->n_channels = ARRAY_SIZE(ath10k_5ghz_channels); 999562306a36Sopenharmony_ci band->channels = channels; 999662306a36Sopenharmony_ci band->n_bitrates = ath10k_a_rates_size; 999762306a36Sopenharmony_ci band->bitrates = ath10k_a_rates; 999862306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; 999962306a36Sopenharmony_ci } 1000062306a36Sopenharmony_ci 1000162306a36Sopenharmony_ci wiphy_read_of_freq_limits(ar->hw->wiphy); 1000262306a36Sopenharmony_ci ath10k_mac_setup_ht_vht_cap(ar); 1000362306a36Sopenharmony_ci 1000462306a36Sopenharmony_ci ar->hw->wiphy->interface_modes = 1000562306a36Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | 1000662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 1000762306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT); 1000862306a36Sopenharmony_ci 1000962306a36Sopenharmony_ci ar->hw->wiphy->available_antennas_rx = ar->cfg_rx_chainmask; 1001062306a36Sopenharmony_ci ar->hw->wiphy->available_antennas_tx = ar->cfg_tx_chainmask; 1001162306a36Sopenharmony_ci 1001262306a36Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->normal_mode_fw.fw_file.fw_features)) 1001362306a36Sopenharmony_ci ar->hw->wiphy->interface_modes |= 1001462306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE) | 1001562306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 1001662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO); 1001762306a36Sopenharmony_ci 1001862306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SIGNAL_DBM); 1001962306a36Sopenharmony_ci 1002062306a36Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_NO_PS, 1002162306a36Sopenharmony_ci ar->running_fw->fw_file.fw_features)) { 1002262306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_PS); 1002362306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); 1002462306a36Sopenharmony_ci } 1002562306a36Sopenharmony_ci 1002662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, MFP_CAPABLE); 1002762306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS); 1002862306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); 1002962306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, AP_LINK_PS); 1003062306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); 1003162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); 1003262306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); 1003362306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); 1003462306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF); 1003562306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); 1003662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, QUEUE_CONTROL); 1003762306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); 1003862306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); 1003962306a36Sopenharmony_ci 1004062306a36Sopenharmony_ci if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) 1004162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); 1004262306a36Sopenharmony_ci 1004362306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; 1004462306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 1004562306a36Sopenharmony_ci 1004662306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) 1004762306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; 1004862306a36Sopenharmony_ci 1004962306a36Sopenharmony_ci if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) { 1005062306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); 1005162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); 1005262306a36Sopenharmony_ci } 1005362306a36Sopenharmony_ci 1005462306a36Sopenharmony_ci ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; 1005562306a36Sopenharmony_ci ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; 1005662306a36Sopenharmony_ci 1005762306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) { 1005862306a36Sopenharmony_ci ar->hw->wiphy->max_sched_scan_ssids = WMI_PNO_MAX_SUPP_NETWORKS; 1005962306a36Sopenharmony_ci ar->hw->wiphy->max_match_sets = WMI_PNO_MAX_SUPP_NETWORKS; 1006062306a36Sopenharmony_ci ar->hw->wiphy->max_sched_scan_ie_len = WMI_PNO_MAX_IE_LENGTH; 1006162306a36Sopenharmony_ci ar->hw->wiphy->max_sched_scan_plans = WMI_PNO_MAX_SCHED_SCAN_PLANS; 1006262306a36Sopenharmony_ci ar->hw->wiphy->max_sched_scan_plan_interval = 1006362306a36Sopenharmony_ci WMI_PNO_MAX_SCHED_SCAN_PLAN_INT; 1006462306a36Sopenharmony_ci ar->hw->wiphy->max_sched_scan_plan_iterations = 1006562306a36Sopenharmony_ci WMI_PNO_MAX_SCHED_SCAN_PLAN_ITRNS; 1006662306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR; 1006762306a36Sopenharmony_ci } 1006862306a36Sopenharmony_ci 1006962306a36Sopenharmony_ci ar->hw->vif_data_size = sizeof(struct ath10k_vif); 1007062306a36Sopenharmony_ci ar->hw->sta_data_size = sizeof(struct ath10k_sta); 1007162306a36Sopenharmony_ci ar->hw->txq_data_size = sizeof(struct ath10k_txq); 1007262306a36Sopenharmony_ci 1007362306a36Sopenharmony_ci ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL; 1007462306a36Sopenharmony_ci 1007562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) { 1007662306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; 1007762306a36Sopenharmony_ci 1007862306a36Sopenharmony_ci /* Firmware delivers WPS/P2P Probe Requests frames to driver so 1007962306a36Sopenharmony_ci * that userspace (e.g. wpa_supplicant/hostapd) can generate 1008062306a36Sopenharmony_ci * correct Probe Responses. This is more of a hack advert.. 1008162306a36Sopenharmony_ci */ 1008262306a36Sopenharmony_ci ar->hw->wiphy->probe_resp_offload |= 1008362306a36Sopenharmony_ci NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | 1008462306a36Sopenharmony_ci NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | 1008562306a36Sopenharmony_ci NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; 1008662306a36Sopenharmony_ci } 1008762306a36Sopenharmony_ci 1008862306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map) || 1008962306a36Sopenharmony_ci test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, ar->wmi.svc_map)) { 1009062306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; 1009162306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TDLS_WIDER_BANDWIDTH, ar->wmi.svc_map)) 1009262306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); 1009362306a36Sopenharmony_ci } 1009462306a36Sopenharmony_ci 1009562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) 1009662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA); 1009762306a36Sopenharmony_ci 1009862306a36Sopenharmony_ci if (ath10k_frame_mode == ATH10K_HW_TXRX_ETHERNET) { 1009962306a36Sopenharmony_ci if (ar->wmi.vdev_param->tx_encap_type != 1010062306a36Sopenharmony_ci WMI_VDEV_PARAM_UNSUPPORTED) 1010162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); 1010262306a36Sopenharmony_ci } 1010362306a36Sopenharmony_ci 1010462306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 1010562306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 1010662306a36Sopenharmony_ci ar->hw->wiphy->max_remain_on_channel_duration = 5000; 1010762306a36Sopenharmony_ci 1010862306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 1010962306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 1011062306a36Sopenharmony_ci NL80211_FEATURE_AP_SCAN; 1011162306a36Sopenharmony_ci 1011262306a36Sopenharmony_ci ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; 1011362306a36Sopenharmony_ci 1011462306a36Sopenharmony_ci ret = ath10k_wow_init(ar); 1011562306a36Sopenharmony_ci if (ret) { 1011662306a36Sopenharmony_ci ath10k_warn(ar, "failed to init wow: %d\n", ret); 1011762306a36Sopenharmony_ci goto err_free; 1011862306a36Sopenharmony_ci } 1011962306a36Sopenharmony_ci 1012062306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); 1012162306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 1012262306a36Sopenharmony_ci NL80211_EXT_FEATURE_SET_SCAN_DWELL); 1012362306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL); 1012462306a36Sopenharmony_ci 1012562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || 1012662306a36Sopenharmony_ci test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) 1012762306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 1012862306a36Sopenharmony_ci NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); 1012962306a36Sopenharmony_ci 1013062306a36Sopenharmony_ci if (ath10k_peer_stats_enabled(ar) || 1013162306a36Sopenharmony_ci test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map)) 1013262306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 1013362306a36Sopenharmony_ci NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 1013462306a36Sopenharmony_ci 1013562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_RTT_RESPONDER_ROLE, ar->wmi.svc_map)) 1013662306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 1013762306a36Sopenharmony_ci NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); 1013862306a36Sopenharmony_ci 1013962306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_TX_PWR_PER_PEER, ar->wmi.svc_map)) 1014062306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 1014162306a36Sopenharmony_ci NL80211_EXT_FEATURE_STA_TX_PWR); 1014262306a36Sopenharmony_ci 1014362306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_PEER_TID_CONFIGS_SUPPORT, ar->wmi.svc_map)) { 1014462306a36Sopenharmony_ci ar->hw->wiphy->tid_config_support.vif |= 1014562306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_NOACK) | 1014662306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_RETRY_SHORT) | 1014762306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_RETRY_LONG) | 1014862306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL) | 1014962306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE) | 1015062306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE); 1015162306a36Sopenharmony_ci 1015262306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, 1015362306a36Sopenharmony_ci ar->wmi.svc_map)) { 1015462306a36Sopenharmony_ci ar->hw->wiphy->tid_config_support.vif |= 1015562306a36Sopenharmony_ci BIT(NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL); 1015662306a36Sopenharmony_ci } 1015762306a36Sopenharmony_ci 1015862306a36Sopenharmony_ci ar->hw->wiphy->tid_config_support.peer = 1015962306a36Sopenharmony_ci ar->hw->wiphy->tid_config_support.vif; 1016062306a36Sopenharmony_ci ar->hw->wiphy->max_data_retry_count = ATH10K_MAX_RETRY_COUNT; 1016162306a36Sopenharmony_ci } else { 1016262306a36Sopenharmony_ci ar->ops->set_tid_config = NULL; 1016362306a36Sopenharmony_ci } 1016462306a36Sopenharmony_ci /* 1016562306a36Sopenharmony_ci * on LL hardware queues are managed entirely by the FW 1016662306a36Sopenharmony_ci * so we only advertise to mac we can do the queues thing 1016762306a36Sopenharmony_ci */ 1016862306a36Sopenharmony_ci ar->hw->queues = IEEE80211_MAX_QUEUES; 1016962306a36Sopenharmony_ci 1017062306a36Sopenharmony_ci /* vdev_ids are used as hw queue numbers. Make sure offchan tx queue is 1017162306a36Sopenharmony_ci * something that vdev_ids can't reach so that we don't stop the queue 1017262306a36Sopenharmony_ci * accidentally. 1017362306a36Sopenharmony_ci */ 1017462306a36Sopenharmony_ci ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1; 1017562306a36Sopenharmony_ci 1017662306a36Sopenharmony_ci switch (ar->running_fw->fw_file.wmi_op_version) { 1017762306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_MAIN: 1017862306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = ath10k_if_comb; 1017962306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1018062306a36Sopenharmony_ci ARRAY_SIZE(ath10k_if_comb); 1018162306a36Sopenharmony_ci ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); 1018262306a36Sopenharmony_ci break; 1018362306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_TLV: 1018462306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) { 1018562306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = 1018662306a36Sopenharmony_ci ath10k_tlv_qcs_if_comb; 1018762306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1018862306a36Sopenharmony_ci ARRAY_SIZE(ath10k_tlv_qcs_if_comb); 1018962306a36Sopenharmony_ci } else { 1019062306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = ath10k_tlv_if_comb; 1019162306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1019262306a36Sopenharmony_ci ARRAY_SIZE(ath10k_tlv_if_comb); 1019362306a36Sopenharmony_ci } 1019462306a36Sopenharmony_ci ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); 1019562306a36Sopenharmony_ci break; 1019662306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_10_1: 1019762306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_10_2: 1019862306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_10_2_4: 1019962306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb; 1020062306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1020162306a36Sopenharmony_ci ARRAY_SIZE(ath10k_10x_if_comb); 1020262306a36Sopenharmony_ci break; 1020362306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_10_4: 1020462306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; 1020562306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1020662306a36Sopenharmony_ci ARRAY_SIZE(ath10k_10_4_if_comb); 1020762306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_VDEV_DIFFERENT_BEACON_INTERVAL_SUPPORT, 1020862306a36Sopenharmony_ci ar->wmi.svc_map)) { 1020962306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = 1021062306a36Sopenharmony_ci ath10k_10_4_bcn_int_if_comb; 1021162306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1021262306a36Sopenharmony_ci ARRAY_SIZE(ath10k_10_4_bcn_int_if_comb); 1021362306a36Sopenharmony_ci } 1021462306a36Sopenharmony_ci break; 1021562306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_UNSET: 1021662306a36Sopenharmony_ci case ATH10K_FW_WMI_OP_VERSION_MAX: 1021762306a36Sopenharmony_ci WARN_ON(1); 1021862306a36Sopenharmony_ci ret = -EINVAL; 1021962306a36Sopenharmony_ci goto err_free; 1022062306a36Sopenharmony_ci } 1022162306a36Sopenharmony_ci 1022262306a36Sopenharmony_ci if (ar->hw_params.dynamic_sar_support) 1022362306a36Sopenharmony_ci ar->hw->wiphy->sar_capa = &ath10k_sar_capa; 1022462306a36Sopenharmony_ci 1022562306a36Sopenharmony_ci if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) 1022662306a36Sopenharmony_ci ar->hw->netdev_features = NETIF_F_HW_CSUM; 1022762306a36Sopenharmony_ci 1022862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED)) { 1022962306a36Sopenharmony_ci /* Init ath dfs pattern detector */ 1023062306a36Sopenharmony_ci ar->ath_common.debug_mask = ATH_DBG_DFS; 1023162306a36Sopenharmony_ci ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common, 1023262306a36Sopenharmony_ci NL80211_DFS_UNSET); 1023362306a36Sopenharmony_ci 1023462306a36Sopenharmony_ci if (!ar->dfs_detector) 1023562306a36Sopenharmony_ci ath10k_warn(ar, "failed to initialise DFS pattern detector\n"); 1023662306a36Sopenharmony_ci } 1023762306a36Sopenharmony_ci 1023862306a36Sopenharmony_ci ret = ath10k_mac_init_rd(ar); 1023962306a36Sopenharmony_ci if (ret) { 1024062306a36Sopenharmony_ci ath10k_err(ar, "failed to derive regdom: %d\n", ret); 1024162306a36Sopenharmony_ci goto err_dfs_detector_exit; 1024262306a36Sopenharmony_ci } 1024362306a36Sopenharmony_ci 1024462306a36Sopenharmony_ci /* Disable set_coverage_class for chipsets that do not support it. */ 1024562306a36Sopenharmony_ci if (!ar->hw_params.hw_ops->set_coverage_class) 1024662306a36Sopenharmony_ci ar->ops->set_coverage_class = NULL; 1024762306a36Sopenharmony_ci 1024862306a36Sopenharmony_ci ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, 1024962306a36Sopenharmony_ci ath10k_reg_notifier); 1025062306a36Sopenharmony_ci if (ret) { 1025162306a36Sopenharmony_ci ath10k_err(ar, "failed to initialise regulatory: %i\n", ret); 1025262306a36Sopenharmony_ci goto err_dfs_detector_exit; 1025362306a36Sopenharmony_ci } 1025462306a36Sopenharmony_ci 1025562306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_SPOOF_MAC_SUPPORT, ar->wmi.svc_map)) { 1025662306a36Sopenharmony_ci ar->hw->wiphy->features |= 1025762306a36Sopenharmony_ci NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; 1025862306a36Sopenharmony_ci } 1025962306a36Sopenharmony_ci 1026062306a36Sopenharmony_ci ar->hw->wiphy->cipher_suites = cipher_suites; 1026162306a36Sopenharmony_ci 1026262306a36Sopenharmony_ci /* QCA988x and QCA6174 family chips do not support CCMP-256, GCMP-128 1026362306a36Sopenharmony_ci * and GCMP-256 ciphers in hardware. Fetch number of ciphers supported 1026462306a36Sopenharmony_ci * from chip specific hw_param table. 1026562306a36Sopenharmony_ci */ 1026662306a36Sopenharmony_ci if (!ar->hw_params.n_cipher_suites || 1026762306a36Sopenharmony_ci ar->hw_params.n_cipher_suites > ARRAY_SIZE(cipher_suites)) { 1026862306a36Sopenharmony_ci ath10k_err(ar, "invalid hw_params.n_cipher_suites %d\n", 1026962306a36Sopenharmony_ci ar->hw_params.n_cipher_suites); 1027062306a36Sopenharmony_ci ar->hw_params.n_cipher_suites = 8; 1027162306a36Sopenharmony_ci } 1027262306a36Sopenharmony_ci ar->hw->wiphy->n_cipher_suites = ar->hw_params.n_cipher_suites; 1027362306a36Sopenharmony_ci 1027462306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 1027562306a36Sopenharmony_ci 1027662306a36Sopenharmony_ci ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; 1027762306a36Sopenharmony_ci 1027862306a36Sopenharmony_ci ret = ieee80211_register_hw(ar->hw); 1027962306a36Sopenharmony_ci if (ret) { 1028062306a36Sopenharmony_ci ath10k_err(ar, "failed to register ieee80211: %d\n", ret); 1028162306a36Sopenharmony_ci goto err_dfs_detector_exit; 1028262306a36Sopenharmony_ci } 1028362306a36Sopenharmony_ci 1028462306a36Sopenharmony_ci if (test_bit(WMI_SERVICE_PER_PACKET_SW_ENCRYPT, ar->wmi.svc_map)) { 1028562306a36Sopenharmony_ci ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); 1028662306a36Sopenharmony_ci ar->hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN); 1028762306a36Sopenharmony_ci } 1028862306a36Sopenharmony_ci 1028962306a36Sopenharmony_ci if (!ath_is_world_regd(&ar->ath_common.reg_world_copy) && 1029062306a36Sopenharmony_ci !ath_is_world_regd(&ar->ath_common.regulatory)) { 1029162306a36Sopenharmony_ci ret = regulatory_hint(ar->hw->wiphy, 1029262306a36Sopenharmony_ci ar->ath_common.regulatory.alpha2); 1029362306a36Sopenharmony_ci if (ret) 1029462306a36Sopenharmony_ci goto err_unregister; 1029562306a36Sopenharmony_ci } 1029662306a36Sopenharmony_ci 1029762306a36Sopenharmony_ci return 0; 1029862306a36Sopenharmony_ci 1029962306a36Sopenharmony_cierr_unregister: 1030062306a36Sopenharmony_ci ieee80211_unregister_hw(ar->hw); 1030162306a36Sopenharmony_ci 1030262306a36Sopenharmony_cierr_dfs_detector_exit: 1030362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) 1030462306a36Sopenharmony_ci ar->dfs_detector->exit(ar->dfs_detector); 1030562306a36Sopenharmony_ci 1030662306a36Sopenharmony_cierr_free: 1030762306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 1030862306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); 1030962306a36Sopenharmony_ci 1031062306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, NULL); 1031162306a36Sopenharmony_ci return ret; 1031262306a36Sopenharmony_ci} 1031362306a36Sopenharmony_ci 1031462306a36Sopenharmony_civoid ath10k_mac_unregister(struct ath10k *ar) 1031562306a36Sopenharmony_ci{ 1031662306a36Sopenharmony_ci ieee80211_unregister_hw(ar->hw); 1031762306a36Sopenharmony_ci 1031862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) 1031962306a36Sopenharmony_ci ar->dfs_detector->exit(ar->dfs_detector); 1032062306a36Sopenharmony_ci 1032162306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 1032262306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); 1032362306a36Sopenharmony_ci 1032462306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, NULL); 1032562306a36Sopenharmony_ci} 10326